From 54545640b0db7747137655f84bc67fd290ecb904 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 4 Sep 2009 11:45:52 -0700 Subject: Add back the RDF tone generator Tracking the rocket on the ground may be easier using tones than using the digital data stream, so we'll try that and see what we think. This reverts commit 3a3bfd471a868d546d83cdc431b53c8f5208edb9. Signed-off-by: Keith Packard --- src/ao_flight.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index be9b3bb6..2b062c13 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -227,6 +227,7 @@ ao_flight(void) /* Turn on telemetry system */ + ao_rdf_set(1); ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD); ao_flight_state = ao_flight_pad; @@ -277,6 +278,9 @@ ao_flight(void) /* Increase telemetry rate */ ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_FLIGHT); + /* disable RDF beacon */ + ao_rdf_set(0); + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); break; } @@ -356,6 +360,9 @@ ao_flight(void) /* slow down the ADC sample rate */ ao_timer_set_adc_interval(10); + /* Enable RDF beacon */ + ao_rdf_set(1); + /* * Start recording min/max accel and pres for a while * to figure out when the rocket has landed -- cgit v1.2.3 From fee46389b70a624ab5b1128a8b4c3083c7747bcb Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 4 Sep 2009 11:46:55 -0700 Subject: Make RDF beacon only run on pad and after landing. It's pretty much impossible to RDF the rocket during flight, and it interferes with the telemetry data stream. Leave it enabled on the pad so that radios can be tested, and then re-enable it once the rocket has landed. This patch also turns the rdf 'on' time into a parameter so it can be changed, and then sets that parameter to 500ms, once every 5 seconds. Signed-off-by: Keith Packard --- src/ao.h | 2 +- src/ao_flight.c | 5 ++--- src/ao_radio.c | 18 +++++++++++++++--- src/ao_telemetry.c | 9 ++++++--- 4 files changed, 24 insertions(+), 10 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao.h b/src/ao.h index 37f21508..4116be65 100644 --- a/src/ao.h +++ b/src/ao.h @@ -800,7 +800,7 @@ void ao_radio_recv(__xdata struct ao_radio_recv *recv) __reentrant; void -ao_radio_rdf(void); +ao_radio_rdf(int ms); void ao_radio_rdf_abort(void); diff --git a/src/ao_flight.c b/src/ao_flight.c index 2b062c13..ec89e7c2 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -360,9 +360,6 @@ ao_flight(void) /* slow down the ADC sample rate */ ao_timer_set_adc_interval(10); - /* Enable RDF beacon */ - ao_rdf_set(1); - /* * Start recording min/max accel and pres for a while * to figure out when the rocket has landed @@ -445,6 +442,8 @@ ao_flight(void) /* turn off the ADC capture */ ao_timer_set_adc_interval(0); + /* Enable RDF beacon */ + ao_rdf_set(1); ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); } diff --git a/src/ao_radio.c b/src/ao_radio.c index e4d42c6c..76fa3e5d 100644 --- a/src/ao_radio.c +++ b/src/ao_radio.c @@ -223,7 +223,6 @@ static __code uint8_t rdf_setup[] = { (RDF_DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)), /* packet length */ - RF_PKTLEN_OFF, RDF_PACKET_LEN, RF_PKTCTRL1_OFF, ((1 << PKTCTRL1_PQT_SHIFT)| PKTCTRL1_ADR_CHK_NONE), RF_PKTCTRL0_OFF, (RF_PKTCTRL0_PKT_FORMAT_NORMAL| @@ -324,19 +323,32 @@ __xdata ao_radio_rdf_running; __xdata ao_radio_rdf_value = 0x55; void -ao_radio_rdf(void) +ao_radio_rdf(int ms) { uint8_t i; + uint8_t pkt_len; ao_mutex_get(&ao_radio_mutex); ao_radio_idle(); ao_radio_rdf_running = 1; for (i = 0; i < sizeof (rdf_setup); i += 2) RF[rdf_setup[i]] = rdf_setup[i+1]; + /* + * Compute the packet length as follows: + * + * 2000 bps (for a 1kHz tone) + * so, for 'ms' milliseconds, we need + * 2 * ms bits, or ms / 4 bytes + */ + if (ms > (255 * 4)) + ms = 255 * 4; + pkt_len = ms >> 2; + RF[RF_PKTLEN_OFF] = pkt_len; + ao_dma_set_transfer(ao_radio_dma, &ao_radio_rdf_value, &RFDXADDR, - RDF_PACKET_LEN, + pkt_len, DMA_CFG0_WORDSIZE_8 | DMA_CFG0_TMODE_SINGLE | DMA_CFG0_TRIGGER_RADIO, diff --git a/src/ao_telemetry.c b/src/ao_telemetry.c index 7eefee3c..d52e589c 100644 --- a/src/ao_telemetry.c +++ b/src/ao_telemetry.c @@ -21,7 +21,8 @@ __xdata uint16_t ao_telemetry_interval = 0; __xdata uint8_t ao_rdf = 0; __xdata uint16_t ao_rdf_time; -#define AO_RDF_INTERVAL AO_SEC_TO_TICKS(3) +#define AO_RDF_INTERVAL_TICKS AO_SEC_TO_TICKS(5) +#define AO_RDF_LENGTH_MS 500 void ao_telemetry(void) @@ -51,8 +52,8 @@ ao_telemetry(void) if (ao_rdf && (int16_t) (ao_time() - ao_rdf_time) >= 0) { - ao_rdf_time = ao_time() + AO_RDF_INTERVAL; - ao_radio_rdf(); + ao_rdf_time = ao_time() + AO_RDF_INTERVAL_TICKS; + ao_radio_rdf(AO_RDF_LENGTH_MS); ao_delay(ao_telemetry_interval); } } @@ -71,6 +72,8 @@ ao_rdf_set(uint8_t rdf) ao_rdf = rdf; if (rdf == 0) ao_radio_rdf_abort(); + else + ao_rdf_time = ao_time(); } __xdata struct ao_task ao_telemetry_task; -- cgit v1.2.3 From d709a0688eff84e25e24d755850ef045d6b0c3de Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 16 Oct 2009 12:56:45 +0900 Subject: Save some DSEG space by marking cmd functions __reentrant __reentrant causes the compiler to place args and locals on the stack instead of in the data segment. Signed-off-by: Keith Packard --- src/ao_adc.c | 4 ++-- src/ao_ee.c | 20 ++++++++++---------- src/ao_flight.c | 2 +- src/ao_gps_sirf.c | 2 +- src/ao_log.c | 2 +- src/ao_usb.c | 2 +- 6 files changed, 16 insertions(+), 16 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao_adc.c b/src/ao_adc.c index 26209dcf..d9672671 100644 --- a/src/ao_adc.c +++ b/src/ao_adc.c @@ -61,9 +61,9 @@ ao_adc_isr(void) interrupt 1 } static void -ao_adc_dump(void) +ao_adc_dump(void) __reentrant { - __xdata struct ao_adc packet; + static __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, diff --git a/src/ao_ee.c b/src/ao_ee.c index 9b6db234..26cfb7fd 100644 --- a/src/ao_ee.c +++ b/src/ao_ee.c @@ -351,11 +351,11 @@ ao_ee_read_config(uint8_t *buf, uint16_t len) __reentrant } static void -ee_dump(void) +ee_dump(void) __reentrant { - __xdata uint8_t b; - __xdata uint16_t block; - __xdata uint8_t i; + uint8_t b; + uint16_t block; + uint8_t i; ao_cmd_hex(); block = ao_cmd_lex_i; @@ -377,13 +377,13 @@ ee_dump(void) } static void -ee_store(void) +ee_store(void) __reentrant { - __xdata uint16_t block; - __xdata uint8_t i; - __xdata uint16_t len; - __xdata uint8_t b; - __xdata uint32_t addr; + uint16_t block; + uint8_t i; + uint16_t len; + uint8_t b; + uint32_t addr; ao_cmd_hex(); block = ao_cmd_lex_i; diff --git a/src/ao_flight.c b/src/ao_flight.c index ec89e7c2..c43d0711 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -458,7 +458,7 @@ ao_flight(void) #define AO_VEL_COUNT_TO_MS(count) ((int16_t) ((count) / 2700)) static void -ao_flight_status(void) +ao_flight_status(void) __reentrant { printf("STATE: %7s accel: %d speed: %d altitude: %d main: %d\n", ao_state_names[ao_flight_state], diff --git a/src/ao_gps_sirf.c b/src/ao_gps_sirf.c index 2b3a5178..58438760 100644 --- a/src/ao_gps_sirf.c +++ b/src/ao_gps_sirf.c @@ -302,7 +302,7 @@ static const char ao_gps_set_message_rate[] = { }; void -ao_sirf_set_message_rate(uint8_t msg, uint8_t rate) +ao_sirf_set_message_rate(uint8_t msg, uint8_t rate) __reentrant { uint16_t cksum = 0x00a6; uint8_t i; diff --git a/src/ao_log.c b/src/ao_log.c index 7945ace4..b2bfbd6f 100644 --- a/src/ao_log.c +++ b/src/ao_log.c @@ -192,7 +192,7 @@ ao_log_stop(void) } static void -dump_log(void) +dump_log(void) __reentrant { uint8_t more; diff --git a/src/ao_usb.c b/src/ao_usb.c index 22665725..8926b9ca 100644 --- a/src/ao_usb.c +++ b/src/ao_usb.c @@ -72,7 +72,7 @@ uint8_t * __xdata ao_usb_ep0_in_data; __xdata uint8_t ao_usb_ep0_in_len; __xdata uint8_t ao_usb_ep0_in_buf[2]; __xdata uint8_t ao_usb_ep0_out_len; -__xdata uint8_t *__data ao_usb_ep0_out_data; +__xdata uint8_t *__xdata ao_usb_ep0_out_data; __xdata uint8_t ao_usb_configuration; /* Send an IN data packet */ -- cgit v1.2.3 From ca5d323a3d206050d95f52a61e92c69e1f54e7b5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 1 Nov 2009 20:57:03 -0800 Subject: Enable packet-based communcation to command processor This splits the packet code into master/slave halves and hooks the slave side up to the getchar/putchar/flush logic in ao_stdio.c Signed-off-by: Keith Packard --- src/Makefile | 2 + src/ao.h | 53 ++++++++++++++- src/ao_flight.c | 4 +- src/ao_flight_test.c | 1 + src/ao_packet.c | 177 +++++++++++-------------------------------------- src/ao_packet_master.c | 142 +++++++++++++++++++++++++++++++++++++++ src/ao_packet_slave.c | 58 ++++++++++++++++ src/ao_stdio.c | 44 ++++++++++-- src/ao_teledongle.c | 3 +- src/ao_telemetrum.c | 2 +- src/ao_usb.c | 28 +++++--- 11 files changed, 356 insertions(+), 158 deletions(-) create mode 100644 src/ao_packet_master.c create mode 100644 src/ao_packet_slave.c (limited to 'src/ao_flight.c') diff --git a/src/Makefile b/src/Makefile index 4575f443..d984e9dc 100644 --- a/src/Makefile +++ b/src/Makefile @@ -45,6 +45,7 @@ ALTOS_DRIVER_SRC = \ TELE_COMMON_SRC = \ ao_gps_print.c \ ao_packet.c \ + ao_packet_slave.c \ ao_state.c # @@ -52,6 +53,7 @@ TELE_COMMON_SRC = \ # TELE_RECEIVER_SRC =\ ao_monitor.c \ + ao_packet_master.c \ ao_rssi.c # diff --git a/src/ao.h b/src/ao.h index aeceb870..65a594c0 100644 --- a/src/ao.h +++ b/src/ao.h @@ -106,6 +106,7 @@ ao_start_scheduler(void); #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 */ +#define AO_PANIC_STDIO 7 /* Too many stdio handlers registered */ /* Stop the operating system, beeping and blinking the reason */ void @@ -873,9 +874,24 @@ ao_monitor_init(uint8_t led, uint8_t monitoring) __reentrant; * ao_stdio.c */ +#define AO_READ_AGAIN ((char) -1) + +struct ao_stdio { + char (*pollchar)(void); + void (*putchar)(char c) __reentrant; + void (*flush)(void); +}; + void flush(void); +extern __xdata uint8_t ao_stdin_ready; + +void +ao_add_stdio(char (*pollchar)(void), + void (*putchar)(char) __reentrant, + void (*flush)(void)); + /* * ao_ignite.c */ @@ -997,7 +1013,42 @@ struct ao_packet_recv { uint8_t status; }; +extern __xdata struct ao_packet_recv ao_rx_packet; +extern __xdata struct ao_packet ao_tx_packet; +extern __xdata struct ao_task ao_packet_task; +extern __xdata uint8_t ao_packet_enable; +extern __xdata uint8_t ao_packet_master_sleeping; +extern __pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used; + +void +ao_packet_send(void); + +uint8_t +ao_packet_recv(void); + +void +ao_packet_flush(void); + +void +ao_packet_putchar(char c) __reentrant; + +char +ao_packet_pollchar(void) __critical; + +/* ao_packet_master.c */ + +void +ao_packet_master_init(void); + +/* ao_packet_slave.c */ + +void +ao_packet_slave_start(void); + +void +ao_packet_slave_stop(void); + void -ao_packet_init(void); +ao_packet_slave_init(void); #endif /* _AO_H_ */ diff --git a/src/ao_flight.c b/src/ao_flight.c index c43d0711..e91a5daa 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -235,9 +235,9 @@ ao_flight(void) } else { ao_flight_state = ao_flight_idle; - /* Turn on the Green LED in idle mode + /* Turn on packet system in idle mode */ - ao_led_on(AO_LED_GREEN); + ao_packet_slave_start(); ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); } /* signal successful initialization by turning off the LED */ diff --git a/src/ao_flight_test.c b/src/ao_flight_test.c index 9fcb00c2..83c63016 100644 --- a/src/ao_flight_test.c +++ b/src/ao_flight_test.c @@ -69,6 +69,7 @@ uint8_t ao_adc_head; #define ao_usb_disable() #define ao_telemetry_set_interval(x) #define ao_rdf_set(rdf) +#define ao_packet_slave_start() enum ao_igniter { ao_igniter_drogue = 0, diff --git a/src/ao_packet.c b/src/ao_packet.c index ba559512..3ce7e9ab 100644 --- a/src/ao_packet.c +++ b/src/ao_packet.c @@ -17,16 +17,17 @@ #include "ao.h" -static __xdata struct ao_packet_recv rx_packet; -static __xdata struct ao_packet tx_packet; +__xdata struct ao_packet_recv ao_rx_packet; +__xdata struct ao_packet ao_tx_packet; +__pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used; + static __xdata char tx_data[AO_PACKET_MAX]; static __xdata char rx_data[AO_PACKET_MAX]; -static __pdata uint8_t rx_len, rx_used, tx_used; static __pdata uint8_t rx_seq; -static __xdata struct ao_task ao_packet_task; -static __xdata uint8_t ao_packet_enable; -static __xdata uint8_t ao_packet_master_sleeping; +__xdata struct ao_task ao_packet_task; +__xdata uint8_t ao_packet_enable; +__xdata uint8_t ao_packet_master_sleeping; void ao_packet_send(void) @@ -34,18 +35,18 @@ ao_packet_send(void) ao_led_on(AO_LED_RED); ao_config_get(); ao_mutex_get(&ao_radio_mutex); - if (tx_used && tx_packet.len == 0) { - memcpy(&tx_packet.d, tx_data, tx_used); - tx_packet.len = tx_used; - tx_packet.seq++; - tx_used = 0; + if (ao_packet_tx_used && ao_tx_packet.len == 0) { + memcpy(&ao_tx_packet.d, tx_data, ao_packet_tx_used); + ao_tx_packet.len = ao_packet_tx_used; + ao_tx_packet.seq++; + ao_packet_tx_used = 0; ao_wakeup(&tx_data); } ao_radio_idle(); ao_radio_done = 0; RF_CHANNR = ao_config.radio_channel; ao_dma_set_transfer(ao_radio_dma, - &tx_packet, + &ao_tx_packet, &RFDXADDR, sizeof (struct ao_packet), DMA_CFG0_WORDSIZE_8 | @@ -74,7 +75,7 @@ ao_packet_recv(void) RF_CHANNR = ao_config.radio_channel; ao_dma_set_transfer(ao_radio_dma, &RFDXADDR, - &rx_packet, + &ao_rx_packet, sizeof (struct ao_packet_recv), DMA_CFG0_WORDSIZE_8 | DMA_CFG0_TMODE_SINGLE | @@ -92,160 +93,60 @@ ao_packet_recv(void) ao_led_off(AO_LED_GREEN); if (dma_done & AO_DMA_DONE) { - if (!(rx_packet.status & PKT_APPEND_STATUS_1_CRC_OK)) + if (!(ao_rx_packet.status & PKT_APPEND_STATUS_1_CRC_OK)) return AO_DMA_ABORTED; - if (rx_packet.packet.len == AO_PACKET_SYN) { - rx_seq = rx_packet.packet.seq; - tx_packet.seq = rx_packet.packet.ack; - tx_packet.ack = rx_seq; - } else if (rx_packet.packet.len) { - if (rx_packet.packet.seq == (uint8_t) (rx_seq + (uint8_t) 1) && rx_used == rx_len) { -#if 0 - printf ("rx len %3d seq %3d ack %3d\n", - rx_packet.packet.len, - rx_packet.packet.seq, - rx_packet.packet.ack); - flush(); -#endif - memcpy(rx_data, rx_packet.packet.d, rx_packet.packet.len); - rx_used = 0; - rx_len = rx_packet.packet.len; - rx_seq = rx_packet.packet.seq; - tx_packet.ack = rx_seq; - ao_wakeup(&rx_data); + if (ao_rx_packet.packet.len == AO_PACKET_SYN) { + rx_seq = ao_rx_packet.packet.seq; + ao_tx_packet.seq = ao_rx_packet.packet.ack; + ao_tx_packet.ack = rx_seq; + } else if (ao_rx_packet.packet.len) { + if (ao_rx_packet.packet.seq == (uint8_t) (rx_seq + (uint8_t) 1) && ao_packet_rx_used == ao_packet_rx_len) { + memcpy(rx_data, ao_rx_packet.packet.d, ao_rx_packet.packet.len); + ao_packet_rx_used = 0; + ao_packet_rx_len = ao_rx_packet.packet.len; + rx_seq = ao_rx_packet.packet.seq; + ao_tx_packet.ack = rx_seq; + ao_wakeup(&ao_stdin_ready); } } - if (rx_packet.packet.ack == tx_packet.seq) { - tx_packet.len = 0; - ao_wakeup(&tx_packet); + if (ao_rx_packet.packet.ack == ao_tx_packet.seq) { + ao_tx_packet.len = 0; + ao_wakeup(&ao_tx_packet); } } return dma_done; } -void -ao_packet_slave(void) -{ - ao_radio_set_packet(); - tx_packet.addr = ao_serial_number; - tx_packet.len = AO_PACKET_SYN; - while (ao_packet_enable) { - ao_packet_recv(); - ao_packet_send(); - } - ao_exit(); -} - -/* Thread for the master side of the packet link */ - -void -ao_packet_master(void) -{ - uint8_t status; - - ao_radio_set_packet(); - tx_packet.addr = ao_serial_number; - tx_packet.len = AO_PACKET_SYN; - while (ao_packet_enable) { - ao_packet_send(); - ao_alarm(AO_MS_TO_TICKS(100)); - status = ao_packet_recv(); - if (status & AO_DMA_DONE) { - /* if we can transmit data, do so */ - if (tx_used && tx_packet.len == 0) - continue; - ao_packet_master_sleeping = 1; - ao_delay(AO_MS_TO_TICKS(1000)); - ao_packet_master_sleeping = 0; - } - } - ao_exit(); -} - void ao_packet_flush(void) { /* If there is data to send, and this is the master, * then poke the master to send all queued data */ - if (tx_used && ao_packet_master_sleeping) + if (ao_packet_tx_used && ao_packet_master_sleeping) ao_wake_task(&ao_packet_task); } void -ao_packet_putchar(char c) +ao_packet_putchar(char c) __reentrant { - while (tx_used == AO_PACKET_MAX && ao_packet_enable) { + while (ao_packet_tx_used == AO_PACKET_MAX && ao_packet_enable) { ao_packet_flush(); ao_sleep(&tx_data); } if (ao_packet_enable) - tx_data[tx_used++] = c; + tx_data[ao_packet_tx_used++] = c; } char -ao_packet_getchar(void) __critical +ao_packet_pollchar(void) __critical { - while (rx_used == rx_len && ao_packet_enable) { - /* poke the master to get more data */ - if (ao_packet_master_sleeping) - ao_wake_task(&ao_packet_task); - ao_sleep(&rx_data); - } - if (!ao_packet_enable) - return 0; + return AO_READ_AGAIN; - return rx_data[rx_used++]; -} - -static void -ao_packet_echo(void) __reentrant -{ - uint8_t c; - while (ao_packet_enable) { - c = ao_packet_getchar(); - if (ao_packet_enable) { - putchar(c); - if (c == (uint8_t) '\n' || c == (uint8_t) '\r') - flush(); - } - } - ao_exit(); -} - -static __xdata struct ao_task ao_packet_echo_task; - -static void -ao_packet_forward(void) __reentrant -{ - char c; - ao_packet_enable = 1; - ao_cmd_white(); - - if (ao_cmd_lex_c == 'm') - ao_add_task(&ao_packet_task, ao_packet_master, "master"); - else - ao_add_task(&ao_packet_task, ao_packet_slave, "slave"); - ao_add_task(&ao_packet_echo_task, ao_packet_echo, "echo"); - while ((c = getchar()) != '~') - ao_packet_putchar(c); - ao_packet_enable = 0; - ao_radio_abort(); - while (ao_packet_echo_task.wchan || ao_packet_task.wchan) { - ao_wake_task(&ao_packet_echo_task); - ao_wake_task(&ao_packet_task); - } -} - -__code struct ao_cmds ao_packet_cmds[] = { - { 'p', ao_packet_forward, "p {m|s} Remote packet link. m=master, s=slave" }, - { 0, ao_packet_forward, NULL }, -}; + if (ao_packet_rx_used == ao_packet_rx_len) + return AO_READ_AGAIN; -void -ao_packet_init(void) -{ - ao_cmd_register(&ao_packet_cmds[0]); + return rx_data[ao_packet_rx_used++]; } diff --git a/src/ao_packet_master.c b/src/ao_packet_master.c new file mode 100644 index 00000000..2751f414 --- /dev/null +++ b/src/ao_packet_master.c @@ -0,0 +1,142 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +static char +ao_packet_getchar(void) +{ + char c; + while ((c = ao_packet_pollchar()) == AO_READ_AGAIN) + { + if (!ao_packet_enable) + break; + if (ao_packet_master_sleeping) + ao_wake_task(&ao_packet_task); + ao_sleep(&ao_stdin_ready); + } + return c; +} + +static void +ao_packet_echo(void) __reentrant +{ + uint8_t c; + while (ao_packet_enable) { + c = ao_packet_getchar(); + if (ao_packet_enable) + putchar(c); + } + ao_exit(); +} + +static __xdata struct ao_task ao_packet_echo_task; +static __xdata uint16_t ao_packet_master_delay; +static __xdata uint16_t ao_packet_master_time; + +#define AO_PACKET_MASTER_DELAY_SHORT AO_MS_TO_TICKS(100) +#define AO_PACKET_MASTER_DELAY_LONG AO_MS_TO_TICKS(1000) +#define AO_PACKET_MASTER_DELAY_TIMEOUT AO_MS_TO_TICKS(2000) + +static void +ao_packet_master_busy(void) +{ + ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT; + ao_packet_master_time = ao_time(); +} + +static void +ao_packet_master_check_busy(void) +{ + int16_t idle; + if (ao_packet_master_delay != AO_PACKET_MASTER_DELAY_SHORT) + return; + idle = (int16_t) (ao_time() - ao_packet_master_time); + + if (idle > AO_PACKET_MASTER_DELAY_TIMEOUT) + ao_packet_master_delay = AO_PACKET_MASTER_DELAY_LONG; +} + +void +ao_packet_master(void) +{ + uint8_t status; + + ao_radio_set_packet(); + ao_tx_packet.addr = ao_serial_number; + ao_tx_packet.len = AO_PACKET_SYN; + ao_packet_master_time = ao_time(); + ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT; + while (ao_packet_enable) { + ao_packet_send(); + if (ao_tx_packet.len) + ao_packet_master_busy(); + ao_packet_master_check_busy(); + ao_alarm(ao_packet_master_delay); + status = ao_packet_recv(); + if (status & AO_DMA_DONE) { + /* if we can transmit data, do so */ + if (ao_packet_tx_used && ao_tx_packet.len == 0) + continue; + if (ao_rx_packet.packet.len) + ao_packet_master_busy(); + else + flush(); + ao_packet_master_sleeping = 1; + ao_delay(ao_packet_master_delay); + ao_packet_master_sleeping = 0; + } + } + ao_exit(); +} + +static void +ao_packet_forward(void) __reentrant +{ + char c; + ao_packet_enable = 1; + ao_cmd_white(); + + flush(); + ao_set_monitor(0); + ao_add_task(&ao_packet_task, ao_packet_master, "master"); + ao_add_task(&ao_packet_echo_task, ao_packet_echo, "echo"); + while ((c = getchar()) != '~') { + if (c == '\r') c = '\n'; + ao_packet_putchar(c); + } + ao_packet_enable = 0; + ao_radio_abort(); + while (ao_packet_echo_task.wchan || ao_packet_task.wchan) { + ao_wake_task(&ao_packet_echo_task); + ao_wake_task(&ao_packet_task); + ao_yield(); + } +} + + + +__code struct ao_cmds ao_packet_master_cmds[] = { + { 'p', ao_packet_forward, "p Remote packet link." }, + { 0, ao_packet_forward, NULL }, +}; + +void +ao_packet_master_init(void) +{ + ao_cmd_register(&ao_packet_master_cmds[0]); +} diff --git a/src/ao_packet_slave.c b/src/ao_packet_slave.c new file mode 100644 index 00000000..ba5ad1c1 --- /dev/null +++ b/src/ao_packet_slave.c @@ -0,0 +1,58 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_packet_slave(void) +{ + ao_radio_set_packet(); + ao_tx_packet.addr = ao_serial_number; + ao_tx_packet.len = AO_PACKET_SYN; + while (ao_packet_enable) { + ao_packet_recv(); + ao_packet_send(); + } + ao_exit(); +} + +void +ao_packet_slave_start(void) +{ + ao_packet_enable = 1; + ao_add_task(&ao_packet_task, ao_packet_slave, "slave"); +} + +void +ao_packet_slave_stop(void) +{ + ao_packet_enable = 0; + ao_radio_abort(); + while (ao_packet_task.wchan) { + ao_wake_task(&ao_packet_task); + ao_yield(); + } + ao_radio_set_telemetry(); +} + +void +ao_packet_slave_init(void) +{ + ao_add_stdio(ao_packet_pollchar, + ao_packet_putchar, + ao_packet_flush); +} diff --git a/src/ao_stdio.c b/src/ao_stdio.c index fb8ce093..7bc416e1 100644 --- a/src/ao_stdio.c +++ b/src/ao_stdio.c @@ -21,22 +21,56 @@ * Basic I/O functions to support SDCC stdio package */ +#define AO_NUM_STDIOS 2 + +static __xdata struct ao_stdio stdios[AO_NUM_STDIOS]; +static __data int8_t ao_cur_stdio; +static __data int8_t ao_num_stdios; + void putchar(char c) { if (c == '\n') - ao_usb_putchar('\r'); - ao_usb_putchar(c); + (*stdios[ao_cur_stdio].putchar)('\r'); + (*stdios[ao_cur_stdio].putchar)(c); } void flush(void) { - ao_usb_flush(); + stdios[ao_cur_stdio].flush(); } +__xdata uint8_t ao_stdin_ready; + char -getchar(void) +getchar(void) __reentrant +{ + char c; + int8_t stdio = ao_cur_stdio; + + for (;;) { + c = stdios[stdio].pollchar(); + if (c != AO_READ_AGAIN) + break; + if (++stdio == ao_num_stdios) + stdio = 0; + if (stdio == ao_cur_stdio) + ao_sleep(&ao_stdin_ready); + } + ao_cur_stdio = stdio; + return c; +} + +void +ao_add_stdio(char (*pollchar)(void), + void (*putchar)(char), + void (*flush)(void)) { - return ao_usb_getchar(); + if (ao_num_stdios == AO_NUM_STDIOS) + ao_panic(AO_PANIC_STDIO); + stdios[ao_num_stdios].pollchar = pollchar; + stdios[ao_num_stdios].putchar = putchar; + stdios[ao_num_stdios].flush = flush; + ao_num_stdios++; } diff --git a/src/ao_teledongle.c b/src/ao_teledongle.c index 98642180..e4828d80 100644 --- a/src/ao_teledongle.c +++ b/src/ao_teledongle.c @@ -33,7 +33,8 @@ main(void) ao_monitor_init(AO_LED_GREEN, TRUE); ao_rssi_init(AO_LED_RED); ao_radio_init(); - ao_packet_init(); + ao_packet_slave_init(); + ao_packet_master_init(); ao_config_init(); ao_start_scheduler(); } diff --git a/src/ao_telemetrum.c b/src/ao_telemetrum.c index 07737f30..5250078e 100644 --- a/src/ao_telemetrum.c +++ b/src/ao_telemetrum.c @@ -40,7 +40,7 @@ main(void) ao_gps_report_init(); ao_telemetry_init(); ao_radio_init(); - ao_packet_init(); + ao_packet_slave_init(); ao_igniter_init(); ao_config_init(); ao_start_scheduler(); diff --git a/src/ao_usb.c b/src/ao_usb.c index 8926b9ca..daca71a7 100644 --- a/src/ao_usb.c +++ b/src/ao_usb.c @@ -53,7 +53,7 @@ ao_usb_isr(void) interrupt 6 ao_wakeup(&ao_usb_in_bytes); if (USBOIF & (1 << AO_USB_OUT_EP)) - ao_wakeup(&ao_usb_out_bytes); + ao_wakeup(&ao_stdin_ready); if (USBCIF & USBCIF_RSTIF) ao_usb_set_interrupts(); @@ -360,7 +360,7 @@ ao_usb_flush(void) __critical } void -ao_usb_putchar(char c) __critical +ao_usb_putchar(char c) __critical __reentrant { if (!ao_usb_running) return; @@ -374,16 +374,13 @@ ao_usb_putchar(char c) __critical } char -ao_usb_getchar(void) __critical +ao_usb_pollchar(void) __critical { - __xdata char c; + char c; while (ao_usb_out_bytes == 0) { - for (;;) { - USBINDEX = AO_USB_OUT_EP; - if ((USBCSOL & USBCSOL_OUTPKT_RDY) != 0) - break; - ao_sleep(&ao_usb_out_bytes); - } + USBINDEX = AO_USB_OUT_EP; + if ((USBCSOL & USBCSOL_OUTPKT_RDY) == 0) + return AO_READ_AGAIN; ao_usb_out_bytes = (USBCNTH << 8) | USBCNTL; } --ao_usb_out_bytes; @@ -395,6 +392,16 @@ ao_usb_getchar(void) __critical return c; } +char +ao_usb_getchar(void) +{ + char c; + + while ((c = ao_usb_pollchar()) == AO_READ_AGAIN) + ao_sleep(&ao_stdin_ready); + return c; +} + void ao_usb_enable(void) { @@ -438,4 +445,5 @@ ao_usb_init(void) ao_usb_enable(); ao_add_task(&ao_usb_task, ao_usb_ep0, "usb"); + ao_add_stdio(ao_usb_pollchar, ao_usb_putchar, ao_usb_flush); } -- cgit v1.2.3 From 144db05f6b286a0450d486f69ce192632a2c0656 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Nov 2009 21:38:18 -0800 Subject: Add two-point accelerometer calibration. Calibration now uses two values, one upside right and the other upside down instead of a single horizontal value. This allows the use of other accelerometers and compensates for variations in the divider circuit to provide more accurate data. --- debian/rules | 2 +- src/ao.h | 10 +++++---- src/ao_config.c | 61 +++++++++++++++++++++++++++++++++++++--------------- src/ao_flight.c | 46 +++++++++++++++++++-------------------- src/ao_flight_test.c | 7 ++++-- 5 files changed, 79 insertions(+), 47 deletions(-) (limited to 'src/ao_flight.c') diff --git a/debian/rules b/debian/rules index ac594c07..260ba773 100755 --- a/debian/rules +++ b/debian/rules @@ -9,7 +9,7 @@ DEB_VERSION := $(shell git describe | tr - +) prebuild: git-dch --release --new-version=$(DEB_VERSION) git log > ChangeLog - git commit ChangeLog debian/changelog \ + git commit -n ChangeLog debian/changelog \ -m "update changelogs for Debian build" git tag debian/$(DEB_VERSION) git push --tags origin master diff --git a/src/ao.h b/src/ao.h index 4cceefe1..22e8785f 100644 --- a/src/ao.h +++ b/src/ao.h @@ -117,8 +117,9 @@ ao_panic(uint8_t reason); */ /* Our timer runs at 100Hz */ -#define AO_MS_TO_TICKS(ms) ((ms) / 10) -#define AO_SEC_TO_TICKS(s) ((s) * 100) +#define AO_HERTZ 100 +#define AO_MS_TO_TICKS(ms) ((ms) / (1000 / AO_HERTZ)) +#define AO_SEC_TO_TICKS(s) ((s) * AO_HERTZ) /* Returns the current time in ticks */ uint16_t @@ -928,16 +929,17 @@ ao_igniter_init(void); */ #define AO_CONFIG_MAJOR 1 -#define AO_CONFIG_MINOR 1 +#define AO_CONFIG_MINOR 2 struct ao_config { uint8_t major; uint8_t minor; uint16_t main_deploy; - int16_t accel_zero_g; + int16_t accel_plus_g; uint8_t radio_channel; char callsign[AO_MAX_CALLSIGN + 1]; uint8_t apogee_delay; + int16_t accel_minus_g; }; extern __xdata struct ao_config ao_config; diff --git a/src/ao_config.c b/src/ao_config.c index 021fb6f6..85fcff8c 100644 --- a/src/ao_config.c +++ b/src/ao_config.c @@ -45,7 +45,8 @@ _ao_config_get(void) ao_config.minor = AO_CONFIG_MINOR; ao_config.main_deploy = AO_CONFIG_DEFAULT_MAIN_DEPLOY; ao_config.radio_channel = AO_CONFIG_DEFAULT_RADIO_CHANNEL; - ao_config.accel_zero_g = AO_CONFIG_DEFAULT_ACCEL_ZERO_G; + ao_config.accel_plus_g = 0; + ao_config.accel_minus_g = 0; memset(&ao_config.callsign, '\0', sizeof (ao_config.callsign)); memcpy(&ao_config.callsign, AO_CONFIG_DEFAULT_CALLSIGN, sizeof(AO_CONFIG_DEFAULT_CALLSIGN) - 1); @@ -53,9 +54,14 @@ _ao_config_get(void) ao_config_dirty = 1; } if (ao_config.minor < AO_CONFIG_MINOR) { - /* Fixups for major version 1 */ + /* Fixups for mior version 1 */ if (ao_config.minor < 1) ao_config.apogee_delay = AO_CONFIG_DEFAULT_APOGEE_DELAY; + /* Fixupes for minor version 2 */ + if (ao_config.minor < 2) { + ao_config.accel_plus_g = 0; + ao_config.accel_minus_g = 0; + } ao_config.minor = AO_CONFIG_MINOR; ao_config_dirty = 1; } @@ -152,23 +158,28 @@ ao_config_main_deploy_set(void) __reentrant } void -ao_config_accel_zero_g_show(void) __reentrant +ao_config_accel_calibrate_show(void) __reentrant { - printf("Accel zero g point: %d\n", - ao_config.accel_zero_g); + printf("Accel cal +1g: %d -1g: %d\n", + ao_config.accel_plus_g, ao_config.accel_minus_g); } -#define ZERO_G_SAMPLES 1000 +#define ACCEL_CALIBRATE_SAMPLES 1024 +#define ACCEL_CALIBRATE_SHIFT 10 static int16_t -ao_config_accel_zero_g_auto(void) __reentrant +ao_config_accel_calibrate_auto(char *orientation) __reentrant { uint16_t i; int32_t accel_total; uint8_t cal_adc_ring; - puts("Calibrating accelerometer..."); flush(); - i = ZERO_G_SAMPLES; + printf("Orient %s and press a key...", orientation); + flush(); + (void) getchar(); + puts("\r\n"); flush(); + puts("Calibrating..."); flush(); + i = ACCEL_CALIBRATE_SAMPLES; accel_total = 0; cal_adc_ring = ao_adc_head; while (i) { @@ -179,22 +190,38 @@ ao_config_accel_zero_g_auto(void) __reentrant i--; } } - return (int16_t) (accel_total / ZERO_G_SAMPLES); + return accel_total >> ACCEL_CALIBRATE_SHIFT; } + void -ao_config_accel_zero_g_set(void) __reentrant +ao_config_accel_calibrate_set(void) __reentrant { + int16_t up, down; ao_cmd_decimal(); if (ao_cmd_status != ao_cmd_success) return; - if (ao_cmd_lex_i == 0) - ao_cmd_lex_i = ao_config_accel_zero_g_auto(); + if (ao_cmd_lex_i == 0) { + up = ao_config_accel_calibrate_auto("antenna up"); + down = ao_config_accel_calibrate_auto("antenna down"); + } else { + up = ao_cmd_lex_i; + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + down = ao_cmd_lex_i; + } + if (up >= down) { + printf("Invalid accel calibration: antenna up (%d) should be less than antenna down (%d)\n", + up, down); + return; + } ao_mutex_get(&ao_config_mutex); _ao_config_get(); - ao_config.accel_zero_g = ao_cmd_lex_i; + ao_config.accel_plus_g = up; + ao_config.accel_minus_g = down; ao_config_dirty = 1; ao_mutex_put(&ao_config_mutex); - ao_config_accel_zero_g_show(); + ao_config_accel_calibrate_show(); } void @@ -237,8 +264,8 @@ ao_config_write(void) __reentrant; __code struct ao_config_var ao_config_vars[] = { { 'm', ao_config_main_deploy_set, ao_config_main_deploy_show, "m Set height above launch for main deploy (in meters)" }, - { 'a', ao_config_accel_zero_g_set, ao_config_accel_zero_g_show, - "a Set accelerometer zero g point (0 for auto)" }, + { 'a', ao_config_accel_calibrate_set, ao_config_accel_calibrate_show, + "a <+g> <-g> Set accelerometer calibration (0 for auto)" }, { 'r', ao_config_radio_channel_set, ao_config_radio_channel_show, "r Set radio channel (freq = 434.550 + channel * .1)" }, { 'c', ao_config_callsign_set, ao_config_callsign_show, diff --git a/src/ao_flight.c b/src/ao_flight.c index e91a5daa..92c955fb 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -48,6 +48,7 @@ __pdata int16_t ao_interval_max_pres; __data uint8_t ao_flight_adc; __pdata int16_t ao_raw_accel, ao_raw_accel_prev, ao_raw_pres; +__pdata int16_t ao_accel_2g; /* Accelerometer calibration * @@ -72,19 +73,18 @@ __pdata int16_t ao_raw_accel, ao_raw_accel_prev, ao_raw_pres; #define GRAVITY 9.80665 /* convert m/s to velocity count */ -#define VEL_MPS_TO_COUNT(mps) ((int32_t) (((mps) / GRAVITY) * ACCEL_G * 100)) +#define VEL_MPS_TO_COUNT(mps) (((int32_t) (((mps) / GRAVITY) * (AO_HERTZ/2))) * (int32_t) ao_accel_2g) #define ACCEL_G 265 -#define ACCEL_ZERO_G 16000 -#define ACCEL_NOSE_UP (ACCEL_G * 2 /3) -#define ACCEL_BOOST ACCEL_G * 2 +#define ACCEL_NOSE_UP (ao_accel_2g / 4) +#define ACCEL_BOOST ao_accel_2g #define ACCEL_INT_LAND (ACCEL_G / 10) -#define ACCEL_VEL_LAND VEL_MPS_TO_COUNT(10) #define ACCEL_VEL_MACH VEL_MPS_TO_COUNT(200) -#define ACCEL_VEL_APOGEE VEL_MPS_TO_COUNT(2) -#define ACCEL_VEL_MAIN VEL_MPS_TO_COUNT(100) #define ACCEL_VEL_BOOST VEL_MPS_TO_COUNT(5) +int32_t accel_vel_mach; +int32_t accel_vel_boost; + /* * Barometer calibration * @@ -170,14 +170,14 @@ ao_flight(void) * so subtract instead of add. */ ticks = ao_flight_tick - ao_flight_prev_tick; - ao_vel_change = (((ao_raw_accel >> 1) + (ao_raw_accel_prev >> 1)) - ao_ground_accel); + ao_vel_change = ao_ground_accel - (((ao_raw_accel + 1) >> 1) + ((ao_raw_accel_prev + 1) >> 1)); ao_raw_accel_prev = ao_raw_accel; /* one is a common interval */ if (ticks == 1) - ao_flight_vel -= (int32_t) ao_vel_change; + ao_flight_vel += (int32_t) ao_vel_change; else - ao_flight_vel -= (int32_t) ao_vel_change * (int32_t) ticks; + ao_flight_vel += (int32_t) ao_vel_change * (int32_t) ticks; ao_flight_adc = ao_adc_ring_next(ao_flight_adc); } @@ -211,6 +211,9 @@ ao_flight(void) ao_min_pres = ao_ground_pres; ao_config_get(); ao_main_pres = ao_altitude_to_pres(ao_pres_to_altitude(ao_ground_pres) + ao_config.main_deploy); + ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g; + accel_vel_mach = ACCEL_VEL_MACH; + accel_vel_boost = ACCEL_VEL_BOOST; ao_flight_vel = 0; ao_min_vel = 0; ao_old_vel = ao_flight_vel; @@ -218,8 +221,9 @@ ao_flight(void) /* Go to pad state if the nose is pointing up */ ao_config_get(); - if (ao_flight_accel < ao_config.accel_zero_g - ACCEL_NOSE_UP) { - + if (ao_config.accel_plus_g != 0 && ao_config.accel_minus_g != 0 && + ao_flight_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP) + { /* Disable the USB controller in flight mode * to save power */ @@ -337,19 +341,15 @@ ao_flight(void) /* apogee detect: coast to drogue deploy: * - * accelerometer: abs(velocity) > min_velocity + 2m/s - * OR * barometer: fall at least 10m * - * If the barometer saturates because the flight - * goes over its measuring range (about 53k'), - * requiring a 10m fall will avoid prematurely - * detecting apogee; the accelerometer will take - * over in that case and the integrated velocity - * measurement should suffice to find apogee + * It would be nice to use the accelerometer + * to detect apogee as well, but tests have + * shown that flights far from vertical would + * grossly mis-detect apogee. So, for now, + * we'll trust to a single sensor for this test */ - if (/* abs(ao_flight_vel) > ao_min_vel + ACCEL_VEL_APOGEE || */ - ao_flight_pres > ao_min_pres + BARO_APOGEE) + if (ao_flight_pres > ao_min_pres + BARO_APOGEE) { /* ignite the drogue charge */ ao_ignite(ao_igniter_drogue); @@ -462,7 +462,7 @@ ao_flight_status(void) __reentrant { printf("STATE: %7s accel: %d speed: %d altitude: %d main: %d\n", ao_state_names[ao_flight_state], - AO_ACCEL_COUNT_TO_MSS(ACCEL_ZERO_G - ao_flight_accel), + AO_ACCEL_COUNT_TO_MSS( - ao_flight_accel), AO_VEL_COUNT_TO_MS(ao_flight_vel), ao_pres_to_altitude(ao_flight_pres), ao_pres_to_altitude(ao_main_pres)); diff --git a/src/ao_flight_test.c b/src/ao_flight_test.c index 83c63016..61f48cb6 100644 --- a/src/ao_flight_test.c +++ b/src/ao_flight_test.c @@ -22,6 +22,8 @@ #include #include +#define AO_HERTZ 100 + #define AO_ADC_RING 64 #define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1)) #define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1)) @@ -144,12 +146,13 @@ ao_altitude_to_pres(int16_t alt) __reentrant struct ao_config { uint16_t main_deploy; - int16_t accel_zero_g; + int16_t accel_plus_g; + int16_t accel_minus_g; }; #define ao_config_get() -struct ao_config ao_config = { 250, 16000 }; +struct ao_config ao_config = { 250, 15937, 16467 }; #include "ao_flight.c" -- cgit v1.2.3 From 79718e798e96567f0ba11c61f187e432fdcf95ee Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Nov 2009 21:48:16 -0800 Subject: Remove "f" command --- src/ao_flight.c | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index 92c955fb..f50491d9 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -454,27 +454,8 @@ ao_flight(void) } } -#define AO_ACCEL_COUNT_TO_MSS(count) ((count) / 27) -#define AO_VEL_COUNT_TO_MS(count) ((int16_t) ((count) / 2700)) - -static void -ao_flight_status(void) __reentrant -{ - printf("STATE: %7s accel: %d speed: %d altitude: %d main: %d\n", - ao_state_names[ao_flight_state], - AO_ACCEL_COUNT_TO_MSS( - ao_flight_accel), - AO_VEL_COUNT_TO_MS(ao_flight_vel), - ao_pres_to_altitude(ao_flight_pres), - ao_pres_to_altitude(ao_main_pres)); -} - static __xdata struct ao_task flight_task; -__code struct ao_cmds ao_flight_cmds[] = { - { 'f', ao_flight_status, "f Display current flight state" }, - { 0, ao_flight_status, NULL } -}; - void ao_flight_init(void) { @@ -486,5 +467,4 @@ ao_flight_init(void) ao_interval_end = AO_INTERVAL_TICKS; ao_add_task(&flight_task, ao_flight, "flight"); - ao_cmd_register(&ao_flight_cmds[0]); } -- cgit v1.2.3 From 1c654a9369294c9b8066c33f91161d8005b96680 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 14 Nov 2009 22:17:24 -0800 Subject: Loosen tolerances for main->landed transition Detecting that the rocket has landed is required for the system to flush the eeprom log and re-enable the RDF beacon. This patch changes the landed state entry requirements for the accelerometer to require only that the accelerometer stay within a quarter of a g (down from 1/10g) and changes the testing interval from 20 seconds to 5 seconds. The requirement that the barometric altitude be within 1000m of the launch altitude and that the barometer change by no more than 0.05kPa are unchanged. Signed-off-by: Keith Packard --- src/ao_flight.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index f50491d9..f57573d0 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -75,10 +75,10 @@ __pdata int16_t ao_accel_2g; /* convert m/s to velocity count */ #define VEL_MPS_TO_COUNT(mps) (((int32_t) (((mps) / GRAVITY) * (AO_HERTZ/2))) * (int32_t) ao_accel_2g) -#define ACCEL_G 265 -#define ACCEL_NOSE_UP (ao_accel_2g / 4) +#define ACCEL_NOSE_UP (ao_accel_2g >> 2) #define ACCEL_BOOST ao_accel_2g -#define ACCEL_INT_LAND (ACCEL_G / 10) +#define ACCEL_COAST (ao_accel_2g >> 3) +#define ACCEL_INT_LAND (ao_accel_2g >> 3) #define ACCEL_VEL_MACH VEL_MPS_TO_COUNT(200) #define ACCEL_VEL_BOOST VEL_MPS_TO_COUNT(5) @@ -132,7 +132,7 @@ __xdata int32_t ao_raw_accel_sum, ao_raw_pres_sum; /* Landing is detected by getting constant readings from both pressure and accelerometer * for a fairly long time (AO_INTERVAL_TICKS) */ -#define AO_INTERVAL_TICKS AO_SEC_TO_TICKS(20) +#define AO_INTERVAL_TICKS AO_SEC_TO_TICKS(5) #define abs(a) ((a) < 0 ? -(a) : (a)) @@ -301,7 +301,7 @@ ao_flight(void) * deceleration, or by waiting until the maximum burn duration * (15 seconds) has past. */ - if (ao_flight_accel > ao_ground_accel + (ACCEL_G >> 2) || + if (ao_flight_accel > ao_ground_accel + ACCEL_COAST || (int16_t) (ao_flight_tick - ao_launch_tick) > BOOST_TICKS_MAX) { ao_flight_state = ao_flight_fast; @@ -432,20 +432,20 @@ ao_flight(void) ao_interval_end = ao_flight_tick + AO_INTERVAL_TICKS; ao_interval_cur_min_pres = ao_interval_cur_max_pres = ao_flight_pres; ao_interval_cur_min_accel = ao_interval_cur_max_accel = ao_flight_accel; - } - if ((uint16_t) (ao_interval_max_accel - ao_interval_min_accel) < (uint16_t) ACCEL_INT_LAND && - ao_flight_pres > ao_ground_pres - BARO_LAND && - (uint16_t) (ao_interval_max_pres - ao_interval_min_pres) < (uint16_t) BARO_INT_LAND) - { - ao_flight_state = ao_flight_landed; + if ((uint16_t) (ao_interval_max_accel - ao_interval_min_accel) < (uint16_t) ACCEL_INT_LAND && + ao_flight_pres > ao_ground_pres - BARO_LAND && + (uint16_t) (ao_interval_max_pres - ao_interval_min_pres) < (uint16_t) BARO_INT_LAND) + { + ao_flight_state = ao_flight_landed; - /* turn off the ADC capture */ - ao_timer_set_adc_interval(0); - /* Enable RDF beacon */ - ao_rdf_set(1); + /* turn off the ADC capture */ + ao_timer_set_adc_interval(0); + /* Enable RDF beacon */ + ao_rdf_set(1); - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } } break; case ao_flight_landed: -- cgit v1.2.3 From 0c2533be15858774ef9381aa8c8344356fd5b971 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 9 Jan 2010 22:06:19 -0800 Subject: Force idle mode by shorting the SPI clock to ground at boot time. This allows you to override the flight mode detection code in case the accelerometer calibration is broken somehow. Hold the SPI clock shoted to ground until the LED comes on, then remove it. Signed-off-by: Keith Packard --- src/ao.h | 1 + src/ao_flight.c | 8 ++++++-- src/ao_telemetrum.c | 10 ++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao.h b/src/ao.h index 1f27fe92..2c6eb2b9 100644 --- a/src/ao.h +++ b/src/ao.h @@ -618,6 +618,7 @@ extern __pdata int16_t ao_ground_pres; extern __pdata int16_t ao_ground_accel; extern __pdata int16_t ao_min_pres; extern __pdata uint16_t ao_launch_time; +extern __xdata uint8_t ao_flight_force_idle; /* Flight thread */ void diff --git a/src/ao_flight.c b/src/ao_flight.c index f57573d0..e0fd97f2 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -50,6 +50,8 @@ __data uint8_t ao_flight_adc; __pdata int16_t ao_raw_accel, ao_raw_accel_prev, ao_raw_pres; __pdata int16_t ao_accel_2g; +__xdata uint8_t ao_flight_force_idle; + /* Accelerometer calibration * * We're sampling the accelerometer through a resistor divider which @@ -221,8 +223,10 @@ ao_flight(void) /* Go to pad state if the nose is pointing up */ ao_config_get(); - if (ao_config.accel_plus_g != 0 && ao_config.accel_minus_g != 0 && - ao_flight_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP) + if (ao_config.accel_plus_g != 0 && + ao_config.accel_minus_g != 0 && + ao_flight_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP && + !ao_flight_force_idle) { /* Disable the USB controller in flight mode * to save power diff --git a/src/ao_telemetrum.c b/src/ao_telemetrum.c index 0de3572a..89743837 100644 --- a/src/ao_telemetrum.c +++ b/src/ao_telemetrum.c @@ -29,10 +29,20 @@ main(void) { ao_clock_init(); + /* Turn on the red LED until the system is stable */ ao_led_init(AO_LED_RED); ao_led_on(AO_LED_RED); + /* A hack -- look at the SPI clock pin, if it's sitting at + * ground, then we force the computer to idle mode instead of + * flight mode + */ + if (P1_3 == 0) { + ao_flight_force_idle = 1; + while (P1_3 == 0) + ; + } ao_timer_init(); ao_adc_init(); ao_beep_init(); -- cgit v1.2.3 From 876e9a10b9096ead85fbe08ec9a6a0329cf7cbd4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 13 Feb 2010 16:42:27 -0800 Subject: Log GPS data on pad after boost detect. This wakes up the two GPS reporting tasks and gets them to report out any existing GPS data to the log file. To make sure the timestamps in that GPS data are accurate, this also records GPS time on receipt of the GPS data instead of when that is logged. Signed-off-by: Keith Packard --- src/ao.h | 2 ++ src/ao_flight.c | 4 ++++ src/ao_gps_report.c | 4 ++-- src/ao_gps_sirf.c | 2 ++ src/ao_gps_skytraq.c | 4 ++++ src/ao_gps_test.c | 2 ++ src/ao_gps_test_skytraq.c | 2 ++ 7 files changed, 18 insertions(+), 2 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao.h b/src/ao.h index 2c6eb2b9..d6be2223 100644 --- a/src/ao.h +++ b/src/ao.h @@ -731,6 +731,8 @@ ao_serial_init(void); #define AO_GPS_RUNNING (1 << 5) #define AO_GPS_DATE_VALID (1 << 6) +extern __xdata uint16_t ao_gps_tick; + struct ao_gps_data { uint8_t year; uint8_t month; diff --git a/src/ao_flight.c b/src/ao_flight.c index e0fd97f2..980c16be 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -289,6 +289,10 @@ ao_flight(void) /* disable RDF beacon */ ao_rdf_set(0); + /* Record current GPS position by waking up GPS log tasks */ + ao_wakeup(&ao_gps_data); + ao_wakeup(&ao_gps_tracking_data); + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); break; } diff --git a/src/ao_gps_report.c b/src/ao_gps_report.c index e3e27523..cceb79ff 100644 --- a/src/ao_gps_report.c +++ b/src/ao_gps_report.c @@ -33,7 +33,7 @@ ao_gps_report(void) if (!(gps_data.flags & AO_GPS_VALID)) continue; - gps_log.tick = ao_time(); + gps_log.tick = ao_gps_tick; 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; @@ -71,13 +71,13 @@ ao_gps_tracking_report(void) for (;;) { ao_sleep(&ao_gps_tracking_data); ao_mutex_get(&ao_gps_mutex); + gps_log.tick = ao_gps_tick; 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)) diff --git a/src/ao_gps_sirf.c b/src/ao_gps_sirf.c index 64b66c95..a6167e6b 100644 --- a/src/ao_gps_sirf.c +++ b/src/ao_gps_sirf.c @@ -20,6 +20,7 @@ #endif __xdata uint8_t ao_gps_mutex; +__xdata uint16_t ao_gps_tick; __xdata struct ao_gps_data ao_gps_data; __xdata struct ao_gps_tracking_data ao_gps_tracking_data; @@ -390,6 +391,7 @@ ao_gps(void) __reentrant switch (i) { case 41: ao_mutex_get(&ao_gps_mutex); + ao_gps_tick = ao_time(); ao_gps_data.hour = ao_sirf_data.utc_hour; ao_gps_data.minute = ao_sirf_data.utc_minute; ao_gps_data.second = ao_sirf_data.utc_second / 1000; diff --git a/src/ao_gps_skytraq.c b/src/ao_gps_skytraq.c index 0dd45c0c..ae8c7ef7 100644 --- a/src/ao_gps_skytraq.c +++ b/src/ao_gps_skytraq.c @@ -28,9 +28,11 @@ static __xdata char ao_gps_char; static __xdata uint8_t ao_gps_cksum; static __xdata uint8_t ao_gps_error; +__xdata uint16_t ao_gps_tick; __xdata struct ao_gps_data ao_gps_data; __xdata struct ao_gps_tracking_data ao_gps_tracking_data; +static __xdata uint16_t ao_gps_next_tick; static __xdata struct ao_gps_data ao_gps_next; static __xdata uint8_t ao_gps_date_flags; static __xdata struct ao_gps_tracking_data ao_gps_tracking_next; @@ -248,6 +250,7 @@ ao_gps(void) __reentrant * *66 checksum */ + ao_gps_next_tick = ao_time(); ao_gps_next.flags = AO_GPS_RUNNING | ao_gps_date_flags; ao_gps_next.hour = ao_gps_decimal(2); ao_gps_next.minute = ao_gps_decimal(2); @@ -297,6 +300,7 @@ ao_gps(void) __reentrant ao_gps_error = 1; if (!ao_gps_error) { ao_mutex_get(&ao_gps_mutex); + ao_gps_tick = ao_gps_next_tick; memcpy(&ao_gps_data, &ao_gps_next, sizeof (struct ao_gps_data)); ao_mutex_put(&ao_gps_mutex); ao_wakeup(&ao_gps_data); diff --git a/src/ao_gps_test.c b/src/ao_gps_test.c index fddfedfd..cdcc6f4c 100644 --- a/src/ao_gps_test.c +++ b/src/ao_gps_test.c @@ -400,6 +400,8 @@ ao_serial_set_speed(uint8_t speed) tcflush(fd, TCIFLUSH); } +#define ao_time() 0 + #include "ao_gps_print.c" #include "ao_gps_sirf.c" diff --git a/src/ao_gps_test_skytraq.c b/src/ao_gps_test_skytraq.c index ccf96378..7fa10eaa 100644 --- a/src/ao_gps_test_skytraq.c +++ b/src/ao_gps_test_skytraq.c @@ -408,6 +408,8 @@ ao_serial_set_speed(uint8_t speed) tcflush(fd, TCIFLUSH); } +#define ao_time() 0 + #include "ao_gps_print.c" #include "ao_gps_skytraq.c" -- cgit v1.2.3 From 57de960b8148bf485607898c3d66af6994d76481 Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Fri, 7 Jan 2011 20:52:33 -0800 Subject: altos: Remove unused accel_vel_mach and accel_vel_boost variables Presumably left-over debugging code. Signed-off-by: Keith Packard --- src/ao_flight.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index 980c16be..5567d87f 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -84,9 +84,6 @@ __xdata uint8_t ao_flight_force_idle; #define ACCEL_VEL_MACH VEL_MPS_TO_COUNT(200) #define ACCEL_VEL_BOOST VEL_MPS_TO_COUNT(5) -int32_t accel_vel_mach; -int32_t accel_vel_boost; - /* * Barometer calibration * @@ -214,8 +211,6 @@ ao_flight(void) ao_config_get(); ao_main_pres = ao_altitude_to_pres(ao_pres_to_altitude(ao_ground_pres) + ao_config.main_deploy); ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g; - accel_vel_mach = ACCEL_VEL_MACH; - accel_vel_boost = ACCEL_VEL_BOOST; ao_flight_vel = 0; ao_min_vel = 0; ao_old_vel = ao_flight_vel; -- cgit v1.2.3 From c437b14b7fc7afdfc7b809a04d7fa29d5e742307 Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Fri, 7 Jan 2011 21:00:10 -0800 Subject: altos: Remove redundant initialization of ao_interval variables These are all initialized in the ao_flight_drogue state transition. Signed-off-by: Keith Packard --- src/ao_flight.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index 5567d87f..7fe85cb1 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -463,11 +463,5 @@ void ao_flight_init(void) { ao_flight_state = ao_flight_startup; - ao_interval_min_accel = 0; - ao_interval_max_accel = 0x7fff; - ao_interval_min_pres = 0; - ao_interval_max_pres = 0x7fff; - ao_interval_end = AO_INTERVAL_TICKS; - ao_add_task(&flight_task, ao_flight, "flight"); } -- cgit v1.2.3 From 118fe84c9ff1cc9d1653e67a2315e22e19d60a14 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 15 Jan 2011 11:26:31 -0800 Subject: altos: average 512 accel/baro samples at startup instead of 1000 This lets us use a simple shift instead of a divide, saving a huge amount of code space. Signed-off-by: Keith Packard --- src/ao_flight.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index 7fe85cb1..9f651ae2 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -196,17 +196,17 @@ ao_flight(void) /* startup state: * - * Collect 1000 samples of acceleration and pressure + * Collect 512 samples of acceleration and pressure * data and average them to find the resting values */ - if (nsamples < 1000) { + if (nsamples < 512) { ao_raw_accel_sum += ao_raw_accel; ao_raw_pres_sum += ao_raw_pres; ++nsamples; continue; } - ao_ground_accel = (ao_raw_accel_sum / nsamples); - ao_ground_pres = (ao_raw_pres_sum / nsamples); + ao_ground_accel = ao_raw_accel_sum >> 9; + ao_ground_pres = ao_raw_pres_sum >> 9; ao_min_pres = ao_ground_pres; ao_config_get(); ao_main_pres = ao_altitude_to_pres(ao_pres_to_altitude(ao_ground_pres) + ao_config.main_deploy); -- cgit v1.2.3 From 58838c0b96a91da0bd0cd77c3ff312b589c08136 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sat, 15 Jan 2011 23:21:26 +1300 Subject: altos: Added check for an accel value above 1.5g When detecting flight or idle mode, this should indicate that accel cal values are out of whack. Signed-off-by: Mike Beattie --- src/ao_flight.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index 9f651ae2..5a9a8d80 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -221,6 +221,7 @@ ao_flight(void) if (ao_config.accel_plus_g != 0 && ao_config.accel_minus_g != 0 && ao_flight_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP && + ao_flight_accel > ao_config.accel_plus_g - ACCEL_NOSE_UP && !ao_flight_force_idle) { /* Disable the USB controller in flight mode -- cgit v1.2.3 From add2802a8a33336180fe6856241a7f4a8200e89c Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 16 Jan 2011 00:10:30 +1300 Subject: altos: Added check for out of bounds accel Chose invalid flight mode instead of idle to give user feedback. Signed-off-by: Mike Beattie --- src/ao_flight.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index 5a9a8d80..01dbb11b 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -237,9 +237,18 @@ ao_flight(void) ao_flight_state = ao_flight_pad; ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); } else { - ao_flight_state = ao_flight_idle; + if (ao_flight_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP || + ao_flight_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP) + { + /* Detected an accel value outside -1.5g to 1.5g + * -> invalid mode + */ + ao_flight_state = ao_flight_invalid; + } else { + ao_flight_state = ao_flight_idle; + } - /* Turn on packet system in idle mode + /* Turn on packet system in idle or invalid mode */ ao_packet_slave_start(); ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); -- cgit v1.2.3 From afd3d3cdb8c2291c1c7cda7908392d68cd04f87f Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Mon, 17 Jan 2011 15:03:40 +1300 Subject: Rework invalid accel cal detection code Slightly reduces code space. Uncalibrated accelerometer now enters invalid state as well. Signed-off-by: Mike Beattie --- src/ao_flight.c | 63 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 26 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index 01dbb11b..e99692a3 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -216,45 +216,56 @@ ao_flight(void) ao_old_vel = ao_flight_vel; ao_old_vel_tick = ao_flight_tick; - /* Go to pad state if the nose is pointing up */ + /* Check to see what mode we should go to. + * - Invalid mode if accel cal appears to be out + * - pad mode if we're upright, + * - idle mode otherwise + */ ao_config_get(); - if (ao_config.accel_plus_g != 0 && - ao_config.accel_minus_g != 0 && - ao_flight_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP && - ao_flight_accel > ao_config.accel_plus_g - ACCEL_NOSE_UP && - !ao_flight_force_idle) + if (ao_config.accel_plus_g == 0 || + ao_config.accel_minus_g == 0 || + ao_flight_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP || + ao_flight_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP) { + /* Detected an accel value outside -1.5g to 1.5g + * (or uncalibrated values), so we go into invalid mode + */ + ao_flight_state = ao_flight_invalid; + /* Allow packet mode in invalid flight state, + * Still need to be able to fix the problem! + */ + ao_packet_slave_start(); + + } else if (ao_flight_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP && + !ao_flight_force_idle) + { + /* Set pad mode - we can fly! */ + ao_flight_state = ao_flight_pad; + /* Disable the USB controller in flight mode * to save power */ ao_usb_disable(); - /* Turn on telemetry system - */ + /* Turn on telemetry system */ ao_rdf_set(1); ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD); - ao_flight_state = ao_flight_pad; - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + /* signal successful initialization by turning off the LED */ + ao_led_off(AO_LED_RED); } else { - if (ao_flight_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP || - ao_flight_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP) - { - /* Detected an accel value outside -1.5g to 1.5g - * -> invalid mode - */ - ao_flight_state = ao_flight_invalid; - } else { - ao_flight_state = ao_flight_idle; - } - - /* Turn on packet system in idle or invalid mode - */ + /* Set idle mode */ + ao_flight_state = ao_flight_idle; + + /* Turn on packet system in idle mode */ ao_packet_slave_start(); - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + + /* signal successful initialization by turning off the LED */ + ao_led_off(AO_LED_RED); } - /* signal successful initialization by turning off the LED */ - ao_led_off(AO_LED_RED); + /* wakeup threads due to state change */ + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + break; case ao_flight_pad: -- cgit v1.2.3 From 69290588980bb15732a99eca5c911a3b6e9a37b9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 15 Jan 2011 12:12:02 -0800 Subject: altos: Ensure flight code gets first crack at new ADC data Instead of having everyone wait on the raw ADC ring, have the flight code wait on that and have everyone else wait for the flight code to finish looking at the data and move its pointer forwards. Signed-off-by: Keith Packard --- src/ao.h | 2 +- src/ao_adc.c | 10 ++-------- src/ao_config.c | 6 +++--- src/ao_flight.c | 3 ++- src/ao_flight_test.c | 2 +- src/ao_ignite.c | 1 - src/ao_log.c | 4 ++-- src/ao_test.c | 2 +- 8 files changed, 12 insertions(+), 18 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao.h b/src/ao.h index 5721c344..abac22a3 100644 --- a/src/ao.h +++ b/src/ao.h @@ -649,7 +649,7 @@ enum ao_flight_state { ao_flight_invalid = 9 }; -extern __xdata struct ao_adc ao_flight_data; +extern __data uint8_t ao_flight_adc; extern __pdata enum ao_flight_state ao_flight_state; extern __pdata uint16_t ao_flight_tick; extern __pdata int16_t ao_flight_accel; diff --git a/src/ao_adc.c b/src/ao_adc.c index 49d2519e..f577b458 100644 --- a/src/ao_adc.c +++ b/src/ao_adc.c @@ -27,16 +27,10 @@ ao_adc_poll(void) ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 0; } -void -ao_adc_sleep(void) -{ - ao_sleep(&ao_adc_ring); -} - void ao_adc_get(__xdata struct ao_adc *packet) { - uint8_t i = ao_adc_ring_prev(ao_adc_head); + uint8_t i = ao_adc_ring_prev(ao_flight_adc); memcpy(packet, &ao_adc_ring[i], sizeof (struct ao_adc)); } @@ -65,7 +59,7 @@ ao_adc_isr(void) __interrupt 1 /* record this conversion series */ ao_adc_ring[ao_adc_head].tick = ao_time(); ao_adc_head = ao_adc_ring_next(ao_adc_head); - ao_wakeup(ao_adc_ring); + ao_wakeup(DATA_TO_XDATA(&ao_adc_head)); } } diff --git a/src/ao_config.c b/src/ao_config.c index e97b7eb1..bbee3b44 100644 --- a/src/ao_config.c +++ b/src/ao_config.c @@ -209,10 +209,10 @@ ao_config_accel_calibrate_auto(char *orientation) __reentrant puts("Calibrating..."); flush(); i = ACCEL_CALIBRATE_SAMPLES; accel_total = 0; - cal_adc_ring = ao_adc_head; + cal_adc_ring = ao_flight_adc; while (i) { - ao_sleep(&ao_adc_ring); - while (i && cal_adc_ring != ao_adc_head) { + ao_sleep(DATA_TO_XDATA(&ao_flight_adc)); + while (i && cal_adc_ring != ao_flight_adc) { accel_total += (int32_t) ao_adc_ring[cal_adc_ring].accel; cal_adc_ring = ao_adc_ring_next(cal_adc_ring); i--; diff --git a/src/ao_flight.c b/src/ao_flight.c index e99692a3..9eb9a014 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -146,7 +146,8 @@ ao_flight(void) ao_raw_pres = 0; ao_flight_tick = 0; for (;;) { - ao_sleep(&ao_adc_ring); + ao_wakeup(DATA_TO_XDATA(&ao_flight_adc)); + ao_sleep(DATA_TO_XDATA(&ao_adc_head)); while (ao_flight_adc != ao_adc_head) { __pdata uint8_t ticks; __pdata int16_t ao_vel_change; diff --git a/src/ao_flight_test.c b/src/ao_flight_test.c index 108d2c19..5c619518 100644 --- a/src/ao_flight_test.c +++ b/src/ao_flight_test.c @@ -180,7 +180,7 @@ void ao_sleep(void *wchan) { ao_dump_state(); - if (wchan == &ao_adc_ring) { + if (wchan == &ao_adc_head) { char type; uint16_t tick; uint16_t a, b; diff --git a/src/ao_ignite.c b/src/ao_ignite.c index f2b15dd2..603fcd25 100644 --- a/src/ao_ignite.c +++ b/src/ao_ignite.c @@ -52,7 +52,6 @@ ao_igniter_status(enum ao_igniter igniter) __xdata uint8_t request, firing, fired; __critical { - ao_adc_sleep(); ao_adc_get(&adc); request = ao_ignition[igniter].request; fired = ao_ignition[igniter].fired; diff --git a/src/ao_log.c b/src/ao_log.c index fa072550..099c5f6f 100644 --- a/src/ao_log.c +++ b/src/ao_log.c @@ -99,10 +99,10 @@ ao_log(void) /* Write the whole contents of the ring to the log * when starting up. */ - ao_log_adc_pos = ao_adc_ring_next(ao_adc_head); + ao_log_adc_pos = ao_adc_ring_next(ao_flight_adc); for (;;) { /* Write samples to EEPROM */ - while (ao_log_adc_pos != ao_adc_head) { + while (ao_log_adc_pos != ao_flight_adc) { log.type = AO_LOG_SENSOR; log.tick = ao_adc_ring[ao_log_adc_pos].tick; log.u.sensor.accel = ao_adc_ring[ao_log_adc_pos].accel; diff --git a/src/ao_test.c b/src/ao_test.c index b9f7d338..14c2eb75 100644 --- a/src/ao_test.c +++ b/src/ao_test.c @@ -53,7 +53,7 @@ blink_1(void) static __xdata struct ao_adc adc; for (;;) { - ao_sleep(&ao_adc_ring); + ao_sleep(&ao_adc_head); ao_adc_get(&adc); if (adc.accel < 15900) ao_led_on(AO_LED_RED); -- cgit v1.2.3 From 2887fe7affc0706dbeb2f04df9a00a9b799903ed Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 15 Jan 2011 12:25:57 -0800 Subject: altos: Optimize fetching of ADC data in flight code This stores the address of the desired sample in a local variable and then fetches through that. Saves quite a few instructions. Signed-off-by: Keith Packard --- src/ao_flight.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index 9eb9a014..637acd52 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -151,12 +151,14 @@ ao_flight(void) while (ao_flight_adc != ao_adc_head) { __pdata uint8_t ticks; __pdata int16_t ao_vel_change; + __xdata struct ao_adc *ao_adc; ao_flight_prev_tick = ao_flight_tick; /* Capture a sample */ - ao_raw_accel = ao_adc_ring[ao_flight_adc].accel; - ao_raw_pres = ao_adc_ring[ao_flight_adc].pres; - ao_flight_tick = ao_adc_ring[ao_flight_adc].tick; + ao_adc = &ao_adc_ring[ao_flight_adc]; + ao_flight_tick = ao_adc->tick; + ao_raw_accel = ao_adc->accel; + ao_raw_pres = ao_adc->pres; ao_flight_accel -= ao_flight_accel >> 4; ao_flight_accel += ao_raw_accel >> 4; -- cgit v1.2.3 From 4b71c4f4ed6cae23a7f4a2e7ae697da9ec614898 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 15 Jan 2011 12:26:53 -0800 Subject: altos: Use 5V reference data to correct accelerometer measurements. When the 3.3V and 5V values shift relative to each other (usually due to changes in power consumption), the measured acceleration will appear to shift. This patch converts the 3.3V referenced acceleration value into a 5V referenced acceleration, eliminating this error. Signed-off-by: Keith Packard --- src/ao_flight.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index 637acd52..81aecad3 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -158,6 +158,90 @@ ao_flight(void) ao_adc = &ao_adc_ring[ao_flight_adc]; ao_flight_tick = ao_adc->tick; ao_raw_accel = ao_adc->accel; +#if HAS_ACCEL_REF + /* + * Ok, the math here is a bit tricky. + * + * ao_raw_accel: ADC output for acceleration + * ao_accel_ref: ADC output for the 5V reference. + * ao_cook_accel: Corrected acceleration value + * Vcc: 3.3V supply to the CC1111 + * Vac: 5V supply to the accelerometer + * accel: input voltage to accelerometer ADC pin + * ref: input voltage to 5V reference ADC pin + * + * + * Measured acceleration is ratiometric to Vcc: + * + * ao_raw_accel accel + * ------------ = ----- + * 32767 Vcc + * + * Measured 5v reference is also ratiometric to Vcc: + * + * ao_accel_ref ref + * ------------ = ----- + * 32767 Vcc + * + * + * ao_accel_ref = 32767 * (ref / Vcc) + * + * Acceleration is measured ratiometric to the 5V supply, + * so what we want is: + * + * ao_cook_accel accel + * ------------- = ----- + * 32767 ref + * + * + * accel Vcc + * = ----- * --- + * Vcc ref + * + * ao_raw_accel 32767 + * = ------------ * ------------ + * 32737 ao_accel_ref + * + * Multiply through by 32767: + * + * ao_raw_accel * 32767 + * ao_cook_accel = -------------------- + * ao_accel_ref + * + * Now, the tricky part. Getting this to compile efficiently + * and keeping all of the values in-range. + * + * First off, we need to use a shift of 16 instead of * 32767 as SDCC + * does the obvious optimizations for byte-granularity shifts: + * + * ao_cook_accel = (ao_raw_accel << 16) / ao_accel_ref + * + * Next, lets check our input ranges: + * + * 0 <= ao_raw_accel <= 0x7fff (singled ended ADC conversion) + * 0x7000 <= ao_accel_ref <= 0x7fff (the 5V ref value is close to 0x7fff) + * + * Plugging in our input ranges, we get an output range of 0 - 0x12490, + * which is 17 bits. That won't work. If we take the accel ref and shift + * by a bit, we'll change its range: + * + * 0xe000 <= ao_accel_ref<<1 <= 0xfffe + * + * ao_cook_accel = (ao_raw_accel << 16) / (ao_accel_ref << 1) + * + * Now the output range is 0 - 0x9248, which nicely fits in 16 bits. It + * is, however, one bit too large for our signed computations. So, we + * take the result and shift that by a bit: + * + * ao_cook_accel = ((ao_raw_accel << 16) / (ao_accel_ref << 1)) >> 1 + * + * This finally creates an output range of 0 - 0x4924. As the ADC only + * provides 11 bits of data, we haven't actually lost any precision, + * just dropped a bit of noise off the low end. + */ + ao_raw_accel = (uint16_t) ((((uint32_t) ao_raw_accel << 16) / (ao_accel_ref[ao_flight_adc] << 1))) >> 1; + ao_adc->accel = ao_raw_accel; +#endif ao_raw_pres = ao_adc->pres; ao_flight_accel -= ao_flight_accel >> 4; -- cgit v1.2.3 From 02611efea0c485d78fad08c696c1f56e868d36b8 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 6 Mar 2011 20:56:25 -0800 Subject: altos: Make serial, usb, beeper and accelerometer optional components Not all boards will have these, so fix places that use them to deal with that. Signed-off-by: Keith Packard --- src/Makefile.proto | 23 +++++++++-- src/ao.h | 14 ++++++- src/ao_flight.c | 114 +++++++++++++++++++++++++++++++++++++++++---------- src/ao_flight_test.c | 9 ++++ src/ao_log.c | 2 + src/ao_panic.c | 8 ++++ src/ao_pins.h | 18 ++++++++ src/ao_product.c | 4 +- src/ao_report.c | 34 ++++++++------- src/ao_telemetry.c | 6 +++ 10 files changed, 189 insertions(+), 43 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/Makefile.proto b/src/Makefile.proto index 709cbca7..30cd5798 100644 --- a/src/Makefile.proto +++ b/src/Makefile.proto @@ -42,11 +42,15 @@ ALTOS_SRC = \ # Shared AltOS drivers # ALTOS_DRIVER_SRC = \ - ao_beep.c \ ao_config.c \ ao_led.c \ ao_radio.c \ - ao_stdio.c \ + ao_stdio.c + +BEEP_DRIVER_SRC = \ + ao_beep.c + +USB_DRIVER_SRC = \ ao_usb.c TELE_COMMON_SRC = \ @@ -68,7 +72,12 @@ TELE_RECEIVER_SRC =\ # TELE_DRIVER_SRC = \ - ao_convert.c \ + ao_convert.c + +# +# Serial port driver +# +SERIAL_DRIVER_SRC = \ ao_serial.c # @@ -89,7 +98,9 @@ DBG_SRC = \ TM_DRIVER_SRC = \ ao_adc.c \ ao_gps_report.c \ - ao_ignite.c + ao_ignite.c \ + $(BEEP_DRIVER_SRC) \ + $(USB_DRIVER_SRC) # # 25LC1024 driver source @@ -142,6 +153,7 @@ TM_BASE_SRC = \ $(ALTOS_SRC) \ $(ALTOS_DRIVER_SRC) \ $(TELE_DRIVER_SRC) \ + $(SERIAL_DRIVER_SRC) \ $(TELE_COMMON_SRC) \ $(TM_DRIVER_SRC) \ $(TM_TASK_SRC) \ @@ -158,6 +170,7 @@ TI_SRC = \ $(ALTOS_DRIVER_SRC) \ $(TELE_RECEIVER_SRC) \ $(TELE_COMMON_SRC) \ + $(USB_DRIVER_SRC) \ $(TI_MAIN_SRC) \ $(DBG_SRC) @@ -172,6 +185,7 @@ TT_SRC = \ $(TELE_RECEIVER_SRC) \ $(TELE_DRIVER_SRC) \ $(TELE_COMMON_SRC) \ + $(USB_DRIVER_SRC) \ $(TT_MAIN_SRC) @@ -187,6 +201,7 @@ TD_SRC = \ $(ALTOS_DRIVER_SRC) \ $(TELE_RECEIVER_SRC) \ $(TELE_COMMON_SRC) \ + $(USB_DRIVER_SRC) \ $(TD_MAIN_SRC) include Makefile.defs diff --git a/src/ao.h b/src/ao.h index 791064e8..5bbe5158 100644 --- a/src/ao.h +++ b/src/ao.h @@ -164,9 +164,13 @@ struct ao_adc { #if HAS_ADC +#if HAS_ACCEL #ifndef HAS_ACCEL_REF #error Please define HAS_ACCEL_REF #endif +#else +#define HAS_ACCEL_REF 0 +#endif /* * ao_adc.c @@ -303,7 +307,14 @@ extern __code __at (0x00a0) uint16_t ao_romconfig_version; extern __code __at (0x00a2) uint16_t ao_romconfig_check; extern __code __at (0x00a4) uint16_t ao_serial_number; extern __code __at (0x00a6) uint32_t ao_radio_cal; + +#ifndef HAS_USB +#error Please define HAS_USB +#endif + +#if HAS_USB extern __code __at (0x00aa) uint8_t ao_usb_descriptors []; +#endif /* * ao_usb.c @@ -327,9 +338,11 @@ ao_usb_pollchar(void); void ao_usb_flush(void); +#if HAS_USB /* USB interrupt handler */ void ao_usb_isr(void) __interrupt 6; +#endif /* Enable the USB controller */ void @@ -1062,7 +1075,6 @@ ao_rssi_init(uint8_t rssi_led); * each instance of a product */ -extern __code __at(0x00aa) uint8_t ao_usb_descriptors []; extern const char ao_version[]; extern const char ao_manufacturer[]; extern const char ao_product[]; diff --git a/src/ao_flight.c b/src/ao_flight.c index 81aecad3..843865e8 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -19,39 +19,57 @@ #include "ao.h" #endif +#ifndef HAS_ACCEL +#error Please define HAS_ACCEL +#endif + +#ifndef HAS_GPS +#error Please define HAS_GPS +#endif + +#ifndef HAS_USB +#error Please define HAS_USB +#endif + /* Main flight thread. */ __pdata enum ao_flight_state ao_flight_state; /* current flight state */ __pdata uint16_t ao_flight_tick; /* time of last data */ __pdata uint16_t ao_flight_prev_tick; /* time of previous data */ -__pdata int16_t ao_flight_accel; /* filtered acceleration */ __pdata int16_t ao_flight_pres; /* filtered pressure */ __pdata int16_t ao_ground_pres; /* startup pressure */ -__pdata int16_t ao_ground_accel; /* startup acceleration */ __pdata int16_t ao_min_pres; /* minimum recorded pressure */ __pdata uint16_t ao_launch_tick; /* time of launch detect */ __pdata int16_t ao_main_pres; /* pressure to eject main */ +#if HAS_ACCEL +__pdata int16_t ao_flight_accel; /* filtered acceleration */ +__pdata int16_t ao_ground_accel; /* startup acceleration */ +#endif /* * track min/max data over a long interval to detect * resting */ __pdata uint16_t ao_interval_end; -__pdata int16_t ao_interval_cur_min_accel; -__pdata int16_t ao_interval_cur_max_accel; __pdata int16_t ao_interval_cur_min_pres; __pdata int16_t ao_interval_cur_max_pres; -__pdata int16_t ao_interval_min_accel; -__pdata int16_t ao_interval_max_accel; __pdata int16_t ao_interval_min_pres; __pdata int16_t ao_interval_max_pres; +#if HAS_ACCEL +__pdata int16_t ao_interval_cur_min_accel; +__pdata int16_t ao_interval_cur_max_accel; +__pdata int16_t ao_interval_min_accel; +__pdata int16_t ao_interval_max_accel; +#endif __data uint8_t ao_flight_adc; -__pdata int16_t ao_raw_accel, ao_raw_accel_prev, ao_raw_pres; -__pdata int16_t ao_accel_2g; - +__pdata int16_t ao_raw_pres; __xdata uint8_t ao_flight_force_idle; +#if HAS_ACCEL +__pdata int16_t ao_raw_accel, ao_raw_accel_prev; +__pdata int16_t ao_accel_2g; + /* Accelerometer calibration * * We're sampling the accelerometer through a resistor divider which @@ -84,6 +102,8 @@ __xdata uint8_t ao_flight_force_idle; #define ACCEL_VEL_MACH VEL_MPS_TO_COUNT(200) #define ACCEL_VEL_BOOST VEL_MPS_TO_COUNT(5) +#endif + /* * Barometer calibration * @@ -117,6 +137,7 @@ __xdata uint8_t ao_flight_force_idle; #define BOOST_TICKS_MAX AO_SEC_TO_TICKS(15) +#if HAS_ACCEL /* This value is scaled in a weird way. It's a running total of accelerometer * readings minus the ground accelerometer reading. That means it measures * velocity, and quite accurately too. As it gets updated 100 times a second, @@ -126,7 +147,10 @@ __pdata int32_t ao_flight_vel; __pdata int32_t ao_min_vel; __pdata int32_t ao_old_vel; __pdata int16_t ao_old_vel_tick; -__xdata int32_t ao_raw_accel_sum, ao_raw_pres_sum; +__xdata int32_t ao_raw_accel_sum; +#endif + +__xdata int32_t ao_raw_pres_sum; /* Landing is detected by getting constant readings from both pressure and accelerometer * for a fairly long time (AO_INTERVAL_TICKS) @@ -141,22 +165,31 @@ ao_flight(void) __pdata static uint16_t nsamples = 0; ao_flight_adc = ao_adc_head; + ao_raw_pres = 0; +#if HAS_ACCEL ao_raw_accel_prev = 0; ao_raw_accel = 0; - ao_raw_pres = 0; +#endif ao_flight_tick = 0; for (;;) { ao_wakeup(DATA_TO_XDATA(&ao_flight_adc)); ao_sleep(DATA_TO_XDATA(&ao_adc_head)); while (ao_flight_adc != ao_adc_head) { +#if HAS_ACCEL __pdata uint8_t ticks; __pdata int16_t ao_vel_change; +#endif __xdata struct ao_adc *ao_adc; ao_flight_prev_tick = ao_flight_tick; /* Capture a sample */ ao_adc = &ao_adc_ring[ao_flight_adc]; ao_flight_tick = ao_adc->tick; + ao_raw_pres = ao_adc->pres; + ao_flight_pres -= ao_flight_pres >> 4; + ao_flight_pres += ao_raw_pres >> 4; + +#if HAS_ACCEL ao_raw_accel = ao_adc->accel; #if HAS_ACCEL_REF /* @@ -242,12 +275,9 @@ ao_flight(void) ao_raw_accel = (uint16_t) ((((uint32_t) ao_raw_accel << 16) / (ao_accel_ref[ao_flight_adc] << 1))) >> 1; ao_adc->accel = ao_raw_accel; #endif - ao_raw_pres = ao_adc->pres; ao_flight_accel -= ao_flight_accel >> 4; ao_flight_accel += ao_raw_accel >> 4; - ao_flight_pres -= ao_flight_pres >> 4; - ao_flight_pres += ao_raw_pres >> 4; /* Update velocity * * The accelerometer is mounted so that @@ -264,12 +294,14 @@ ao_flight(void) ao_flight_vel += (int32_t) ao_vel_change; else ao_flight_vel += (int32_t) ao_vel_change * (int32_t) ticks; +#endif ao_flight_adc = ao_adc_ring_next(ao_flight_adc); } if (ao_flight_pres < ao_min_pres) ao_min_pres = ao_flight_pres; +#if HAS_ACCEL if (ao_flight_vel >= 0) { if (ao_flight_vel < ao_min_vel) ao_min_vel = ao_flight_vel; @@ -277,6 +309,7 @@ ao_flight(void) if (-ao_flight_vel < ao_min_vel) ao_min_vel = -ao_flight_vel; } +#endif switch (ao_flight_state) { case ao_flight_startup: @@ -287,21 +320,27 @@ ao_flight(void) * data and average them to find the resting values */ if (nsamples < 512) { +#if HAS_ACCEL ao_raw_accel_sum += ao_raw_accel; +#endif ao_raw_pres_sum += ao_raw_pres; ++nsamples; continue; } +#if HAS_ACCEL ao_ground_accel = ao_raw_accel_sum >> 9; +#endif ao_ground_pres = ao_raw_pres_sum >> 9; ao_min_pres = ao_ground_pres; ao_config_get(); ao_main_pres = ao_altitude_to_pres(ao_pres_to_altitude(ao_ground_pres) + ao_config.main_deploy); +#if HAS_ACCEL ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g; ao_flight_vel = 0; ao_min_vel = 0; ao_old_vel = ao_flight_vel; ao_old_vel_tick = ao_flight_tick; +#endif /* Check to see what mode we should go to. * - Invalid mode if accel cal appears to be out @@ -309,6 +348,7 @@ ao_flight(void) * - idle mode otherwise */ ao_config_get(); +#if HAS_ACCEL if (ao_config.accel_plus_g == 0 || ao_config.accel_minus_g == 0 || ao_flight_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP || @@ -323,17 +363,23 @@ ao_flight(void) */ ao_packet_slave_start(); - } else if (ao_flight_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP && - !ao_flight_force_idle) + } else +#endif + if (!ao_flight_force_idle +#if HAS_ACCEL + && ao_flight_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP +#endif + ) { /* Set pad mode - we can fly! */ ao_flight_state = ao_flight_pad; +#if HAS_USB /* Disable the USB controller in flight mode * to save power */ ao_usb_disable(); - +#endif /* Turn on telemetry system */ ao_rdf_set(1); ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD); @@ -356,6 +402,7 @@ ao_flight(void) break; case ao_flight_pad: +#if HAS_ACCEL /* Trim velocity * * Once a second, remove any velocity from @@ -366,6 +413,7 @@ ao_flight(void) ao_flight_vel -= ao_old_vel; ao_old_vel = ao_flight_vel; } +#endif /* pad to boost: * * accelerometer: > 2g AND velocity > 5m/s @@ -376,11 +424,18 @@ ao_flight(void) * the barometer, but we use both to make sure this * transition is detected */ - if ((ao_flight_accel < ao_ground_accel - ACCEL_BOOST && - ao_flight_vel > ACCEL_VEL_BOOST) || + if ( +#if HAS_ACCEL + (ao_flight_accel < ao_ground_accel - ACCEL_BOOST && + ao_flight_vel > ACCEL_VEL_BOOST) || +#endif ao_flight_pres < ao_ground_pres - BARO_LAUNCH) { +#if HAS_ACCEL ao_flight_state = ao_flight_boost; +#else + ao_flight_state = ao_flight_coast; +#endif ao_launch_tick = ao_flight_tick; /* start logging data */ @@ -392,14 +447,17 @@ ao_flight(void) /* disable RDF beacon */ ao_rdf_set(0); +#if HAS_GPS /* Record current GPS position by waking up GPS log tasks */ ao_wakeup(&ao_gps_data); ao_wakeup(&ao_gps_tracking_data); +#endif ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); break; } break; +#if HAS_ACCEL case ao_flight_boost: /* boost to fast: @@ -448,6 +506,7 @@ ao_flight(void) ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); } break; +#endif case ao_flight_coast: /* apogee detect: coast to drogue deploy: @@ -478,8 +537,10 @@ ao_flight(void) /* Set the 'last' limits to max range to prevent * early resting detection */ +#if HAS_ACCEL ao_interval_min_accel = 0; ao_interval_max_accel = 0x7fff; +#endif ao_interval_min_pres = 0; ao_interval_max_pres = 0x7fff; @@ -487,7 +548,9 @@ ao_flight(void) ao_interval_end = ao_flight_tick + AO_INTERVAL_TICKS; ao_interval_cur_min_pres = ao_interval_cur_max_pres = ao_flight_pres; +#if HAS_ACCEL ao_interval_cur_min_accel = ao_interval_cur_max_accel = ao_flight_accel; +#endif /* and enter drogue state */ ao_flight_state = ao_flight_drogue; @@ -530,21 +593,28 @@ ao_flight(void) ao_interval_cur_min_pres = ao_flight_pres; if (ao_flight_pres > ao_interval_cur_max_pres) ao_interval_cur_max_pres = ao_flight_pres; +#if HAS_ACCEL if (ao_flight_accel < ao_interval_cur_min_accel) ao_interval_cur_min_accel = ao_flight_accel; if (ao_flight_accel > ao_interval_cur_max_accel) ao_interval_cur_max_accel = ao_flight_accel; +#endif if ((int16_t) (ao_flight_tick - ao_interval_end) >= 0) { ao_interval_max_pres = ao_interval_cur_max_pres; ao_interval_min_pres = ao_interval_cur_min_pres; + ao_interval_cur_min_pres = ao_interval_cur_max_pres = ao_flight_pres; +#if HAS_ACCEL ao_interval_max_accel = ao_interval_cur_max_accel; ao_interval_min_accel = ao_interval_cur_min_accel; - ao_interval_end = ao_flight_tick + AO_INTERVAL_TICKS; - ao_interval_cur_min_pres = ao_interval_cur_max_pres = ao_flight_pres; ao_interval_cur_min_accel = ao_interval_cur_max_accel = ao_flight_accel; +#endif + ao_interval_end = ao_flight_tick + AO_INTERVAL_TICKS; - if ((uint16_t) (ao_interval_max_accel - ao_interval_min_accel) < (uint16_t) ACCEL_INT_LAND && + if ( +#if HAS_ACCEL + (uint16_t) (ao_interval_max_accel - ao_interval_min_accel) < (uint16_t) ACCEL_INT_LAND && +#endif ao_flight_pres > ao_ground_pres - BARO_LAND && (uint16_t) (ao_interval_max_pres - ao_interval_min_pres) < (uint16_t) BARO_INT_LAND) { diff --git a/src/ao_flight_test.c b/src/ao_flight_test.c index 0c2006d5..e75bc8df 100644 --- a/src/ao_flight_test.c +++ b/src/ao_flight_test.c @@ -155,6 +155,15 @@ struct ao_config ao_config; #define DATA_TO_XDATA(x) (x) +#define HAS_FLIGHT 1 +#define HAS_ADC 1 +#define HAS_USB 1 +#define HAS_GPS 1 +#ifndef HAS_ACCEL +#define HAS_ACCEL 1 +#endif +#define HAS_ACCEL_REF 0 + #include "ao_flight.c" void diff --git a/src/ao_log.c b/src/ao_log.c index 1b10961d..817d3e6f 100644 --- a/src/ao_log.c +++ b/src/ao_log.c @@ -92,7 +92,9 @@ ao_log(void) log.type = AO_LOG_FLIGHT; log.tick = ao_flight_tick; +#if HAS_ACCEL log.u.flight.ground_accel = ao_ground_accel; +#endif log.u.flight.flight = ao_flight_number; ao_log_data(&log); diff --git a/src/ao_panic.c b/src/ao_panic.c index e996371e..fdada201 100644 --- a/src/ao_panic.c +++ b/src/ao_panic.c @@ -17,6 +17,14 @@ #include "ao.h" +#ifndef HAS_BEEP +#error Please define HAS_BEEP +#endif + +#if !HAS_BEEP +#define ao_beep(x) +#endif + static void ao_panic_delay(uint8_t n) { diff --git a/src/ao_pins.h b/src/ao_pins.h index 2c5b9db5..59604588 100644 --- a/src/ao_pins.h +++ b/src/ao_pins.h @@ -19,6 +19,9 @@ #define _AO_PINS_H_ #if defined(TELEMETRUM_V_1_0) + #define HAS_USB 1 + #define HAS_BEEP 1 + #define HAS_GPS 1 #define HAS_SERIAL_1 1 #define HAS_ADC 1 #define HAS_EEPROM 1 @@ -32,9 +35,13 @@ #define LEDS_AVAILABLE (AO_LED_RED) #define HAS_EXTERNAL_TEMP 0 #define HAS_ACCEL_REF 0 + #define HAS_ACCEL 1 #endif #if defined(TELEMETRUM_V_1_1) + #define HAS_USB 1 + #define HAS_BEEP 1 + #define HAS_GPS 1 #define HAS_SERIAL_1 1 #define HAS_ADC 1 #define HAS_EEPROM 1 @@ -52,9 +59,12 @@ #define SPI_CS_ON_P0 0 #define M25_CS_MASK 0x02 /* CS0 is P1_1 */ #define M25_MAX_CHIPS 1 + #define HAS_ACCEL 1 #endif #if defined(TELEDONGLE_V_0_2) + #define HAS_USB 1 + #define HAS_BEEP 0 #define HAS_SERIAL_1 0 #define HAS_ADC 0 #define HAS_DBG 1 @@ -71,6 +81,9 @@ #endif #if defined(TELEMETRUM_V_0_1) + #define HAS_USB 1 + #define HAS_BEEP 1 + #define HAS_GPS 1 #define HAS_SERIAL_1 1 #define HAS_ADC 1 #define HAS_DBG 0 @@ -86,9 +99,12 @@ #define HAS_ACCEL_REF 0 #define SPI_CS_ON_P1 1 #define SPI_CS_ON_P0 0 + #define HAS_ACCEL 1 #endif #if defined(TELEDONGLE_V_0_1) + #define HAS_USB 1 + #define HAS_BEEP 0 #define HAS_SERIAL_1 0 #define HAS_ADC 0 #define HAS_DBG 0 @@ -105,6 +121,8 @@ #endif #if defined(TIDONGLE) + #define HAS_USB 1 + #define HAS_BEEP 0 #define HAS_SERIAL_1 0 #define HAS_ADC 0 #define HAS_DBG 1 diff --git a/src/ao_product.c b/src/ao_product.c index 82d6298f..54ba2a14 100644 --- a/src/ao_product.c +++ b/src/ao_product.c @@ -16,7 +16,6 @@ */ #include "ao.h" -#include "ao_usb.h" #include PRODUCT_DEFS /* Defines which mark this particular AltOS product */ @@ -27,6 +26,8 @@ const char ao_product[] = AO_iProduct_STRING; #define LE_WORD(x) ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8)) +#if HAS_USB +#include "ao_usb.h" /* USB descriptors in one giant block of bytes */ __code __at(0x00aa) uint8_t ao_usb_descriptors [] = { @@ -151,3 +152,4 @@ __code __at(0x00aa) uint8_t ao_usb_descriptors [] = /* Terminating zero */ 0 }; +#endif diff --git a/src/ao_report.c b/src/ao_report.c index cc8b512b..c9ee7cae 100644 --- a/src/ao_report.c +++ b/src/ao_report.c @@ -37,10 +37,14 @@ static const uint8_t flight_reports[] = { MORSE4(1,0,0,1), /* invalid 'X' */ }; -#if 1 -#define signal(time) ao_beep_for(AO_BEEP_MID, time) +#if HAS_BEEP +#define low(time) ao_beep_for(AO_BEEP_LOW, time) +#define mid(time) ao_beep_for(AO_BEEP_MID, time) +#define high(time) ao_beep_for(AO_BEEP_HIGH, time) #else -#define signal(time) ao_led_for(AO_LED_RED, time) +#define low(time) ao_led_for(AO_LED_RED, time) +#define mid(time) ao_led_for(AO_LED_RED|AO_LED_GREEN, time) +#define high(time) ao_led_for(AO_LED_GREEN, time) #endif #define pause(time) ao_delay(time) @@ -56,9 +60,9 @@ ao_report_beep(void) __reentrant return; while (l--) { if (r & 8) - signal(AO_MS_TO_TICKS(600)); + mid(AO_MS_TO_TICKS(600)); else - signal(AO_MS_TO_TICKS(200)); + mid(AO_MS_TO_TICKS(200)); pause(AO_MS_TO_TICKS(200)); r >>= 1; } @@ -69,12 +73,12 @@ static void ao_report_digit(uint8_t digit) __reentrant { if (!digit) { - signal(AO_MS_TO_TICKS(500)); + mid(AO_MS_TO_TICKS(500)); pause(AO_MS_TO_TICKS(200)); } else { while (digit--) { - signal(AO_MS_TO_TICKS(200)); - pause(AO_MS_TO_TICKS(200)); + mid(AO_MS_TO_TICKS(200)); + mid(AO_MS_TO_TICKS(200)); } } pause(AO_MS_TO_TICKS(300)); @@ -118,24 +122,24 @@ ao_report_continuity(void) __reentrant (ao_report_igniter_ready(ao_igniter_main) << 1)); if (c) { while (c--) { - ao_beep_for(AO_BEEP_HIGH, AO_MS_TO_TICKS(25)); + high(AO_MS_TO_TICKS(25)); pause(AO_MS_TO_TICKS(100)); } } else { c = 10; while (c--) { - ao_beep_for(AO_BEEP_HIGH, AO_MS_TO_TICKS(20)); - ao_beep_for(AO_BEEP_LOW, AO_MS_TO_TICKS(20)); + high(AO_MS_TO_TICKS(20)); + low(AO_MS_TO_TICKS(20)); } } if (ao_log_full()) { pause(AO_MS_TO_TICKS(100)); c = 2; while (c--) { - ao_beep_for(AO_BEEP_LOW, AO_MS_TO_TICKS(100)); - ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(100)); - ao_beep_for(AO_BEEP_HIGH, AO_MS_TO_TICKS(100)); - ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(100)); + low(AO_MS_TO_TICKS(100)); + mid(AO_MS_TO_TICKS(100)); + high(AO_MS_TO_TICKS(100)); + mid(AO_MS_TO_TICKS(100)); } } c = 50; diff --git a/src/ao_telemetry.c b/src/ao_telemetry.c index 7aad929f..dd79f3fc 100644 --- a/src/ao_telemetry.c +++ b/src/ao_telemetry.c @@ -42,16 +42,22 @@ ao_telemetry(void) while (ao_telemetry_interval == 0) ao_sleep(&ao_telemetry_interval); telemetry.flight_state = ao_flight_state; +#if HAS_ACCEL telemetry.flight_accel = ao_flight_accel; telemetry.ground_accel = ao_ground_accel; telemetry.flight_vel = ao_flight_vel; +#endif telemetry.flight_pres = ao_flight_pres; telemetry.ground_pres = ao_ground_pres; +#if HAS_ADC ao_adc_get(&telemetry.adc); +#endif +#if HAS_GPS 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); +#endif ao_radio_send(&telemetry, sizeof (telemetry)); ao_delay(ao_telemetry_interval); if (ao_rdf && -- cgit v1.2.3 From 2d41358c80f2eb8b6e98d699149bb941a6671475 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 6 Mar 2011 21:00:52 -0800 Subject: altos: Start with packet slave running. Turn off in pad mode. Instead of turning slave mode on in idle mode, start with it running and disable it in pad mode instead. This means packet mode is available in startup mode too. Signed-off-by: Keith Packard --- src/ao_flight.c | 11 ++++------- src/ao_packet_slave.c | 4 ++++ src/ao_pins.h | 6 ++++++ 3 files changed, 14 insertions(+), 7 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index 843865e8..8e370c4f 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -358,10 +358,6 @@ ao_flight(void) * (or uncalibrated values), so we go into invalid mode */ ao_flight_state = ao_flight_invalid; - /* Allow packet mode in invalid flight state, - * Still need to be able to fix the problem! - */ - ao_packet_slave_start(); } else #endif @@ -380,6 +376,10 @@ ao_flight(void) */ ao_usb_disable(); #endif + + /* Disable packet mode in pad state */ + ao_packet_slave_stop(); + /* Turn on telemetry system */ ao_rdf_set(1); ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD); @@ -390,9 +390,6 @@ ao_flight(void) /* Set idle mode */ ao_flight_state = ao_flight_idle; - /* Turn on packet system in idle mode */ - ao_packet_slave_start(); - /* signal successful initialization by turning off the LED */ ao_led_off(AO_LED_RED); } diff --git a/src/ao_packet_slave.c b/src/ao_packet_slave.c index 39d04bbb..eb456dab 100644 --- a/src/ao_packet_slave.c +++ b/src/ao_packet_slave.c @@ -26,6 +26,9 @@ ao_packet_slave(void) while (ao_packet_enable) { if (ao_packet_recv()) { memcpy(&ao_tx_packet.callsign, &ao_rx_packet.packet.callsign, AO_MAX_CALLSIGN); +#if HAS_FLIGHT + ao_flight_force_idle = TRUE; +#endif ao_packet_send(); } } @@ -60,4 +63,5 @@ ao_packet_slave_init(void) ao_add_stdio(ao_packet_pollchar, ao_packet_putchar, NULL); + ao_packet_slave_start(); } diff --git a/src/ao_pins.h b/src/ao_pins.h index 59604588..a486b9ba 100644 --- a/src/ao_pins.h +++ b/src/ao_pins.h @@ -19,6 +19,7 @@ #define _AO_PINS_H_ #if defined(TELEMETRUM_V_1_0) + #define HAS_FLIGHT 1 #define HAS_USB 1 #define HAS_BEEP 1 #define HAS_GPS 1 @@ -39,6 +40,7 @@ #endif #if defined(TELEMETRUM_V_1_1) + #define HAS_FLIGHT 1 #define HAS_USB 1 #define HAS_BEEP 1 #define HAS_GPS 1 @@ -63,6 +65,7 @@ #endif #if defined(TELEDONGLE_V_0_2) + #define HAS_FLIGHT 0 #define HAS_USB 1 #define HAS_BEEP 0 #define HAS_SERIAL_1 0 @@ -81,6 +84,7 @@ #endif #if defined(TELEMETRUM_V_0_1) + #define HAS_FLIGHT 1 #define HAS_USB 1 #define HAS_BEEP 1 #define HAS_GPS 1 @@ -103,6 +107,7 @@ #endif #if defined(TELEDONGLE_V_0_1) + #define HAS_FLIGHT 0 #define HAS_USB 1 #define HAS_BEEP 0 #define HAS_SERIAL_1 0 @@ -121,6 +126,7 @@ #endif #if defined(TIDONGLE) + #define HAS_FLIGHT 0 #define HAS_USB 1 #define HAS_BEEP 0 #define HAS_SERIAL_1 0 -- cgit v1.2.3 From 62eae8a17d870e8ac6937ba23da01a5fbc652c6c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 18 Mar 2011 16:53:11 -0700 Subject: altos: Add kalman filters for baro-only boards This adds a baro-only kalman filter to track the state of the rocket, and then uses it to control flight events instead of the existing ad-hoc mechanisms. Signed-off-by: Keith Packard --- src/ao_flight.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++-- src/ao_flight_test.c | 70 +++++++++++++++++++++++++++++----- src/ao_pins.h | 4 ++ 3 files changed, 165 insertions(+), 13 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index 8e370c4f..e8130baa 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -31,6 +31,10 @@ #error Please define HAS_USB #endif +#ifndef USE_KALMAN +#error Please define USE_KALMAN +#endif + /* Main flight thread. */ __pdata enum ao_flight_state ao_flight_state; /* current flight state */ @@ -150,6 +154,62 @@ __pdata int16_t ao_old_vel_tick; __xdata int32_t ao_raw_accel_sum; #endif +#if USE_KALMAN +__pdata int16_t ao_ground_height; +__pdata int32_t ao_k_max_height; +__pdata int32_t ao_k_height; +__pdata int32_t ao_k_speed; +__pdata int32_t ao_k_accel; + +#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5)) +#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5)) + +#define from_fix(x) ((x) >> 16) + +#define AO_K0_100 to_fix16(0.05680323) +#define AO_K1_100 to_fix16(0.16608182) +#define AO_K2_100 to_fix16(0.24279580) + +#define AO_K_STEP_100 to_fix16(0.01) +#define AO_K_STEP_2_2_100 to_fix16(0.00005) + +#define AO_K0_10 to_fix16(0.23772023) +#define AO_K1_10 to_fix16(0.32214149) +#define AO_K2_10 to_fix16(0.21827159) + +#define AO_K_STEP_10 to_fix16(0.1) +#define AO_K_STEP_2_2_10 to_fix16(0.005) + +static void +ao_kalman_baro(void) +{ + int16_t err = ((ao_pres_to_altitude(ao_raw_pres) - ao_ground_height)) + - (int16_t) (ao_k_height >> 16); + +#ifdef AO_FLIGHT_TEST + if (ao_flight_tick - ao_flight_prev_tick > 5) { + ao_k_height += ((ao_k_speed >> 16) * AO_K_STEP_10 + + (ao_k_accel >> 16) * AO_K_STEP_2_2_10); + ao_k_speed += (ao_k_accel >> 16) * AO_K_STEP_10; + + /* correct */ + ao_k_height += (int32_t) AO_K0_10 * err; + ao_k_speed += (int32_t) AO_K1_10 * err; + ao_k_accel += (int32_t) AO_K2_10 * err; + return; + } +#endif + ao_k_height += ((ao_k_speed >> 16) * AO_K_STEP_100 + + (ao_k_accel >> 16) * AO_K_STEP_2_2_100); + ao_k_speed += (ao_k_accel >> 16) * AO_K_STEP_100; + + /* correct */ + ao_k_height += (int32_t) AO_K0_100 * err; + ao_k_speed += (int32_t) AO_K1_100 * err; + ao_k_accel += (int32_t) AO_K2_100 * err; +} +#endif + __xdata int32_t ao_raw_pres_sum; /* Landing is detected by getting constant readings from both pressure and accelerometer @@ -296,6 +356,10 @@ ao_flight(void) ao_flight_vel += (int32_t) ao_vel_change * (int32_t) ticks; #endif +#if USE_KALMAN + if (ao_flight_state > ao_flight_idle) + ao_kalman_baro(); +#endif ao_flight_adc = ao_adc_ring_next(ao_flight_adc); } @@ -333,6 +397,9 @@ ao_flight(void) ao_ground_pres = ao_raw_pres_sum >> 9; ao_min_pres = ao_ground_pres; ao_config_get(); +#if USE_KALMAN + ao_ground_height = ao_pres_to_altitude(ao_ground_pres); +#endif ao_main_pres = ao_altitude_to_pres(ao_pres_to_altitude(ao_ground_pres) + ao_config.main_deploy); #if HAS_ACCEL ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g; @@ -369,7 +436,6 @@ ao_flight(void) { /* Set pad mode - we can fly! */ ao_flight_state = ao_flight_pad; - #if HAS_USB /* Disable the USB controller in flight mode * to save power @@ -421,14 +487,20 @@ ao_flight(void) * the barometer, but we use both to make sure this * transition is detected */ +#if USE_KALMAN + if ((ao_k_accel > to_fix32(20) && + ao_k_speed > to_fix32(5)) || + ao_k_height > to_fix32(20)) +#else if ( #if HAS_ACCEL (ao_flight_accel < ao_ground_accel - ACCEL_BOOST && ao_flight_vel > ACCEL_VEL_BOOST) || #endif ao_flight_pres < ao_ground_pres - BARO_LAUNCH) +#endif { -#if HAS_ACCEL +#if HAS_ACCEL || USE_KALMAN ao_flight_state = ao_flight_boost; #else ao_flight_state = ao_flight_coast; @@ -454,7 +526,7 @@ ao_flight(void) break; } break; -#if HAS_ACCEL +#if HAS_ACCEL || USE_KALMAN case ao_flight_boost: /* boost to fast: @@ -467,8 +539,13 @@ ao_flight(void) * deceleration, or by waiting until the maximum burn duration * (15 seconds) has past. */ +#if USE_KALMAN + if ((ao_k_accel < to_fix32(-10) && ao_k_height > to_fix32(100)) || + (int16_t) (ao_flight_tick - ao_launch_tick) > BOOST_TICKS_MAX) +#else if (ao_flight_accel > ao_ground_accel + ACCEL_COAST || (int16_t) (ao_flight_tick - ao_launch_tick) > BOOST_TICKS_MAX) +#endif { ao_flight_state = ao_flight_fast; ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); @@ -492,20 +569,34 @@ ao_flight(void) * how big a pressure change the mach transition * generates would be useful here. */ +#if USE_KALMAN + if (ao_k_speed < to_fix32(200) || + ao_k_height < ao_k_max_height - to_fix32(500)) +#else if (ao_flight_vel < ACCEL_VEL_MACH || ao_flight_pres > ao_min_pres + BARO_COAST) +#endif { +#if HAS_ACCEL /* set min velocity to current velocity for * apogee detect */ ao_min_vel = abs(ao_flight_vel); +#endif ao_flight_state = ao_flight_coast; ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); } break; -#endif +#endif /* HAS_ACCEL */ case ao_flight_coast: +#if USE_KALMAN + /* apogee detect: coast to drogue deploy: + * + * speed: < 0 + */ + if (ao_k_speed < 0) +#else /* apogee detect: coast to drogue deploy: * * barometer: fall at least 10m @@ -517,6 +608,7 @@ ao_flight(void) * we'll trust to a single sensor for this test */ if (ao_flight_pres > ao_min_pres + BARO_APOGEE) +#endif { /* ignite the drogue charge */ ao_ignite(ao_igniter_drogue); @@ -569,7 +661,11 @@ ao_flight(void) * at that point. Perhaps also use the drogue sense lines * to notice continutity? */ +#if USE_KALMAN + if (from_fix(ao_k_height) < ao_config.main_deploy) +#else if (ao_flight_pres >= ao_main_pres) +#endif { ao_ignite(ao_igniter_main); ao_flight_state = ao_flight_main; diff --git a/src/ao_flight_test.c b/src/ao_flight_test.c index a635803f..16167644 100644 --- a/src/ao_flight_test.c +++ b/src/ao_flight_test.c @@ -21,6 +21,7 @@ #include #include #include +#include #define AO_HERTZ 100 @@ -62,6 +63,7 @@ enum ao_flight_state { struct ao_adc ao_adc_ring[AO_ADC_RING]; uint8_t ao_adc_head; +int ao_summary = 0; #define ao_led_on(l) #define ao_led_off(l) @@ -79,10 +81,13 @@ enum ao_igniter { ao_igniter_main = 1 }; +struct ao_adc ao_adc_static; + void ao_ignite(enum ao_igniter igniter) { - printf ("ignite %s\n", igniter == ao_igniter_drogue ? "drogue" : "main"); + printf ("ignite %s at %7.2f\n", igniter == ao_igniter_drogue ? "drogue" : "main", + (double) ao_adc_static.tick / 100.0); } struct ao_task { @@ -99,8 +104,6 @@ struct ao_task { #define AO_FLIGHT_TEST -struct ao_adc ao_adc_static; - FILE *emulator_in; void @@ -140,20 +143,37 @@ struct ao_config ao_config; #ifndef HAS_ACCEL #define HAS_ACCEL 1 #define HAS_ACCEL_REF 0 +#define USE_KALMAN 0 +#else +#define USE_KALMAN 1 #endif #include "ao_flight.c" +#define to_double(f) ((f) / 65536.0) + void ao_insert(void) { ao_adc_ring[ao_adc_head] = ao_adc_static; ao_adc_head = ao_adc_ring_next(ao_adc_head); + if (ao_summary) + return; if (ao_flight_state != ao_flight_startup) { +#if USE_KALMAN + printf("time %7.2f accel %d pres %d k_height %8.2f k_speed %8.5f k_accel %8.5f\n", + (double) ao_adc_static.tick / 100, + ao_adc_static.accel, + ao_adc_static.pres, + to_double(ao_k_height), + to_double(ao_k_speed), + to_double(ao_k_accel)); +#else printf("time %g accel %d pres %d\n", (double) ao_adc_static.tick / 100, ao_adc_static.accel, ao_adc_static.pres); +#endif } } @@ -269,6 +289,8 @@ ao_dump_state(void) { if (ao_flight_state == ao_flight_startup) return; + if (ao_summary) + return; #if HAS_ACCEL printf ("\t\t\t\t\t%s accel %g vel %g alt %d main %d\n", ao_state_names[ao_flight_state], @@ -286,14 +308,44 @@ ao_dump_state(void) exit(0); } +static const struct option options[] = { + { .name = "summary", .has_arg = 0, .val = 's' }, + { 0, 0, 0, 0}, +}; + +void run_flight_fixed(char *name, FILE *f, int summary) +{ + emulator_in = f; + ao_summary = summary; + ao_flight_init(); + ao_flight(); +} + int main (int argc, char **argv) { - emulator_in = fopen (argv[1], "r"); - if (!emulator_in) { - perror(argv[1]); - exit(1); + int summary = 0; + int c; + int i; + + while ((c = getopt_long(argc, argv, "s", options, NULL)) != -1) { + switch (c) { + case 's': + summary = 1; + break; + } } - ao_flight_init(); - ao_flight(); + + if (optind == argc) + run_flight_fixed("", stdin, summary); + else + for (i = optind; i < argc; i++) { + FILE *f = fopen(argv[i], "r"); + if (!f) { + perror(argv[i]); + continue; + } + run_flight_fixed(argv[i], f, summary); + fclose(f); + } } diff --git a/src/ao_pins.h b/src/ao_pins.h index 0de39970..353b5fd5 100644 --- a/src/ao_pins.h +++ b/src/ao_pins.h @@ -27,6 +27,7 @@ #define HAS_ADC 1 #define HAS_EEPROM 1 #define HAS_DBG 1 + #define USE_KALMAN 0 #define DBG_ON_P1 1 #define DBG_ON_P0 0 #define IGNITE_ON_P2 1 @@ -50,6 +51,7 @@ #define HAS_ADC 1 #define HAS_EEPROM 1 #define HAS_DBG 1 + #define USE_KALMAN 0 #define DBG_ON_P1 1 #define DBG_ON_P0 0 #define IGNITE_ON_P2 1 @@ -98,6 +100,7 @@ #define HAS_ADC 1 #define HAS_EEPROM 1 #define HAS_DBG 0 + #define USE_KALMAN 1 #define IGNITE_ON_P2 0 #define IGNITE_ON_P0 1 #define PACKET_HAS_MASTER 0 @@ -118,6 +121,7 @@ #define HAS_SERIAL_1 1 #define HAS_ADC 1 #define HAS_DBG 0 + #define USE_KALMAN 0 #define HAS_EEPROM 1 #define DBG_ON_P1 0 #define DBG_ON_P0 1 -- cgit v1.2.3 From 1aeb759c48f475ffaaae787515e080440c8386c3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 19 Mar 2011 12:28:08 -0700 Subject: altos: Baro-only boards must not detect launch on accel or speed data The baro sensor generates too much noise to use small changes in computed speed or acceleration to cause a false launch detect. Signed-off-by: Keith Packard --- src/ao_flight.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index e8130baa..71dd4891 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -488,9 +488,20 @@ ao_flight(void) * transition is detected */ #if USE_KALMAN +#if HAS_ACCEL + /* + * With an accelerometer, either to detect launch + */ if ((ao_k_accel > to_fix32(20) && ao_k_speed > to_fix32(5)) || ao_k_height > to_fix32(20)) +#else + /* + * Without an accelerometer, the barometer is far too + * noisy to rely on speed or acceleration data + */ + if (ao_k_height > to_fix32(20)) +#endif #else if ( #if HAS_ACCEL -- cgit v1.2.3 From ad6bb342d237988404fa32540b38c61d6ddc1f0d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 19 Mar 2011 23:51:02 -0700 Subject: altos: The kalman code requires a constant sample rate The kalman function can't handle a variable sample rate, so keep the ADC running at full speed for the whole flight instead of slowing it down after apogee. Signed-off-by: Keith Packard --- src/ao_flight.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index 71dd4891..493913b2 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -627,8 +627,10 @@ ao_flight(void) /* slow down the telemetry system */ ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_RECOVER); +#if !USE_KALMAN /* slow down the ADC sample rate */ ao_timer_set_adc_interval(10); +#endif /* * Start recording min/max accel and pres for a while -- cgit v1.2.3 From 7b009b2efe3af8722c358c304c2243652594e0d5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 22 Mar 2011 05:42:51 +0900 Subject: altos: Switch telemetrum over to kalman filter This changes the full telemetry stream to include kalman data instead of the old ad-hoc flight data. It's compatible in that the packet sizes are the same so teledongle can receive either and figure out which it has received. A few plotting and testing tools are added to make validating the new code easier. Signed-off-by: Keith Packard --- src/ao.h | 36 ++-- src/ao_flash.c | 8 +- src/ao_flight.c | 495 +++++++++++++++++++++--------------------------- src/ao_flight_test.c | 82 ++++---- src/ao_log_tiny.c | 2 +- src/ao_monitor.c | 34 ++-- src/ao_pins.h | 5 - src/ao_report.c | 2 +- src/ao_telemetry.c | 7 +- src/ao_telemetry_tiny.c | 6 +- src/test/.gitignore | 1 + src/test/Makefile | 13 +- src/test/plottest | 16 ++ src/test/run-one | 32 ++++ src/test/test-flights | 1 - 15 files changed, 367 insertions(+), 373 deletions(-) create mode 100755 src/test/plottest create mode 100755 src/test/run-one (limited to 'src/ao_flight.c') diff --git a/src/ao.h b/src/ao.h index 527390b0..b88bef1f 100644 --- a/src/ao.h +++ b/src/ao.h @@ -34,7 +34,7 @@ /* 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 0x80 +#define AO_STACK_START 0x90 #define AO_STACK_END 0xfe #define AO_STACK_SIZE (AO_STACK_END - AO_STACK_START + 1) @@ -470,7 +470,7 @@ extern __xdata uint16_t ao_storage_unit; /* Initialize above values. Can only be called once the OS is running */ void -ao_storage_setup(void); +ao_storage_setup(void) __reentrant; /* Write data. Returns 0 on failure, 1 on success */ uint8_t @@ -698,21 +698,19 @@ enum ao_flight_state { extern __data uint8_t ao_flight_adc; extern __pdata enum ao_flight_state ao_flight_state; extern __pdata uint16_t ao_flight_tick; -extern __pdata int16_t ao_flight_accel; -extern __pdata int16_t ao_flight_pres; -extern __pdata int32_t ao_flight_vel; -extern __pdata int16_t ao_ground_pres; +extern __xdata int16_t ao_ground_pres; extern __pdata int16_t ao_ground_accel; -extern __pdata int16_t ao_min_pres; extern __pdata uint16_t ao_launch_time; extern __xdata uint8_t ao_flight_force_idle; -#ifdef USE_KALMAN extern __pdata int16_t ao_ground_height; -extern __pdata int32_t ao_k_max_height; -extern __pdata int32_t ao_k_height; -extern __pdata int32_t ao_k_speed; -extern __pdata int32_t ao_k_accel; -#endif +extern __pdata int16_t ao_max_height; +extern __pdata int16_t ao_height; /* meters */ +extern __pdata int16_t ao_speed; /* m/s * 16 */ +extern __pdata int16_t ao_accel; /* m/s² * 16 */ + +#define AO_M_TO_HEIGHT(m) ((int16_t) (m)) +#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16)) +#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16)) /* Flight thread */ void @@ -912,10 +910,16 @@ struct ao_telemetry { uint16_t serial; uint16_t flight; uint8_t flight_state; - int16_t flight_accel; + int16_t accel; int16_t ground_accel; - int32_t flight_vel; - int16_t flight_pres; + union { + struct { + int16_t speed; + int16_t unused; + } k; + int32_t flight_vel; + } u; + int16_t height; int16_t ground_pres; int16_t accel_plus_g; int16_t accel_minus_g; diff --git a/src/ao_flash.c b/src/ao_flash.c index 3a264ceb..d323926f 100644 --- a/src/ao_flash.c +++ b/src/ao_flash.c @@ -93,12 +93,12 @@ static __pdata uint16_t ao_flash_block = FLASH_BLOCK_NONE; static __pdata uint8_t ao_flash_block_dirty; static __pdata uint8_t ao_flash_write_pending; static __pdata uint8_t ao_flash_setup_done; -static __data uint8_t ao_flash_block_shift; -static __data uint16_t ao_flash_block_size; -static __data uint16_t ao_flash_block_mask; +static __pdata uint8_t ao_flash_block_shift; +static __pdata uint16_t ao_flash_block_size; +static __pdata uint16_t ao_flash_block_mask; void -ao_storage_setup(void) +ao_storage_setup(void) __reentrant { uint8_t status; diff --git a/src/ao_flight.c b/src/ao_flight.c index 493913b2..c65670f0 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -31,22 +31,14 @@ #error Please define HAS_USB #endif -#ifndef USE_KALMAN -#error Please define USE_KALMAN -#endif - /* Main flight thread. */ __pdata enum ao_flight_state ao_flight_state; /* current flight state */ __pdata uint16_t ao_flight_tick; /* time of last data */ __pdata uint16_t ao_flight_prev_tick; /* time of previous data */ -__pdata int16_t ao_flight_pres; /* filtered pressure */ -__pdata int16_t ao_ground_pres; /* startup pressure */ -__pdata int16_t ao_min_pres; /* minimum recorded pressure */ +__xdata int16_t ao_ground_pres; /* startup pressure */ __pdata uint16_t ao_launch_tick; /* time of launch detect */ -__pdata int16_t ao_main_pres; /* pressure to eject main */ #if HAS_ACCEL -__pdata int16_t ao_flight_accel; /* filtered acceleration */ __pdata int16_t ao_ground_accel; /* startup acceleration */ #endif @@ -55,16 +47,8 @@ __pdata int16_t ao_ground_accel; /* startup acceleration */ * resting */ __pdata uint16_t ao_interval_end; -__pdata int16_t ao_interval_cur_min_pres; -__pdata int16_t ao_interval_cur_max_pres; -__pdata int16_t ao_interval_min_pres; -__pdata int16_t ao_interval_max_pres; -#if HAS_ACCEL -__pdata int16_t ao_interval_cur_min_accel; -__pdata int16_t ao_interval_cur_max_accel; -__pdata int16_t ao_interval_min_accel; -__pdata int16_t ao_interval_max_accel; -#endif +__pdata int16_t ao_interval_min_height; +__pdata int16_t ao_interval_max_height; __data uint8_t ao_flight_adc; __pdata int16_t ao_raw_pres; @@ -96,15 +80,8 @@ __pdata int16_t ao_accel_2g; */ #define GRAVITY 9.80665 -/* convert m/s to velocity count */ -#define VEL_MPS_TO_COUNT(mps) (((int32_t) (((mps) / GRAVITY) * (AO_HERTZ/2))) * (int32_t) ao_accel_2g) #define ACCEL_NOSE_UP (ao_accel_2g >> 2) -#define ACCEL_BOOST ao_accel_2g -#define ACCEL_COAST (ao_accel_2g >> 3) -#define ACCEL_INT_LAND (ao_accel_2g >> 3) -#define ACCEL_VEL_MACH VEL_MPS_TO_COUNT(200) -#define ACCEL_VEL_BOOST VEL_MPS_TO_COUNT(5) #endif @@ -127,91 +104,185 @@ __pdata int16_t ao_accel_2g; * 27 mV/kPa * 32767 / 3300 counts/mV = 268.1 counts/kPa */ -#define BARO_kPa 268 -#define BARO_LAUNCH (BARO_kPa / 5) /* .2kPa, or about 20m */ -#define BARO_APOGEE (BARO_kPa / 10) /* .1kPa, or about 10m */ -#define BARO_COAST (BARO_kPa * 5) /* 5kpa, or about 500m */ -#define BARO_MAIN (BARO_kPa) /* 1kPa, or about 100m */ -#define BARO_INT_LAND (BARO_kPa / 20) /* .05kPa, or about 5m */ -#define BARO_LAND (BARO_kPa * 10) /* 10kPa or about 1000m */ - /* We also have a clock, which can be used to sanity check things in * case of other failures */ #define BOOST_TICKS_MAX AO_SEC_TO_TICKS(15) -#if HAS_ACCEL -/* This value is scaled in a weird way. It's a running total of accelerometer - * readings minus the ground accelerometer reading. That means it measures - * velocity, and quite accurately too. As it gets updated 100 times a second, - * it's scaled by 100 - */ -__pdata int32_t ao_flight_vel; -__pdata int32_t ao_min_vel; -__pdata int32_t ao_old_vel; -__pdata int16_t ao_old_vel_tick; -__xdata int32_t ao_raw_accel_sum; -#endif - -#if USE_KALMAN -__pdata int16_t ao_ground_height; -__pdata int32_t ao_k_max_height; -__pdata int32_t ao_k_height; -__pdata int32_t ao_k_speed; -__pdata int32_t ao_k_accel; - #define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5)) #define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5)) - #define from_fix(x) ((x) >> 16) -#define AO_K0_100 to_fix16(0.05680323) -#define AO_K1_100 to_fix16(0.16608182) -#define AO_K2_100 to_fix16(0.24279580) +#include "ao_kalman.h" + +__pdata int16_t ao_ground_height; +__pdata int16_t ao_height; +__pdata int16_t ao_speed; +__pdata int16_t ao_accel; +__pdata int16_t ao_max_height; + +static __pdata int32_t ao_k_height; +static __pdata int32_t ao_k_speed; +static __pdata int32_t ao_k_accel; #define AO_K_STEP_100 to_fix16(0.01) #define AO_K_STEP_2_2_100 to_fix16(0.00005) -#define AO_K0_10 to_fix16(0.23772023) -#define AO_K1_10 to_fix16(0.32214149) -#define AO_K2_10 to_fix16(0.21827159) - #define AO_K_STEP_10 to_fix16(0.1) #define AO_K_STEP_2_2_10 to_fix16(0.005) +/* + * Above this height, the baro sensor doesn't work + */ +#define AO_MAX_BARO_HEIGHT 8000 + +/* + * Above this speed, baro measurements are unreliable + */ +#define AO_MAX_BARO_SPEED 300 + +static void +ao_kalman_predict(void) +{ +#ifdef AO_FLIGHT_TEST + if (ao_flight_tick - ao_flight_prev_tick > 5) { + ao_k_height += ((int32_t) ao_speed * AO_K_STEP_10 + + (int32_t) ao_accel * AO_K_STEP_2_2_10) >> 4; + ao_k_speed += (int32_t) ao_accel * AO_K_STEP_10; + + return; + } +#endif + ao_k_height += ((int32_t) ao_speed * AO_K_STEP_100 + + (int32_t) ao_accel * AO_K_STEP_2_2_100) >> 4; + ao_k_speed += (int32_t) ao_accel * AO_K_STEP_100; +} + +static __pdata int16_t ao_error_h; +static __pdata int16_t ao_raw_alt; +static __pdata int16_t ao_raw_height; +static __pdata int16_t ao_error_h_sq_avg; + static void -ao_kalman_baro(void) +ao_kalman_err_height(void) { - int16_t err = ((ao_pres_to_altitude(ao_raw_pres) - ao_ground_height)) - - (int16_t) (ao_k_height >> 16); + int16_t e; + ao_error_h = ao_raw_height - (int16_t) (ao_k_height >> 16); + + e = ao_error_h; + if (e < 0) + e = -e; + if (e > 127) + e = 127; + ao_error_h_sq_avg -= ao_error_h_sq_avg >> 4; + ao_error_h_sq_avg += (e * e) >> 4; +} +static void +ao_kalman_correct_baro(void) +{ + ao_kalman_err_height(); #ifdef AO_FLIGHT_TEST if (ao_flight_tick - ao_flight_prev_tick > 5) { - ao_k_height += ((ao_k_speed >> 16) * AO_K_STEP_10 + - (ao_k_accel >> 16) * AO_K_STEP_2_2_10); - ao_k_speed += (ao_k_accel >> 16) * AO_K_STEP_10; - - /* correct */ - ao_k_height += (int32_t) AO_K0_10 * err; - ao_k_speed += (int32_t) AO_K1_10 * err; - ao_k_accel += (int32_t) AO_K2_10 * err; + ao_k_height += (int32_t) AO_BARO_K0_10 * ao_error_h; + ao_k_speed += (int32_t) AO_BARO_K1_10 * ao_error_h; + ao_k_accel += (int32_t) AO_BARO_K2_10 * ao_error_h; return; } #endif - ao_k_height += ((ao_k_speed >> 16) * AO_K_STEP_100 + - (ao_k_accel >> 16) * AO_K_STEP_2_2_100); - ao_k_speed += (ao_k_accel >> 16) * AO_K_STEP_100; - - /* correct */ - ao_k_height += (int32_t) AO_K0_100 * err; - ao_k_speed += (int32_t) AO_K1_100 * err; - ao_k_accel += (int32_t) AO_K2_100 * err; + ao_k_height += (int32_t) AO_BARO_K0_100 * ao_error_h; + ao_k_speed += (int32_t) AO_BARO_K1_100 * ao_error_h; + ao_k_accel += (int32_t) AO_BARO_K2_100 * ao_error_h; } + +#if HAS_ACCEL +static __pdata int16_t ao_error_a; +static __pdata int32_t ao_accel_scale; + +static void +ao_kalman_err_accel(void) +{ + int32_t accel; + + accel = (ao_ground_accel - ao_raw_accel) * ao_accel_scale; + + /* Can't use ao_accel here as it is the pre-prediction value still */ + ao_error_a = (accel - ao_k_accel) >> 16; +} + +static void +ao_kalman_correct_both(void) +{ + ao_kalman_err_height(); + ao_kalman_err_accel(); + +#if 0 + /* + * Check to see if things are crazy here -- + * if the computed height is far above the + * measured height, we assume that the flight + * trajectory is not vertical, and so ignore + * the accelerometer for the remainder of the + * flight. + */ + if (ao_error_h_sq_avg > 10) + { + ao_kalman_correct_baro(); + return; + } +#endif + +#ifdef AO_FLIGHT_TEST + if (ao_flight_tick - ao_flight_prev_tick > 5) { + ao_k_height += + (int32_t) AO_BOTH_K00_10 * ao_error_h + + (int32_t) (AO_BOTH_K01_10 >> 4) * ao_error_a; + ao_k_speed += + ((int32_t) AO_BOTH_K10_10 << 4) * ao_error_h + + (int32_t) AO_BOTH_K11_10 * ao_error_a; + ao_k_accel += + ((int32_t) AO_BOTH_K20_10 << 4) * ao_error_h + + (int32_t) AO_BOTH_K21_10 * ao_error_a; + return; + } +#endif + ao_k_height += + (int32_t) AO_BOTH_K00_100 * ao_error_h + + (int32_t) AO_BOTH_K01_100 * ao_error_a; + ao_k_speed += + (int32_t) AO_BOTH_K10_100 * ao_error_h + + (int32_t) AO_BOTH_K11_100 * ao_error_a; + ao_k_accel += + (int32_t) AO_BOTH_K20_100 * ao_error_h + + (int32_t) AO_BOTH_K21_100 * ao_error_a; +} + +static void +ao_kalman_correct_accel(void) +{ + ao_kalman_err_accel(); + +#ifdef AO_FLIGHT_TEST + if (ao_flight_tick - ao_flight_prev_tick > 5) { + ao_k_height +=(int32_t) AO_ACCEL_K0_10 * ao_error_a; + ao_k_speed += (int32_t) AO_ACCEL_K1_10 * ao_error_a; + ao_k_accel += (int32_t) AO_ACCEL_K2_10 * ao_error_a; + return; + } #endif + ao_k_height += (int32_t) AO_ACCEL_K0_100 * ao_error_a; + ao_k_speed += (int32_t) AO_ACCEL_K1_100 * ao_error_a; + ao_k_accel += (int32_t) AO_ACCEL_K2_100 * ao_error_a; +} +#endif /* HAS_ACCEL */ __xdata int32_t ao_raw_pres_sum; +#ifdef HAS_ACCEL +__xdata int32_t ao_raw_accel_sum; +#endif + /* Landing is detected by getting constant readings from both pressure and accelerometer * for a fairly long time (AO_INTERVAL_TICKS) */ @@ -235,10 +306,6 @@ ao_flight(void) ao_wakeup(DATA_TO_XDATA(&ao_flight_adc)); ao_sleep(DATA_TO_XDATA(&ao_adc_head)); while (ao_flight_adc != ao_adc_head) { -#if HAS_ACCEL - __pdata uint8_t ticks; - __pdata int16_t ao_vel_change; -#endif __xdata struct ao_adc *ao_adc; ao_flight_prev_tick = ao_flight_tick; @@ -246,9 +313,8 @@ ao_flight(void) ao_adc = &ao_adc_ring[ao_flight_adc]; ao_flight_tick = ao_adc->tick; ao_raw_pres = ao_adc->pres; - ao_flight_pres -= ao_flight_pres >> 4; - ao_flight_pres += ao_raw_pres >> 4; - + ao_raw_alt = ao_pres_to_altitude(ao_raw_pres); + ao_raw_height = ao_raw_alt - ao_ground_height; #if HAS_ACCEL ao_raw_accel = ao_adc->accel; #if HAS_ACCEL_REF @@ -335,45 +401,31 @@ ao_flight(void) ao_raw_accel = (uint16_t) ((((uint32_t) ao_raw_accel << 16) / (ao_accel_ref[ao_flight_adc] << 1))) >> 1; ao_adc->accel = ao_raw_accel; #endif - - ao_flight_accel -= ao_flight_accel >> 4; - ao_flight_accel += ao_raw_accel >> 4; - /* Update velocity - * - * The accelerometer is mounted so that - * acceleration yields negative values - * while deceleration yields positive values, - * so subtract instead of add. - */ - ticks = ao_flight_tick - ao_flight_prev_tick; - ao_vel_change = ao_ground_accel - (((ao_raw_accel + 1) >> 1) + ((ao_raw_accel_prev + 1) >> 1)); - ao_raw_accel_prev = ao_raw_accel; - - /* one is a common interval */ - if (ticks == 1) - ao_flight_vel += (int32_t) ao_vel_change; - else - ao_flight_vel += (int32_t) ao_vel_change * (int32_t) ticks; #endif -#if USE_KALMAN - if (ao_flight_state > ao_flight_idle) - ao_kalman_baro(); -#endif - ao_flight_adc = ao_adc_ring_next(ao_flight_adc); - } - - if (ao_flight_pres < ao_min_pres) - ao_min_pres = ao_flight_pres; + if (ao_flight_state > ao_flight_idle) { + ao_kalman_predict(); #if HAS_ACCEL - if (ao_flight_vel >= 0) { - if (ao_flight_vel < ao_min_vel) - ao_min_vel = ao_flight_vel; - } else { - if (-ao_flight_vel < ao_min_vel) - ao_min_vel = -ao_flight_vel; + if (ao_flight_state <= ao_flight_coast) { +#ifndef FORCE_ACCEL + if (/*ao_speed < AO_MS_TO_SPEED(AO_MAX_BARO_SPEED) &&*/ + ao_raw_alt < AO_MAX_BARO_HEIGHT) + ao_kalman_correct_both(); + else +#endif + ao_kalman_correct_accel(); + } else +#endif + if (ao_raw_alt < AO_MAX_BARO_HEIGHT || ao_flight_state >= ao_flight_drogue) + ao_kalman_correct_baro(); + ao_height = from_fix(ao_k_height); + ao_speed = from_fix(ao_k_speed); + ao_accel = from_fix(ao_k_accel); + if (ao_height > ao_max_height) + ao_max_height = ao_height; + } + ao_flight_adc = ao_adc_ring_next(ao_flight_adc); } -#endif switch (ao_flight_state) { case ao_flight_startup: @@ -391,35 +443,25 @@ ao_flight(void) ++nsamples; continue; } + ao_config_get(); #if HAS_ACCEL ao_ground_accel = ao_raw_accel_sum >> 9; + ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g; + ao_accel_scale = to_fix32(GRAVITY * 2 * 16) / ao_accel_2g; #endif ao_ground_pres = ao_raw_pres_sum >> 9; - ao_min_pres = ao_ground_pres; - ao_config_get(); -#if USE_KALMAN ao_ground_height = ao_pres_to_altitude(ao_ground_pres); -#endif - ao_main_pres = ao_altitude_to_pres(ao_pres_to_altitude(ao_ground_pres) + ao_config.main_deploy); -#if HAS_ACCEL - ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g; - ao_flight_vel = 0; - ao_min_vel = 0; - ao_old_vel = ao_flight_vel; - ao_old_vel_tick = ao_flight_tick; -#endif /* Check to see what mode we should go to. * - Invalid mode if accel cal appears to be out * - pad mode if we're upright, * - idle mode otherwise */ - ao_config_get(); #if HAS_ACCEL if (ao_config.accel_plus_g == 0 || ao_config.accel_minus_g == 0 || - ao_flight_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP || - ao_flight_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP) + ao_ground_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP || + ao_ground_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP) { /* Detected an accel value outside -1.5g to 1.5g * (or uncalibrated values), so we go into invalid mode @@ -430,7 +472,7 @@ ao_flight(void) #endif if (!ao_flight_force_idle #if HAS_ACCEL - && ao_flight_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP + && ao_ground_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP #endif ) { @@ -465,57 +507,27 @@ ao_flight(void) break; case ao_flight_pad: -#if HAS_ACCEL - /* Trim velocity - * - * Once a second, remove any velocity from - * a second ago - */ - if ((int16_t) (ao_flight_tick - ao_old_vel_tick) >= AO_SEC_TO_TICKS(1)) { - ao_old_vel_tick = ao_flight_tick; - ao_flight_vel -= ao_old_vel; - ao_old_vel = ao_flight_vel; - } -#endif /* pad to boost: * - * accelerometer: > 2g AND velocity > 5m/s - * OR * barometer: > 20m vertical motion + * OR + * accelerometer: > 2g AND velocity > 5m/s * * The accelerometer should always detect motion before * the barometer, but we use both to make sure this - * transition is detected + * transition is detected. If the device + * doesn't have an accelerometer, then ignore the + * speed and acceleration as they are quite noisy + * on the pad. */ -#if USE_KALMAN + if (ao_height > AO_M_TO_HEIGHT(20) #if HAS_ACCEL - /* - * With an accelerometer, either to detect launch - */ - if ((ao_k_accel > to_fix32(20) && - ao_k_speed > to_fix32(5)) || - ao_k_height > to_fix32(20)) -#else - /* - * Without an accelerometer, the barometer is far too - * noisy to rely on speed or acceleration data - */ - if (ao_k_height > to_fix32(20)) -#endif -#else - if ( -#if HAS_ACCEL - (ao_flight_accel < ao_ground_accel - ACCEL_BOOST && - ao_flight_vel > ACCEL_VEL_BOOST) || -#endif - ao_flight_pres < ao_ground_pres - BARO_LAUNCH) + || (ao_accel > AO_MSS_TO_ACCEL(20) && + ao_speed > AO_MS_TO_SPEED(5)) #endif + ) { -#if HAS_ACCEL || USE_KALMAN ao_flight_state = ao_flight_boost; -#else - ao_flight_state = ao_flight_coast; -#endif ao_launch_tick = ao_flight_tick; /* start logging data */ @@ -537,7 +549,6 @@ ao_flight(void) break; } break; -#if HAS_ACCEL || USE_KALMAN case ao_flight_boost: /* boost to fast: @@ -550,13 +561,8 @@ ao_flight(void) * deceleration, or by waiting until the maximum burn duration * (15 seconds) has past. */ -#if USE_KALMAN - if ((ao_k_accel < to_fix32(-10) && ao_k_height > to_fix32(100)) || - (int16_t) (ao_flight_tick - ao_launch_tick) > BOOST_TICKS_MAX) -#else - if (ao_flight_accel > ao_ground_accel + ACCEL_COAST || + if ((ao_accel < AO_MSS_TO_ACCEL(-2.5) && ao_height > AO_M_TO_HEIGHT(100)) || (int16_t) (ao_flight_tick - ao_launch_tick) > BOOST_TICKS_MAX) -#endif { ao_flight_state = ao_flight_fast; ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); @@ -564,62 +570,28 @@ ao_flight(void) } break; case ao_flight_fast: - - /* fast to coast: - * - * accelerometer: integrated velocity < 200 m/s - * OR - * barometer: fall at least 500m from max altitude - * - * This extra state is required to avoid mis-detecting - * apogee due to mach transitions. - * - * XXX this is essentially a single-detector test - * as the 500m altitude change would likely result - * in a loss of the rocket. More data on precisely - * how big a pressure change the mach transition - * generates would be useful here. + /* + * This is essentially the same as coast, + * but the barometer is being ignored as + * it may be unreliable. */ -#if USE_KALMAN - if (ao_k_speed < to_fix32(200) || - ao_k_height < ao_k_max_height - to_fix32(500)) -#else - if (ao_flight_vel < ACCEL_VEL_MACH || - ao_flight_pres > ao_min_pres + BARO_COAST) -#endif - { -#if HAS_ACCEL - /* set min velocity to current velocity for - * apogee detect - */ - ao_min_vel = abs(ao_flight_vel); -#endif + if (ao_speed < AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) { ao_flight_state = ao_flight_coast; ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + break; } break; -#endif /* HAS_ACCEL */ case ao_flight_coast: -#if USE_KALMAN /* apogee detect: coast to drogue deploy: * * speed: < 0 - */ - if (ao_k_speed < 0) -#else - /* apogee detect: coast to drogue deploy: - * - * barometer: fall at least 10m * - * It would be nice to use the accelerometer - * to detect apogee as well, but tests have - * shown that flights far from vertical would - * grossly mis-detect apogee. So, for now, - * we'll trust to a single sensor for this test + * Also make sure the model altitude is tracking + * the measured altitude reasonably closely; otherwise + * we're probably transsonic. */ - if (ao_flight_pres > ao_min_pres + BARO_APOGEE) -#endif + if (ao_speed < 0 && (ao_raw_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 100)) { /* ignite the drogue charge */ ao_ignite(ao_igniter_drogue); @@ -627,32 +599,15 @@ ao_flight(void) /* slow down the telemetry system */ ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_RECOVER); -#if !USE_KALMAN - /* slow down the ADC sample rate */ - ao_timer_set_adc_interval(10); -#endif - /* - * Start recording min/max accel and pres for a while + * Start recording min/max height * to figure out when the rocket has landed */ - /* Set the 'last' limits to max range to prevent - * early resting detection - */ -#if HAS_ACCEL - ao_interval_min_accel = 0; - ao_interval_max_accel = 0x7fff; -#endif - ao_interval_min_pres = 0; - ao_interval_max_pres = 0x7fff; /* initialize interval values */ ao_interval_end = ao_flight_tick + AO_INTERVAL_TICKS; - ao_interval_cur_min_pres = ao_interval_cur_max_pres = ao_flight_pres; -#if HAS_ACCEL - ao_interval_cur_min_accel = ao_interval_cur_max_accel = ao_flight_accel; -#endif + ao_interval_min_height = ao_interval_max_height = ao_height; /* and enter drogue state */ ao_flight_state = ao_flight_drogue; @@ -674,11 +629,7 @@ ao_flight(void) * at that point. Perhaps also use the drogue sense lines * to notice continutity? */ -#if USE_KALMAN - if (from_fix(ao_k_height) < ao_config.main_deploy) -#else - if (ao_flight_pres >= ao_main_pres) -#endif + if (ao_height <= ao_config.main_deploy) { ao_ignite(ao_igniter_main); ao_flight_state = ao_flight_main; @@ -690,39 +641,17 @@ ao_flight(void) /* drogue/main to land: * - * accelerometer: value stable - * AND * barometer: altitude stable and within 1000m of the launch altitude */ - if (ao_flight_pres < ao_interval_cur_min_pres) - ao_interval_cur_min_pres = ao_flight_pres; - if (ao_flight_pres > ao_interval_cur_max_pres) - ao_interval_cur_max_pres = ao_flight_pres; -#if HAS_ACCEL - if (ao_flight_accel < ao_interval_cur_min_accel) - ao_interval_cur_min_accel = ao_flight_accel; - if (ao_flight_accel > ao_interval_cur_max_accel) - ao_interval_cur_max_accel = ao_flight_accel; -#endif + if (ao_height < ao_interval_min_height) + ao_interval_min_height = ao_height; + if (ao_height > ao_interval_max_height) + ao_interval_max_height = ao_height; if ((int16_t) (ao_flight_tick - ao_interval_end) >= 0) { - ao_interval_max_pres = ao_interval_cur_max_pres; - ao_interval_min_pres = ao_interval_cur_min_pres; - ao_interval_cur_min_pres = ao_interval_cur_max_pres = ao_flight_pres; -#if HAS_ACCEL - ao_interval_max_accel = ao_interval_cur_max_accel; - ao_interval_min_accel = ao_interval_cur_min_accel; - ao_interval_cur_min_accel = ao_interval_cur_max_accel = ao_flight_accel; -#endif - ao_interval_end = ao_flight_tick + AO_INTERVAL_TICKS; - - if ( -#if HAS_ACCEL - (uint16_t) (ao_interval_max_accel - ao_interval_min_accel) < (uint16_t) ACCEL_INT_LAND && -#endif - ao_flight_pres > ao_ground_pres - BARO_LAND && - (uint16_t) (ao_interval_max_pres - ao_interval_min_pres) < (uint16_t) BARO_INT_LAND) + if (ao_height < AO_M_TO_HEIGHT(1000) && + ao_interval_max_height - ao_interval_min_height < AO_M_TO_HEIGHT(5)) { ao_flight_state = ao_flight_landed; @@ -733,6 +662,8 @@ ao_flight(void) ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); } + ao_interval_min_height = ao_interval_max_height = ao_height; + ao_interval_end = ao_flight_tick + AO_INTERVAL_TICKS; } break; case ao_flight_landed: diff --git a/src/ao_flight_test.c b/src/ao_flight_test.c index 16167644..e7bfbdd2 100644 --- a/src/ao_flight_test.c +++ b/src/ao_flight_test.c @@ -29,6 +29,10 @@ #define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1)) #define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1)) +#define AO_M_TO_HEIGHT(m) ((int16_t) (m)) +#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16)) +#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16)) + /* * One set of samples read from the A/D converter */ @@ -143,15 +147,26 @@ struct ao_config ao_config; #ifndef HAS_ACCEL #define HAS_ACCEL 1 #define HAS_ACCEL_REF 0 -#define USE_KALMAN 0 -#else -#define USE_KALMAN 1 #endif #include "ao_flight.c" #define to_double(f) ((f) / 65536.0) +#define GRAVITY 9.80665 +extern int16_t ao_ground_accel, ao_raw_accel; +extern int16_t ao_accel_2g; + +int32_t drogue_height; +int32_t main_height; + +int tick_offset; +uint16_t prev_tick; +static int ao_records_read = 0; +static int ao_eof_read = 0; +static int ao_flight_ground_accel; +static int ao_flight_started = 0; + void ao_insert(void) { @@ -159,33 +174,39 @@ ao_insert(void) ao_adc_head = ao_adc_ring_next(ao_adc_head); if (ao_summary) return; - if (ao_flight_state != ao_flight_startup) { -#if USE_KALMAN - printf("time %7.2f accel %d pres %d k_height %8.2f k_speed %8.5f k_accel %8.5f\n", - (double) ao_adc_static.tick / 100, - ao_adc_static.accel, - ao_adc_static.pres, - to_double(ao_k_height), - to_double(ao_k_speed), - to_double(ao_k_accel)); -#else - printf("time %g accel %d pres %d\n", - (double) ao_adc_static.tick / 100, - ao_adc_static.accel, - ao_adc_static.pres); -#endif + if (ao_flight_state == ao_flight_startup) + return; + { + double height = ao_pres_to_altitude(ao_raw_pres) - ao_ground_height; + double accel = ((ao_flight_ground_accel - ao_adc_static.accel) * GRAVITY * 2.0) / + (ao_config.accel_minus_g - ao_config.accel_plus_g); + + if (!tick_offset) + tick_offset = ao_adc_static.tick; + if (!drogue_height && ao_flight_state >= ao_flight_drogue) + drogue_height = ao_k_height; + if (!main_height && ao_flight_state >= ao_flight_main) + main_height = ao_k_height; + if ((prev_tick - ao_adc_static.tick) > 0) + tick_offset += 65536; + prev_tick = ao_adc_static.tick; + printf("%7.2f height %g accel %g state %s k_height %g k_speed %g k_accel %g drogue %g main %g error %d\n", + (double) (ao_adc_static.tick + tick_offset) / 100, + height, + accel, + ao_state_names[ao_flight_state], + ao_k_height / 65536.0, + ao_k_speed / 65536.0 / 16.0, + ao_k_accel / 65536.0 / 16.0, + drogue_height / 65536.0, + main_height / 65536.0, + ao_error_h_sq_avg); } } -static int ao_records_read = 0; -static int ao_eof_read = 0; -static int ao_flight_ground_accel; -static int ao_flight_started = 0; - void ao_sleep(void *wchan) { - ao_dump_state(); if (wchan == &ao_adc_head) { char type; uint16_t tick; @@ -291,19 +312,6 @@ ao_dump_state(void) return; if (ao_summary) return; -#if HAS_ACCEL - printf ("\t\t\t\t\t%s accel %g vel %g alt %d main %d\n", - ao_state_names[ao_flight_state], - (ao_ground_accel - ao_flight_accel) / COUNTS_PER_G * GRAVITY, - (double) ao_flight_vel / 100 / COUNTS_PER_G * GRAVITY, - ao_pres_to_altitude(ao_flight_pres) - ao_pres_to_altitude(ao_ground_pres), - ao_pres_to_altitude(ao_main_pres) - ao_pres_to_altitude(ao_ground_pres)); -#else - printf ("\t\t\t\t\t%s alt %d main %d\n", - ao_state_names[ao_flight_state], - ao_pres_to_altitude(ao_flight_pres) - ao_pres_to_altitude(ao_ground_pres), - ao_pres_to_altitude(ao_main_pres) - ao_pres_to_altitude(ao_ground_pres)); -#endif if (ao_flight_state == ao_flight_landed) exit(0); } diff --git a/src/ao_log_tiny.c b/src/ao_log_tiny.c index fad2a242..f0c0662a 100644 --- a/src/ao_log_tiny.c +++ b/src/ao_log_tiny.c @@ -69,7 +69,7 @@ ao_log(void) if (ao_log_tiny_state == ao_flight_landed) ao_log_stop(); } - ao_log_tiny_data(ao_k_height >> 16); + ao_log_tiny_data(ao_height); time += ao_log_tiny_interval; delay = time - ao_time(); if (delay > 0) diff --git a/src/ao_monitor.c b/src/ao_monitor.c index d6fd8305..8f290071 100644 --- a/src/ao_monitor.c +++ b/src/ao_monitor.c @@ -92,23 +92,23 @@ ao_monitor(void) 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 + if (recv.telemetry.u.k.unused == 0x8000) { + /* Kalman state values */ + printf(AO_TELEM_KALMAN_HEIGHT " %d " + AO_TELEM_KALMAN_SPEED " %d " + AO_TELEM_KALMAN_ACCEL " %d ", + recv.telemetry.height, + recv.telemetry.u.k.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.accel, + recv.telemetry.u.flight_vel, + recv.telemetry.height); + } ao_gps_print(&recv.telemetry.gps); ao_gps_tracking_print(&recv.telemetry.gps_tracking); putchar('\n'); diff --git a/src/ao_pins.h b/src/ao_pins.h index c602268b..a4a93aab 100644 --- a/src/ao_pins.h +++ b/src/ao_pins.h @@ -28,7 +28,6 @@ #define HAS_EEPROM 1 #define USE_INTERNAL_FLASH 0 #define HAS_DBG 1 - #define USE_KALMAN 0 #define DBG_ON_P1 1 #define DBG_ON_P0 0 #define IGNITE_ON_P2 1 @@ -53,7 +52,6 @@ #define HAS_EEPROM 1 #define USE_INTERNAL_FLASH 0 #define HAS_DBG 1 - #define USE_KALMAN 0 #define DBG_ON_P1 1 #define DBG_ON_P0 0 #define IGNITE_ON_P2 1 @@ -103,7 +101,6 @@ #define HAS_EEPROM 1 #define USE_INTERNAL_FLASH 1 #define HAS_DBG 0 - #define USE_KALMAN 1 #define IGNITE_ON_P2 0 #define IGNITE_ON_P0 1 #define PACKET_HAS_MASTER 0 @@ -126,7 +123,6 @@ #define HAS_EEPROM 1 #define USE_INTERNAL_FLASH 1 #define HAS_DBG 0 - #define USE_KALMAN 1 #define IGNITE_ON_P2 0 #define IGNITE_ON_P0 1 #define PACKET_HAS_MASTER 0 @@ -147,7 +143,6 @@ #define HAS_SERIAL_1 1 #define HAS_ADC 1 #define HAS_DBG 0 - #define USE_KALMAN 0 #define HAS_EEPROM 1 #define USE_INTERNAL_FLASH 0 #define DBG_ON_P1 0 diff --git a/src/ao_report.c b/src/ao_report.c index 3223390f..4f7fd657 100644 --- a/src/ao_report.c +++ b/src/ao_report.c @@ -87,7 +87,7 @@ ao_report_digit(uint8_t digit) __reentrant static void ao_report_altitude(void) { - __xdata int16_t agl = ao_pres_to_altitude(ao_min_pres) - ao_pres_to_altitude(ao_ground_pres); + __xdata int16_t agl = ao_max_height; __xdata uint8_t digits[10]; __xdata uint8_t ndigits, i; diff --git a/src/ao_telemetry.c b/src/ao_telemetry.c index 6556ce32..9a86882f 100644 --- a/src/ao_telemetry.c +++ b/src/ao_telemetry.c @@ -45,12 +45,13 @@ ao_telemetry(void) time = ao_rdf_time = ao_time(); while (ao_telemetry_interval) { telemetry.flight_state = ao_flight_state; + telemetry.height = ao_height; + telemetry.u.k.speed = ao_speed; + telemetry.accel = ao_accel; + telemetry.u.k.unused = 0x8000; #if HAS_ACCEL - telemetry.flight_accel = ao_flight_accel; telemetry.ground_accel = ao_ground_accel; - telemetry.flight_vel = ao_flight_vel; #endif - telemetry.flight_pres = ao_flight_pres; telemetry.ground_pres = ao_ground_pres; #if HAS_ADC ao_adc_get(&telemetry.adc); diff --git a/src/ao_telemetry_tiny.c b/src/ao_telemetry_tiny.c index 83ba7fc0..6f2ddda1 100644 --- a/src/ao_telemetry_tiny.c +++ b/src/ao_telemetry_tiny.c @@ -43,9 +43,9 @@ ao_telemetry_tiny(void) time = ao_rdf_time = ao_time(); while (ao_telemetry_tiny_interval) { telemetry_tiny.flight_state = ao_flight_state; - telemetry_tiny.height = ao_k_height >> 16; - telemetry_tiny.speed = ao_k_speed >> 12; - telemetry_tiny.accel = ao_k_accel >> 12; + telemetry_tiny.height = ao_height; + telemetry_tiny.speed = ao_speed; + telemetry_tiny.accel = ao_accel; telemetry_tiny.ground_pres = ao_ground_pres; ao_adc_get(&telemetry_tiny.adc); ao_radio_send(&telemetry_tiny, sizeof (telemetry_tiny)); diff --git a/src/test/.gitignore b/src/test/.gitignore index 0a43de8a..33c7ef35 100644 --- a/src/test/.gitignore +++ b/src/test/.gitignore @@ -1,5 +1,6 @@ ao_flight_test ao_flight_test_baro +ao_flight_test_accel ao_gps_test ao_gps_test_skytraq ao_convert_test diff --git a/src/test/Makefile b/src/test/Makefile index 853713fa..433f749b 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -1,6 +1,7 @@ vpath % .. +vpath % ../kalman -PROGS=ao_flight_test ao_flight_test_baro ao_gps_test ao_gps_test_skytraq ao_convert_test +PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_gps_test ao_gps_test_skytraq ao_convert_test CFLAGS=-I.. -I. @@ -11,12 +12,15 @@ clean: install: -ao_flight_test: ao_flight_test.c ao_host.h ao_flight.c altitude.h +ao_flight_test: ao_flight_test.c ao_host.h ao_flight.c altitude.h ao_kalman.h cc -g -o $@ $< -ao_flight_test_baro: ao_flight_test.c ao_host.h ao_flight.c altitude.h +ao_flight_test_baro: ao_flight_test.c ao_host.h ao_flight.c altitude.h ao_kalman.h cc -g -o $@ -DHAS_ACCEL=0 ../ao_flight_test.c +ao_flight_test_accel: ao_flight_test.c ao_host.h ao_flight.c altitude.h ao_kalman.h + cc -g -o $@ -DFORCE_ACCEL=1 ../ao_flight_test.c + ao_gps_test: ao_gps_test.c ao_gps_sirf.c ao_gps_print.c ao_host.h cc -g -o $@ $< @@ -25,3 +29,6 @@ ao_gps_test_skytraq: ao_gps_test_skytraq.c ao_gps_skytraq.c ao_gps_print.c ao_ho ao_convert_test: ao_convert_test.c ao_convert.c altitude.h cc -g -o $@ $< + +../ao_kalman.h: make-kalman kalman.5c kalman_filter.5c load_csv.5c matrix.5c + sh $< > $@ diff --git a/src/test/plottest b/src/test/plottest new file mode 100755 index 00000000..76af5ee7 --- /dev/null +++ b/src/test/plottest @@ -0,0 +1,16 @@ +gnuplot -persist << EOF +set ylabel "altitude (m)" +set y2label "velocity (m/s), acceleration(m/s²)" +set xlabel "time (s)" +set xtics border out nomirror +set ytics border out nomirror +set y2tics border out nomirror +plot "$1" using 1:3 with lines axes x1y1 title "raw height",\ +"$1" using 1:5 with lines axes x1y2 title "raw accel",\ +"$1" using 1:9 with lines axes x1y1 title "height",\ +"$1" using 1:11 with lines axes x1y2 title "speed",\ +"$1" using 1:13 with lines axes x1y2 title "accel",\ +"$1" using 1:15 with lines axes x1y1 title "drogue",\ +"$1" using 1:17 with lines axes x1y1 title "main",\ +"$1" using 1:19 with lines axes x1y1 title "error" +EOF diff --git a/src/test/run-one b/src/test/run-one new file mode 100755 index 00000000..f9d21576 --- /dev/null +++ b/src/test/run-one @@ -0,0 +1,32 @@ +#!/bin/sh + +./ao_flight_test "$1" > run-out.full +./ao_flight_test_baro "$1" > run-out.baro +./ao_flight_test_accel "$1" > run-out.accel + +gnuplot -persist << EOF +set ylabel "altitude (m)" +set y2label "velocity (m/s), acceleration(m/s²)" +set xlabel "time (s)" +set xtics border out nomirror +set ytics border out nomirror +set y2tics border out nomirror +set title "$1" +plot "run-out.full" using 1:3 with lines lw 2 lt 1 axes x1y1 title "raw height",\ +"run-out.full" using 1:5 with lines lw 2 lt 1 axes x1y2 title "raw accel",\ +"run-out.full" using 1:9 with lines lt 2 axes x1y1 title "full height",\ +"run-out.full" using 1:11 with lines lt 2 axes x1y2 title "full speed",\ +"run-out.full" using 1:13 with lines lt 2 axes x1y2 title "full accel",\ +"run-out.full" using 1:15 with lines lt 2 axes x1y1 title "full drogue",\ +"run-out.full" using 1:17 with lines lt 2 axes x1y1 title "full main", \ +"run-out.baro" using 1:9 with lines lt 3 axes x1y1 title "baro height",\ +"run-out.baro" using 1:11 with lines lt 3 axes x1y2 title "baro speed",\ +"run-out.baro" using 1:13 with lines lt 3 axes x1y2 title "baro accel",\ +"run-out.baro" using 1:15 with lines lt 3 axes x1y1 title "baro drogue",\ +"run-out.baro" using 1:17 with lines lt 3 axes x1y1 title "baro main",\ +"run-out.accel" using 1:9 with lines lt 4 axes x1y1 title "accel height",\ +"run-out.accel" using 1:11 with lines lt 4 axes x1y2 title "accel speed",\ +"run-out.accel" using 1:13 with lines lt 4 axes x1y2 title "accel accel",\ +"run-out.accel" using 1:15 with lines lt 4 axes x1y1 title "accel drogue",\ +"run-out.accel" using 1:17 with lines lt 4 axes x1y1 title "accel main" +EOF diff --git a/src/test/test-flights b/src/test/test-flights index a9a2ecca..afdaba5a 100644 --- a/src/test/test-flights +++ b/src/test/test-flights @@ -7,7 +7,6 @@ 2009-07-18-serial-001-flight-007.eeprom 2009-08-22-serial-001-flight-001.eeprom 2009-08-22-serial-010-flight-001.eeprom -2009-09-05-serial-008-flight-002.eeprom 2009-09-05-serial-010-flight-002.eeprom 2009-09-05-serial-011-flight-001.eeprom 2009-09-11-serial-008-flight-003.eeprom -- cgit v1.2.3 From c14d6c5ace1d67bd948273ceb7eb6807b29c3806 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 22 Mar 2011 08:51:23 +0900 Subject: altos: Compute a 'trust' value for the barometer Instead of making the baro use/don't-use decision binary, use a 'trust value' which slowly migrates from baro+accel to accel-only mode. This eliminates bumps in the data from a rapid shift. Signed-off-by: Keith Packard --- src/ao_flight.c | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index c65670f0..b86603e4 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -135,7 +135,7 @@ static __pdata int32_t ao_k_accel; /* * Above this height, the baro sensor doesn't work */ -#define AO_MAX_BARO_HEIGHT 8000 +#define AO_MAX_BARO_HEIGHT 12000 /* * Above this speed, baro measurements are unreliable @@ -168,6 +168,11 @@ static void ao_kalman_err_height(void) { int16_t e; + int16_t height_distrust; +#if HAS_ACCEL + int16_t speed_distrust; +#endif + ao_error_h = ao_raw_height - (int16_t) (ao_k_height >> 16); e = ao_error_h; @@ -177,6 +182,31 @@ ao_kalman_err_height(void) e = 127; ao_error_h_sq_avg -= ao_error_h_sq_avg >> 4; ao_error_h_sq_avg += (e * e) >> 4; + + height_distrust = ao_raw_height - AO_MAX_BARO_HEIGHT; +#ifdef AO_FLIGHT_TEST + if (height_distrust > 0) + printf ("height_distrust %d\n", height_distrust); +#endif +#if HAS_ACCEL + speed_distrust = (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) >> 4; +#ifdef AO_FLIGHT_TEST + if (speed_distrust > 0) + printf ("speed distrust %d\n", speed_distrust); +#endif + if (speed_distrust <= 0) + speed_distrust = 0; + else if (speed_distrust > height_distrust) + height_distrust = speed_distrust; +#endif + if (height_distrust <= 0) + height_distrust = 0; + + if (height_distrust) { + if (height_distrust > 0x100) + height_distrust = 0x100; + ao_error_h = (int16_t) ((int32_t) ao_error_h * (0x100 - height_distrust)) >> 8; + } } static void @@ -407,16 +437,13 @@ ao_flight(void) ao_kalman_predict(); #if HAS_ACCEL if (ao_flight_state <= ao_flight_coast) { -#ifndef FORCE_ACCEL - if (/*ao_speed < AO_MS_TO_SPEED(AO_MAX_BARO_SPEED) &&*/ - ao_raw_alt < AO_MAX_BARO_HEIGHT) - ao_kalman_correct_both(); - else +#ifdef FORCE_ACCEL + ao_kalman_correct_accel(); +#else + ao_kalman_correct_both(); #endif - ao_kalman_correct_accel(); } else #endif - if (ao_raw_alt < AO_MAX_BARO_HEIGHT || ao_flight_state >= ao_flight_drogue) ao_kalman_correct_baro(); ao_height = from_fix(ao_k_height); ao_speed = from_fix(ao_k_speed); -- cgit v1.2.3 From f3053b1f3c85d4fd84b3c6cc87858f433166df34 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 22 Mar 2011 17:04:07 +0900 Subject: altos: Clean up some debug stuff in ao_flight.c Remove some spurious printf debugging. Remove an attempt at discovering broken accelerometer code. Signed-off-by: Keith Packard --- src/ao_flight.c | 24 ------------------------ 1 file changed, 24 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index b86603e4..7f194e04 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -184,16 +184,8 @@ ao_kalman_err_height(void) ao_error_h_sq_avg += (e * e) >> 4; height_distrust = ao_raw_height - AO_MAX_BARO_HEIGHT; -#ifdef AO_FLIGHT_TEST - if (height_distrust > 0) - printf ("height_distrust %d\n", height_distrust); -#endif #if HAS_ACCEL speed_distrust = (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) >> 4; -#ifdef AO_FLIGHT_TEST - if (speed_distrust > 0) - printf ("speed distrust %d\n", speed_distrust); -#endif if (speed_distrust <= 0) speed_distrust = 0; else if (speed_distrust > height_distrust) @@ -247,22 +239,6 @@ ao_kalman_correct_both(void) ao_kalman_err_height(); ao_kalman_err_accel(); -#if 0 - /* - * Check to see if things are crazy here -- - * if the computed height is far above the - * measured height, we assume that the flight - * trajectory is not vertical, and so ignore - * the accelerometer for the remainder of the - * flight. - */ - if (ao_error_h_sq_avg > 10) - { - ao_kalman_correct_baro(); - return; - } -#endif - #ifdef AO_FLIGHT_TEST if (ao_flight_tick - ao_flight_prev_tick > 5) { ao_k_height += -- cgit v1.2.3 From f30de5766c1eefb18c7d024a2cf10ce02de41071 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 22 Mar 2011 21:29:05 +0900 Subject: altos: Add ao_flight_debug code Trace the kalman filter to make sure it's working. Signed-off-by: Keith Packard --- src/ao_flight.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index 7f194e04..4c65344f 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -153,6 +153,11 @@ ao_kalman_predict(void) return; } + if (ao_flight_debug) { + printf ("predict speed %g + (%g * %g) = %g\n", + ao_k_speed / (65536.0 * 16.0), ao_accel / 16.0, AO_K_STEP_100 / 65536.0, + (ao_k_speed + (int32_t) ao_accel * AO_K_STEP_100) / (65536.0 * 16.0)); + } #endif ao_k_height += ((int32_t) ao_speed * AO_K_STEP_100 + (int32_t) ao_accel * AO_K_STEP_2_2_100) >> 4; @@ -195,9 +200,21 @@ ao_kalman_err_height(void) height_distrust = 0; if (height_distrust) { +#ifdef AO_FLIGHT_TEST + int old_ao_error_h = ao_error_h; +#endif if (height_distrust > 0x100) height_distrust = 0x100; ao_error_h = (int16_t) ((int32_t) ao_error_h * (0x100 - height_distrust)) >> 8; +#ifdef AO_FLIGHT_TEST + if (ao_flight_debug) { + printf("over height %g over speed %g distrust: %g height: error %d -> %d\n", + (double) (ao_raw_height - AO_MAX_BARO_HEIGHT), + (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) / 16.0, + height_distrust / 256.0, + old_ao_error_h, ao_error_h); + } +#endif } } @@ -241,6 +258,15 @@ ao_kalman_correct_both(void) #ifdef AO_FLIGHT_TEST if (ao_flight_tick - ao_flight_prev_tick > 5) { + if (ao_flight_debug) { + printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n", + ao_k_speed / (65536.0 * 16.0), + (double) ao_error_h, AO_BOTH_K10_10 / 65536.0, + (double) ao_error_a, AO_BOTH_K11_10 / 65536.0, + (ao_k_speed + + (int32_t) AO_BOTH_K10_10 * ao_error_h + + (int32_t) AO_BOTH_K11_10 * ao_error_a) / (65536.0 * 16.0)); + } ao_k_height += (int32_t) AO_BOTH_K00_10 * ao_error_h + (int32_t) (AO_BOTH_K01_10 >> 4) * ao_error_a; @@ -252,6 +278,15 @@ ao_kalman_correct_both(void) (int32_t) AO_BOTH_K21_10 * ao_error_a; return; } + if (ao_flight_debug) { + printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n", + ao_k_speed / (65536.0 * 16.0), + (double) ao_error_h, AO_BOTH_K10_100 / 65536.0, + (double) ao_error_a, AO_BOTH_K11_100 / 65536.0, + (ao_k_speed + + (int32_t) AO_BOTH_K10_100 * ao_error_h + + (int32_t) AO_BOTH_K11_100 * ao_error_a) / (65536.0 * 16.0)); + } #endif ao_k_height += (int32_t) AO_BOTH_K00_100 * ao_error_h + @@ -264,23 +299,23 @@ ao_kalman_correct_both(void) (int32_t) AO_BOTH_K21_100 * ao_error_a; } +#ifdef FORCE_ACCEL static void ao_kalman_correct_accel(void) { ao_kalman_err_accel(); -#ifdef AO_FLIGHT_TEST if (ao_flight_tick - ao_flight_prev_tick > 5) { ao_k_height +=(int32_t) AO_ACCEL_K0_10 * ao_error_a; ao_k_speed += (int32_t) AO_ACCEL_K1_10 * ao_error_a; ao_k_accel += (int32_t) AO_ACCEL_K2_10 * ao_error_a; return; } -#endif ao_k_height += (int32_t) AO_ACCEL_K0_100 * ao_error_a; ao_k_speed += (int32_t) AO_ACCEL_K1_100 * ao_error_a; ao_k_accel += (int32_t) AO_ACCEL_K2_100 * ao_error_a; } +#endif #endif /* HAS_ACCEL */ __xdata int32_t ao_raw_pres_sum; -- cgit v1.2.3 From a80d3836cfce3d4cfa7a71068539415c2dc421cd Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 22 Mar 2011 21:50:29 +0900 Subject: altos: Missing parens and some bad arithmetic in the kalman code Fixed point computations are a pain. Signed-off-by: Keith Packard --- src/ao_flight.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index 4c65344f..39325a69 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -140,7 +140,7 @@ static __pdata int32_t ao_k_accel; /* * Above this speed, baro measurements are unreliable */ -#define AO_MAX_BARO_SPEED 300 +#define AO_MAX_BARO_SPEED 200 static void ao_kalman_predict(void) @@ -185,12 +185,20 @@ ao_kalman_err_height(void) e = -e; if (e > 127) e = 127; +#if HAS_ACCEL + ao_error_h_sq_avg -= ao_error_h_sq_avg >> 2; + ao_error_h_sq_avg += (e * e) >> 2; +#else ao_error_h_sq_avg -= ao_error_h_sq_avg >> 4; ao_error_h_sq_avg += (e * e) >> 4; +#endif height_distrust = ao_raw_height - AO_MAX_BARO_HEIGHT; #if HAS_ACCEL - speed_distrust = (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) >> 4; + /* speed is stored * 16, but we need to ramp between 200 and 328, so + * we want to multiply by 2. The result is a shift by 3. + */ + speed_distrust = (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) >> (4 - 1); if (speed_distrust <= 0) speed_distrust = 0; else if (speed_distrust > height_distrust) @@ -205,7 +213,7 @@ ao_kalman_err_height(void) #endif if (height_distrust > 0x100) height_distrust = 0x100; - ao_error_h = (int16_t) ((int32_t) ao_error_h * (0x100 - height_distrust)) >> 8; + ao_error_h = (int16_t) (((int32_t) ao_error_h * (0x100 - height_distrust)) >> 8); #ifdef AO_FLIGHT_TEST if (ao_flight_debug) { printf("over height %g over speed %g distrust: %g height: error %d -> %d\n", @@ -269,12 +277,12 @@ ao_kalman_correct_both(void) } ao_k_height += (int32_t) AO_BOTH_K00_10 * ao_error_h + - (int32_t) (AO_BOTH_K01_10 >> 4) * ao_error_a; + (int32_t) AO_BOTH_K01_10 * ao_error_a; ao_k_speed += - ((int32_t) AO_BOTH_K10_10 << 4) * ao_error_h + + (int32_t) AO_BOTH_K10_10 * ao_error_h + (int32_t) AO_BOTH_K11_10 * ao_error_a; ao_k_accel += - ((int32_t) AO_BOTH_K20_10 << 4) * ao_error_h + + (int32_t) AO_BOTH_K20_10 * ao_error_h + (int32_t) AO_BOTH_K21_10 * ao_error_a; return; } @@ -602,23 +610,31 @@ ao_flight(void) if ((ao_accel < AO_MSS_TO_ACCEL(-2.5) && ao_height > AO_M_TO_HEIGHT(100)) || (int16_t) (ao_flight_tick - ao_launch_tick) > BOOST_TICKS_MAX) { +#if HAS_ACCEL ao_flight_state = ao_flight_fast; +#else + ao_flight_state = ao_flight_coast; +#endif ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); break; } break; +#if HAS_ACCEL case ao_flight_fast: /* * This is essentially the same as coast, * but the barometer is being ignored as * it may be unreliable. */ - if (ao_speed < AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) { + if (ao_speed < AO_MS_TO_SPEED(AO_MAX_BARO_SPEED) && + (ao_raw_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 30)) + { ao_flight_state = ao_flight_coast; ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); break; } break; +#endif case ao_flight_coast: /* apogee detect: coast to drogue deploy: @@ -629,7 +645,11 @@ ao_flight(void) * the measured altitude reasonably closely; otherwise * we're probably transsonic. */ - if (ao_speed < 0 && (ao_raw_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 100)) + if (ao_speed < 0 +#if !HAS_ACCEL + && (ao_raw_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 30) +#endif + ) { /* ignite the drogue charge */ ao_ignite(ao_igniter_drogue); -- cgit v1.2.3 From 32364c9e0d346e0e5d517e18d4e90b8ff2fa944f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 23 Mar 2011 10:33:38 +0900 Subject: altos: Ignore alt error for fast->coast. Allow larger error for baro apogee. With the fixed kalman filter, transitions across mach don't cause bumps in the merged filter. And, with working kalman bits, the signal for broken baro detection is stronger and so we can allow for baro apogee detection in cases where noise occurs close to apogee. Bump the kalman filter to trust the baro less so that the model tracks across mach. Signed-off-by: Keith Packard --- src/ao_flight.c | 5 ++--- src/make-kalman | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index 39325a69..88f0544f 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -626,8 +626,7 @@ ao_flight(void) * but the barometer is being ignored as * it may be unreliable. */ - if (ao_speed < AO_MS_TO_SPEED(AO_MAX_BARO_SPEED) && - (ao_raw_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 30)) + if (ao_speed < AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) { ao_flight_state = ao_flight_coast; ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); @@ -647,7 +646,7 @@ ao_flight(void) */ if (ao_speed < 0 #if !HAS_ACCEL - && (ao_raw_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 30) + && (ao_raw_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 100) #endif ) { diff --git a/src/make-kalman b/src/make-kalman index 6fb181ec..5a25e1ec 100644 --- a/src/make-kalman +++ b/src/make-kalman @@ -2,8 +2,8 @@ cd ../kalman -SIGMA_BOTH="-M 2 -H 4 -A 4" -SIGMA_BARO="-M 2 -H 4 -A 4" +SIGMA_BOTH="-M 2 -H 6 -A 2" +SIGMA_BARO="-M 2 -H 6 -A 2" SIGMA_ACCEL="-M 2 -H 4 -A 4" nickle kalman.5c -p AO_BOTH -c both -t 0.01 $SIGMA_BOTH -- cgit v1.2.3 From c754759a2d503633d527da4ebb20eb859cd506fd Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 28 Mar 2011 17:54:44 -0700 Subject: altos: Split up flight code into separate flight/sample/kalman bits The flight code mashed together data processing, filtering and actual flight managament into one giant pile. Split things up so that we have: ao_sample.c: Sensor data processing. Reads the ring, handles calibration ao_kalman.c: Filter the data to track the accel/speed/height values ao_flight.c: Flight state management, specific to rocketry. The plan is to re-use ao_sample.c and ao_kalman.c for hardware not specifically designed for rocketry, like TeleNano. Signed-off-by: Keith Packard --- src/Makefile.proto | 6 + src/ao.h | 131 +++++++++++++-- src/ao_adc.c | 2 +- src/ao_config.c | 6 +- src/ao_flight.c | 452 ++------------------------------------------------- src/ao_flight_test.c | 43 ++++- src/ao_kalman.c | 245 ++++++++++++++++++++++++++++ src/ao_log_big.c | 8 +- src/ao_sample.c | 206 +++++++++++++++++++++++ src/ao_stdio.c | 2 +- 10 files changed, 635 insertions(+), 466 deletions(-) create mode 100644 src/ao_kalman.c create mode 100644 src/ao_sample.c (limited to 'src/ao_flight.c') diff --git a/src/Makefile.proto b/src/Makefile.proto index 85c0c46e..8dd21a64 100644 --- a/src/Makefile.proto +++ b/src/Makefile.proto @@ -147,6 +147,8 @@ SKY_DRIVER_SRC = \ # TM_TASK_SRC = \ ao_flight.c \ + ao_sample.c \ + ao_kalman.c \ ao_log.c \ ao_log_big.c \ ao_report.c \ @@ -179,6 +181,8 @@ TMINI_DRIVER_SRC = \ TMINI_TASK_SRC = \ ao_flight.c \ + ao_sample.c \ + ao_kalman.c \ ao_log.c \ ao_log_tiny.c \ ao_report.c \ @@ -207,6 +211,8 @@ TNANO_DRIVER_SRC = \ TNANO_TASK_SRC = \ ao_flight.c \ + ao_sample.c \ + ao_kalman.c \ ao_log.c \ ao_log_tiny.c \ ao_report.c \ diff --git a/src/ao.h b/src/ao.h index b88bef1f..42c3edda 100644 --- a/src/ao.h +++ b/src/ao.h @@ -695,22 +695,10 @@ enum ao_flight_state { ao_flight_invalid = 9 }; -extern __data uint8_t ao_flight_adc; extern __pdata enum ao_flight_state ao_flight_state; -extern __pdata uint16_t ao_flight_tick; -extern __xdata int16_t ao_ground_pres; -extern __pdata int16_t ao_ground_accel; + extern __pdata uint16_t ao_launch_time; extern __xdata uint8_t ao_flight_force_idle; -extern __pdata int16_t ao_ground_height; -extern __pdata int16_t ao_max_height; -extern __pdata int16_t ao_height; /* meters */ -extern __pdata int16_t ao_speed; /* m/s * 16 */ -extern __pdata int16_t ao_accel; /* m/s² * 16 */ - -#define AO_M_TO_HEIGHT(m) ((int16_t) (m)) -#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16)) -#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16)) /* Flight thread */ void @@ -720,6 +708,121 @@ ao_flight(void); void ao_flight_init(void); +/* + * ao_sample.c + */ + +/* + * Barometer calibration + * + * We directly sample the barometer. The specs say: + * + * Pressure range: 15-115 kPa + * Voltage at 115kPa: 2.82 + * Output scale: 27mV/kPa + * + * If we want to detect launch with the barometer, we need + * a large enough bump to not be fooled by noise. At typical + * launch elevations (0-2000m), a 200Pa pressure change cooresponds + * to about a 20m elevation change. This is 5.4mV, or about 3LSB. + * As all of our calculations are done in 16 bits, we'll actually see a change + * of 16 times this though + * + * 27 mV/kPa * 32767 / 3300 counts/mV = 268.1 counts/kPa + */ + +/* Accelerometer calibration + * + * We're sampling the accelerometer through a resistor divider which + * consists of 5k and 10k resistors. This multiplies the values by 2/3. + * That goes into the cc1111 A/D converter, which is running at 11 bits + * of precision with the bits in the MSB of the 16 bit value. Only positive + * values are used, so values should range from 0-32752 for 0-3.3V. The + * specs say we should see 40mV/g (uncalibrated), multiply by 2/3 for what + * the A/D converter sees (26.67 mV/g). We should see 32752/3300 counts/mV, + * for a final computation of: + * + * 26.67 mV/g * 32767/3300 counts/mV = 264.8 counts/g + * + * Zero g was measured at 16000 (we would expect 16384). + * Note that this value is only require to tell if the + * rocket is standing upright. Once that is determined, + * the value of the accelerometer is averaged for 100 samples + * to find the resting accelerometer value, which is used + * for all further flight computations + */ + +#define GRAVITY 9.80665 + +/* + * Above this height, the baro sensor doesn't work + */ +#define AO_MAX_BARO_HEIGHT 12000 + +/* + * Above this speed, baro measurements are unreliable + */ +#define AO_MAX_BARO_SPEED 200 + +#define ACCEL_NOSE_UP (ao_accel_2g >> 2) + +/* + * Speed and acceleration are scaled by 16 to provide a bit more + * resolution while still having reasonable range. Note that this + * limits speed to 2047m/s (around mach 6) and acceleration to + * 2047m/s² (over 200g) + */ + +#define AO_M_TO_HEIGHT(m) ((int16_t) (m)) +#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16)) +#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16)) + +extern __pdata uint16_t ao_sample_tick; /* time of last data */ +extern __pdata int16_t ao_sample_pres; /* most recent pressure sensor reading */ +extern __pdata int16_t ao_sample_alt; /* MSL of ao_sample_pres */ +extern __pdata int16_t ao_sample_height; /* AGL of ao_sample_pres */ +extern __data uint8_t ao_sample_adc; /* Ring position of last processed sample */ + +#if HAS_ACCEL +extern __pdata int16_t ao_sample_accel; /* most recent accel sensor reading */ +#endif + +extern __xdata int16_t ao_ground_pres; /* startup pressure */ +extern __xdata int16_t ao_ground_height; /* MSL of ao_ground_pres */ + +#if HAS_ACCEL +extern __xdata int16_t ao_ground_accel; /* startup acceleration */ +extern __xdata int16_t ao_accel_2g; /* factory accel calibration */ +extern __xdata int32_t ao_accel_scale; /* sensor to m/s² conversion */ +#endif + +void ao_sample_init(void); + +/* returns FALSE in preflight mode, TRUE in flight mode */ +uint8_t ao_sample(void); + +/* + * ao_kalman.c + */ + +#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5)) +#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5)) +#define from_fix(x) ((x) >> 16) + +extern __pdata int16_t ao_height; /* meters */ +extern __pdata int16_t ao_speed; /* m/s * 16 */ +extern __pdata int16_t ao_accel; /* m/s² * 16 */ +extern __pdata int16_t ao_max_height; /* max of ao_height */ + +extern __pdata int16_t ao_error_h; +extern __pdata int16_t ao_error_h_sq_avg; + +#if HAS_ACCEL +extern __pdata int16_t ao_error_a; +#endif + +void ao_kalman(void); + /* * ao_report.c */ @@ -1054,7 +1157,7 @@ extern __xdata uint8_t ao_stdin_ready; void ao_add_stdio(char (*pollchar)(void), void (*putchar)(char) __reentrant, - void (*flush)(void)); + void (*flush)(void)) __reentrant; /* * ao_ignite.c diff --git a/src/ao_adc.c b/src/ao_adc.c index d77e7753..48568383 100644 --- a/src/ao_adc.c +++ b/src/ao_adc.c @@ -41,7 +41,7 @@ ao_adc_poll(void) void ao_adc_get(__xdata struct ao_adc *packet) { - uint8_t i = ao_adc_ring_prev(ao_flight_adc); + uint8_t i = ao_adc_ring_prev(ao_sample_adc); memcpy(packet, &ao_adc_ring[i], sizeof (struct ao_adc)); } diff --git a/src/ao_config.c b/src/ao_config.c index 771b21a1..319febb9 100644 --- a/src/ao_config.c +++ b/src/ao_config.c @@ -215,10 +215,10 @@ ao_config_accel_calibrate_auto(char *orientation) __reentrant puts("Calibrating..."); flush(); i = ACCEL_CALIBRATE_SAMPLES; accel_total = 0; - cal_adc_ring = ao_flight_adc; + cal_adc_ring = ao_sample_adc; while (i) { - ao_sleep(DATA_TO_XDATA(&ao_flight_adc)); - while (i && cal_adc_ring != ao_flight_adc) { + ao_sleep(DATA_TO_XDATA(&ao_sample_adc)); + while (i && cal_adc_ring != ao_sample_adc) { accel_total += (int32_t) ao_adc_ring[cal_adc_ring].accel; cal_adc_ring = ao_adc_ring_next(cal_adc_ring); i--; diff --git a/src/ao_flight.c b/src/ao_flight.c index 88f0544f..94fbf178 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -34,13 +34,7 @@ /* Main flight thread. */ __pdata enum ao_flight_state ao_flight_state; /* current flight state */ -__pdata uint16_t ao_flight_tick; /* time of last data */ -__pdata uint16_t ao_flight_prev_tick; /* time of previous data */ -__xdata int16_t ao_ground_pres; /* startup pressure */ __pdata uint16_t ao_launch_tick; /* time of launch detect */ -#if HAS_ACCEL -__pdata int16_t ao_ground_accel; /* startup acceleration */ -#endif /* * track min/max data over a long interval to detect @@ -50,59 +44,7 @@ __pdata uint16_t ao_interval_end; __pdata int16_t ao_interval_min_height; __pdata int16_t ao_interval_max_height; -__data uint8_t ao_flight_adc; -__pdata int16_t ao_raw_pres; -__xdata uint8_t ao_flight_force_idle; - -#if HAS_ACCEL -__pdata int16_t ao_raw_accel, ao_raw_accel_prev; -__pdata int16_t ao_accel_2g; - -/* Accelerometer calibration - * - * We're sampling the accelerometer through a resistor divider which - * consists of 5k and 10k resistors. This multiplies the values by 2/3. - * That goes into the cc1111 A/D converter, which is running at 11 bits - * of precision with the bits in the MSB of the 16 bit value. Only positive - * values are used, so values should range from 0-32752 for 0-3.3V. The - * specs say we should see 40mV/g (uncalibrated), multiply by 2/3 for what - * the A/D converter sees (26.67 mV/g). We should see 32752/3300 counts/mV, - * for a final computation of: - * - * 26.67 mV/g * 32767/3300 counts/mV = 264.8 counts/g - * - * Zero g was measured at 16000 (we would expect 16384). - * Note that this value is only require to tell if the - * rocket is standing upright. Once that is determined, - * the value of the accelerometer is averaged for 100 samples - * to find the resting accelerometer value, which is used - * for all further flight computations - */ - -#define GRAVITY 9.80665 - -#define ACCEL_NOSE_UP (ao_accel_2g >> 2) - -#endif - -/* - * Barometer calibration - * - * We directly sample the barometer. The specs say: - * - * Pressure range: 15-115 kPa - * Voltage at 115kPa: 2.82 - * Output scale: 27mV/kPa - * - * If we want to detect launch with the barometer, we need - * a large enough bump to not be fooled by noise. At typical - * launch elevations (0-2000m), a 200Pa pressure change cooresponds - * to about a 20m elevation change. This is 5.4mV, or about 3LSB. - * As all of our calculations are done in 16 bits, we'll actually see a change - * of 16 times this though - * - * 27 mV/kPa * 32767 / 3300 counts/mV = 268.1 counts/kPa - */ +__xdata uint8_t ao_flight_force_idle; /* We also have a clock, which can be used to sanity check things in * case of other failures @@ -110,228 +52,6 @@ __pdata int16_t ao_accel_2g; #define BOOST_TICKS_MAX AO_SEC_TO_TICKS(15) -#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5)) -#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5)) -#define from_fix(x) ((x) >> 16) - -#include "ao_kalman.h" - -__pdata int16_t ao_ground_height; -__pdata int16_t ao_height; -__pdata int16_t ao_speed; -__pdata int16_t ao_accel; -__pdata int16_t ao_max_height; - -static __pdata int32_t ao_k_height; -static __pdata int32_t ao_k_speed; -static __pdata int32_t ao_k_accel; - -#define AO_K_STEP_100 to_fix16(0.01) -#define AO_K_STEP_2_2_100 to_fix16(0.00005) - -#define AO_K_STEP_10 to_fix16(0.1) -#define AO_K_STEP_2_2_10 to_fix16(0.005) - -/* - * Above this height, the baro sensor doesn't work - */ -#define AO_MAX_BARO_HEIGHT 12000 - -/* - * Above this speed, baro measurements are unreliable - */ -#define AO_MAX_BARO_SPEED 200 - -static void -ao_kalman_predict(void) -{ -#ifdef AO_FLIGHT_TEST - if (ao_flight_tick - ao_flight_prev_tick > 5) { - ao_k_height += ((int32_t) ao_speed * AO_K_STEP_10 + - (int32_t) ao_accel * AO_K_STEP_2_2_10) >> 4; - ao_k_speed += (int32_t) ao_accel * AO_K_STEP_10; - - return; - } - if (ao_flight_debug) { - printf ("predict speed %g + (%g * %g) = %g\n", - ao_k_speed / (65536.0 * 16.0), ao_accel / 16.0, AO_K_STEP_100 / 65536.0, - (ao_k_speed + (int32_t) ao_accel * AO_K_STEP_100) / (65536.0 * 16.0)); - } -#endif - ao_k_height += ((int32_t) ao_speed * AO_K_STEP_100 + - (int32_t) ao_accel * AO_K_STEP_2_2_100) >> 4; - ao_k_speed += (int32_t) ao_accel * AO_K_STEP_100; -} - -static __pdata int16_t ao_error_h; -static __pdata int16_t ao_raw_alt; -static __pdata int16_t ao_raw_height; -static __pdata int16_t ao_error_h_sq_avg; - -static void -ao_kalman_err_height(void) -{ - int16_t e; - int16_t height_distrust; -#if HAS_ACCEL - int16_t speed_distrust; -#endif - - ao_error_h = ao_raw_height - (int16_t) (ao_k_height >> 16); - - e = ao_error_h; - if (e < 0) - e = -e; - if (e > 127) - e = 127; -#if HAS_ACCEL - ao_error_h_sq_avg -= ao_error_h_sq_avg >> 2; - ao_error_h_sq_avg += (e * e) >> 2; -#else - ao_error_h_sq_avg -= ao_error_h_sq_avg >> 4; - ao_error_h_sq_avg += (e * e) >> 4; -#endif - - height_distrust = ao_raw_height - AO_MAX_BARO_HEIGHT; -#if HAS_ACCEL - /* speed is stored * 16, but we need to ramp between 200 and 328, so - * we want to multiply by 2. The result is a shift by 3. - */ - speed_distrust = (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) >> (4 - 1); - if (speed_distrust <= 0) - speed_distrust = 0; - else if (speed_distrust > height_distrust) - height_distrust = speed_distrust; -#endif - if (height_distrust <= 0) - height_distrust = 0; - - if (height_distrust) { -#ifdef AO_FLIGHT_TEST - int old_ao_error_h = ao_error_h; -#endif - if (height_distrust > 0x100) - height_distrust = 0x100; - ao_error_h = (int16_t) (((int32_t) ao_error_h * (0x100 - height_distrust)) >> 8); -#ifdef AO_FLIGHT_TEST - if (ao_flight_debug) { - printf("over height %g over speed %g distrust: %g height: error %d -> %d\n", - (double) (ao_raw_height - AO_MAX_BARO_HEIGHT), - (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) / 16.0, - height_distrust / 256.0, - old_ao_error_h, ao_error_h); - } -#endif - } -} - -static void -ao_kalman_correct_baro(void) -{ - ao_kalman_err_height(); -#ifdef AO_FLIGHT_TEST - if (ao_flight_tick - ao_flight_prev_tick > 5) { - ao_k_height += (int32_t) AO_BARO_K0_10 * ao_error_h; - ao_k_speed += (int32_t) AO_BARO_K1_10 * ao_error_h; - ao_k_accel += (int32_t) AO_BARO_K2_10 * ao_error_h; - return; - } -#endif - ao_k_height += (int32_t) AO_BARO_K0_100 * ao_error_h; - ao_k_speed += (int32_t) AO_BARO_K1_100 * ao_error_h; - ao_k_accel += (int32_t) AO_BARO_K2_100 * ao_error_h; -} - -#if HAS_ACCEL -static __pdata int16_t ao_error_a; -static __pdata int32_t ao_accel_scale; - -static void -ao_kalman_err_accel(void) -{ - int32_t accel; - - accel = (ao_ground_accel - ao_raw_accel) * ao_accel_scale; - - /* Can't use ao_accel here as it is the pre-prediction value still */ - ao_error_a = (accel - ao_k_accel) >> 16; -} - -static void -ao_kalman_correct_both(void) -{ - ao_kalman_err_height(); - ao_kalman_err_accel(); - -#ifdef AO_FLIGHT_TEST - if (ao_flight_tick - ao_flight_prev_tick > 5) { - if (ao_flight_debug) { - printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n", - ao_k_speed / (65536.0 * 16.0), - (double) ao_error_h, AO_BOTH_K10_10 / 65536.0, - (double) ao_error_a, AO_BOTH_K11_10 / 65536.0, - (ao_k_speed + - (int32_t) AO_BOTH_K10_10 * ao_error_h + - (int32_t) AO_BOTH_K11_10 * ao_error_a) / (65536.0 * 16.0)); - } - ao_k_height += - (int32_t) AO_BOTH_K00_10 * ao_error_h + - (int32_t) AO_BOTH_K01_10 * ao_error_a; - ao_k_speed += - (int32_t) AO_BOTH_K10_10 * ao_error_h + - (int32_t) AO_BOTH_K11_10 * ao_error_a; - ao_k_accel += - (int32_t) AO_BOTH_K20_10 * ao_error_h + - (int32_t) AO_BOTH_K21_10 * ao_error_a; - return; - } - if (ao_flight_debug) { - printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n", - ao_k_speed / (65536.0 * 16.0), - (double) ao_error_h, AO_BOTH_K10_100 / 65536.0, - (double) ao_error_a, AO_BOTH_K11_100 / 65536.0, - (ao_k_speed + - (int32_t) AO_BOTH_K10_100 * ao_error_h + - (int32_t) AO_BOTH_K11_100 * ao_error_a) / (65536.0 * 16.0)); - } -#endif - ao_k_height += - (int32_t) AO_BOTH_K00_100 * ao_error_h + - (int32_t) AO_BOTH_K01_100 * ao_error_a; - ao_k_speed += - (int32_t) AO_BOTH_K10_100 * ao_error_h + - (int32_t) AO_BOTH_K11_100 * ao_error_a; - ao_k_accel += - (int32_t) AO_BOTH_K20_100 * ao_error_h + - (int32_t) AO_BOTH_K21_100 * ao_error_a; -} - -#ifdef FORCE_ACCEL -static void -ao_kalman_correct_accel(void) -{ - ao_kalman_err_accel(); - - if (ao_flight_tick - ao_flight_prev_tick > 5) { - ao_k_height +=(int32_t) AO_ACCEL_K0_10 * ao_error_a; - ao_k_speed += (int32_t) AO_ACCEL_K1_10 * ao_error_a; - ao_k_accel += (int32_t) AO_ACCEL_K2_10 * ao_error_a; - return; - } - ao_k_height += (int32_t) AO_ACCEL_K0_100 * ao_error_a; - ao_k_speed += (int32_t) AO_ACCEL_K1_100 * ao_error_a; - ao_k_accel += (int32_t) AO_ACCEL_K2_100 * ao_error_a; -} -#endif -#endif /* HAS_ACCEL */ - -__xdata int32_t ao_raw_pres_sum; - -#ifdef HAS_ACCEL -__xdata int32_t ao_raw_accel_sum; -#endif - /* Landing is detected by getting constant readings from both pressure and accelerometer * for a fairly long time (AO_INTERVAL_TICKS) */ @@ -342,162 +62,20 @@ __xdata int32_t ao_raw_accel_sum; void ao_flight(void) { - __pdata static uint16_t nsamples = 0; - - ao_flight_adc = ao_adc_head; - ao_raw_pres = 0; -#if HAS_ACCEL - ao_raw_accel_prev = 0; - ao_raw_accel = 0; -#endif - ao_flight_tick = 0; + ao_sample_init(); + ao_flight_state = ao_flight_startup; for (;;) { - ao_wakeup(DATA_TO_XDATA(&ao_flight_adc)); - ao_sleep(DATA_TO_XDATA(&ao_adc_head)); - while (ao_flight_adc != ao_adc_head) { - __xdata struct ao_adc *ao_adc; - ao_flight_prev_tick = ao_flight_tick; - - /* Capture a sample */ - ao_adc = &ao_adc_ring[ao_flight_adc]; - ao_flight_tick = ao_adc->tick; - ao_raw_pres = ao_adc->pres; - ao_raw_alt = ao_pres_to_altitude(ao_raw_pres); - ao_raw_height = ao_raw_alt - ao_ground_height; -#if HAS_ACCEL - ao_raw_accel = ao_adc->accel; -#if HAS_ACCEL_REF - /* - * Ok, the math here is a bit tricky. - * - * ao_raw_accel: ADC output for acceleration - * ao_accel_ref: ADC output for the 5V reference. - * ao_cook_accel: Corrected acceleration value - * Vcc: 3.3V supply to the CC1111 - * Vac: 5V supply to the accelerometer - * accel: input voltage to accelerometer ADC pin - * ref: input voltage to 5V reference ADC pin - * - * - * Measured acceleration is ratiometric to Vcc: - * - * ao_raw_accel accel - * ------------ = ----- - * 32767 Vcc - * - * Measured 5v reference is also ratiometric to Vcc: - * - * ao_accel_ref ref - * ------------ = ----- - * 32767 Vcc - * - * - * ao_accel_ref = 32767 * (ref / Vcc) - * - * Acceleration is measured ratiometric to the 5V supply, - * so what we want is: - * - * ao_cook_accel accel - * ------------- = ----- - * 32767 ref - * - * - * accel Vcc - * = ----- * --- - * Vcc ref - * - * ao_raw_accel 32767 - * = ------------ * ------------ - * 32737 ao_accel_ref - * - * Multiply through by 32767: - * - * ao_raw_accel * 32767 - * ao_cook_accel = -------------------- - * ao_accel_ref - * - * Now, the tricky part. Getting this to compile efficiently - * and keeping all of the values in-range. - * - * First off, we need to use a shift of 16 instead of * 32767 as SDCC - * does the obvious optimizations for byte-granularity shifts: - * - * ao_cook_accel = (ao_raw_accel << 16) / ao_accel_ref - * - * Next, lets check our input ranges: - * - * 0 <= ao_raw_accel <= 0x7fff (singled ended ADC conversion) - * 0x7000 <= ao_accel_ref <= 0x7fff (the 5V ref value is close to 0x7fff) - * - * Plugging in our input ranges, we get an output range of 0 - 0x12490, - * which is 17 bits. That won't work. If we take the accel ref and shift - * by a bit, we'll change its range: - * - * 0xe000 <= ao_accel_ref<<1 <= 0xfffe - * - * ao_cook_accel = (ao_raw_accel << 16) / (ao_accel_ref << 1) - * - * Now the output range is 0 - 0x9248, which nicely fits in 16 bits. It - * is, however, one bit too large for our signed computations. So, we - * take the result and shift that by a bit: - * - * ao_cook_accel = ((ao_raw_accel << 16) / (ao_accel_ref << 1)) >> 1 - * - * This finally creates an output range of 0 - 0x4924. As the ADC only - * provides 11 bits of data, we haven't actually lost any precision, - * just dropped a bit of noise off the low end. - */ - ao_raw_accel = (uint16_t) ((((uint32_t) ao_raw_accel << 16) / (ao_accel_ref[ao_flight_adc] << 1))) >> 1; - ao_adc->accel = ao_raw_accel; -#endif -#endif - if (ao_flight_state > ao_flight_idle) { - ao_kalman_predict(); -#if HAS_ACCEL - if (ao_flight_state <= ao_flight_coast) { -#ifdef FORCE_ACCEL - ao_kalman_correct_accel(); -#else - ao_kalman_correct_both(); -#endif - } else -#endif - ao_kalman_correct_baro(); - ao_height = from_fix(ao_k_height); - ao_speed = from_fix(ao_k_speed); - ao_accel = from_fix(ao_k_accel); - if (ao_height > ao_max_height) - ao_max_height = ao_height; - } - ao_flight_adc = ao_adc_ring_next(ao_flight_adc); - } + /* + * Process ADC samples, just looping + * until the sensors are calibrated. + */ + if (!ao_sample()) + continue; switch (ao_flight_state) { case ao_flight_startup: - /* startup state: - * - * Collect 512 samples of acceleration and pressure - * data and average them to find the resting values - */ - if (nsamples < 512) { -#if HAS_ACCEL - ao_raw_accel_sum += ao_raw_accel; -#endif - ao_raw_pres_sum += ao_raw_pres; - ++nsamples; - continue; - } - ao_config_get(); -#if HAS_ACCEL - ao_ground_accel = ao_raw_accel_sum >> 9; - ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g; - ao_accel_scale = to_fix32(GRAVITY * 2 * 16) / ao_accel_2g; -#endif - ao_ground_pres = ao_raw_pres_sum >> 9; - ao_ground_height = ao_pres_to_altitude(ao_ground_pres); - /* Check to see what mode we should go to. * - Invalid mode if accel cal appears to be out * - pad mode if we're upright, @@ -574,7 +152,7 @@ ao_flight(void) ) { ao_flight_state = ao_flight_boost; - ao_launch_tick = ao_flight_tick; + ao_launch_tick = ao_sample_tick; /* start logging data */ ao_log_start(); @@ -608,7 +186,7 @@ ao_flight(void) * (15 seconds) has past. */ if ((ao_accel < AO_MSS_TO_ACCEL(-2.5) && ao_height > AO_M_TO_HEIGHT(100)) || - (int16_t) (ao_flight_tick - ao_launch_tick) > BOOST_TICKS_MAX) + (int16_t) (ao_sample_tick - ao_launch_tick) > BOOST_TICKS_MAX) { #if HAS_ACCEL ao_flight_state = ao_flight_fast; @@ -646,7 +224,7 @@ ao_flight(void) */ if (ao_speed < 0 #if !HAS_ACCEL - && (ao_raw_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 100) + && (ao_sample_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 100) #endif ) { @@ -662,7 +240,7 @@ ao_flight(void) */ /* initialize interval values */ - ao_interval_end = ao_flight_tick + AO_INTERVAL_TICKS; + ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; ao_interval_min_height = ao_interval_max_height = ao_height; @@ -706,7 +284,7 @@ ao_flight(void) if (ao_height > ao_interval_max_height) ao_interval_max_height = ao_height; - if ((int16_t) (ao_flight_tick - ao_interval_end) >= 0) { + if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) { if (ao_height < AO_M_TO_HEIGHT(1000) && ao_interval_max_height - ao_interval_min_height < AO_M_TO_HEIGHT(5)) { @@ -720,7 +298,7 @@ ao_flight(void) ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); } ao_interval_min_height = ao_interval_max_height = ao_height; - ao_interval_end = ao_flight_tick + AO_INTERVAL_TICKS; + ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; } break; case ao_flight_landed: diff --git a/src/ao_flight_test.c b/src/ao_flight_test.c index 91aa0f73..f41acbca 100644 --- a/src/ao_flight_test.c +++ b/src/ao_flight_test.c @@ -53,6 +53,22 @@ struct ao_adc { #define __code #define __reentrant +#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5)) +#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5)) +#define from_fix(x) ((x) >> 16) + +/* + * Above this height, the baro sensor doesn't work + */ +#define AO_MAX_BARO_HEIGHT 12000 + +/* + * Above this speed, baro measurements are unreliable + */ +#define AO_MAX_BARO_SPEED 200 + +#define ACCEL_NOSE_UP (ao_accel_2g >> 2) + enum ao_flight_state { ao_flight_startup = 0, ao_flight_idle = 1, @@ -66,6 +82,11 @@ enum ao_flight_state { ao_flight_invalid = 9 }; +extern enum ao_flight_state ao_flight_state; + +#define FALSE 0 +#define TRUE 1 + struct ao_adc ao_adc_ring[AO_ADC_RING]; uint8_t ao_adc_head; int ao_summary = 0; @@ -171,15 +192,25 @@ struct ao_config ao_config; #define HAS_ACCEL_REF 0 #endif -#include "ao_flight.c" - -#define to_double(f) ((f) / 65536.0) - #define GRAVITY 9.80665 -extern int16_t ao_ground_accel, ao_raw_accel; +extern int16_t ao_ground_accel, ao_flight_accel; extern int16_t ao_accel_2g; +extern uint16_t ao_sample_tick; + +extern int16_t ao_sample_height; +extern int16_t ao_sample_accel; +extern int32_t ao_accel_scale; + +int ao_sample_prev_tick; uint16_t prev_tick; + +#include "ao_kalman.c" +#include "ao_sample.c" +#include "ao_flight.c" + +#define to_double(f) ((f) / 65536.0) + static int ao_records_read = 0; static int ao_eof_read = 0; static int ao_flight_ground_accel; @@ -224,7 +255,7 @@ ao_insert(void) ao_adc_ring[ao_adc_head] = ao_adc_static; ao_adc_head = ao_adc_ring_next(ao_adc_head); if (ao_flight_state != ao_flight_startup) { - double height = ao_pres_to_altitude(ao_raw_pres) - ao_ground_height; + double height = ao_pres_to_altitude(ao_sample_pres) - ao_ground_height; double accel = ((ao_flight_ground_accel - ao_adc_static.accel) * GRAVITY * 2.0) / (ao_config.accel_minus_g - ao_config.accel_plus_g); diff --git a/src/ao_kalman.c b/src/ao_kalman.c new file mode 100644 index 00000000..ee99f375 --- /dev/null +++ b/src/ao_kalman.c @@ -0,0 +1,245 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_FLIGHT_TEST +#include "ao.h" +#endif + +#include "ao_kalman.h" + +static __pdata int32_t ao_k_height; +static __pdata int32_t ao_k_speed; +static __pdata int32_t ao_k_accel; + +#define AO_K_STEP_100 to_fix16(0.01) +#define AO_K_STEP_2_2_100 to_fix16(0.00005) + +#define AO_K_STEP_10 to_fix16(0.1) +#define AO_K_STEP_2_2_10 to_fix16(0.005) + +__pdata int16_t ao_height; +__pdata int16_t ao_speed; +__pdata int16_t ao_accel; +__pdata int16_t ao_max_height; + +__pdata int16_t ao_error_h; +__pdata int16_t ao_error_h_sq_avg; + +#if HAS_ACCEL +__pdata int16_t ao_error_a; +#endif + +static void +ao_kalman_predict(void) +{ +#ifdef AO_FLIGHT_TEST + if (ao_sample_tick - ao_sample_prev_tick > 5) { + ao_k_height += ((int32_t) ao_speed * AO_K_STEP_10 + + (int32_t) ao_accel * AO_K_STEP_2_2_10) >> 4; + ao_k_speed += (int32_t) ao_accel * AO_K_STEP_10; + + return; + } + if (ao_flight_debug) { + printf ("predict speed %g + (%g * %g) = %g\n", + ao_k_speed / (65536.0 * 16.0), ao_accel / 16.0, AO_K_STEP_100 / 65536.0, + (ao_k_speed + (int32_t) ao_accel * AO_K_STEP_100) / (65536.0 * 16.0)); + } +#endif + ao_k_height += ((int32_t) ao_speed * AO_K_STEP_100 + + (int32_t) ao_accel * AO_K_STEP_2_2_100) >> 4; + ao_k_speed += (int32_t) ao_accel * AO_K_STEP_100; +} + +static void +ao_kalman_err_height(void) +{ + int16_t e; + int16_t height_distrust; +#if HAS_ACCEL + int16_t speed_distrust; +#endif + + ao_error_h = ao_sample_height - (int16_t) (ao_k_height >> 16); + + e = ao_error_h; + if (e < 0) + e = -e; + if (e > 127) + e = 127; +#if HAS_ACCEL + ao_error_h_sq_avg -= ao_error_h_sq_avg >> 2; + ao_error_h_sq_avg += (e * e) >> 2; +#else + ao_error_h_sq_avg -= ao_error_h_sq_avg >> 4; + ao_error_h_sq_avg += (e * e) >> 4; +#endif + + height_distrust = ao_sample_height - AO_MAX_BARO_HEIGHT; +#if HAS_ACCEL + /* speed is stored * 16, but we need to ramp between 200 and 328, so + * we want to multiply by 2. The result is a shift by 3. + */ + speed_distrust = (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) >> (4 - 1); + if (speed_distrust <= 0) + speed_distrust = 0; + else if (speed_distrust > height_distrust) + height_distrust = speed_distrust; +#endif + if (height_distrust <= 0) + height_distrust = 0; + + if (height_distrust) { +#ifdef AO_FLIGHT_TEST + int old_ao_error_h = ao_error_h; +#endif + if (height_distrust > 0x100) + height_distrust = 0x100; + ao_error_h = (int16_t) (((int32_t) ao_error_h * (0x100 - height_distrust)) >> 8); +#ifdef AO_FLIGHT_TEST + if (ao_flight_debug) { + printf("over height %g over speed %g distrust: %g height: error %d -> %d\n", + (double) (ao_sample_height - AO_MAX_BARO_HEIGHT), + (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) / 16.0, + height_distrust / 256.0, + old_ao_error_h, ao_error_h); + } +#endif + } +} + +static void +ao_kalman_correct_baro(void) +{ + ao_kalman_err_height(); +#ifdef AO_FLIGHT_TEST + if (ao_sample_tick - ao_sample_prev_tick > 5) { + ao_k_height += (int32_t) AO_BARO_K0_10 * ao_error_h; + ao_k_speed += (int32_t) AO_BARO_K1_10 * ao_error_h; + ao_k_accel += (int32_t) AO_BARO_K2_10 * ao_error_h; + return; + } +#endif + ao_k_height += (int32_t) AO_BARO_K0_100 * ao_error_h; + ao_k_speed += (int32_t) AO_BARO_K1_100 * ao_error_h; + ao_k_accel += (int32_t) AO_BARO_K2_100 * ao_error_h; +} + +#if HAS_ACCEL + +static void +ao_kalman_err_accel(void) +{ + int32_t accel; + + accel = (ao_ground_accel - ao_sample_accel) * ao_accel_scale; + + /* Can't use ao_accel here as it is the pre-prediction value still */ + ao_error_a = (accel - ao_k_accel) >> 16; +} + +static void +ao_kalman_correct_both(void) +{ + ao_kalman_err_height(); + ao_kalman_err_accel(); + +#ifdef AO_FLIGHT_TEST + if (ao_sample_tick - ao_sample_prev_tick > 5) { + if (ao_flight_debug) { + printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n", + ao_k_speed / (65536.0 * 16.0), + (double) ao_error_h, AO_BOTH_K10_10 / 65536.0, + (double) ao_error_a, AO_BOTH_K11_10 / 65536.0, + (ao_k_speed + + (int32_t) AO_BOTH_K10_10 * ao_error_h + + (int32_t) AO_BOTH_K11_10 * ao_error_a) / (65536.0 * 16.0)); + } + ao_k_height += + (int32_t) AO_BOTH_K00_10 * ao_error_h + + (int32_t) AO_BOTH_K01_10 * ao_error_a; + ao_k_speed += + (int32_t) AO_BOTH_K10_10 * ao_error_h + + (int32_t) AO_BOTH_K11_10 * ao_error_a; + ao_k_accel += + (int32_t) AO_BOTH_K20_10 * ao_error_h + + (int32_t) AO_BOTH_K21_10 * ao_error_a; + return; + } + if (ao_flight_debug) { + printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n", + ao_k_speed / (65536.0 * 16.0), + (double) ao_error_h, AO_BOTH_K10_100 / 65536.0, + (double) ao_error_a, AO_BOTH_K11_100 / 65536.0, + (ao_k_speed + + (int32_t) AO_BOTH_K10_100 * ao_error_h + + (int32_t) AO_BOTH_K11_100 * ao_error_a) / (65536.0 * 16.0)); + } +#endif + ao_k_height += + (int32_t) AO_BOTH_K00_100 * ao_error_h + + (int32_t) AO_BOTH_K01_100 * ao_error_a; + ao_k_speed += + (int32_t) AO_BOTH_K10_100 * ao_error_h + + (int32_t) AO_BOTH_K11_100 * ao_error_a; + ao_k_accel += + (int32_t) AO_BOTH_K20_100 * ao_error_h + + (int32_t) AO_BOTH_K21_100 * ao_error_a; +} + +#ifdef FORCE_ACCEL +static void +ao_kalman_correct_accel(void) +{ + ao_kalman_err_accel(); + + if (ao_sample_tick - ao_sample_prev_tick > 5) { + ao_k_height +=(int32_t) AO_ACCEL_K0_10 * ao_error_a; + ao_k_speed += (int32_t) AO_ACCEL_K1_10 * ao_error_a; + ao_k_accel += (int32_t) AO_ACCEL_K2_10 * ao_error_a; + return; + } + ao_k_height += (int32_t) AO_ACCEL_K0_100 * ao_error_a; + ao_k_speed += (int32_t) AO_ACCEL_K1_100 * ao_error_a; + ao_k_accel += (int32_t) AO_ACCEL_K2_100 * ao_error_a; +} +#endif +#endif /* HAS_ACCEL */ + +void +ao_kalman(void) +{ + ao_kalman_predict(); +#if HAS_ACCEL + if (ao_flight_state <= ao_flight_coast) { +#ifdef FORCE_ACCEL + ao_kalman_correct_accel(); +#else + ao_kalman_correct_both(); +#endif + } else +#endif + ao_kalman_correct_baro(); + ao_height = from_fix(ao_k_height); + ao_speed = from_fix(ao_k_speed); + ao_accel = from_fix(ao_k_accel); + if (ao_height > ao_max_height) + ao_max_height = ao_height; +#ifdef AO_FLIGHT_TEST + ao_sample_prev_tick = ao_sample_tick; +#endif +} diff --git a/src/ao_log_big.c b/src/ao_log_big.c index ab6b02f5..0c6cff85 100644 --- a/src/ao_log_big.c +++ b/src/ao_log_big.c @@ -82,7 +82,7 @@ ao_log(void) ao_sleep(&ao_log_running); log.type = AO_LOG_FLIGHT; - log.tick = ao_flight_tick; + log.tick = ao_sample_tick; #if HAS_ACCEL log.u.flight.ground_accel = ao_ground_accel; #endif @@ -92,12 +92,12 @@ ao_log(void) /* Write the whole contents of the ring to the log * when starting up. */ - ao_log_adc_pos = ao_adc_ring_next(ao_flight_adc); + ao_log_adc_pos = ao_adc_ring_next(ao_sample_adc); next_other = next_sensor = ao_adc_ring[ao_log_adc_pos].tick; ao_log_state = ao_flight_startup; for (;;) { /* Write samples to EEPROM */ - while (ao_log_adc_pos != ao_flight_adc) { + while (ao_log_adc_pos != ao_sample_adc) { log.tick = ao_adc_ring[ao_log_adc_pos].tick; if ((int16_t) (log.tick - next_sensor) >= 0) { log.type = AO_LOG_SENSOR; @@ -126,7 +126,7 @@ ao_log(void) if (ao_flight_state != ao_log_state) { ao_log_state = ao_flight_state; log.type = AO_LOG_STATE; - log.tick = ao_flight_tick; + log.tick = ao_sample_tick; log.u.state.state = ao_log_state; log.u.state.reason = 0; ao_log_data(&log); diff --git a/src/ao_sample.c b/src/ao_sample.c new file mode 100644 index 00000000..ef403393 --- /dev/null +++ b/src/ao_sample.c @@ -0,0 +1,206 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_FLIGHT_TEST +#include "ao.h" +#endif + +/* + * Current sensor values + */ + +__pdata uint16_t ao_sample_tick; /* time of last data */ +__pdata int16_t ao_sample_pres; +__pdata int16_t ao_sample_alt; +__pdata int16_t ao_sample_height; +#if HAS_ACCEL +__pdata int16_t ao_sample_accel; +#endif + +__data uint8_t ao_sample_adc; + +/* + * Sensor calibration values + */ + +__xdata int16_t ao_ground_pres; /* startup pressure */ +__xdata int16_t ao_ground_height; /* MSL of ao_ground_pres */ + +#if HAS_ACCEL +__xdata int16_t ao_ground_accel; /* startup acceleration */ +__xdata int16_t ao_accel_2g; /* factory accel calibration */ +__xdata int32_t ao_accel_scale; /* sensor to m/s² conversion */ +#endif + +static __xdata uint8_t ao_preflight; /* in preflight mode */ + +static __xdata uint16_t nsamples; +__xdata int32_t ao_sample_pres_sum; +#if HAS_ACCEL +__xdata int32_t ao_sample_accel_sum; +#endif + +static void +ao_sample_preflight(void) +{ + /* startup state: + * + * Collect 512 samples of acceleration and pressure + * data and average them to find the resting values + */ + if (nsamples < 512) { +#if HAS_ACCEL + ao_sample_accel_sum += ao_sample_accel; +#endif + ao_sample_pres_sum += ao_sample_pres; + ++nsamples; + ao_preflight = FALSE; + } + ao_config_get(); +#if HAS_ACCEL + ao_ground_accel = ao_sample_accel_sum >> 9; + ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g; + ao_accel_scale = to_fix32(GRAVITY * 2 * 16) / ao_accel_2g; +#endif + ao_ground_pres = ao_sample_pres_sum >> 9; + ao_ground_height = ao_pres_to_altitude(ao_ground_pres); +} + +uint8_t +ao_sample(void) +{ + ao_wakeup(DATA_TO_XDATA(&ao_sample_adc)); + ao_sleep(DATA_TO_XDATA(&ao_adc_head)); + while (ao_sample_adc != ao_adc_head) { + __xdata struct ao_adc *ao_adc; + + /* Capture a sample */ + ao_adc = &ao_adc_ring[ao_sample_adc]; + ao_sample_tick = ao_adc->tick; + ao_sample_pres = ao_adc->pres; + ao_sample_alt = ao_pres_to_altitude(ao_sample_pres); + ao_sample_height = ao_sample_alt - ao_ground_height; +#if HAS_ACCEL + ao_sample_accel = ao_adc->accel; +#if HAS_ACCEL_REF + /* + * Ok, the math here is a bit tricky. + * + * ao_sample_accel: ADC output for acceleration + * ao_accel_ref: ADC output for the 5V reference. + * ao_cook_accel: Corrected acceleration value + * Vcc: 3.3V supply to the CC1111 + * Vac: 5V supply to the accelerometer + * accel: input voltage to accelerometer ADC pin + * ref: input voltage to 5V reference ADC pin + * + * + * Measured acceleration is ratiometric to Vcc: + * + * ao_sample_accel accel + * ------------ = ----- + * 32767 Vcc + * + * Measured 5v reference is also ratiometric to Vcc: + * + * ao_accel_ref ref + * ------------ = ----- + * 32767 Vcc + * + * + * ao_accel_ref = 32767 * (ref / Vcc) + * + * Acceleration is measured ratiometric to the 5V supply, + * so what we want is: + * + * ao_cook_accel accel + * ------------- = ----- + * 32767 ref + * + * + * accel Vcc + * = ----- * --- + * Vcc ref + * + * ao_sample_accel 32767 + * = ------------ * ------------ + * 32737 ao_accel_ref + * + * Multiply through by 32767: + * + * ao_sample_accel * 32767 + * ao_cook_accel = -------------------- + * ao_accel_ref + * + * Now, the tricky part. Getting this to compile efficiently + * and keeping all of the values in-range. + * + * First off, we need to use a shift of 16 instead of * 32767 as SDCC + * does the obvious optimizations for byte-granularity shifts: + * + * ao_cook_accel = (ao_sample_accel << 16) / ao_accel_ref + * + * Next, lets check our input ranges: + * + * 0 <= ao_sample_accel <= 0x7fff (singled ended ADC conversion) + * 0x7000 <= ao_accel_ref <= 0x7fff (the 5V ref value is close to 0x7fff) + * + * Plugging in our input ranges, we get an output range of 0 - 0x12490, + * which is 17 bits. That won't work. If we take the accel ref and shift + * by a bit, we'll change its range: + * + * 0xe000 <= ao_accel_ref<<1 <= 0xfffe + * + * ao_cook_accel = (ao_sample_accel << 16) / (ao_accel_ref << 1) + * + * Now the output range is 0 - 0x9248, which nicely fits in 16 bits. It + * is, however, one bit too large for our signed computations. So, we + * take the result and shift that by a bit: + * + * ao_cook_accel = ((ao_sample_accel << 16) / (ao_accel_ref << 1)) >> 1 + * + * This finally creates an output range of 0 - 0x4924. As the ADC only + * provides 11 bits of data, we haven't actually lost any precision, + * just dropped a bit of noise off the low end. + */ + ao_sample_accel = (uint16_t) ((((uint32_t) ao_sample_accel << 16) / (ao_accel_ref[ao_sample_adc] << 1))) >> 1; + ao_adc->accel = ao_sample_accel; +#endif +#endif + + if (ao_preflight) + ao_sample_preflight(); + else + ao_kalman(); + ao_sample_adc = ao_adc_ring_next(ao_sample_adc); + } + return !ao_preflight; +} + +void +ao_sample_init(void) +{ + nsamples = 0; + ao_sample_pres_sum = 0; + ao_sample_pres = 0; +#if HAS_ACCEL + ao_sample_accel_sum = 0; + ao_sample_accel = 0; +#endif + ao_sample_adc = ao_adc_head; + ao_preflight = TRUE; +} diff --git a/src/ao_stdio.c b/src/ao_stdio.c index 78bbd3c3..6e1f5eff 100644 --- a/src/ao_stdio.c +++ b/src/ao_stdio.c @@ -66,7 +66,7 @@ getchar(void) __reentrant __critical void ao_add_stdio(char (*pollchar)(void), void (*putchar)(char), - void (*flush)(void)) + void (*flush)(void)) __reentrant { if (ao_num_stdios == AO_NUM_STDIOS) ao_panic(AO_PANIC_STDIO); -- cgit v1.2.3 From 011e37f27b3926a42c8c1a74e0f179bb48829ec7 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 29 Mar 2011 18:10:46 -0700 Subject: altos: Run RDF beacon after apogee instead of waiting for landing This provides tracking when GPS fails, or on TeleMini. Signed-off-by: Keith Packard --- src/ao_flight.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index 94fbf178..c6cbbf7c 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -234,6 +234,9 @@ ao_flight(void) /* slow down the telemetry system */ ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_RECOVER); + /* Turn the RDF beacon back on */ + ao_rdf_set(1); + /* * Start recording min/max height * to figure out when the rocket has landed @@ -292,8 +295,6 @@ ao_flight(void) /* turn off the ADC capture */ ao_timer_set_adc_interval(0); - /* Enable RDF beacon */ - ao_rdf_set(1); ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); } -- cgit v1.2.3 From 038d7b25ba833da4be458409670d3f95e8aaf17b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 6 Jul 2011 15:51:52 -0700 Subject: altos: Switch ao_flight and ao_flight_nano __xdata to __pdata Signed-off-by: Keith Packard --- src/ao.h | 2 +- src/ao_flight.c | 5 +---- src/ao_flight_nano.c | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao.h b/src/ao.h index 8836a286..ac5615bb 100644 --- a/src/ao.h +++ b/src/ao.h @@ -707,7 +707,7 @@ enum ao_flight_state { extern __pdata enum ao_flight_state ao_flight_state; extern __pdata uint16_t ao_launch_time; -extern __xdata uint8_t ao_flight_force_idle; +extern __pdata uint8_t ao_flight_force_idle; /* Flight thread */ void diff --git a/src/ao_flight.c b/src/ao_flight.c index c6cbbf7c..f1b60d69 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -44,7 +44,7 @@ __pdata uint16_t ao_interval_end; __pdata int16_t ao_interval_min_height; __pdata int16_t ao_interval_max_height; -__xdata uint8_t ao_flight_force_idle; +__pdata uint8_t ao_flight_force_idle; /* We also have a clock, which can be used to sanity check things in * case of other failures @@ -170,7 +170,6 @@ ao_flight(void) #endif ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - break; } break; case ao_flight_boost: @@ -194,7 +193,6 @@ ao_flight(void) ao_flight_state = ao_flight_coast; #endif ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - break; } break; #if HAS_ACCEL @@ -208,7 +206,6 @@ ao_flight(void) { ao_flight_state = ao_flight_coast; ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - break; } break; #endif diff --git a/src/ao_flight_nano.c b/src/ao_flight_nano.c index 32770227..2e332b12 100644 --- a/src/ao_flight_nano.c +++ b/src/ao_flight_nano.c @@ -30,7 +30,7 @@ __pdata uint16_t ao_interval_end; __pdata int16_t ao_interval_min_height; __pdata int16_t ao_interval_max_height; -__xdata uint8_t ao_flight_force_idle; +__pdata uint8_t ao_flight_force_idle; /* Landing is detected by getting constant readings from both pressure and accelerometer * for a fairly long time (AO_INTERVAL_TICKS) -- cgit v1.2.3 From e19a117b99e8374ca0e8e35948e23bc672ad1a32 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 1 Aug 2011 22:33:38 -0700 Subject: altos: Average height values for landing detection Instead of using the direct output of the kalman filter and hoping that is quiet enough to detect landing, filter that with a long exponential decay filter and then check to make sure that doesn't change more than 2m in 5 seconds as a trigger for landing detection. Tested with existing telemetrum flight logs and it correctly detects landing in all cases. Signed-off-by: Keith Packard --- src/ao.h | 1 + src/ao_flight.c | 15 +++++++------- src/ao_flight_test.c | 58 ++++++++++++++++++++++++++++++++++++++++++++-------- src/ao_kalman.c | 14 +++++++++++++ 4 files changed, 72 insertions(+), 16 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao.h b/src/ao.h index d3e588b6..9cde9cba 100644 --- a/src/ao.h +++ b/src/ao.h @@ -829,6 +829,7 @@ extern __pdata int16_t ao_height; /* meters */ extern __pdata int16_t ao_speed; /* m/s * 16 */ extern __pdata int16_t ao_accel; /* m/s² * 16 */ extern __pdata int16_t ao_max_height; /* max of ao_height */ +extern __pdata int16_t ao_avg_height; /* running average of height */ extern __pdata int16_t ao_error_h; extern __pdata int16_t ao_error_h_sq_avg; diff --git a/src/ao_flight.c b/src/ao_flight.c index f1b60d69..a8760ff0 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -43,7 +43,6 @@ __pdata uint16_t ao_launch_tick; /* time of launch detect */ __pdata uint16_t ao_interval_end; __pdata int16_t ao_interval_min_height; __pdata int16_t ao_interval_max_height; - __pdata uint8_t ao_flight_force_idle; /* We also have a clock, which can be used to sanity check things in @@ -242,7 +241,7 @@ ao_flight(void) /* initialize interval values */ ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; - ao_interval_min_height = ao_interval_max_height = ao_height; + ao_interval_min_height = ao_interval_max_height = ao_avg_height; /* and enter drogue state */ ao_flight_state = ao_flight_drogue; @@ -279,14 +278,14 @@ ao_flight(void) * barometer: altitude stable and within 1000m of the launch altitude */ - if (ao_height < ao_interval_min_height) - ao_interval_min_height = ao_height; - if (ao_height > ao_interval_max_height) - ao_interval_max_height = ao_height; + if (ao_avg_height < ao_interval_min_height) + ao_interval_min_height = ao_avg_height; + if (ao_avg_height > ao_interval_max_height) + ao_interval_max_height = ao_avg_height; if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) { if (ao_height < AO_M_TO_HEIGHT(1000) && - ao_interval_max_height - ao_interval_min_height < AO_M_TO_HEIGHT(5)) + ao_interval_max_height - ao_interval_min_height <= AO_M_TO_HEIGHT(2)) { ao_flight_state = ao_flight_landed; @@ -295,7 +294,7 @@ ao_flight(void) ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); } - ao_interval_min_height = ao_interval_max_height = ao_height; + ao_interval_min_height = ao_interval_max_height = ao_avg_height; ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; } break; diff --git a/src/ao_flight_test.c b/src/ao_flight_test.c index 72ad1450..e55d5ade 100644 --- a/src/ao_flight_test.c +++ b/src/ao_flight_test.c @@ -155,6 +155,7 @@ FILE *emulator_in; char *emulator_app; char *emulator_name; double emulator_error_max = 4; +double emulator_height_error_max = 20; /* noise in the baro sensor */ void ao_dump_state(void); @@ -224,12 +225,20 @@ static int ao_test_max_height; static double ao_test_max_height_time; static int ao_test_main_height; static double ao_test_main_height_time; +static double ao_test_landed_time; +static double ao_test_landed_height; +static double ao_test_landed_time; +static int landed_set; +static double landed_time; +static double landed_height; void ao_test_exit(void) { double drogue_error; double main_error; + double landed_error; + double landed_time_error; if (!ao_test_main_height_time) { ao_test_main_height_time = ao_test_max_height_time; @@ -237,16 +246,23 @@ ao_test_exit(void) } drogue_error = fabs(ao_test_max_height_time - drogue_time); main_error = fabs(ao_test_main_height_time - main_time); - if (drogue_error > emulator_error_max || main_error > emulator_error_max) { + landed_error = fabs(ao_test_landed_height - landed_height); + landed_time_error = ao_test_landed_time - landed_time; + if (drogue_error > emulator_error_max || main_error > emulator_error_max || + landed_time_error > emulator_error_max || landed_error > emulator_height_error_max) { printf ("%s %s\n", emulator_app, emulator_name); printf ("\tApogee error %g\n", drogue_error); printf ("\tMain error %g\n", main_error); - printf ("\tActual: apogee: %d at %7.2f main: %d at %7.2f\n", + printf ("\tLanded height error %g\n", landed_error); + printf ("\tLanded time error %g\n", landed_time_error); + printf ("\tActual: apogee: %d at %7.2f main: %d at %7.2f landed %7.2f at %7.2f\n", ao_test_max_height, ao_test_max_height_time, - ao_test_main_height, ao_test_main_height_time); - printf ("\tComputed: apogee: %d at %7.2f main: %d at %7.2f\n", - drogue_height, drogue_time, main_height, main_time); + ao_test_main_height, ao_test_main_height_time, + ao_test_landed_height, ao_test_landed_time); + printf ("\tComputed: apogee: %d at %7.2f main: %d at %7.2f landed %7.2f at %7.2f\n", + drogue_height, drogue_time, main_height, main_time, + landed_height, landed_time); exit (1); } exit(0); @@ -274,14 +290,27 @@ ao_insert(void) if (ao_test_max_height < height) { ao_test_max_height = height; ao_test_max_height_time = time; + ao_test_landed_height = height; + ao_test_landed_time = time; } if (height > ao_config.main_deploy) { ao_test_main_height_time = time; ao_test_main_height = height; } + if (ao_test_landed_height > height) { + ao_test_landed_height = height; + ao_test_landed_time = time; + } + + if (ao_flight_state == ao_flight_landed && !landed_set) { + landed_set = 1; + landed_time = time; + landed_height = height; + } + if (!ao_summary) { - printf("%7.2f height %g accel %g state %s k_height %g k_speed %g k_accel %g drogue %d main %d error %d\n", + printf("%7.2f height %8.2f accel %8.3f state %-8.8s k_height %8.2f k_speed %8.3f k_accel %8.3f avg_height %5d drogue %4d main %4d error %5d\n", time, height, accel, @@ -289,11 +318,13 @@ ao_insert(void) ao_k_height / 65536.0, ao_k_speed / 65536.0 / 16.0, ao_k_accel / 65536.0 / 16.0, + ao_avg_height, drogue_height, main_height, ao_error_h_sq_avg); - if (ao_flight_state == ao_flight_landed) - ao_test_exit(); + +// if (ao_flight_state == ao_flight_landed) +// ao_test_exit(); } } } @@ -495,6 +526,17 @@ ao_sleep(void *wchan) a = atoi(words[12]); b = atoi(words[14]); } + } else if (nword == 3 && strcmp(words[0], "BARO") == 0) { + tick = strtol(words[1], NULL, 16); + a = 16384 - 328; + b = strtol(words[2], NULL, 10); + type = 'A'; + if (!ao_flight_started) { + ao_flight_ground_accel = 16384 - 328; + ao_config.accel_plus_g = 16384 - 328; + ao_config.accel_minus_g = 16384 + 328; + ao_flight_started = 1; + } } else if (nword == 2 && strcmp(words[0], "TELEM") == 0) { char *hex = words[1]; char elt[3]; diff --git a/src/ao_kalman.c b/src/ao_kalman.c index 4e6cbb06..ab97fc34 100644 --- a/src/ao_kalman.c +++ b/src/ao_kalman.c @@ -38,6 +38,8 @@ __pdata int16_t ao_height; __pdata int16_t ao_speed; __pdata int16_t ao_accel; __pdata int16_t ao_max_height; +static __pdata int32_t ao_avg_height_scaled; +__pdata int16_t ao_avg_height; __pdata int16_t ao_error_h; __pdata int16_t ao_error_h_sq_avg; @@ -275,6 +277,18 @@ ao_kalman(void) ao_accel = from_fix(ao_k_accel); if (ao_height > ao_max_height) ao_max_height = ao_height; +#ifdef AO_FLIGHT_TEST + if (ao_sample_tick - ao_sample_prev_tick > 50) { + ao_avg_height = ao_height; + } else if (ao_sample_tick - ao_sample_prev_tick > 5) { + ao_avg_height_scaled = ao_avg_height_scaled - ao_avg_height + ao_height; + ao_avg_height = (ao_avg_height_scaled + 3) >> 2; + } else +#endif + { + ao_avg_height_scaled = ao_avg_height_scaled - ao_avg_height + ao_height; + ao_avg_height = (ao_avg_height_scaled + 15) >> 5; + } #ifdef AO_FLIGHT_TEST ao_sample_prev_tick = ao_sample_tick; #endif -- cgit v1.2.3 From 82e04a0e3a3296288a524ec582785a36fd644331 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 2 Aug 2011 02:09:23 -0700 Subject: altos: Require sequencing through 'main' state before landing The old version of the code would permit the flight to go straight from 'drogue' to 'landed' without passing through 'main' at all. This meant that a false landing detection would leave the main charge unfired, potentially causing the airframe to land on drogue alone. Requiring that the flight sequence pass through main ensures that the main charge will get fired at the right time, although if the airframe lands higher than that altitude, it will not go to 'landed' mode ever. Signed-off-by: Keith Packard --- src/ao_flight.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index a8760ff0..af3d6bfa 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -233,16 +233,6 @@ ao_flight(void) /* Turn the RDF beacon back on */ ao_rdf_set(1); - /* - * Start recording min/max height - * to figure out when the rocket has landed - */ - - /* initialize interval values */ - ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; - - ao_interval_min_height = ao_interval_max_height = ao_avg_height; - /* and enter drogue state */ ao_flight_state = ao_flight_drogue; ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); @@ -266,16 +256,28 @@ ao_flight(void) if (ao_height <= ao_config.main_deploy) { ao_ignite(ao_igniter_main); + + /* + * Start recording min/max height + * to figure out when the rocket has landed + */ + + /* initialize interval values */ + ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; + + ao_interval_min_height = ao_interval_max_height = ao_avg_height; + ao_flight_state = ao_flight_main; ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); } + break; /* fall through... */ case ao_flight_main: - /* drogue/main to land: + /* main to land: * - * barometer: altitude stable and within 1000m of the launch altitude + * barometer: altitude stable */ if (ao_avg_height < ao_interval_min_height) @@ -284,8 +286,7 @@ ao_flight(void) ao_interval_max_height = ao_avg_height; if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) { - if (ao_height < AO_M_TO_HEIGHT(1000) && - ao_interval_max_height - ao_interval_min_height <= AO_M_TO_HEIGHT(2)) + if (ao_interval_max_height - ao_interval_min_height <= AO_M_TO_HEIGHT(2)) { ao_flight_state = ao_flight_landed; -- cgit v1.2.3 From 709485f20fb039f8dd087c8491c5f5a76718ae53 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 13 Aug 2011 23:58:03 -0700 Subject: altos: use raw height while waiting for landing This avoids any noise introduced by the kalman filter, making landing detection much more reliable. This patch also changes the interval to 10s so that the height bounds can be increased to 4m. Signed-off-by: Keith Packard --- src/ao_flight.c | 4 ++-- src/ao_kalman.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/ao_flight.c') diff --git a/src/ao_flight.c b/src/ao_flight.c index af3d6bfa..85c1825b 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -54,7 +54,7 @@ __pdata uint8_t ao_flight_force_idle; /* Landing is detected by getting constant readings from both pressure and accelerometer * for a fairly long time (AO_INTERVAL_TICKS) */ -#define AO_INTERVAL_TICKS AO_SEC_TO_TICKS(5) +#define AO_INTERVAL_TICKS AO_SEC_TO_TICKS(10) #define abs(a) ((a) < 0 ? -(a) : (a)) @@ -286,7 +286,7 @@ ao_flight(void) ao_interval_max_height = ao_avg_height; if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) { - if (ao_interval_max_height - ao_interval_min_height <= AO_M_TO_HEIGHT(2)) + if (ao_interval_max_height - ao_interval_min_height <= AO_M_TO_HEIGHT(4)) { ao_flight_state = ao_flight_landed; diff --git a/src/ao_kalman.c b/src/ao_kalman.c index 203d727a..ee01949e 100644 --- a/src/ao_kalman.c +++ b/src/ao_kalman.c @@ -277,7 +277,7 @@ ao_kalman(void) ao_accel = from_fix(ao_k_accel); if (ao_height > ao_max_height) ao_max_height = ao_height; - ao_avg_height_scaled = ao_avg_height_scaled - ao_avg_height + ao_height; + ao_avg_height_scaled = ao_avg_height_scaled - ao_avg_height + ao_sample_height; #ifdef AO_FLIGHT_TEST if (ao_sample_tick - ao_sample_prev_tick > 50) ao_avg_height = (ao_avg_height_scaled + 1) >> 1; -- cgit v1.2.3 From 9513be7f9d3d0b0ec29f6487fa9dc8f1ac24d0de Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 25 Aug 2011 20:43:44 -0700 Subject: altos: Restructure altos build to prepare for multi-arch support Split out sources into separate directories: core: architecture and product independent bits cc1111: cc1111-specific code drivers: architecture independent drivers product: product-specific sources and Makefile fragments util: scripts for building stuff This should have no effect on the built products, but testing is encouraged Signed-off-by: Keith Packard --- configure.ac | 2 +- src/25lc1024.h | 41 - src/Makefile | 25 +- src/Makefile.proto | 380 -------- src/_bp.c | 26 - src/altitude.h | 132 --- src/ao-make-product.5c | 103 -- src/ao.h | 1610 -------------------------------- src/ao_adc.c | 196 ---- src/ao_adc_fake.c | 27 - src/ao_beep.c | 52 -- src/ao_btm.c | 302 ------ src/ao_cmd.c | 320 ------- src/ao_companion.c | 132 --- src/ao_config.c | 542 ----------- src/ao_convert.c | 85 -- src/ao_convert_test.c | 75 -- src/ao_dbg.c | 364 -------- src/ao_dma.c | 131 --- src/ao_ee.c | 241 ----- src/ao_ee_fake.c | 37 - src/ao_flash.c | 318 ------- src/ao_flight.c | 315 ------- src/ao_flight_nano.c | 120 --- src/ao_flight_test.c | 716 -------------- src/ao_gps_print.c | 112 --- src/ao_gps_report.c | 99 -- src/ao_gps_sirf.c | 442 --------- src/ao_gps_skytraq.c | 490 ---------- src/ao_gps_test.c | 508 ---------- src/ao_gps_test_skytraq.c | 490 ---------- src/ao_host.h | 127 --- src/ao_ignite.c | 218 ----- src/ao_intflash.c | 209 ----- src/ao_kalman.c | 292 ------ src/ao_led.c | 61 -- src/ao_log.c | 284 ------ src/ao_log_big.c | 158 ---- src/ao_log_telem.c | 30 - src/ao_log_tiny.c | 161 ---- src/ao_m25.c | 380 -------- src/ao_main.c | 43 - src/ao_monitor.c | 277 ------ src/ao_mutex.c | 41 - src/ao_packet.c | 148 --- src/ao_packet_master.c | 144 --- src/ao_packet_slave.c | 64 -- src/ao_panic.c | 66 -- src/ao_pins.h | 408 -------- src/ao_product.c | 155 --- src/ao_radio.c | 475 ---------- src/ao_reboot.c | 28 - src/ao_report.c | 180 ---- src/ao_romconfig.c | 32 - src/ao_rssi.c | 53 -- src/ao_sample.c | 209 ----- src/ao_serial.c | 175 ---- src/ao_spi.c | 157 ---- src/ao_state.c | 23 - src/ao_stdio.c | 84 -- src/ao_storage.c | 184 ---- src/ao_task.c | 275 ------ src/ao_telebt.c | 50 - src/ao_teledongle.c | 40 - src/ao_telem.h | 172 ---- src/ao_telemetrum.c | 70 -- src/ao_telemetry.c | 270 ------ src/ao_telemini.c | 49 - src/ao_telenano.c | 43 - src/ao_teleterra.c | 38 - src/ao_test.c | 117 --- src/ao_tidongle.c | 42 - src/ao_timer.c | 111 --- src/ao_usb.c | 460 --------- src/ao_usb.h | 100 -- src/at45db161d.h | 45 - src/cc1111.h | 1306 -------------------------- src/cc1111/Makefile.cc1111 | 27 + src/cc1111/_bp.c | 26 + src/cc1111/ao_adc.c | 196 ++++ src/cc1111/ao_beep.c | 52 ++ src/cc1111/ao_dbg.c | 364 ++++++++ src/cc1111/ao_dma.c | 131 +++ src/cc1111/ao_ignite.c | 218 +++++ src/cc1111/ao_intflash.c | 209 +++++ src/cc1111/ao_led.c | 61 ++ src/cc1111/ao_packet.c | 148 +++ src/cc1111/ao_packet_master.c | 144 +++ src/cc1111/ao_packet_slave.c | 64 ++ src/cc1111/ao_radio.c | 475 ++++++++++ src/cc1111/ao_reboot.c | 28 + src/cc1111/ao_romconfig.c | 32 + src/cc1111/ao_serial.c | 175 ++++ src/cc1111/ao_spi.c | 157 ++++ src/cc1111/ao_timer.c | 111 +++ src/cc1111/ao_usb.c | 460 +++++++++ src/cc1111/ao_usb.h | 100 ++ src/cc1111/cc1111.h | 1306 ++++++++++++++++++++++++++ src/check-stack | 13 - src/core/altitude.h | 132 +++ src/core/ao.h | 1610 ++++++++++++++++++++++++++++++++ src/core/ao_cmd.c | 320 +++++++ src/core/ao_config.c | 542 +++++++++++ src/core/ao_convert.c | 85 ++ src/core/ao_convert_test.c | 75 ++ src/core/ao_ee_fake.c | 37 + src/core/ao_flight.c | 315 +++++++ src/core/ao_flight_nano.c | 120 +++ src/core/ao_gps_print.c | 112 +++ src/core/ao_gps_report.c | 99 ++ src/core/ao_host.h | 127 +++ src/core/ao_kalman.c | 292 ++++++ src/core/ao_log.c | 284 ++++++ src/core/ao_log_big.c | 158 ++++ src/core/ao_log_telem.c | 30 + src/core/ao_log_tiny.c | 161 ++++ src/core/ao_monitor.c | 277 ++++++ src/core/ao_mutex.c | 41 + src/core/ao_panic.c | 66 ++ src/core/ao_pins.h | 408 ++++++++ src/core/ao_product.c | 155 +++ src/core/ao_report.c | 180 ++++ src/core/ao_rssi.c | 53 ++ src/core/ao_sample.c | 209 +++++ src/core/ao_state.c | 23 + src/core/ao_stdio.c | 84 ++ src/core/ao_storage.c | 184 ++++ src/core/ao_task.c | 275 ++++++ src/core/ao_telem.h | 172 ++++ src/core/ao_telemetry.c | 270 ++++++ src/drivers/ao_25lc1024.c | 241 +++++ src/drivers/ao_25lc1024.h | 41 + src/drivers/ao_at45db161d.c | 318 +++++++ src/drivers/ao_at45db161d.h | 45 + src/drivers/ao_btm.c | 302 ++++++ src/drivers/ao_companion.c | 132 +++ src/drivers/ao_gps_sirf.c | 442 +++++++++ src/drivers/ao_gps_skytraq.c | 490 ++++++++++ src/drivers/ao_m25.c | 380 ++++++++ src/gps-cksum | 17 - src/make-altitude | 283 ------ src/make-kalman | 19 - src/product/Makefile.telebt | 97 ++ src/product/Makefile.teledongle | 96 ++ src/product/Makefile.telemetrum | 111 +++ src/product/Makefile.telemini | 100 ++ src/product/Makefile.telenano | 99 ++ src/product/ao_telebt.c | 50 + src/product/ao_teledongle.c | 40 + src/product/ao_telemetrum.c | 70 ++ src/product/ao_telemini.c | 49 + src/product/ao_telenano.c | 43 + src/product/ao_teleterra.c | 38 + src/product/ao_test.c | 117 +++ src/product/ao_tidongle.c | 42 + src/sirf-cksum | 44 - src/skytraq-cksum | 44 - src/telebt-v0.0/Makefile | 10 +- src/telebt-v0.0/Makefile.defs | 8 - src/telebt-v0.1/Makefile | 20 +- src/telebt-v0.1/Makefile.defs | 8 - src/teledongle-v0.1/Makefile | 9 +- src/teledongle-v0.1/Makefile.defs | 9 - src/teledongle-v0.2/Makefile | 9 +- src/teledongle-v0.2/Makefile.defs | 9 - src/telemetrum-v0.1-sirf/Makefile | 17 +- src/telemetrum-v0.1-sirf/Makefile.defs | 12 - src/telemetrum-v0.1-sky/Makefile | 17 +- src/telemetrum-v0.1-sky/Makefile.defs | 12 - src/telemetrum-v1.0/Makefile | 17 +- src/telemetrum-v1.0/Makefile.defs | 13 - src/telemetrum-v1.1/Makefile | 17 +- src/telemetrum-v1.1/Makefile.defs | 13 - src/telemini-v1.0/Makefile | 9 +- src/telemini-v1.0/Makefile.defs | 9 - src/telenano-v0.1/Makefile | 10 +- src/telenano-v0.1/Makefile.defs | 9 - src/test/Makefile | 20 +- src/test/ao_flight_test.c | 716 ++++++++++++++ src/test/ao_gps_test.c | 508 ++++++++++ src/test/ao_gps_test_skytraq.c | 490 ++++++++++ src/tidongle/Makefile | 93 +- src/tidongle/Makefile.defs | 9 - src/util/ao-make-product.5c | 103 ++ src/util/check-stack | 13 + src/util/gps-cksum | 17 + src/util/make-altitude | 283 ++++++ src/util/make-kalman | 19 + src/util/sirf-cksum | 44 + src/util/skytraq-cksum | 44 + 190 files changed, 17208 insertions(+), 17018 deletions(-) delete mode 100644 src/25lc1024.h delete mode 100644 src/Makefile.proto delete mode 100644 src/_bp.c delete mode 100644 src/altitude.h delete mode 100644 src/ao-make-product.5c delete mode 100644 src/ao.h delete mode 100644 src/ao_adc.c delete mode 100644 src/ao_adc_fake.c delete mode 100644 src/ao_beep.c delete mode 100644 src/ao_btm.c delete mode 100644 src/ao_cmd.c delete mode 100644 src/ao_companion.c delete mode 100644 src/ao_config.c delete mode 100644 src/ao_convert.c delete mode 100644 src/ao_convert_test.c delete mode 100644 src/ao_dbg.c delete mode 100644 src/ao_dma.c delete mode 100644 src/ao_ee.c delete mode 100644 src/ao_ee_fake.c delete mode 100644 src/ao_flash.c delete mode 100644 src/ao_flight.c delete mode 100644 src/ao_flight_nano.c delete mode 100644 src/ao_flight_test.c delete mode 100644 src/ao_gps_print.c delete mode 100644 src/ao_gps_report.c delete mode 100644 src/ao_gps_sirf.c delete mode 100644 src/ao_gps_skytraq.c delete mode 100644 src/ao_gps_test.c delete mode 100644 src/ao_gps_test_skytraq.c delete mode 100644 src/ao_host.h delete mode 100644 src/ao_ignite.c delete mode 100644 src/ao_intflash.c delete mode 100644 src/ao_kalman.c delete mode 100644 src/ao_led.c delete mode 100644 src/ao_log.c delete mode 100644 src/ao_log_big.c delete mode 100644 src/ao_log_telem.c delete mode 100644 src/ao_log_tiny.c delete mode 100644 src/ao_m25.c delete mode 100644 src/ao_main.c delete mode 100644 src/ao_monitor.c delete mode 100644 src/ao_mutex.c delete mode 100644 src/ao_packet.c delete mode 100644 src/ao_packet_master.c delete mode 100644 src/ao_packet_slave.c delete mode 100644 src/ao_panic.c delete mode 100644 src/ao_pins.h delete mode 100644 src/ao_product.c delete mode 100644 src/ao_radio.c delete mode 100644 src/ao_reboot.c delete mode 100644 src/ao_report.c delete mode 100644 src/ao_romconfig.c delete mode 100644 src/ao_rssi.c delete mode 100644 src/ao_sample.c delete mode 100644 src/ao_serial.c delete mode 100644 src/ao_spi.c delete mode 100644 src/ao_state.c delete mode 100644 src/ao_stdio.c delete mode 100644 src/ao_storage.c delete mode 100644 src/ao_task.c delete mode 100644 src/ao_telebt.c delete mode 100644 src/ao_teledongle.c delete mode 100644 src/ao_telem.h delete mode 100644 src/ao_telemetrum.c delete mode 100644 src/ao_telemetry.c delete mode 100644 src/ao_telemini.c delete mode 100644 src/ao_telenano.c delete mode 100644 src/ao_teleterra.c delete mode 100644 src/ao_test.c delete mode 100644 src/ao_tidongle.c delete mode 100644 src/ao_timer.c delete mode 100644 src/ao_usb.c delete mode 100644 src/ao_usb.h delete mode 100644 src/at45db161d.h delete mode 100644 src/cc1111.h create mode 100644 src/cc1111/Makefile.cc1111 create mode 100644 src/cc1111/_bp.c create mode 100644 src/cc1111/ao_adc.c create mode 100644 src/cc1111/ao_beep.c create mode 100644 src/cc1111/ao_dbg.c create mode 100644 src/cc1111/ao_dma.c create mode 100644 src/cc1111/ao_ignite.c create mode 100644 src/cc1111/ao_intflash.c create mode 100644 src/cc1111/ao_led.c create mode 100644 src/cc1111/ao_packet.c create mode 100644 src/cc1111/ao_packet_master.c create mode 100644 src/cc1111/ao_packet_slave.c create mode 100644 src/cc1111/ao_radio.c create mode 100644 src/cc1111/ao_reboot.c create mode 100644 src/cc1111/ao_romconfig.c create mode 100644 src/cc1111/ao_serial.c create mode 100644 src/cc1111/ao_spi.c create mode 100644 src/cc1111/ao_timer.c create mode 100644 src/cc1111/ao_usb.c create mode 100644 src/cc1111/ao_usb.h create mode 100644 src/cc1111/cc1111.h delete mode 100755 src/check-stack create mode 100644 src/core/altitude.h create mode 100644 src/core/ao.h create mode 100644 src/core/ao_cmd.c create mode 100644 src/core/ao_config.c create mode 100644 src/core/ao_convert.c create mode 100644 src/core/ao_convert_test.c create mode 100644 src/core/ao_ee_fake.c create mode 100644 src/core/ao_flight.c create mode 100644 src/core/ao_flight_nano.c create mode 100644 src/core/ao_gps_print.c create mode 100644 src/core/ao_gps_report.c create mode 100644 src/core/ao_host.h create mode 100644 src/core/ao_kalman.c create mode 100644 src/core/ao_log.c create mode 100644 src/core/ao_log_big.c create mode 100644 src/core/ao_log_telem.c create mode 100644 src/core/ao_log_tiny.c create mode 100644 src/core/ao_monitor.c create mode 100644 src/core/ao_mutex.c create mode 100644 src/core/ao_panic.c create mode 100644 src/core/ao_pins.h create mode 100644 src/core/ao_product.c create mode 100644 src/core/ao_report.c create mode 100644 src/core/ao_rssi.c create mode 100644 src/core/ao_sample.c create mode 100644 src/core/ao_state.c create mode 100644 src/core/ao_stdio.c create mode 100644 src/core/ao_storage.c create mode 100644 src/core/ao_task.c create mode 100644 src/core/ao_telem.h create mode 100644 src/core/ao_telemetry.c create mode 100644 src/drivers/ao_25lc1024.c create mode 100644 src/drivers/ao_25lc1024.h create mode 100644 src/drivers/ao_at45db161d.c create mode 100644 src/drivers/ao_at45db161d.h create mode 100644 src/drivers/ao_btm.c create mode 100644 src/drivers/ao_companion.c create mode 100644 src/drivers/ao_gps_sirf.c create mode 100644 src/drivers/ao_gps_skytraq.c create mode 100644 src/drivers/ao_m25.c delete mode 100755 src/gps-cksum delete mode 100644 src/make-altitude delete mode 100644 src/make-kalman create mode 100644 src/product/Makefile.telebt create mode 100644 src/product/Makefile.teledongle create mode 100644 src/product/Makefile.telemetrum create mode 100644 src/product/Makefile.telemini create mode 100644 src/product/Makefile.telenano create mode 100644 src/product/ao_telebt.c create mode 100644 src/product/ao_teledongle.c create mode 100644 src/product/ao_telemetrum.c create mode 100644 src/product/ao_telemini.c create mode 100644 src/product/ao_telenano.c create mode 100644 src/product/ao_teleterra.c create mode 100644 src/product/ao_test.c create mode 100644 src/product/ao_tidongle.c delete mode 100755 src/sirf-cksum delete mode 100644 src/skytraq-cksum delete mode 100644 src/telebt-v0.0/Makefile.defs delete mode 100644 src/telebt-v0.1/Makefile.defs delete mode 100644 src/teledongle-v0.1/Makefile.defs delete mode 100644 src/teledongle-v0.2/Makefile.defs delete mode 100644 src/telemetrum-v0.1-sirf/Makefile.defs delete mode 100644 src/telemetrum-v0.1-sky/Makefile.defs delete mode 100644 src/telemetrum-v1.0/Makefile.defs delete mode 100644 src/telemetrum-v1.1/Makefile.defs delete mode 100644 src/telemini-v1.0/Makefile.defs delete mode 100644 src/telenano-v0.1/Makefile.defs create mode 100644 src/test/ao_flight_test.c create mode 100644 src/test/ao_gps_test.c create mode 100644 src/test/ao_gps_test_skytraq.c delete mode 100644 src/tidongle/Makefile.defs create mode 100644 src/util/ao-make-product.5c create mode 100755 src/util/check-stack create mode 100755 src/util/gps-cksum create mode 100644 src/util/make-altitude create mode 100644 src/util/make-kalman create mode 100755 src/util/sirf-cksum create mode 100644 src/util/skytraq-cksum (limited to 'src/ao_flight.c') diff --git a/configure.ac b/configure.ac index f9002508..da9d9991 100644 --- a/configure.ac +++ b/configure.ac @@ -19,7 +19,7 @@ dnl Process this file with autoconf to create configure. AC_PREREQ(2.57) AC_INIT([altos], 1.0) -AC_CONFIG_SRCDIR([src/ao.h]) +AC_CONFIG_SRCDIR([src/core/ao.h]) AM_INIT_AUTOMAKE([foreign dist-bzip2]) AM_MAINTAINER_MODE diff --git a/src/25lc1024.h b/src/25lc1024.h deleted file mode 100644 index 44e52387..00000000 --- a/src/25lc1024.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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. - */ - -/* Defines for the 25LC1024 1Mbit SPI Bus Serial EEPROM */ - -#ifndef _25LC1024_H_ -#define _25LC1024_H_ - -#define EE_READ 0x03 -#define EE_WRITE 0x02 -#define EE_WREN 0x06 -#define EE_WRDI 0x04 -#define EE_RDSR 0x05 -#define EE_WRSR 0x01 -#define EE_PE 0x42 -#define EE_SE 0xd8 -#define EE_CE 0xc7 -#define EE_RDID 0xab -#define EE_DPD 0xb9 - -#define EE_STATUS_WIP (1 << 0) -#define EE_STATUS_WEL (1 << 1) -#define EE_STATUS_BP0 (1 << 2) -#define EE_STATUS_BP1 (1 << 3) -#define EE_STATUS_WPEN (1 << 7) - -#endif /* _25LC1024_H_ */ diff --git a/src/Makefile b/src/Makefile index 018f0c5c..4e40c2bf 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2,7 +2,13 @@ # AltOS build # # -CC=sdcc + +vpath make-altitude util +vpath make-kalman util +vpath kalman.5c kalman +vpath kalman_filter.5c kalman +vpath load_csv.5c kalman +vpath matrix.5c kalman include Version @@ -14,7 +20,7 @@ SUBDIRS=\ telemetrum-v0.1-sky telemetrum-v0.1-sirf \ tidongle test -all: all-recursive +all: all-local all-recursive RECURSIVE_TARGETS = all-recursive clean-recursive install-recursive @@ -27,8 +33,21 @@ $(RECURSIVE_TARGETS): distclean: clean -clean: clean-recursive +clean: clean-local clean-recursive install: install-recursive uninstall: + +all-recursive: all-local + +all-local: altitude.h ao_kalman.h + +altitude.h: make-altitude + nickle $< > $@ + +ao_kalman.h: make-kalman kalman.5c kalman_filter.5c load_csv.5c matrix.5c + sh $< kalman > $@ + +clean-local: + rm -f altitude.h ao_kalman.h \ No newline at end of file diff --git a/src/Makefile.proto b/src/Makefile.proto deleted file mode 100644 index 8f98d354..00000000 --- a/src/Makefile.proto +++ /dev/null @@ -1,380 +0,0 @@ -# -# AltOS build -# -# -vpath %.c .. -vpath %.h .. -vpath make-altitude .. -vpath make-kalman .. -vpath kalman.5c ../kalman -vpath kalman_filter.5c ../kalman -vpath load_csv.5c ../kalman -vpath matrix.5c ../kalman -vpath ao-make-product.5c .. - -CC=sdcc - -ifndef VERSION -include ../Version -endif - -CFLAGS=--model-small --debug --opt-code-speed -DCODESIZE=$(CODESIZE) - -CODESIZE ?= 0x8000 - -LDFLAGS=--out-fmt-ihx --code-loc 0x0000 --code-size $(CODESIZE) \ - --xram-loc 0xf000 --xram-size 0xda2 --iram-size 0xff - -INC = \ - ao.h \ - ao_pins.h \ - cc1111.h \ - altitude.h \ - ao_kalman.h \ - 25lc1024.h - -# -# Common AltOS sources -# -ALTOS_SRC = \ - ao_cmd.c \ - ao_dma.c \ - ao_mutex.c \ - ao_panic.c \ - ao_task.c \ - ao_timer.c \ - ao_romconfig.c \ - _bp.c - -# -# Shared AltOS drivers -# -ALTOS_DRIVER_SRC = \ - ao_config.c \ - ao_led.c \ - ao_radio.c \ - ao_stdio.c - -BEEP_DRIVER_SRC = \ - ao_beep.c - -USB_DRIVER_SRC = \ - ao_usb.c - -TELE_COMMON_SRC = \ - ao_packet.c - -# -# Receiver code -# -TELE_RECEIVER_SRC =\ - ao_monitor.c \ - ao_gps_print.c \ - ao_packet_master.c \ - ao_state.c \ - ao_rssi.c - -# -# Shared Tele drivers (on TeleMetrum, TeleTerra, TeleDongle) -# - -TELE_DRIVER_SRC = \ - ao_convert.c - -# -# Serial port driver -# -SERIAL_DRIVER_SRC = \ - ao_serial.c - -# -# Spi bus driver -# -SPI_DRIVER_SRC = \ - ao_spi.c - -# -# Debug dongle driver (only on TI) -# -DBG_SRC = \ - ao_dbg.c - -# -# Drivers only on TeleMetrum -# -TM_DRIVER_SRC = \ - ao_adc.c \ - ao_gps_report.c \ - ao_ignite.c \ - ao_packet_slave.c \ - $(BEEP_DRIVER_SRC) \ - $(USB_DRIVER_SRC) - -# -# 25LC1024 driver source -EE_DRIVER_SRC = \ - ao_storage.c \ - ao_ee.c - -# -# AT45DB161D driver source - -FLASH_DRIVER_SRC = \ - ao_storage.c \ - ao_flash.c - -# -# Numonyx M25P80 driver source -# - -M25_DRIVER_SRC = \ - ao_storage.c \ - ao_m25.c - -# -# SiRF driver source -# -SIRF_DRIVER_SRC = \ - ao_gps_sirf.c - -# -# Skytraq driver source -# -SKY_DRIVER_SRC = \ - ao_gps_skytraq.c - - -# -# BTM-182 driver source -# -BTM_DRIVER_SRC = \ - ao_btm.c - -# -# Companion port driver source -# -COMPANION_SRC = \ - ao_companion.c - -# -# Tasks run on TeleMetrum -# -TM_TASK_SRC = \ - ao_flight.c \ - ao_sample.c \ - ao_kalman.c \ - ao_log.c \ - ao_log_big.c \ - ao_report.c \ - ao_telemetry.c - -TM_MAIN_SRC = \ - ao_telemetrum.c - -# -# Base sources for TeleMetrum -# -TM_BASE_SRC = \ - $(ALTOS_SRC) \ - $(ALTOS_DRIVER_SRC) \ - $(TELE_DRIVER_SRC) \ - $(SERIAL_DRIVER_SRC) \ - $(TELE_COMMON_SRC) \ - $(TM_DRIVER_SRC) \ - $(TM_TASK_SRC) \ - $(TM_MAIN_SRC) - -# -# Sources for TeleMini -TMINI_DRIVER_SRC = \ - ao_adc.c \ - ao_ignite.c \ - ao_config.c \ - ao_storage.c \ - ao_packet_slave.c \ - ao_intflash.c - -TMINI_TASK_SRC = \ - ao_flight.c \ - ao_sample.c \ - ao_kalman.c \ - ao_log.c \ - ao_log_tiny.c \ - ao_report.c \ - ao_telemetry.c - -TMINI_MAIN_SRC = \ - ao_telemini.c - -TMINI_BASE_SRC = \ - $(ALTOS_SRC) \ - $(ALTOS_DRIVER_SRC) \ - $(TELE_DRIVER_SRC) \ - $(TELE_COMMON_SRC) \ - $(TMINI_DRIVER_SRC) \ - $(TMINI_TASK_SRC) \ - $(TMINI_MAIN_SRC) - -# -# Sources for TeleNano -TNANO_DRIVER_SRC = \ - ao_adc.c \ - ao_config.c \ - ao_storage.c \ - ao_packet_slave.c \ - ao_intflash.c - -TNANO_TASK_SRC = \ - ao_flight_nano.c \ - ao_sample.c \ - ao_kalman.c \ - ao_log.c \ - ao_log_tiny.c \ - ao_report.c \ - ao_telemetry.c - -TNANO_MAIN_SRC = \ - ao_telenano.c - -TNANO_BASE_SRC = \ - $(ALTOS_SRC) \ - $(ALTOS_DRIVER_SRC) \ - $(TELE_DRIVER_SRC) \ - $(TELE_COMMON_SRC) \ - $(TNANO_DRIVER_SRC) \ - $(TNANO_TASK_SRC) \ - $(TNANO_MAIN_SRC) - -# -# Sources for TeleBluetooth -# - -TBT_MAIN_SRC = \ - ao_telebt.c - -TBT_BASE_SRC = \ - $(ALTOS_SRC) \ - $(ALTOS_DRIVER_SRC) \ - $(TELE_RECEIVER_SRC) \ - $(TELE_COMMON_SRC) \ - $(SERIAL_DRIVER_SRC) \ - $(USB_DRIVER_SRC) \ - $(BTM_DRIVER_SRC) \ - $(DBG_SRC) \ - $(TBT_MAIN_SRC) - -TBT_V_0_1_SRC = \ - $(TBT_BASE_SRC) \ - $(SPI_DRIVER_SRC) \ - $(M25_DRIVER_SRC) \ - $(BEEP_DRIVER_SRC) \ - ao_log_telem.c - -# -# TI Dongle sources -# -TI_MAIN_SRC = \ - ao_tidongle.c - -# -# All sources for the TI debug dongle -# -TI_SRC = \ - $(ALTOS_SRC) \ - $(ALTOS_DRIVER_SRC) \ - $(TELE_RECEIVER_SRC) \ - $(TELE_COMMON_SRC) \ - $(USB_DRIVER_SRC) \ - $(TI_MAIN_SRC) \ - $(DBG_SRC) - -TT_MAIN_SRC = \ - ao_teleterra.c -# -# All sources for TeleTerra -# -TT_SRC = \ - $(ALTOS_SRC) \ - $(ALTOS_DRIVER_SRC) \ - $(TELE_RECEIVER_SRC) \ - $(TELE_DRIVER_SRC) \ - $(TELE_COMMON_SRC) \ - $(USB_DRIVER_SRC) \ - $(TT_MAIN_SRC) - - -# -# Sources for TeleDongle -# - -TD_MAIN_SRC = \ - ao_teledongle.c - -TD_SRC = \ - $(ALTOS_SRC) \ - $(ALTOS_DRIVER_SRC) \ - $(TELE_RECEIVER_SRC) \ - $(TELE_COMMON_SRC) \ - $(USB_DRIVER_SRC) \ - $(TD_MAIN_SRC) - -include Makefile.defs - -CFLAGS += $(PRODUCT_DEF) -I. - -NICKLE=nickle -CHECK_STACK=sh ../check-stack - -REL=$(SRC:.c=.rel) ao_product.rel -ADB=$(REL:.rel=.adb) -ASM=$(REL:.rel=.asm) -LNK=$(REL:.rel=.lnk) -LST=$(REL:.rel=.lst) -RST=$(REL:.rel=.rst) -SYM=$(REL:.rel=.sym) - -PCDB=$(PROG:.ihx=.cdb) -PLNK=$(PROG:.ihx=.lnk) -PMAP=$(PROG:.ihx=.map) -PMEM=$(PROG:.ihx=.mem) -PAOM=$(PROG:.ihx=) - -V=0 -# The user has explicitly enabled quiet compilation. -ifeq ($(V),0) -quiet = @printf " $1 $2 $@\n"; $($1) -endif -# Otherwise, print the full command line. -quiet ?= $($1) - -%.rel : %.c $(INC) - $(call quiet,CC,$(PRODUCT_DEF)) $(CFLAGS) -c -o$@ $< - -all: ../$(PROG) - -../$(PROG): $(REL) Makefile Makefile.defs ../Makefile.proto - $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. - $(call quiet,CHECK_STACK) ../ao.h $(PMEM) - -../altitude.h: make-altitude - nickle $< > $@ - -../ao_kalman.h: make-kalman kalman.5c kalman_filter.5c load_csv.5c matrix.5c - sh $< > $@ - -ao_product.h: ao-make-product.5c ../Version - $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ - -$(REL): ao_product.h - -distclean: clean - -clean: - rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) - rm -f $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) - rm -f ao_product.h - rm -f ../$(PROG) - -install: - -uninstall: diff --git a/src/_bp.c b/src/_bp.c deleted file mode 100644 index 6bf135bc..00000000 --- a/src/_bp.c +++ /dev/null @@ -1,26 +0,0 @@ -/*------------------------------------------------------------------------- - - _bp.c :- just declares bp as a variable - - Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999) - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. - - This library 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 Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this program; if not, write to the Free Software - Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - In other words, you are welcome to use, share and improve this program. - You are forbidden to forbid anyone else to use, share and improve - what you give them. Help stamp out software-hoarding! --------------------------------------------------------------------------*/ - -__data unsigned char bp ; diff --git a/src/altitude.h b/src/altitude.h deleted file mode 100644 index a278bbc6..00000000 --- a/src/altitude.h +++ /dev/null @@ -1,132 +0,0 @@ -/*max error 3.197865153490684 at 0.782%. Average error 0.260150920474668*/ -#define NALT 129 -#define ALT_FRAC_BITS 8 - 15835, /* 10.56 kPa 0.000% */ - 15332, /* 11.42 kPa 0.781% */ - 14868, /* 12.29 kPa 1.563% */ - 14435, /* 13.16 kPa 2.344% */ - 14030, /* 14.02 kPa 3.125% */ - 13649, /* 14.90 kPa 3.906% */ - 13290, /* 15.76 kPa 4.688% */ - 12950, /* 16.63 kPa 5.469% */ - 12627, /* 17.50 kPa 6.250% */ - 12320, /* 18.37 kPa 7.031% */ - 12027, /* 19.24 kPa 7.813% */ - 11747, /* 20.10 kPa 8.594% */ - 11479, /* 20.97 kPa 9.375% */ - 11222, /* 21.84 kPa 10.156% */ - 10975, /* 22.71 kPa 10.938% */ - 10736, /* 23.58 kPa 11.719% */ - 10504, /* 24.44 kPa 12.500% */ - 10278, /* 25.31 kPa 13.281% */ - 10059, /* 26.18 kPa 14.063% */ - 9846, /* 27.05 kPa 14.844% */ - 9638, /* 27.91 kPa 15.625% */ - 9435, /* 28.78 kPa 16.406% */ - 9237, /* 29.65 kPa 17.188% */ - 9044, /* 30.52 kPa 17.969% */ - 8855, /* 31.39 kPa 18.750% */ - 8670, /* 32.26 kPa 19.531% */ - 8490, /* 33.13 kPa 20.313% */ - 8313, /* 33.99 kPa 21.094% */ - 8140, /* 34.86 kPa 21.875% */ - 7970, /* 35.73 kPa 22.656% */ - 7803, /* 36.60 kPa 23.438% */ - 7640, /* 37.47 kPa 24.219% */ - 7480, /* 38.33 kPa 25.000% */ - 7322, /* 39.20 kPa 25.781% */ - 7168, /* 40.07 kPa 26.563% */ - 7016, /* 40.94 kPa 27.344% */ - 6867, /* 41.80 kPa 28.125% */ - 6720, /* 42.67 kPa 28.906% */ - 6575, /* 43.54 kPa 29.688% */ - 6433, /* 44.41 kPa 30.469% */ - 6294, /* 45.28 kPa 31.250% */ - 6156, /* 46.15 kPa 32.031% */ - 6020, /* 47.01 kPa 32.813% */ - 5887, /* 47.88 kPa 33.594% */ - 5755, /* 48.75 kPa 34.375% */ - 5625, /* 49.62 kPa 35.156% */ - 5497, /* 50.49 kPa 35.938% */ - 5371, /* 51.35 kPa 36.719% */ - 5247, /* 52.22 kPa 37.500% */ - 5124, /* 53.09 kPa 38.281% */ - 5003, /* 53.96 kPa 39.063% */ - 4883, /* 54.83 kPa 39.844% */ - 4765, /* 55.69 kPa 40.625% */ - 4648, /* 56.56 kPa 41.406% */ - 4533, /* 57.43 kPa 42.188% */ - 4419, /* 58.30 kPa 42.969% */ - 4307, /* 59.17 kPa 43.750% */ - 4196, /* 60.03 kPa 44.531% */ - 4086, /* 60.90 kPa 45.313% */ - 3977, /* 61.77 kPa 46.094% */ - 3870, /* 62.63 kPa 46.875% */ - 3764, /* 63.51 kPa 47.656% */ - 3659, /* 64.38 kPa 48.438% */ - 3555, /* 65.24 kPa 49.219% */ - 3453, /* 66.11 kPa 50.000% */ - 3351, /* 66.98 kPa 50.781% */ - 3250, /* 67.85 kPa 51.563% */ - 3151, /* 68.72 kPa 52.344% */ - 3052, /* 69.58 kPa 53.125% */ - 2955, /* 70.45 kPa 53.906% */ - 2858, /* 71.32 kPa 54.688% */ - 2763, /* 72.19 kPa 55.469% */ - 2668, /* 73.06 kPa 56.250% */ - 2574, /* 73.92 kPa 57.031% */ - 2482, /* 74.79 kPa 57.813% */ - 2390, /* 75.66 kPa 58.594% */ - 2298, /* 76.52 kPa 59.375% */ - 2208, /* 77.40 kPa 60.156% */ - 2119, /* 78.26 kPa 60.938% */ - 2030, /* 79.13 kPa 61.719% */ - 1942, /* 80.00 kPa 62.500% */ - 1855, /* 80.87 kPa 63.281% */ - 1769, /* 81.74 kPa 64.063% */ - 1683, /* 82.60 kPa 64.844% */ - 1598, /* 83.47 kPa 65.625% */ - 1514, /* 84.34 kPa 66.406% */ - 1430, /* 85.21 kPa 67.188% */ - 1347, /* 86.08 kPa 67.969% */ - 1265, /* 86.94 kPa 68.750% */ - 1184, /* 87.81 kPa 69.531% */ - 1103, /* 88.68 kPa 70.313% */ - 1023, /* 89.55 kPa 71.094% */ - 943, /* 90.41 kPa 71.875% */ - 864, /* 91.28 kPa 72.656% */ - 786, /* 92.15 kPa 73.438% */ - 708, /* 93.02 kPa 74.219% */ - 631, /* 93.89 kPa 75.000% */ - 554, /* 94.76 kPa 75.781% */ - 478, /* 95.63 kPa 76.563% */ - 403, /* 96.49 kPa 77.344% */ - 328, /* 97.36 kPa 78.125% */ - 254, /* 98.23 kPa 78.906% */ - 180, /* 99.10 kPa 79.688% */ - 106, /* 99.97 kPa 80.469% */ - 34, /* 100.83 kPa 81.250% */ - -39, /* 101.70 kPa 82.031% */ - -111, /* 102.57 kPa 82.813% */ - -182, /* 103.44 kPa 83.594% */ - -253, /* 104.30 kPa 84.375% */ - -323, /* 105.17 kPa 85.156% */ - -393, /* 106.04 kPa 85.938% */ - -462, /* 106.91 kPa 86.719% */ - -531, /* 107.78 kPa 87.500% */ - -600, /* 108.65 kPa 88.281% */ - -668, /* 109.51 kPa 89.063% */ - -736, /* 110.38 kPa 89.844% */ - -803, /* 111.25 kPa 90.625% */ - -870, /* 112.12 kPa 91.406% */ - -936, /* 112.99 kPa 92.188% */ - -1002, /* 113.85 kPa 92.969% */ - -1068, /* 114.72 kPa 93.750% */ - -1133, /* 115.59 kPa 94.531% */ - -1198, /* 116.46 kPa 95.313% */ - -1262, /* 117.33 kPa 96.094% */ - -1326, /* 118.19 kPa 96.875% */ - -1389, /* 119.06 kPa 97.656% */ - -1453, /* 119.93 kPa 98.438% */ - -1516, /* 120.80 kPa 99.219% */ - -1578, /* 121.67 kPa 100.000% */ diff --git a/src/ao-make-product.5c b/src/ao-make-product.5c deleted file mode 100644 index 5f2eb8e8..00000000 --- a/src/ao-make-product.5c +++ /dev/null @@ -1,103 +0,0 @@ -#!/bin/sh - -autoimport ParseArgs; - -void -write_ucs2(string a, string description) -{ - int len = String::length(a); - - printf("/* %s */\n", description); - printf("#define AO_%s_LEN 0x%02x\n", description, len * 2 + 2); - printf("#define AO_%s_STRING \"%s\"\n", description, a); - printf("#define AO_%s_UCS2", description); - for (int i = 0; i < len; i++) { - int c = a[i]; - if (i > 0) - printf(","); - if (0x20 <= c && c < 128) - printf(" '%c', 0", c); - else - printf(" LE_WORD(0x%04x),", c); - } - printf("\n\n"); -} - -void -write_string(string a, string description) -{ - printf ("/* %s */\n", description); - printf ("#define AO_%s_STRING \"%s\"\n", description, a); -} - -void -write_int(int a, string description) -{ - printf ("/* %s */\n", description); - printf ("#define AO_%s_NUMBER %d\n\n", description, a); -} - -void -write_hex(int a, string description) -{ - printf ("/* %s */\n", description); - printf ("#define AO_%s_NUMBER 0x%04x\n\n", description, a); -} - -string manufacturer = "altusmetrum.org"; -string product = "TeleMetrum"; -string version = "0.0"; -int serial = 1; -int user_argind = 0; -int id_product = 0x000a; - -argdesc argd = { - .args = { - { - .var = { .arg_string = &manufacturer }, - .abbr = 'm', - .name = "manufacturer", - .expr_name = "manf", - .desc = "Manufacturer name." }, - { - .var = { .arg_string = &product }, - .abbr = 'p', - .name = "product", - .expr_name = "prod", - .desc = "Product name." }, - { - .var = { .arg_int = &id_product }, - .abbr = 'i', - .name = "id_product", - .expr_name = "id_p", - .desc = "Product ID." }, - { - .var = { .arg_int = &serial }, - .abbr = 's', - .name = "serial", - .expr_name = "number", - .desc = "Serial number." }, - { - .var = { .arg_string = &version }, - .abbr = 'v', - .name = "version", - .expr_name = "string", - .desc = "Program version." }, - }, - .prog_name = "usb descriptors", -}; - -void -main() -{ - string[dim(argv)-1] nargv = {[n] = argv[n+1]}; - parseargs(&argd, &nargv); - write_ucs2(manufacturer, "iManufacturer"); - write_ucs2(product, "iProduct"); - write_ucs2(sprintf("%06d", serial), "iSerial"); - write_int(serial, "iSerial"); - write_hex(id_product, "idProduct"); - write_string(version, "iVersion"); -} - -main(); diff --git a/src/ao.h b/src/ao.h deleted file mode 100644 index 8ac9ac3d..00000000 --- a/src/ao.h +++ /dev/null @@ -1,1610 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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_H_ -#define _AO_H_ - -#include -#include -#include -#include -#include "cc1111.h" -#include "ao_pins.h" - -#define TRUE 1 -#define FALSE 0 - -/* Convert a __data pointer into an __xdata pointer */ -#define DATA_TO_XDATA(a) ((void __xdata *) ((uint8_t) (a) | 0xff00)) - -/* 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 0x90 -#define AO_STACK_END 0xfe -#define AO_STACK_SIZE (AO_STACK_END - AO_STACK_START + 1) - -/* An AltOS task */ -struct ao_task { - __xdata void *wchan; /* current wait channel (NULL if running) */ - uint16_t alarm; /* abort ao_sleep time */ - uint8_t stack_count; /* amount of saved stack */ - uint8_t task_id; /* unique id */ - __code char *name; /* task name */ - uint8_t stack[AO_STACK_SIZE]; /* saved stack */ -}; - -extern __xdata struct ao_task *__data ao_cur_task; - -#define AO_NUM_TASKS 16 /* maximum number of tasks */ -#define AO_NO_TASK 0 /* no task id */ - -/* - ao_task.c - */ - -/* Suspend the current task until wchan is awoken. - * returns: - * 0 on normal wake - * 1 on alarm - */ -uint8_t -ao_sleep(__xdata void *wchan); - -/* Wake all tasks sleeping on wchan */ -void -ao_wakeup(__xdata void *wchan); - -/* set an alarm to go off in 'delay' ticks */ -void -ao_alarm(uint16_t delay); - -/* Yield the processor to another task */ -void -ao_yield(void) __naked; - -/* Add a task to the run queue */ -void -ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant; - -/* Terminate the current task */ -void -ao_exit(void); - -/* Dump task info to console */ -void -ao_task_info(void); - -/* Start the scheduler. This will not return */ -void -ao_start_scheduler(void); - -/* - * ao_panic.c - */ - -#define AO_PANIC_NO_TASK 1 /* AO_NUM_TASKS is not large enough */ -#define AO_PANIC_DMA 2 /* Attempt to start DMA while active */ -#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 */ -#define AO_PANIC_STDIO 7 /* Too many stdio handlers registered */ -#define AO_PANIC_REBOOT 8 /* Reboot failed */ -#define AO_PANIC_FLASH 9 /* Invalid flash part (or wrong blocksize) */ -#define AO_PANIC_USB 10 /* Trying to send USB packet while busy */ -#define AO_PANIC_BT 11 /* Communications with bluetooth device failed */ - -/* Stop the operating system, beeping and blinking the reason */ -void -ao_panic(uint8_t reason); - -/* - * ao_timer.c - */ - -/* Our timer runs at 100Hz */ -#define AO_HERTZ 100 -#define AO_MS_TO_TICKS(ms) ((ms) / (1000 / AO_HERTZ)) -#define AO_SEC_TO_TICKS(s) ((s) * AO_HERTZ) - -/* Returns the current time in ticks */ -uint16_t -ao_time(void); - -/* Suspend the current task until ticks time has passed */ -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; - -/* Initialize the timer */ -void -ao_timer_init(void); - -/* Initialize the hardware clock. Must be called first */ -void -ao_clock_init(void); - -/* - * One set of samples read from the A/D converter or telemetry - */ -struct ao_adc { - uint16_t tick; /* tick when the sample was read */ - int16_t accel; /* accelerometer */ - int16_t pres; /* pressure sensor */ - int16_t temp; /* temperature sensor */ - int16_t v_batt; /* battery voltage */ - int16_t sense_d; /* drogue continuity sense */ - int16_t sense_m; /* main continuity sense */ -}; - -#ifndef HAS_ADC -#error Please define HAS_ADC -#endif - -#if HAS_ADC - -#if HAS_ACCEL -#ifndef HAS_ACCEL_REF -#error Please define HAS_ACCEL_REF -#endif -#else -#define HAS_ACCEL_REF 0 -#endif - -/* - * ao_adc.c - */ - -#define AO_ADC_RING 32 -#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1)) -#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1)) - - -/* - * A/D data is stored in a ring, with the next sample to be written - * at ao_adc_head - */ -extern volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING]; -extern volatile __data uint8_t ao_adc_head; -#if HAS_ACCEL_REF -extern volatile __xdata uint16_t ao_accel_ref[AO_ADC_RING]; -#endif - -/* Trigger a conversion sequence (called from the timer interrupt) */ -void -ao_adc_poll(void); - -/* Suspend the current task until another A/D sample is converted */ -void -ao_adc_sleep(void); - -/* Get a copy of the last complete A/D sample set */ -void -ao_adc_get(__xdata struct ao_adc *packet); - -/* The A/D interrupt handler */ - -void -ao_adc_isr(void) __interrupt 1; - -/* Initialize the A/D converter */ -void -ao_adc_init(void); - -#endif /* HAS_ADC */ - -/* - * ao_beep.c - */ - -/* - * Various pre-defined beep frequencies - * - * frequency = 1/2 (24e6/32) / beep - */ - -#define AO_BEEP_LOW 150 /* 2500Hz */ -#define AO_BEEP_MID 94 /* 3989Hz */ -#define AO_BEEP_HIGH 75 /* 5000Hz */ -#define AO_BEEP_OFF 0 /* off */ - -#define AO_BEEP_g 240 /* 1562.5Hz */ -#define AO_BEEP_gs 227 /* 1652Hz (1655Hz) */ -#define AO_BEEP_aa 214 /* 1752Hz (1754Hz) */ -#define AO_BEEP_bbf 202 /* 1856Hz (1858Hz) */ -#define AO_BEEP_bb 190 /* 1974Hz (1969Hz) */ -#define AO_BEEP_cc 180 /* 2083Hz (2086Hz) */ -#define AO_BEEP_ccs 170 /* 2205Hz (2210Hz) */ -#define AO_BEEP_dd 160 /* 2344Hz (2341Hz) */ -#define AO_BEEP_eef 151 /* 2483Hz (2480Hz) */ -#define AO_BEEP_ee 143 /* 2622Hz (2628Hz) */ -#define AO_BEEP_ff 135 /* 2778Hz (2784Hz) */ -#define AO_BEEP_ffs 127 /* 2953Hz (2950Hz) */ -#define AO_BEEP_gg 120 /* 3125Hz */ -#define AO_BEEP_ggs 113 /* 3319Hz (3311Hz) */ -#define AO_BEEP_aaa 107 /* 3504Hz (3508Hz) */ -#define AO_BEEP_bbbf 101 /* 3713Hz (3716Hz) */ -#define AO_BEEP_bbb 95 /* 3947Hz (3937Hz) */ -#define AO_BEEP_ccc 90 /* 4167Hz (4171Hz) */ -#define AO_BEEP_cccs 85 /* 4412Hz (4419Hz) */ -#define AO_BEEP_ddd 80 /* 4688Hz (4682Hz) */ -#define AO_BEEP_eeef 76 /* 4934Hz (4961Hz) */ -#define AO_BEEP_eee 71 /* 5282Hz (5256Hz) */ -#define AO_BEEP_fff 67 /* 5597Hz (5568Hz) */ -#define AO_BEEP_fffs 64 /* 5859Hz (5899Hz) */ -#define AO_BEEP_ggg 60 /* 6250Hz */ - -/* Set the beeper to the specified tone */ -void -ao_beep(uint8_t beep); - -/* Turn on the beeper for the specified time */ -void -ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant; - -/* Initialize the beeper */ -void -ao_beep_init(void); - -/* - * ao_led.c - */ - -#define AO_LED_NONE 0 - -/* Turn on the specified LEDs */ -void -ao_led_on(uint8_t colors); - -/* Turn off the specified LEDs */ -void -ao_led_off(uint8_t colors); - -/* Set all of the LEDs to the specified state */ -void -ao_led_set(uint8_t colors); - -/* Toggle the specified LEDs */ -void -ao_led_toggle(uint8_t colors); - -/* Turn on the specified LEDs for the indicated interval */ -void -ao_led_for(uint8_t colors, uint16_t ticks) __reentrant; - -/* Initialize the LEDs */ -void -ao_led_init(uint8_t enable); - -/* - * ao_romconfig.c - */ - -#define AO_ROMCONFIG_VERSION 2 - -extern __code __at (0x00a0) uint16_t ao_romconfig_version; -extern __code __at (0x00a2) uint16_t ao_romconfig_check; -extern __code __at (0x00a4) uint16_t ao_serial_number; -extern __code __at (0x00a6) uint32_t ao_radio_cal; - -#ifndef HAS_USB -#error Please define HAS_USB -#endif - -#if HAS_USB -extern __code __at (0x00aa) uint8_t ao_usb_descriptors []; -#endif - -/* - * ao_usb.c - */ - -/* Put one character to the USB output queue */ -void -ao_usb_putchar(char c); - -/* Get one character from the USB input queue */ -char -ao_usb_getchar(void); - -/* Poll for a charcter on the USB input queue. - * returns AO_READ_AGAIN if none are available - */ -char -ao_usb_pollchar(void); - -/* Flush the USB output queue */ -void -ao_usb_flush(void); - -#if HAS_USB -/* USB interrupt handler */ -void -ao_usb_isr(void) __interrupt 6; -#endif - -/* Enable the USB controller */ -void -ao_usb_enable(void); - -/* Disable the USB controller */ -void -ao_usb_disable(void); - -/* Initialize the USB system */ -void -ao_usb_init(void); - -/* - * ao_cmd.c - */ - -enum ao_cmd_status { - ao_cmd_success = 0, - ao_cmd_lex_error = 1, - ao_cmd_syntax_error = 2, -}; - -extern __pdata uint16_t ao_cmd_lex_i; -extern __pdata uint32_t ao_cmd_lex_u32; -extern __pdata char ao_cmd_lex_c; -extern __pdata 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); - -void -ao_cmd_decimal(void); - -uint8_t -ao_match_word(__code char *word); - -struct ao_cmds { - void (*func)(void); - __code char *help; -}; - -void -ao_cmd_register(__code struct ao_cmds *cmds); - -void -ao_cmd_init(void); - -#if HAS_CMD_FILTER -/* - * Provided by an external module to filter raw command lines - */ -uint8_t -ao_cmd_filter(void); -#endif - -/* - * ao_dma.c - */ - -/* Allocate a DMA channel. the 'done' parameter will be set when the - * dma is finished and will be used to wakeup any waiters - */ - -uint8_t -ao_dma_alloc(__xdata uint8_t * done); - -/* Setup a DMA channel */ -void -ao_dma_set_transfer(uint8_t id, - void __xdata *srcaddr, - void __xdata *dstaddr, - uint16_t count, - uint8_t cfg0, - uint8_t cfg1); - -/* Start a DMA channel */ -void -ao_dma_start(uint8_t id); - -/* Manually trigger a DMA channel */ -void -ao_dma_trigger(uint8_t id); - -/* Abort a running DMA transfer */ -void -ao_dma_abort(uint8_t id); - -/* DMA interrupt routine */ -void -ao_dma_isr(void) __interrupt 8; - -/* - * ao_mutex.c - */ - -void -ao_mutex_get(__xdata uint8_t *ao_mutex) __reentrant; - -void -ao_mutex_put(__xdata uint8_t *ao_mutex) __reentrant; - -/* - * Storage interface, provided by one of the eeprom or flash - * drivers - */ - -/* Total bytes of available storage */ -extern __pdata uint32_t ao_storage_total; - -/* Block size - device is erased in these units. At least 256 bytes */ -extern __pdata uint32_t ao_storage_block; - -/* Byte offset of config block. Will be ao_storage_block bytes long */ -extern __pdata uint32_t ao_storage_config; - -/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */ -extern __pdata uint16_t ao_storage_unit; - -#define AO_STORAGE_ERASE_LOG (ao_storage_config + AO_CONFIG_MAX_SIZE) - -/* Initialize above values. Can only be called once the OS is running */ -void -ao_storage_setup(void) __reentrant; - -/* Write data. Returns 0 on failure, 1 on success */ -uint8_t -ao_storage_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; - -/* Read data. Returns 0 on failure, 1 on success */ -uint8_t -ao_storage_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; - -/* Erase a block of storage. This always clears ao_storage_block bytes */ -uint8_t -ao_storage_erase(uint32_t pos) __reentrant; - -/* Flush any pending writes to stable storage */ -void -ao_storage_flush(void) __reentrant; - -/* Initialize the storage code */ -void -ao_storage_init(void); - -/* - * Low-level functions wrapped by ao_storage.c - */ - -/* Read data within a storage unit */ -uint8_t -ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; - -/* Write data within a storage unit */ -uint8_t -ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; - -/* Initialize low-level device bits */ -void -ao_storage_device_init(void); - -/* Print out information about flash chips */ -void -ao_storage_device_info(void) __reentrant; - -/* - * ao_log.c - */ - -/* We record flight numbers in the first record of - * the log. Tasks may wait for this to be initialized - * by sleeping on this variable. - */ -extern __xdata uint16_t ao_flight_number; - -extern __pdata uint32_t ao_log_current_pos; -extern __pdata uint32_t ao_log_end_pos; -extern __pdata uint32_t ao_log_start_pos; -extern __xdata uint8_t ao_log_running; -extern __pdata enum flight_state ao_log_state; - -/* required functions from the underlying log system */ - -#define AO_LOG_FORMAT_UNKNOWN 0 /* unknown; altosui will have to guess */ -#define AO_LOG_FORMAT_FULL 1 /* 8 byte typed log records */ -#define AO_LOG_FORMAT_TINY 2 /* two byte state/baro records */ -#define AO_LOG_FORMAT_TELEMETRY 3 /* 32 byte ao_telemetry records */ -#define AO_LOG_FORMAT_TELESCIENCE 4 /* 32 byte typed telescience records */ -#define AO_LOG_FORMAT_NONE 127 /* No log at all */ - -extern __code uint8_t ao_log_format; - -/* Return the flight number from the given log slot, 0 if none */ -uint16_t -ao_log_flight(uint8_t slot); - -/* Flush the log */ -void -ao_log_flush(void); - -/* Logging thread main routine */ -void -ao_log(void); - -/* functions provided in ao_log.c */ - -/* Figure out the current flight number */ -void -ao_log_scan(void) __reentrant; - -/* Return the position of the start of the given log slot */ -uint32_t -ao_log_pos(uint8_t slot); - -/* Start logging to eeprom */ -void -ao_log_start(void); - -/* Stop logging */ -void -ao_log_stop(void); - -/* Initialize the logging system */ -void -ao_log_init(void); - -/* Write out the current flight number to the erase log */ -void -ao_log_write_erase(uint8_t pos); - -/* Returns true if there are any logs stored in eeprom */ -uint8_t -ao_log_present(void); - -/* Returns true if there is no more storage space available */ -uint8_t -ao_log_full(void); - -/* - * ao_log_big.c - */ - -/* - * The data log is recorded in the eeprom as a sequence - * of data packets. - * - * Each packet starts with a 4-byte header that has the - * packet type, the packet checksum and the tick count. Then - * they all contain 2 16 bit values which hold packet-specific - * data. - * - * For each flight, the first packet - * is FLIGHT packet, indicating the serial number of the - * device and a unique number marking the number of flights - * recorded by this device. - * - * During flight, data from the accelerometer and barometer - * are recorded in SENSOR packets, using the raw 16-bit values - * read from the A/D converter. - * - * Also during flight, but at a lower rate, the deployment - * sensors are recorded in DEPLOY packets. The goal here is to - * detect failure in the deployment circuits. - * - * STATE packets hold state transitions as the flight computer - * transitions through different stages of the flight. - */ -#define AO_LOG_FLIGHT 'F' -#define AO_LOG_SENSOR 'A' -#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_GPS_SAT 'V' -#define AO_LOG_GPS_DATE 'Y' - -#define AO_LOG_POS_NONE (~0UL) - -struct ao_log_record { - char type; - uint8_t csum; - uint16_t tick; - union { - struct { - int16_t ground_accel; - uint16_t flight; - } flight; - struct { - int16_t accel; - int16_t pres; - } sensor; - struct { - int16_t temp; - int16_t v_batt; - } temp_volt; - struct { - int16_t drogue; - int16_t main; - } deploy; - struct { - uint16_t state; - uint16_t reason; - } state; - struct { - uint8_t hour; - uint8_t minute; - uint8_t second; - uint8_t flags; - } gps_time; - int32_t gps_latitude; - int32_t gps_longitude; - struct { - int16_t altitude; - uint16_t unused; - } gps_altitude; - struct { - uint16_t svid; - uint8_t unused; - uint8_t c_n; - } gps_sat; - struct { - uint8_t year; - uint8_t month; - uint8_t day; - uint8_t extra; - } gps_date; - struct { - uint16_t d0; - uint16_t d1; - } anon; - } u; -}; - -/* Write a record to the eeprom log */ -uint8_t -ao_log_data(__xdata struct ao_log_record *log) __reentrant; - -/* - * ao_flight.c - */ - -enum ao_flight_state { - ao_flight_startup = 0, - ao_flight_idle = 1, - ao_flight_pad = 2, - ao_flight_boost = 3, - ao_flight_fast = 4, - ao_flight_coast = 5, - ao_flight_drogue = 6, - ao_flight_main = 7, - ao_flight_landed = 8, - ao_flight_invalid = 9 -}; - -extern __pdata enum ao_flight_state ao_flight_state; - -extern __pdata uint16_t ao_launch_time; -extern __pdata uint8_t ao_flight_force_idle; - -/* Flight thread */ -void -ao_flight(void); - -/* Initialize flight thread */ -void -ao_flight_init(void); - -/* - * ao_flight_nano.c - */ - -void -ao_flight_nano_init(void); - -/* - * ao_sample.c - */ - -/* - * Barometer calibration - * - * We directly sample the barometer. The specs say: - * - * Pressure range: 15-115 kPa - * Voltage at 115kPa: 2.82 - * Output scale: 27mV/kPa - * - * If we want to detect launch with the barometer, we need - * a large enough bump to not be fooled by noise. At typical - * launch elevations (0-2000m), a 200Pa pressure change cooresponds - * to about a 20m elevation change. This is 5.4mV, or about 3LSB. - * As all of our calculations are done in 16 bits, we'll actually see a change - * of 16 times this though - * - * 27 mV/kPa * 32767 / 3300 counts/mV = 268.1 counts/kPa - */ - -/* Accelerometer calibration - * - * We're sampling the accelerometer through a resistor divider which - * consists of 5k and 10k resistors. This multiplies the values by 2/3. - * That goes into the cc1111 A/D converter, which is running at 11 bits - * of precision with the bits in the MSB of the 16 bit value. Only positive - * values are used, so values should range from 0-32752 for 0-3.3V. The - * specs say we should see 40mV/g (uncalibrated), multiply by 2/3 for what - * the A/D converter sees (26.67 mV/g). We should see 32752/3300 counts/mV, - * for a final computation of: - * - * 26.67 mV/g * 32767/3300 counts/mV = 264.8 counts/g - * - * Zero g was measured at 16000 (we would expect 16384). - * Note that this value is only require to tell if the - * rocket is standing upright. Once that is determined, - * the value of the accelerometer is averaged for 100 samples - * to find the resting accelerometer value, which is used - * for all further flight computations - */ - -#define GRAVITY 9.80665 - -/* - * Above this height, the baro sensor doesn't work - */ -#define AO_MAX_BARO_HEIGHT 12000 - -/* - * Above this speed, baro measurements are unreliable - */ -#define AO_MAX_BARO_SPEED 200 - -#define ACCEL_NOSE_UP (ao_accel_2g >> 2) - -/* - * Speed and acceleration are scaled by 16 to provide a bit more - * resolution while still having reasonable range. Note that this - * limits speed to 2047m/s (around mach 6) and acceleration to - * 2047m/s² (over 200g) - */ - -#define AO_M_TO_HEIGHT(m) ((int16_t) (m)) -#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16)) -#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16)) - -extern __pdata uint16_t ao_sample_tick; /* time of last data */ -extern __pdata int16_t ao_sample_pres; /* most recent pressure sensor reading */ -extern __pdata int16_t ao_sample_alt; /* MSL of ao_sample_pres */ -extern __pdata int16_t ao_sample_height; /* AGL of ao_sample_pres */ -extern __data uint8_t ao_sample_adc; /* Ring position of last processed sample */ - -#if HAS_ACCEL -extern __pdata int16_t ao_sample_accel; /* most recent accel sensor reading */ -#endif - -extern __pdata int16_t ao_ground_pres; /* startup pressure */ -extern __pdata int16_t ao_ground_height; /* MSL of ao_ground_pres */ - -#if HAS_ACCEL -extern __pdata int16_t ao_ground_accel; /* startup acceleration */ -extern __pdata int16_t ao_accel_2g; /* factory accel calibration */ -extern __pdata int32_t ao_accel_scale; /* sensor to m/s² conversion */ -#endif - -void ao_sample_init(void); - -/* returns FALSE in preflight mode, TRUE in flight mode */ -uint8_t ao_sample(void); - -/* - * ao_kalman.c - */ - -#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5)) -#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5)) -#define from_fix(x) ((x) >> 16) - -extern __pdata int16_t ao_height; /* meters */ -extern __pdata int16_t ao_speed; /* m/s * 16 */ -extern __pdata int16_t ao_accel; /* m/s² * 16 */ -extern __pdata int16_t ao_max_height; /* max of ao_height */ -extern __pdata int16_t ao_avg_height; /* running average of height */ - -extern __pdata int16_t ao_error_h; -extern __pdata int16_t ao_error_h_sq_avg; - -#if HAS_ACCEL -extern __pdata int16_t ao_error_a; -#endif - -void ao_kalman(void); - -/* - * ao_report.c - */ - -void -ao_report_init(void); - -/* - * ao_convert.c - * - * Given raw data, convert to SI units - */ - -/* pressure from the sensor to altitude in meters */ -int16_t -ao_pres_to_altitude(int16_t pres) __reentrant; - -int16_t -ao_altitude_to_pres(int16_t alt) __reentrant; - -int16_t -ao_temp_to_dC(int16_t temp) __reentrant; - -/* - * ao_dbg.c - * - * debug another telemetrum board - */ - -/* Send a byte to the dbg target */ -void -ao_dbg_send_byte(uint8_t byte); - -/* Receive a byte from the dbg target */ -uint8_t -ao_dbg_recv_byte(void); - -/* Start a bulk transfer to/from dbg target memory */ -void -ao_dbg_start_transfer(uint16_t addr); - -/* End a bulk transfer to/from dbg target memory */ -void -ao_dbg_end_transfer(void); - -/* Write a byte to dbg target memory */ -void -ao_dbg_write_byte(uint8_t byte); - -/* Read a byte from dbg target memory */ -uint8_t -ao_dbg_read_byte(void); - -/* Enable dbg mode, switching use of the pins */ -void -ao_dbg_debug_mode(void); - -/* Reset the dbg target */ -void -ao_dbg_reset(void); - -void -ao_dbg_init(void); - -/* - * ao_serial.c - */ - -#ifndef HAS_SERIAL_1 -#error Please define HAS_SERIAL_1 -#endif - -#if HAS_SERIAL_1 -#ifndef USE_SERIAL_STDIN -#error Please define USE_SERIAL_STDIN -#endif - -void -ao_serial_rx1_isr(void) __interrupt 3; - -void -ao_serial_tx1_isr(void) __interrupt 14; - -char -ao_serial_getchar(void) __critical; - -#if USE_SERIAL_STDIN -char -ao_serial_pollchar(void) __critical; - -void -ao_serial_set_stdin(uint8_t stdin); -#endif - -void -ao_serial_putchar(char c) __critical; - -void -ao_serial_drain(void) __critical; - -#define AO_SERIAL_SPEED_4800 0 -#define AO_SERIAL_SPEED_9600 1 -#define AO_SERIAL_SPEED_19200 2 -#define AO_SERIAL_SPEED_57600 3 - -void -ao_serial_set_speed(uint8_t speed); - -void -ao_serial_init(void); -#endif - -/* - * ao_spi.c - */ - -extern __xdata uint8_t ao_spi_mutex; - -#define ao_spi_get_mask(reg,mask) do {\ - ao_mutex_get(&ao_spi_mutex); \ - (reg) &= ~(mask); \ - } while (0) - -#define ao_spi_put_mask(reg,mask) do { \ - (reg) |= (mask); \ - ao_mutex_put(&ao_spi_mutex); \ - } while (0) - -#define ao_spi_get_bit(bit) do {\ - ao_mutex_get(&ao_spi_mutex); \ - (bit) = 0; \ - } while (0) - -#define ao_spi_put_bit(bit) do { \ - (bit) = 1; \ - ao_mutex_put(&ao_spi_mutex); \ - } while (0) - -/* - * The SPI mutex must be held to call either of these - * functions -- this mutex covers the entire SPI operation, - * from chip select low to chip select high - */ - -void -ao_spi_send(void __xdata *block, uint16_t len) __reentrant; - -void -ao_spi_recv(void __xdata *block, uint16_t len) __reentrant; - -void -ao_spi_init(void); - -/* - * ao_telemetry.c - */ -#define AO_MAX_CALLSIGN 8 -#define AO_MAX_VERSION 8 -#define AO_MAX_TELEMETRY 128 - -struct ao_telemetry_generic { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - uint8_t payload[27]; /* 5 */ - /* 32 */ -}; - -#define AO_TELEMETRY_SENSOR_TELEMETRUM 0x01 -#define AO_TELEMETRY_SENSOR_TELEMINI 0x02 -#define AO_TELEMETRY_SENSOR_TELENANO 0x03 - -struct ao_telemetry_sensor { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - - uint8_t state; /* 5 flight state */ - int16_t accel; /* 6 accelerometer (TM only) */ - int16_t pres; /* 8 pressure sensor */ - int16_t temp; /* 10 temperature sensor */ - int16_t v_batt; /* 12 battery voltage */ - int16_t sense_d; /* 14 drogue continuity sense (TM/Tm) */ - int16_t sense_m; /* 16 main continuity sense (TM/Tm) */ - - int16_t acceleration; /* 18 m/s² * 16 */ - int16_t speed; /* 20 m/s * 16 */ - int16_t height; /* 22 m */ - - int16_t ground_pres; /* 24 average pres on pad */ - int16_t ground_accel; /* 26 average accel on pad */ - int16_t accel_plus_g; /* 28 accel calibration at +1g */ - int16_t accel_minus_g; /* 30 accel calibration at -1g */ - /* 32 */ -}; - -#define AO_TELEMETRY_CONFIGURATION 0x04 - -struct ao_telemetry_configuration { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - - uint8_t device; /* 5 device type */ - uint16_t flight; /* 6 flight number */ - uint8_t config_major; /* 8 Config major version */ - uint8_t config_minor; /* 9 Config minor version */ - uint16_t apogee_delay; /* 10 Apogee deploy delay in seconds */ - uint16_t main_deploy; /* 12 Main deploy alt in meters */ - uint16_t flight_log_max; /* 14 Maximum flight log size in kB */ - char callsign[AO_MAX_CALLSIGN]; /* 16 Radio operator identity */ - char version[AO_MAX_VERSION]; /* 24 Software version */ - /* 32 */ -}; - -#define AO_TELEMETRY_LOCATION 0x05 - -#define AO_GPS_MODE_NOT_VALID 'N' -#define AO_GPS_MODE_AUTONOMOUS 'A' -#define AO_GPS_MODE_DIFFERENTIAL 'D' -#define AO_GPS_MODE_ESTIMATED 'E' -#define AO_GPS_MODE_MANUAL 'M' -#define AO_GPS_MODE_SIMULATED 'S' - -struct ao_telemetry_location { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - - uint8_t flags; /* 5 Number of sats and other flags */ - int16_t altitude; /* 6 GPS reported altitude (m) */ - int32_t latitude; /* 8 latitude (degrees * 10⁷) */ - int32_t longitude; /* 12 longitude (degrees * 10⁷) */ - uint8_t year; /* 16 (- 2000) */ - uint8_t month; /* 17 (1-12) */ - uint8_t day; /* 18 (1-31) */ - uint8_t hour; /* 19 (0-23) */ - uint8_t minute; /* 20 (0-59) */ - uint8_t second; /* 21 (0-59) */ - uint8_t pdop; /* 22 (m * 5) */ - uint8_t hdop; /* 23 (m * 5) */ - uint8_t vdop; /* 24 (m * 5) */ - uint8_t mode; /* 25 */ - uint16_t ground_speed; /* 26 cm/s */ - int16_t climb_rate; /* 28 cm/s */ - uint8_t course; /* 30 degrees / 2 */ - uint8_t unused[1]; /* 31 */ - /* 32 */ -}; - -#define AO_TELEMETRY_SATELLITE 0x06 - -struct ao_telemetry_satellite_info { - uint8_t svid; - uint8_t c_n_1; -}; - -struct ao_telemetry_satellite { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - uint8_t channels; /* 5 number of reported sats */ - - struct ao_telemetry_satellite_info sats[12]; /* 6 */ - uint8_t unused[2]; /* 30 */ - /* 32 */ -}; - -#define AO_TELEMETRY_COMPANION 0x07 - -#define AO_COMPANION_MAX_CHANNELS 12 - -struct ao_telemetry_companion { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - uint8_t board_id; /* 5 */ - - uint8_t update_period; /* 6 */ - uint8_t channels; /* 7 */ - uint16_t companion_data[AO_COMPANION_MAX_CHANNELS]; /* 8 */ - /* 32 */ -}; - -union ao_telemetry_all { - struct ao_telemetry_generic generic; - struct ao_telemetry_sensor sensor; - struct ao_telemetry_configuration configuration; - struct ao_telemetry_location location; - struct ao_telemetry_satellite satellite; - struct ao_telemetry_companion companion; -}; - -/* - * ao_gps.c - */ - -#define AO_GPS_NUM_SAT_MASK (0xf << 0) -#define AO_GPS_NUM_SAT_SHIFT (0) - -#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 __pdata uint16_t ao_gps_tick; -extern __xdata uint8_t ao_gps_mutex; -extern __xdata struct ao_telemetry_location ao_gps_data; -extern __xdata struct ao_telemetry_satellite ao_gps_tracking_data; - -struct ao_gps_orig { - uint8_t year; - uint8_t month; - uint8_t day; - uint8_t hour; - uint8_t minute; - uint8_t second; - uint8_t flags; - int32_t latitude; /* degrees * 10⁷ */ - int32_t longitude; /* degrees * 10⁷ */ - int16_t altitude; /* m */ - uint16_t ground_speed; /* cm/s */ - uint8_t course; /* degrees / 2 */ - uint8_t hdop; /* * 5 */ - int16_t climb_rate; /* cm/s */ - uint16_t h_error; /* m */ - uint16_t v_error; /* m */ -}; - -struct ao_gps_sat_orig { - uint8_t svid; - uint8_t c_n_1; -}; - -#define AO_MAX_GPS_TRACKING 12 - -struct ao_gps_tracking_orig { - uint8_t channels; - struct ao_gps_sat_orig sats[AO_MAX_GPS_TRACKING]; -}; - -void -ao_gps(void); - -void -ao_gps_print(__xdata struct ao_gps_orig *gps_data); - -void -ao_gps_tracking_print(__xdata struct ao_gps_tracking_orig *gps_tracking_data); - -void -ao_gps_init(void); - -/* - * ao_gps_report.c - */ - -void -ao_gps_report(void); - -void -ao_gps_report_init(void); - -/* - * ao_telemetry_orig.c - */ - -struct ao_telemetry_orig { - uint16_t serial; - uint16_t flight; - uint8_t flight_state; - int16_t accel; - int16_t ground_accel; - union { - struct { - int16_t speed; - int16_t unused; - } k; - int32_t flight_vel; - } u; - int16_t height; - int16_t ground_pres; - int16_t accel_plus_g; - int16_t accel_minus_g; - struct ao_adc adc; - struct ao_gps_orig gps; - char callsign[AO_MAX_CALLSIGN]; - struct ao_gps_tracking_orig gps_tracking; -}; - -struct ao_telemetry_tiny { - uint16_t serial; - uint16_t flight; - uint8_t flight_state; - int16_t height; /* AGL in meters */ - int16_t speed; /* in m/s * 16 */ - int16_t accel; /* in m/s² * 16 */ - int16_t ground_pres; /* sensor units */ - struct ao_adc adc; /* raw ADC readings */ - char callsign[AO_MAX_CALLSIGN]; -}; - -/* - * ao_radio_recv tacks on rssi and status bytes - */ - -struct ao_telemetry_raw_recv { - uint8_t packet[AO_MAX_TELEMETRY + 2]; -}; - -struct ao_telemetry_orig_recv { - struct ao_telemetry_orig telemetry_orig; - int8_t rssi; - uint8_t status; -}; - -struct ao_telemetry_tiny_recv { - struct ao_telemetry_tiny telemetry_tiny; - int8_t rssi; - uint8_t status; -}; - -/* Set delay between telemetry reports (0 to disable) */ - -#define AO_TELEMETRY_INTERVAL_PAD AO_MS_TO_TICKS(1000) -#define AO_TELEMETRY_INTERVAL_FLIGHT AO_MS_TO_TICKS(100) -#define AO_TELEMETRY_INTERVAL_RECOVER AO_MS_TO_TICKS(1000) - -void -ao_telemetry_set_interval(uint16_t interval); - -void -ao_rdf_set(uint8_t rdf); - -void -ao_telemetry_init(void); - -void -ao_telemetry_orig_init(void); - -void -ao_telemetry_tiny_init(void); - -/* - * ao_radio.c - */ - -extern __xdata uint8_t ao_radio_dma; -extern __xdata uint8_t ao_radio_dma_done; -extern __xdata uint8_t ao_radio_done; -extern __xdata uint8_t ao_radio_mutex; - -void -ao_radio_general_isr(void) __interrupt 16; - -void -ao_radio_get(uint8_t len); - -#define ao_radio_put() ao_mutex_put(&ao_radio_mutex) - -void -ao_radio_set_packet(void); - -void -ao_radio_send(__xdata void *data, uint8_t size) __reentrant; - -uint8_t -ao_radio_recv(__xdata void *data, uint8_t size) __reentrant; - -void -ao_radio_recv_abort(void); - -void -ao_radio_rdf(int ms); - -void -ao_radio_rdf_abort(void); - -void -ao_radio_idle(void); - -void -ao_radio_init(void); - -/* - * ao_monitor.c - */ - -extern const char const * const ao_state_names[]; - -void -ao_monitor(void); - -#define AO_MONITORING_OFF 0 -#define AO_MONITORING_ORIG 1 -#define AO_MONITORING_TINY 2 - -void -ao_set_monitor(uint8_t monitoring); - -void -ao_monitor_init(uint8_t led, uint8_t monitoring) __reentrant; - -/* - * ao_stdio.c - */ - -#define AO_READ_AGAIN ((char) -1) - -struct ao_stdio { - char (*pollchar)(void); - void (*putchar)(char c) __reentrant; - void (*flush)(void); - uint8_t echo; -}; - -extern __xdata struct ao_stdio ao_stdios[]; -extern __pdata int8_t ao_cur_stdio; -extern __pdata int8_t ao_num_stdios; - -void -flush(void); - -extern __xdata uint8_t ao_stdin_ready; - -uint8_t -ao_echo(void); - -int8_t -ao_add_stdio(char (*pollchar)(void), - void (*putchar)(char) __reentrant, - void (*flush)(void)) __reentrant; - -/* - * ao_ignite.c - */ - -enum ao_igniter { - ao_igniter_drogue = 0, - ao_igniter_main = 1 -}; - -void -ao_ignite(enum ao_igniter igniter); - -enum ao_igniter_status { - ao_igniter_unknown, /* unknown status (ambiguous voltage) */ - ao_igniter_ready, /* continuity detected */ - ao_igniter_active, /* igniter firing */ - ao_igniter_open, /* open circuit detected */ -}; - -enum ao_igniter_status -ao_igniter_status(enum ao_igniter igniter); - -void -ao_ignite_set_pins(void); - -void -ao_igniter_init(void); - -/* - * ao_config.c - */ - -#define AO_CONFIG_MAJOR 1 -#define AO_CONFIG_MINOR 8 - -struct ao_config { - uint8_t major; - uint8_t minor; - uint16_t main_deploy; - int16_t accel_plus_g; /* changed for minor version 2 */ - uint8_t radio_channel; - char callsign[AO_MAX_CALLSIGN + 1]; - uint8_t apogee_delay; /* minor version 1 */ - int16_t accel_minus_g; /* minor version 2 */ - uint32_t radio_cal; /* minor version 3 */ - uint32_t flight_log_max; /* minor version 4 */ - uint8_t ignite_mode; /* minor version 5 */ - uint8_t pad_orientation; /* minor version 6 */ - uint32_t radio_setting; /* minor version 7 */ - uint8_t radio_enable; /* minor version 8 */ -}; - -#define AO_IGNITE_MODE_DUAL 0 -#define AO_IGNITE_MODE_APOGEE 1 -#define AO_IGNITE_MODE_MAIN 2 - -#define AO_PAD_ORIENTATION_ANTENNA_UP 0 -#define AO_PAD_ORIENTATION_ANTENNA_DOWN 1 - -extern __xdata struct ao_config ao_config; - -#define AO_CONFIG_MAX_SIZE 128 - -void -ao_config_get(void); - -void -ao_config_put(void); - -void -ao_config_init(void); - -/* - * ao_rssi.c - */ - -void -ao_rssi_set(int rssi_value); - -void -ao_rssi_init(uint8_t rssi_led); - -/* - * ao_product.c - * - * values which need to be defined for - * each instance of a product - */ - -extern const char ao_version[]; -extern const char ao_manufacturer[]; -extern const char ao_product[]; - -/* - * Fifos - */ - -#define AO_FIFO_SIZE 32 - -struct ao_fifo { - uint8_t insert; - uint8_t remove; - char fifo[AO_FIFO_SIZE]; -}; - -#define ao_fifo_insert(f,c) do { \ - (f).fifo[(f).insert] = (c); \ - (f).insert = ((f).insert + 1) & (AO_FIFO_SIZE-1); \ -} while(0) - -#define ao_fifo_remove(f,c) do {\ - c = (f).fifo[(f).remove]; \ - (f).remove = ((f).remove + 1) & (AO_FIFO_SIZE-1); \ -} while(0) - -#define ao_fifo_full(f) ((((f).insert + 1) & (AO_FIFO_SIZE-1)) == (f).remove) -#define ao_fifo_empty(f) ((f).insert == (f).remove) - -/* - * ao_packet.c - * - * Packet-based command interface - */ - -#define AO_PACKET_MAX 64 -#define AO_PACKET_SYN (uint8_t) 0xff - -struct ao_packet { - uint8_t addr; - uint8_t len; - uint8_t seq; - uint8_t ack; - uint8_t d[AO_PACKET_MAX]; - uint8_t callsign[AO_MAX_CALLSIGN]; -}; - -struct ao_packet_recv { - struct ao_packet packet; - int8_t rssi; - uint8_t status; -}; - -extern __xdata struct ao_packet_recv ao_rx_packet; -extern __xdata struct ao_packet ao_tx_packet; -extern __xdata struct ao_task ao_packet_task; -extern __xdata uint8_t ao_packet_enable; -extern __xdata uint8_t ao_packet_master_sleeping; -extern __pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used; - -void -ao_packet_send(void); - -uint8_t -ao_packet_recv(void); - -void -ao_packet_flush(void); - -void -ao_packet_putchar(char c) __reentrant; - -char -ao_packet_pollchar(void) __critical; - -/* ao_packet_master.c */ - -void -ao_packet_master_init(void); - -/* ao_packet_slave.c */ - -void -ao_packet_slave_start(void); - -void -ao_packet_slave_stop(void); - -void -ao_packet_slave_init(uint8_t enable); - -/* ao_btm.c */ - -/* If bt_link is on P2, this interrupt is shared by USB, so the USB - * code calls this function. Otherwise, it's a regular ISR. - */ - -void -ao_btm_isr(void) -#if BT_LINK_ON_P1 - __interrupt 15 -#endif - ; - -void -ao_btm_init(void); - -/* ao_companion.c */ - -#define AO_COMPANION_SETUP 1 -#define AO_COMPANION_FETCH 2 -#define AO_COMPANION_NOTIFY 3 - -struct ao_companion_command { - uint8_t command; - uint8_t flight_state; - uint16_t tick; - uint16_t serial; - uint16_t flight; -}; - -struct ao_companion_setup { - uint16_t board_id; - uint16_t board_id_inverse; - uint8_t update_period; - uint8_t channels; -}; - -extern __pdata uint8_t ao_companion_running; -extern __xdata struct ao_companion_setup ao_companion_setup; -extern __xdata uint8_t ao_companion_mutex; -extern __xdata uint16_t ao_companion_data[AO_COMPANION_MAX_CHANNELS]; - -void -ao_companion_init(void); - -#endif /* _AO_H_ */ diff --git a/src/ao_adc.c b/src/ao_adc.c deleted file mode 100644 index 786dfd11..00000000 --- a/src/ao_adc.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" -#include "ao_pins.h" - -volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING]; -#if HAS_ACCEL_REF -volatile __xdata uint16_t ao_accel_ref[AO_ADC_RING]; -#endif -volatile __data uint8_t ao_adc_head; - -void -ao_adc_poll(void) -{ -#if HAS_ACCEL_REF - ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 2; -#else -# ifdef TELENANO_V_0_1 - ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 1; -# else - ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 0; -# endif -#endif -} - -void -ao_adc_get(__xdata struct ao_adc *packet) -{ - uint8_t i = ao_adc_ring_prev(ao_sample_adc); - memcpy(packet, &ao_adc_ring[i], sizeof (struct ao_adc)); -} - -void -ao_adc_isr(void) __interrupt 1 -{ - uint8_t sequence; - uint8_t __xdata *a; - - sequence = (ADCCON2 & ADCCON2_SCH_MASK) >> ADCCON2_SCH_SHIFT; -#if IGNITE_ON_P2 - /* TeleMetrum readings */ -#if HAS_ACCEL_REF - if (sequence == 2) { - a = (uint8_t __xdata *) (&ao_accel_ref[ao_adc_head]); - sequence = 0; - } else -#endif - { - if (sequence == ADCCON3_ECH_TEMP) - sequence = 2; - a = (uint8_t __xdata *) (&ao_adc_ring[ao_adc_head].accel + sequence); - sequence++; - } -#define GOT_ADC - a[0] = ADCL; - a[1] = ADCH; - if (sequence < 6) { -#if HAS_EXTERNAL_TEMP == 0 - /* start next channel conversion */ - /* v0.2 replaces external temp sensor with internal one */ - if (sequence == 2) - ADCCON3 = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP; - else -#endif - ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | sequence; - } -#endif - -#if IGNITE_ON_P0 - /* TeleMini readings */ - a = (uint8_t __xdata *) (&ao_adc_ring[ao_adc_head].pres); -#ifdef TELEMINI_V_1_0 - switch (sequence) { - case 0: - /* pressure */ - a += 0; - sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 1; - break; - case 1: - /* drogue sense */ - a += 6; - sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 2; - break; - case 2: - /* main sense */ - a += 8; - sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 3; - break; - case 3: - /* battery */ - a += 4; - sequence = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP; - break; - case ADCCON3_ECH_TEMP: - a += 2; - sequence = 0; - break; - } -#define GOT_ADC -#endif -#ifdef TELENANO_V_0_1 - switch (sequence) { - case 1: - /* pressure */ - a += 0; - sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 3; - break; - case 3: - /* battery */ - a += 4; - sequence = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP; - break; - case ADCCON3_ECH_TEMP: - a += 2; - sequence = 0; - break; - } -#define GOT_ADC -#endif - a[0] = ADCL; - a[1] = ADCH; - if (sequence) { - /* Start next conversion */ - ADCCON3 = sequence; - } -#endif -#ifndef GOT_ADC -#error No known ADC configuration set -#endif - - else { - /* record this conversion series */ - ao_adc_ring[ao_adc_head].tick = ao_time(); - ao_adc_head = ao_adc_ring_next(ao_adc_head); - ao_wakeup(DATA_TO_XDATA(&ao_adc_head)); - } -} - -static void -ao_adc_dump(void) __reentrant -{ - static __xdata struct ao_adc packet; - ao_adc_get(&packet); - printf("tick: %5u accel: %5d pres: %5d temp: %5d batt: %5d drogue: %5d main: %5d\n", - packet.tick, packet.accel, packet.pres, packet.temp, - packet.v_batt, packet.sense_d, packet.sense_m); -} - -__code struct ao_cmds ao_adc_cmds[] = { - { ao_adc_dump, "a\0Current ADC" }, - { 0, NULL }, -}; - -void -ao_adc_init(void) -{ -#if IGNITE_ON_P2 - /* TeleMetrum configuration */ - ADCCFG = ((1 << 0) | /* acceleration */ - (1 << 1) | /* pressure */ -#if HAS_EXTERNAL_TEMP - (1 << 2) | /* v0.1 temperature */ -#endif - (1 << 3) | /* battery voltage */ - (1 << 4) | /* drogue sense */ - (1 << 5)); /* main sense */ -#endif - -#if IGNITE_ON_P0 - /* TeleMini configuration */ - ADCCFG = ((1 << 0) | /* pressure */ - (1 << 1) | /* drogue sense */ - (1 << 2) | /* main sense */ - (1 << 3)); /* battery voltage */ -#endif - - /* enable interrupts */ - ADCIF = 0; - IEN0 |= IEN0_ADCIE; - ao_cmd_register(&ao_adc_cmds[0]); -} diff --git a/src/ao_adc_fake.c b/src/ao_adc_fake.c deleted file mode 100644 index 6ca88d4e..00000000 --- a/src/ao_adc_fake.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING]; -volatile __data uint8_t ao_adc_head; - -/* Stub for systems which have no ADC */ -void -ao_adc_poll(void) -{ -} diff --git a/src/ao_beep.c b/src/ao_beep.c deleted file mode 100644 index 3642f4c6..00000000 --- a/src/ao_beep.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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_beep(uint8_t beep) -{ - if (beep == 0) { - P2_0 = 0; - P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_GPIO; - T4CTL = 0; - } else { - P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_PERIPHERAL; - T4CC0 = beep; - T4CTL = TxCTL_DIV_32 | TxCTL_MODE_MODULO | TxCTL_START; - } -} - -void -ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant -{ - ao_beep(beep); - ao_delay(ticks); - ao_beep(0); -} - -void -ao_beep_init(void) -{ - /* Our beeper is on P2_0, which is hooked to timer 4 using - * configuration alternative 2 - */ - P2_0 = 0; - P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_GPIO; - PERCFG = (PERCFG & ~PERCFG_T4CFG_ALT_MASK) | PERCFG_T4CFG_ALT_2; - T4CCTL0 = TxCCTLy_CMP_TOGGLE|TxCCTLy_CMP_MODE_ENABLE; -} diff --git a/src/ao_btm.c b/src/ao_btm.c deleted file mode 100644 index 44155ec1..00000000 --- a/src/ao_btm.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -int8_t ao_btm_stdio; -__xdata uint8_t ao_btm_connected; - -#define AO_BTM_MAX_REPLY 16 -__xdata char ao_btm_reply[AO_BTM_MAX_REPLY]; - -extern volatile __xdata struct ao_fifo ao_usart1_rx_fifo; - -/* - * Read a line of data from the serial port, truncating - * it after a few characters. - */ - -uint8_t -ao_btm_get_line(void) -{ - uint8_t ao_btm_reply_len = 0; - char c; - - for (;;) { - - while ((c = ao_serial_pollchar()) != AO_READ_AGAIN) { - if (ao_btm_reply_len < sizeof (ao_btm_reply)) - ao_btm_reply[ao_btm_reply_len++] = c; - if (c == '\r' || c == '\n') - goto done; - } - for (c = 0; c < 10; c++) { - ao_delay(AO_MS_TO_TICKS(10)); - if (!ao_fifo_empty(ao_usart1_rx_fifo)) - break; - } - if (c == 10) - goto done; - } -done: - for (c = ao_btm_reply_len; c < sizeof (ao_btm_reply);) - ao_btm_reply[c++] = '\0'; - return ao_btm_reply_len; -} - -/* - * Drain the serial port completely - */ -void -ao_btm_drain() -{ - while (ao_btm_get_line()) - ; -} - -/* - * Set the stdio echo for the bluetooth link - */ -void -ao_btm_echo(uint8_t echo) -{ - ao_stdios[ao_btm_stdio].echo = echo; -} - -/* - * Delay between command charaters; the BT module - * can't keep up with 57600 baud - */ - -void -ao_btm_putchar(char c) -{ - ao_serial_putchar(c); - ao_delay(1); -} - -/* - * Wait for the bluetooth device to return - * status from the previously executed command - */ -uint8_t -ao_btm_wait_reply(void) -{ - for (;;) { - ao_btm_get_line(); - if (!strncmp(ao_btm_reply, "OK", 2)) - return 1; - if (!strncmp(ao_btm_reply, "ERROR", 5)) - return -1; - if (ao_btm_reply[0] == '\0') - return 0; - } -} - -void -ao_btm_string(__code char *cmd) -{ - char c; - - while (c = *cmd++) - ao_btm_putchar(c); -} - -uint8_t -ao_btm_cmd(__code char *cmd) -{ - ao_btm_drain(); - ao_btm_string(cmd); - return ao_btm_wait_reply(); -} - -uint8_t -ao_btm_set_name(void) -{ - char sn[8]; - char *s = sn + 8; - char c; - int n; - ao_btm_string("ATN=TeleBT-"); - *--s = '\0'; - *--s = '\r'; - n = ao_serial_number; - do { - *--s = '0' + n % 10; - } while (n /= 10); - while ((c = *s++)) - ao_btm_putchar(c); - return ao_btm_wait_reply(); -} - -uint8_t -ao_btm_try_speed(uint8_t speed) -{ - ao_serial_set_speed(speed); - ao_btm_drain(); - (void) ao_btm_cmd("\rATE0\rATQ0\r"); - if (ao_btm_cmd("AT\r") == 1) - return 1; - return 0; -} - -/* - * A thread to initialize the bluetooth device and - * hang around to blink the LED when connected - */ -void -ao_btm(void) -{ - /* - * Wait for the bluetooth device to boot - */ - ao_delay(AO_SEC_TO_TICKS(3)); - -#if HAS_BEEP - ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200)); -#endif - - /* - * The first time we connect, the BTM-180 comes up at 19200 baud. - * After that, it will remember and come up at 57600 baud. So, see - * if it is already running at 57600 baud, and if that doesn't work - * then tell it to switch to 57600 from 19200 baud. - */ - while (!ao_btm_try_speed(AO_SERIAL_SPEED_57600)) { - ao_delay(AO_SEC_TO_TICKS(1)); - if (ao_btm_try_speed(AO_SERIAL_SPEED_19200)) - ao_btm_cmd("ATL4\r"); - ao_delay(AO_SEC_TO_TICKS(1)); - } - - /* Disable echo */ - ao_btm_cmd("ATE0\r"); - - /* Enable flow control */ - ao_btm_cmd("ATC1\r"); - - /* Set the reported name to something we can find on the host */ - ao_btm_set_name(); - - /* Turn off status reporting */ - ao_btm_cmd("ATQ1\r"); - - ao_btm_stdio = ao_add_stdio(ao_serial_pollchar, - ao_serial_putchar, - NULL); - ao_btm_echo(0); - - for (;;) { - while (!ao_btm_connected) - ao_sleep(&ao_btm_connected); - while (ao_btm_connected) { - ao_led_for(AO_LED_GREEN, AO_MS_TO_TICKS(20)); - ao_delay(AO_SEC_TO_TICKS(3)); - } - } -} - -__xdata struct ao_task ao_btm_task; - -#if BT_LINK_ON_P2 -#define BT_PICTL_ICON PICTL_P2ICON -#define BT_PIFG P2IFG -#define BT_PDIR P2DIR -#define BT_PINP P2INP -#define BT_IEN2_PIE IEN2_P2IE -#endif -#if BT_LINK_ON_P1 -#define BT_PICTL_ICON PICTL_P1ICON -#define BT_PIFG P1IFG -#define BT_PDIR P1DIR -#define BT_PINP P1INP -#define BT_IEN2_PIE IEN2_P1IE -#endif - -void -ao_btm_check_link() __critical -{ - /* Check the pin and configure the interrupt detector to wait for the - * pin to flip the other way - */ - if (BT_LINK_PIN) { - ao_btm_connected = 0; - PICTL |= BT_PICTL_ICON; - } else { - ao_btm_connected = 1; - PICTL &= ~BT_PICTL_ICON; - } -} - -void -ao_btm_isr(void) -#if BT_LINK_ON_P1 - __interrupt 15 -#endif -{ -#if BT_LINK_ON_P1 - P1IF = 0; -#endif - if (BT_PIFG & (1 << BT_LINK_PIN_INDEX)) { - ao_btm_check_link(); - ao_wakeup(&ao_btm_connected); - } - BT_PIFG = 0; -} - -void -ao_btm_init (void) -{ - ao_serial_init(); - ao_serial_set_speed(AO_SERIAL_SPEED_19200); - -#if BT_LINK_ON_P1 - /* - * Configure ser reset line - */ - - P1_6 = 0; - P1DIR |= (1 << 6); -#endif - - /* - * Configure link status line - */ - - /* Set pin to input */ - BT_PDIR &= ~(1 << BT_LINK_PIN_INDEX); - - /* Set pin to tri-state */ - BT_PINP |= (1 << BT_LINK_PIN_INDEX); - - /* Enable interrupts */ - IEN2 |= BT_IEN2_PIE; - - /* Check current pin state */ - ao_btm_check_link(); - -#if BT_LINK_ON_P2 - /* Eable the pin interrupt */ - PICTL |= PICTL_P2IEN; -#endif -#if BT_LINK_ON_P1 - /* Enable pin interrupt */ - P1IEN |= (1 << BT_LINK_PIN_INDEX); -#endif - - ao_add_task(&ao_btm_task, ao_btm, "bt"); -} diff --git a/src/ao_cmd.c b/src/ao_cmd.c deleted file mode 100644 index 1442ebea..00000000 --- a/src/ao_cmd.c +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -__pdata uint16_t ao_cmd_lex_i; -__pdata uint32_t ao_cmd_lex_u32; -__pdata char ao_cmd_lex_c; -__pdata enum ao_cmd_status ao_cmd_status; - -#define CMD_LEN 32 - -static __xdata char cmd_line[CMD_LEN]; -static __pdata uint8_t cmd_len; -static __pdata uint8_t cmd_i; - -static void -put_string(__code char *s) -{ - char c; - while (c = *s++) - putchar(c); -} - -static void -readline(void) -{ - __pdata char c; - if (ao_echo()) - put_string("> "); - cmd_len = 0; - for (;;) { - flush(); - c = getchar(); - /* backspace/delete */ - if (c == '\010' || c == '\177') { - if (cmd_len != 0) { - if (ao_echo()) - put_string("\010 \010"); - --cmd_len; - } - continue; - } - - /* ^U */ - if (c == '\025') { - while (cmd_len != 0) { - if (ao_echo()) - put_string("\010 \010"); - --cmd_len; - } - continue; - } - - /* map CR to NL */ - if (c == '\r') - c = '\n'; - - if (c == '\n') { - if (ao_echo()) - putchar('\n'); - break; - } - - if (cmd_len >= CMD_LEN - 2) { - if (ao_echo()) - putchar('\007'); - continue; - } - cmd_line[cmd_len++] = c; - if (ao_echo()) - putchar(c); - } - cmd_line[cmd_len++] = '\n'; - cmd_line[cmd_len++] = '\0'; - cmd_i = 0; -} - -void -ao_cmd_lex(void) -{ - ao_cmd_lex_c = '\n'; - if (cmd_i < cmd_len) - ao_cmd_lex_c = cmd_line[cmd_i++]; -} - -static void -putnibble(uint8_t v) -{ - if (v < 10) - putchar(v + '0'); - else - putchar(v + ('a' - 10)); -} - -void -ao_cmd_put16(uint16_t v) -{ - ao_cmd_put8(v >> 8); - ao_cmd_put8(v); -} - -void -ao_cmd_put8(uint8_t v) -{ - putnibble((v >> 4) & 0xf); - putnibble(v & 0xf); -} - -void -ao_cmd_white(void) -{ - while (ao_cmd_lex_c == ' ' || ao_cmd_lex_c == '\t') - ao_cmd_lex(); -} - -void -ao_cmd_hex(void) -{ - __pdata uint8_t r = ao_cmd_lex_error; - uint8_t n; - - ao_cmd_lex_i = 0; - ao_cmd_white(); - for(;;) { - if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9') - n = (ao_cmd_lex_c - '0'); - else if ('a' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'f') - n = (ao_cmd_lex_c - 'a' + 10); - else if ('A' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'F') - n = (ao_cmd_lex_c - 'A' + 10); - else - break; - ao_cmd_lex_i = (ao_cmd_lex_i << 4) | n; - r = ao_cmd_success; - ao_cmd_lex(); - } - if (r != ao_cmd_success) - ao_cmd_status = r; -} - -void -ao_cmd_decimal(void) -{ - __pdata uint8_t r = ao_cmd_lex_error; - - ao_cmd_lex_u32 = 0; - ao_cmd_white(); - for(;;) { - if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9') - ao_cmd_lex_u32 = (ao_cmd_lex_u32 * 10) + (ao_cmd_lex_c - '0'); - else - break; - r = ao_cmd_success; - ao_cmd_lex(); - } - if (r != ao_cmd_success) - ao_cmd_status = r; - ao_cmd_lex_i = (uint16_t) ao_cmd_lex_u32; -} - -uint8_t -ao_match_word(__code char *word) -{ - while (*word) { - if (ao_cmd_lex_c != *word) { - ao_cmd_status = ao_cmd_syntax_error; - return 0; - } - word++; - ao_cmd_lex(); - } - return 1; -} - -static void -eol(void) -{ - while (ao_cmd_lex_c != '\n') - ao_cmd_lex(); -} - -static void -echo(void) -{ - ao_cmd_hex(); - if (ao_cmd_status == ao_cmd_success) - ao_stdios[ao_cur_stdio].echo = ao_cmd_lex_i != 0; -} - -static void -ao_reboot(void) -{ - ao_cmd_white(); - if (!ao_match_word("eboot")) - return; - WDCTL = WDCTL_EN | WDCTL_MODE_WATCHDOG | WDCTL_INT_64; - ao_delay(AO_SEC_TO_TICKS(2)); - ao_panic(AO_PANIC_REBOOT); -} - -static void -version(void) -{ - printf("manufacturer %s\n", ao_manufacturer); - printf("product %s\n", ao_product); - printf("serial-number %u\n", ao_serial_number); -#if HAS_EEPROM - printf("log-format %u\n", ao_log_format); -#endif - printf("software-version %s\n", ao_version); -} - -#define NUM_CMDS 11 - -static __code struct ao_cmds *__xdata (ao_cmds[NUM_CMDS]); -static __pdata uint8_t ao_ncmds; - -static void -help(void) -{ - register uint8_t cmds; - register uint8_t cmd; - register __code struct ao_cmds * cs; - - for (cmds = 0; cmds < ao_ncmds; cmds++) { - cs = ao_cmds[cmds]; - for (cmd = 0; cs[cmd].func; cmd++) - printf("%-45s %s\n", - cs[cmd].help, - cs[cmd].help+1+strlen(cs[cmd].help)); - } -} - -static void -report(void) -{ - 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) -{ - char c; - uint8_t cmd, cmds; - __code struct ao_cmds * __xdata cs; - void (*__xdata func)(void); - - for (;;) { - readline(); - ao_cmd_lex(); - ao_cmd_white(); - c = ao_cmd_lex_c; - ao_cmd_lex(); - if (c == '\r' || c == '\n') - continue; - func = (void (*)(void)) NULL; - for (cmds = 0; cmds < ao_ncmds; cmds++) { - cs = ao_cmds[cmds]; - for (cmd = 0; cs[cmd].func; cmd++) - if (cs[cmd].help[0] == c) { - func = cs[cmd].func; - break; - } - if (func) - break; - } - if (func) - (*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, "?\0Help" }, - { ao_task_info, "T\0Show tasks" }, - { echo, "E <0 off, 1 on>\0Set echo mode" }, - { ao_reboot, "r eboot\0Reboot" }, - { version, "v\0Version" }, - { 0, NULL }, -}; - -void -ao_cmd_init(void) -{ - ao_cmd_register(&ao_base_cmds[0]); - ao_add_task(&ao_cmd_task, ao_cmd, "cmd"); -} diff --git a/src/ao_companion.c b/src/ao_companion.c deleted file mode 100644 index 4c8f4269..00000000 --- a/src/ao_companion.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -#define ao_spi_slow() (U0GCR = (UxGCR_CPOL_NEGATIVE | \ - UxGCR_CPHA_FIRST_EDGE | \ - UxGCR_ORDER_MSB | \ - (13 << UxGCR_BAUD_E_SHIFT))) - -#define ao_spi_fast() (U0GCR = (UxGCR_CPOL_NEGATIVE | \ - UxGCR_CPHA_FIRST_EDGE | \ - UxGCR_ORDER_MSB | \ - (17 << UxGCR_BAUD_E_SHIFT))) - -#define COMPANION_SELECT() do { ao_spi_get_bit(COMPANION_CS); ao_spi_slow(); } while (0) -#define COMPANION_DESELECT() do { ao_spi_fast(); ao_spi_put_bit(COMPANION_CS); } while (0) - -static __xdata struct ao_companion_command ao_companion_command; -__xdata struct ao_companion_setup ao_companion_setup; - -__xdata uint16_t ao_companion_data[AO_COMPANION_MAX_CHANNELS]; -__pdata uint8_t ao_companion_running; -__xdata uint8_t ao_companion_mutex; - -static void -ao_companion_send_command(uint8_t command) -{ - ao_companion_command.command = command; - ao_companion_command.flight_state = ao_flight_state; - ao_companion_command.tick = ao_time(); - ao_companion_command.serial = ao_serial_number; - ao_companion_command.flight = ao_flight_number; - ao_spi_send(&ao_companion_command, sizeof (ao_companion_command)); -} - -static uint8_t -ao_companion_get_setup(void) -{ - COMPANION_SELECT(); - ao_companion_send_command(AO_COMPANION_SETUP); - ao_spi_recv(&ao_companion_setup, sizeof (ao_companion_setup)); - COMPANION_DESELECT(); - return (ao_companion_setup.board_id == - ~ao_companion_setup.board_id_inverse); -} - -static void -ao_companion_get_data(void) -{ - COMPANION_SELECT(); - ao_companion_send_command(AO_COMPANION_FETCH); - ao_mutex_get(&ao_companion_mutex); - ao_spi_recv(&ao_companion_data, ao_companion_setup.channels * 2); - ao_mutex_put(&ao_companion_mutex); - COMPANION_DESELECT(); -} - -static void -ao_companion_notify(void) -{ - COMPANION_SELECT(); - ao_companion_send_command(AO_COMPANION_NOTIFY); - COMPANION_DESELECT(); -} - -void -ao_companion(void) -{ - uint8_t i; - while (!ao_flight_number) - ao_sleep(&ao_flight_number); - for (i = 0; i < 10; i++) { - ao_delay(AO_SEC_TO_TICKS(1)); - if ((ao_companion_running = ao_companion_get_setup())) - break; - } - while (ao_companion_running) { - ao_alarm(ao_companion_setup.update_period); - if (ao_sleep(DATA_TO_XDATA(&ao_flight_state))) - ao_companion_get_data(); - else - ao_companion_notify(); - } - ao_exit(); -} - -void -ao_companion_status(void) __reentrant -{ - uint8_t i; - printf("Companion running: %d\n", ao_companion_running); - printf("device: %d\n", ao_companion_setup.board_id); - printf("update period: %d\n", ao_companion_setup.update_period); - printf("channels: %d\n", ao_companion_setup.channels); - printf("data:"); - for(i = 0; i < ao_companion_setup.channels; i++) - printf(" %5u", ao_companion_data[i]); - printf("\n"); -} - -__code struct ao_cmds ao_companion_cmds[] = { - { ao_companion_status, "L\0Companion link status" }, - { 0, NULL }, -}; - -static __xdata struct ao_task ao_companion_task; - -void -ao_companion_init(void) -{ - COMPANION_CS_PORT |= COMPANION_CS_MASK; /* raise all CS pins */ - COMPANION_CS_DIR |= COMPANION_CS_MASK; /* set CS pins as outputs */ - COMPANION_CS_SEL &= ~COMPANION_CS_MASK; /* set CS pins as GPIO */ - - ao_cmd_register(&ao_companion_cmds[0]); - ao_add_task(&ao_companion_task, ao_companion, "companion"); -} diff --git a/src/ao_config.c b/src/ao_config.c deleted file mode 100644 index 0c10e608..00000000 --- a/src/ao_config.c +++ /dev/null @@ -1,542 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -__xdata struct ao_config ao_config; -__pdata uint8_t ao_config_loaded; -__pdata uint8_t ao_config_dirty; -__xdata uint8_t ao_config_mutex; - -#define AO_CONFIG_DEFAULT_MAIN_DEPLOY 250 -#define AO_CONFIG_DEFAULT_RADIO_CHANNEL 0 -#define AO_CONFIG_DEFAULT_CALLSIGN "N0CALL" -#define AO_CONFIG_DEFAULT_ACCEL_ZERO_G 16000 -#define AO_CONFIG_DEFAULT_APOGEE_DELAY 0 -#define AO_CONFIG_DEFAULT_IGNITE_MODE AO_IGNITE_MODE_DUAL -#define AO_CONFIG_DEFAULT_PAD_ORIENTATION AO_PAD_ORIENTATION_ANTENNA_UP -#if HAS_EEPROM -#ifndef USE_INTERNAL_FLASH -#error Please define USE_INTERNAL_FLASH -#endif -#endif -#if USE_INTERNAL_FLASH -#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX ao_storage_config -#else -#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX ((uint32_t) 192 * (uint32_t) 1024) -#endif - -#if HAS_EEPROM -static void -_ao_config_put(void) -{ - ao_storage_setup(); - ao_storage_erase(ao_storage_config); - ao_storage_write(ao_storage_config, &ao_config, sizeof (ao_config)); - ao_log_write_erase(0); - ao_storage_flush(); -} - -void -ao_config_put(void) -{ - ao_mutex_get(&ao_config_mutex); - _ao_config_put(); - ao_mutex_put(&ao_config_mutex); -} -#endif - -static void -_ao_config_get(void) -{ - if (ao_config_loaded) - return; -#if HAS_EEPROM - ao_storage_setup(); - ao_storage_read(ao_storage_config, &ao_config, sizeof (ao_config)); -#endif - if (ao_config.major != AO_CONFIG_MAJOR) { - ao_config.major = AO_CONFIG_MAJOR; - ao_config.minor = 0; - ao_config.main_deploy = AO_CONFIG_DEFAULT_MAIN_DEPLOY; - ao_config.radio_channel = AO_CONFIG_DEFAULT_RADIO_CHANNEL; - memset(&ao_config.callsign, '\0', sizeof (ao_config.callsign)); - memcpy(&ao_config.callsign, AO_CONFIG_DEFAULT_CALLSIGN, - sizeof(AO_CONFIG_DEFAULT_CALLSIGN) - 1); - } - if (ao_config.minor < AO_CONFIG_MINOR) { - /* Fixups for minor version 1 */ - if (ao_config.minor < 1) - ao_config.apogee_delay = AO_CONFIG_DEFAULT_APOGEE_DELAY; - /* Fixups for minor version 2 */ - if (ao_config.minor < 2) { - ao_config.accel_plus_g = 0; - ao_config.accel_minus_g = 0; - } - /* Fixups for minor version 3 */ - if (ao_config.minor < 3) - ao_config.radio_cal = ao_radio_cal; - /* Fixups for minor version 4 */ - if (ao_config.minor < 4) - ao_config.flight_log_max = AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX; - /* Fixupes for minor version 5 */ - if (ao_config.minor < 5) - ao_config.ignite_mode = AO_CONFIG_DEFAULT_IGNITE_MODE; - if (ao_config.minor < 6) - ao_config.pad_orientation = AO_CONFIG_DEFAULT_PAD_ORIENTATION; - if (ao_config.minor < 7) - ao_config.radio_setting = ao_config.radio_cal; - if (ao_config.minor < 8) - ao_config.radio_enable = TRUE; - ao_config.minor = AO_CONFIG_MINOR; - ao_config_dirty = 1; - } - ao_config_loaded = 1; -} - -static void -_ao_config_edit_start(void) -{ - ao_mutex_get(&ao_config_mutex); - _ao_config_get(); -} - -static void -_ao_config_edit_finish(void) -{ - ao_config_dirty = 1; - ao_mutex_put(&ao_config_mutex); -} - -void -ao_config_get(void) -{ - _ao_config_edit_start(); - ao_mutex_put(&ao_config_mutex); -} - -void -ao_config_callsign_show(void) -{ - printf ("Callsign: \"%s\"\n", ao_config.callsign); -} - -void -ao_config_callsign_set(void) __reentrant -{ - uint8_t c; - static __xdata char callsign[AO_MAX_CALLSIGN + 1]; - - memset(callsign, '\0', sizeof callsign); - ao_cmd_white(); - c = 0; - while (ao_cmd_lex_c != '\n') { - if (c < AO_MAX_CALLSIGN) - callsign[c++] = ao_cmd_lex_c; - else - ao_cmd_status = ao_cmd_lex_error; - ao_cmd_lex(); - } - if (ao_cmd_status != ao_cmd_success) - return; - _ao_config_edit_start(); - memcpy(&ao_config.callsign, &callsign, - AO_MAX_CALLSIGN + 1); - _ao_config_edit_finish(); -} - -void -ao_config_radio_channel_show(void) __reentrant -{ - printf("Radio channel: %d\n", - ao_config.radio_channel); -} - -void -ao_config_radio_channel_set(void) __reentrant -{ - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - _ao_config_edit_start(); - ao_config.radio_channel = ao_cmd_lex_i; - _ao_config_edit_finish(); - ao_radio_recv_abort(); -} - -#if HAS_ADC - -void -ao_config_main_deploy_show(void) __reentrant -{ - printf("Main deploy: %d meters\n", - ao_config.main_deploy); -} - -void -ao_config_main_deploy_set(void) __reentrant -{ - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - _ao_config_edit_start(); - ao_config.main_deploy = ao_cmd_lex_i; - _ao_config_edit_finish(); -} - -#if HAS_ACCEL -void -ao_config_accel_calibrate_show(void) __reentrant -{ - printf("Accel cal +1g: %d -1g: %d\n", - ao_config.accel_plus_g, ao_config.accel_minus_g); -} - -#define ACCEL_CALIBRATE_SAMPLES 1024 -#define ACCEL_CALIBRATE_SHIFT 10 - -static int16_t -ao_config_accel_calibrate_auto(char *orientation) __reentrant -{ - uint16_t i; - int32_t accel_total; - uint8_t cal_adc_ring; - - printf("Orient antenna %s and press a key...", orientation); - flush(); - (void) getchar(); - puts("\r\n"); flush(); - puts("Calibrating..."); flush(); - i = ACCEL_CALIBRATE_SAMPLES; - accel_total = 0; - cal_adc_ring = ao_sample_adc; - while (i) { - ao_sleep(DATA_TO_XDATA(&ao_sample_adc)); - while (i && cal_adc_ring != ao_sample_adc) { - accel_total += (int32_t) ao_adc_ring[cal_adc_ring].accel; - cal_adc_ring = ao_adc_ring_next(cal_adc_ring); - i--; - } - } - return accel_total >> ACCEL_CALIBRATE_SHIFT; -} - -void -ao_config_accel_calibrate_set(void) __reentrant -{ - int16_t up, down; - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - if (ao_cmd_lex_i == 0) { - up = ao_config_accel_calibrate_auto("up"); - down = ao_config_accel_calibrate_auto("down"); - } else { - up = ao_cmd_lex_i; - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - down = ao_cmd_lex_i; - } - if (up >= down) { - printf("Invalid accel: up (%d) down (%d)\n", - up, down); - return; - } - _ao_config_edit_start(); - ao_config.accel_plus_g = up; - ao_config.accel_minus_g = down; - _ao_config_edit_finish(); -} -#endif /* HAS_ACCEL */ - -void -ao_config_apogee_delay_show(void) __reentrant -{ - printf("Apogee delay: %d seconds\n", - ao_config.apogee_delay); -} - -void -ao_config_apogee_delay_set(void) __reentrant -{ - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - _ao_config_edit_start(); - ao_config.apogee_delay = ao_cmd_lex_i; - _ao_config_edit_finish(); -} - -#endif /* HAS_ADC */ - -void -ao_config_radio_cal_show(void) __reentrant -{ - printf("Radio cal: %ld\n", ao_config.radio_cal); -} - -void -ao_config_radio_cal_set(void) __reentrant -{ - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - _ao_config_edit_start(); - ao_config.radio_setting = ao_config.radio_cal = ao_cmd_lex_u32; - _ao_config_edit_finish(); -} - -#if HAS_EEPROM -void -ao_config_log_show(void) __reentrant -{ - printf("Max flight log: %d kB\n", (int16_t) (ao_config.flight_log_max >> 10)); -} - -void -ao_config_log_set(void) __reentrant -{ - uint16_t block = (uint16_t) (ao_storage_block >> 10); - uint16_t config = (uint16_t) (ao_storage_config >> 10); - - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - if (ao_log_present()) - printf("Storage must be empty before changing log size\n"); - else if (block > 1024 && (ao_cmd_lex_i & (block - 1))) - printf("Flight log size must be multiple of %d kB\n", block); - else if (ao_cmd_lex_i > config) - printf("Flight log max %d kB\n", config); - else { - _ao_config_edit_start(); - ao_config.flight_log_max = (uint32_t) ao_cmd_lex_i << 10; - _ao_config_edit_finish(); - } -} -#endif /* HAS_EEPROM */ - -#if HAS_IGNITE -void -ao_config_ignite_mode_show(void) __reentrant -{ - printf("Ignite mode: %d\n", ao_config.ignite_mode); -} - -void -ao_config_ignite_mode_set(void) __reentrant -{ - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - _ao_config_edit_start(); - ao_config.ignite_mode = ao_cmd_lex_i; - _ao_config_edit_finish(); -} -#endif - -#if HAS_ACCEL -void -ao_config_pad_orientation_show(void) __reentrant -{ - printf("Pad orientation: %d\n", ao_config.pad_orientation); -} - -void -ao_config_pad_orientation_set(void) __reentrant -{ - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - _ao_config_edit_start(); - ao_cmd_lex_i &= 1; - if (ao_config.pad_orientation != ao_cmd_lex_i) { - uint16_t t; - t = ao_config.accel_plus_g; - ao_config.accel_plus_g = 0x7fff - ao_config.accel_minus_g; - ao_config.accel_minus_g = 0x7fff - t; - } - ao_config.pad_orientation = ao_cmd_lex_i; - _ao_config_edit_finish(); -} -#endif - -void -ao_config_radio_setting_show(void) __reentrant -{ - printf("Radio setting: %ld\n", ao_config.radio_setting); -} - -void -ao_config_radio_setting_set(void) __reentrant -{ - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - _ao_config_edit_start(); - ao_config.radio_setting = ao_cmd_lex_u32; - ao_config.radio_channel = 0; - _ao_config_edit_finish(); - ao_radio_recv_abort(); -} - -void -ao_config_radio_enable_show(void) __reentrant -{ - printf("Radio enable: %d\n", ao_config.radio_enable); -} - -void -ao_config_radio_enable_set(void) __reentrant -{ - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - _ao_config_edit_start(); - ao_config.radio_enable = ao_cmd_lex_i; - _ao_config_edit_finish(); -} - -struct ao_config_var { - __code char *str; - void (*set)(void) __reentrant; - void (*show)(void) __reentrant; -}; - -static void -ao_config_help(void) __reentrant; - -static void -ao_config_show(void) __reentrant; - -static void -ao_config_write(void) __reentrant; - -__code struct ao_config_var ao_config_vars[] = { -#if HAS_ADC - { "m \0Main deploy (in meters)", - ao_config_main_deploy_set, ao_config_main_deploy_show, }, - { "d \0Apogee delay (in seconds)", - ao_config_apogee_delay_set, ao_config_apogee_delay_show }, -#endif /* HAS_ADC */ - { "r \0Radio channel (freq = 434.550 + chan * .1)", - ao_config_radio_channel_set, ao_config_radio_channel_show }, - { "c \0Callsign (8 char max)", - ao_config_callsign_set, ao_config_callsign_show }, - { "R \0Radio freq control (freq = 434.550 * setting/cal)", - ao_config_radio_setting_set, ao_config_radio_setting_show }, - { "e <0 disable, 1 enable>\0Enable telemetry and RDF", - ao_config_radio_enable_set, ao_config_radio_enable_show }, -#if HAS_ACCEL - { "a <+g> <-g>\0Accel calib (0 for auto)", - ao_config_accel_calibrate_set,ao_config_accel_calibrate_show }, -#endif /* HAS_ACCEL */ - { "f \0Radio calib (cal = rf/(xtal/2^16))", - ao_config_radio_cal_set, ao_config_radio_cal_show }, -#if HAS_EEPROM - { "l \0Flight log size in kB", - ao_config_log_set, ao_config_log_show }, -#endif -#if HAS_IGNITE - { "i <0 dual, 1 apogee, 2 main>\0Set igniter mode", - ao_config_ignite_mode_set, ao_config_ignite_mode_show }, -#endif -#if HAS_ACCEL - { "o <0 antenna up, 1 antenna down>\0Set pad orientation", - ao_config_pad_orientation_set,ao_config_pad_orientation_show }, -#endif - { "s\0Show", - ao_config_show, 0 }, -#if HAS_EEPROM - { "w\0Write to eeprom", - ao_config_write, 0 }, -#endif - { "?\0Help", - ao_config_help, 0 }, - { 0, 0, 0 } -}; - -void -ao_config_set(void) -{ - char c; - uint8_t cmd; - void (*__xdata func)(void) __reentrant; - - ao_cmd_white(); - c = ao_cmd_lex_c; - ao_cmd_lex(); - func = 0; - for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++) - if (ao_config_vars[cmd].str[0] == c) { - (*ao_config_vars[cmd].set)(); - return; - } - ao_cmd_status = ao_cmd_syntax_error; -} - -static void -ao_config_help(void) __reentrant -{ - uint8_t cmd; - for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++) - printf("%-20s %s\n", - ao_config_vars[cmd].str, - ao_config_vars[cmd].str+1+strlen(ao_config_vars[cmd].str)); -} - -static void -ao_config_show(void) __reentrant -{ - uint8_t cmd; - printf("Config version: %d.%d\n", - ao_config.major, ao_config.minor); - for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++) - if (ao_config_vars[cmd].show) - (*ao_config_vars[cmd].show)(); -} - -#if HAS_EEPROM -static void -ao_config_write(void) __reentrant -{ - uint8_t saved = 0; - ao_mutex_get(&ao_config_mutex); - if (ao_config_dirty) { - _ao_config_put(); - ao_config_dirty = 0; - saved = 1; - } - ao_mutex_put(&ao_config_mutex); - if (saved) - puts("Saved"); - else - puts("Nothing to save"); -} -#endif - -__code struct ao_cmds ao_config_cmds[] = { - { ao_config_set, "c \0Set config variable (? for help, s to show)" }, - { 0, NULL }, -}; - -void -ao_config_init(void) -{ - ao_cmd_register(&ao_config_cmds[0]); -} diff --git a/src/ao_convert.c b/src/ao_convert.c deleted file mode 100644 index 0969f107..00000000 --- a/src/ao_convert.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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. - */ - -#if !defined(AO_CONVERT_TEST) && !defined(AO_FLIGHT_TEST) -#include "ao.h" -#endif - -static const int16_t altitude_table[] = { -#include "altitude.h" -}; - -#define ALT_FRAC_SCALE (1 << ALT_FRAC_BITS) -#define ALT_FRAC_MASK (ALT_FRAC_SCALE - 1) - -int16_t -ao_pres_to_altitude(int16_t pres) __reentrant -{ - uint8_t o; - int16_t part; - - if (pres < 0) - pres = 0; - o = pres >> ALT_FRAC_BITS; - part = pres & ALT_FRAC_MASK; - - return ((int32_t) altitude_table[o] * (ALT_FRAC_SCALE - part) + - (int32_t) altitude_table[o+1] * part + (ALT_FRAC_SCALE >> 1)) >> ALT_FRAC_BITS; -} - -int16_t -ao_altitude_to_pres(int16_t alt) __reentrant -{ - int16_t span, sub_span; - uint8_t l, h, m; - int32_t pres; - - l = 0; - h = NALT - 1; - while ((h - l) != 1) { - m = (l + h) >> 1; - if (altitude_table[m] < alt) - h = m; - else - l = m; - } - span = altitude_table[l] - altitude_table[h]; - sub_span = altitude_table[l] - alt; - pres = ((((int32_t) l * (span - sub_span) + (int32_t) h * sub_span) << ALT_FRAC_BITS) + (span >> 1)) / span; - if (pres > 32767) - pres = 32767; - if (pres < 0) - pres = 0; - return (int16_t) pres; -} - -int16_t -ao_temp_to_dC(int16_t temp) __reentrant -{ - int16_t ret; - - /* Output voltage at 0°C = 0.755V - * Coefficient = 0.00247V/°C - * Reference voltage = 1.25V - * - * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247 - * = (value - 19791.268) / 32768 * 1.25 / 0.00247 - * ≃ (value - 19791) * 1012 / 65536 - */ - ret = ((temp - 19791) * 1012L) >> 16; - return ret; -} diff --git a/src/ao_convert_test.c b/src/ao_convert_test.c deleted file mode 100644 index e2c28b73..00000000 --- a/src/ao_convert_test.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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 -#define AO_CONVERT_TEST -#include "ao_host.h" -#include "ao_convert.c" - -#define STEP 1 - -static inline i_abs(int i) { return i < 0 ? -i : i; } - -main () -{ - int i; - int16_t p_to_a, p_to_a_to_p; - int16_t a_to_p, a_to_p_to_a; - int max_p_error = 0, max_p_error_p = -1; - int max_a_error = 0, max_a_error_a = -1; - int p_error; - int a_error; - int ret = 0; - - for (i = 0; i < 32767 + STEP; i += STEP) { - if (i > 32767) - i = 32767; - p_to_a = ao_pres_to_altitude(i); - p_to_a_to_p = ao_altitude_to_pres(p_to_a); - p_error = i_abs(p_to_a_to_p - i); - if (p_error > max_p_error) { - max_p_error = p_error; - max_p_error_p = i; - } -// printf ("pres %d alt %d pres %d\n", -// i, p_to_a, p_to_a_to_p); - } - for (i = -1578; i < 15835 + STEP; i += STEP) { - if (i > 15835) - i = 15835; - a_to_p = ao_altitude_to_pres(i); - a_to_p_to_a = ao_pres_to_altitude(a_to_p); - a_error = i_abs(a_to_p_to_a - i); - if (a_error > max_a_error) { - max_a_error = a_error; - max_a_error_a = i; - } -// printf ("alt %d pres %d alt %d\n", -// i, a_to_p, a_to_p_to_a); - } - if (max_p_error > 2) { - printf ("max p error %d at %d\n", max_p_error, - max_p_error_p); - ret++; - } - if (max_a_error > 1) { - printf ("max a error %d at %d\n", max_a_error, - max_a_error_a); - ret++; - } - return ret; -} diff --git a/src/ao_dbg.c b/src/ao_dbg.c deleted file mode 100644 index d4c9567f..00000000 --- a/src/ao_dbg.c +++ /dev/null @@ -1,364 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" -#include "ao_pins.h" - -static void -ao_dbg_send_bits(uint8_t msk, uint8_t val) __reentrant -{ - DBG_PORT = (DBG_PORT & ~msk) | (val & msk); - _asm - nop - nop - _endasm; -} - -void -ao_dbg_send_byte(uint8_t byte) -{ - __pdata uint8_t b, d; - - DBG_PORT |= DBG_DATA; - DBG_PORT_DIR |= DBG_DATA; - for (b = 0; b < 8; b++) { - d = 0; - if (byte & 0x80) - d = DBG_DATA; - byte <<= 1; - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA, DBG_CLOCK|d); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA, 0 |d); - } - DBG_PORT_DIR &= ~DBG_DATA; -} - -uint8_t -ao_dbg_recv_byte(void) -{ - __pdata uint8_t byte, b; - - byte = 0; - for (b = 0; b < 8; b++) { - byte = byte << 1; - ao_dbg_send_bits(DBG_CLOCK, DBG_CLOCK); - if (DBG_DATA_PIN) - byte |= 1; - ao_dbg_send_bits(DBG_CLOCK, 0); - } - return byte; -} - -/* 8051 instructions - */ -#define NOP 0x00 -#define MOV_direct_data 0x75 -#define LJMP 0x02 -#define MOV_Rn_data(n) (0x78 | (n)) -#define DJNZ_Rn_rel(n) (0xd8 | (n)) -#define MOV_A_direct 0xe5 -#define MOV_direct1_direct2 0x85 -#define MOV_direct_A 0xf5 -#define MOV_DPTR_data16 0x90 -#define MOV_A_data 0x74 -#define MOVX_atDPTR_A 0xf0 -#define MOVX_A_atDPTR 0xe0 -#define INC_DPTR 0xa3 -#define TRAP 0xa5 -#define SJMP 0x80 -#define JB 0x20 - -#define DEBUG_INSTR(l) (0x54 | (l)) - -#define SFR_PSW 0xD0 -#define SFR_DPL0 0x82 -#define SFR_DPH0 0x83 -#define SFR_DPL1 0x84 -#define SFR_DPH1 0x85 - -__pdata uint8_t save_acc; -__pdata uint8_t save_psw; -__pdata uint8_t save_dpl0; -__pdata uint8_t save_dph0; -__pdata uint8_t save_dpl1; -__pdata uint8_t save_dph1; - -static uint8_t -ao_dbg_inst1(uint8_t a) __reentrant -{ - ao_dbg_send_byte(DEBUG_INSTR(1)); - ao_dbg_send_byte(a); - return ao_dbg_recv_byte(); -} - -static uint8_t -ao_dbg_inst2(uint8_t a, uint8_t b) __reentrant -{ - ao_dbg_send_byte(DEBUG_INSTR(2)); - ao_dbg_send_byte(a); - ao_dbg_send_byte(b); - return ao_dbg_recv_byte(); -} - -static uint8_t -ao_dbg_inst3(uint8_t a, uint8_t b, uint8_t c) __reentrant -{ - ao_dbg_send_byte(DEBUG_INSTR(3)); - ao_dbg_send_byte(a); - ao_dbg_send_byte(b); - ao_dbg_send_byte(c); - return ao_dbg_recv_byte(); -} - -void -ao_dbg_start_transfer(uint16_t addr) -{ - save_acc = ao_dbg_inst1(NOP); - save_psw = ao_dbg_inst2(MOV_A_direct, SFR_PSW); - save_dpl0 = ao_dbg_inst2(MOV_A_direct, SFR_DPL0); - save_dph0 = ao_dbg_inst2(MOV_A_direct, SFR_DPH0); - save_dpl1 = ao_dbg_inst2(MOV_A_direct, SFR_DPL1); - save_dph1 = ao_dbg_inst2(MOV_A_direct, SFR_DPH1); - ao_dbg_inst3(MOV_DPTR_data16, addr >> 8, addr); -} - -void -ao_dbg_end_transfer(void) -{ - ao_dbg_inst3(MOV_direct_data, SFR_DPL0, save_dpl0); - ao_dbg_inst3(MOV_direct_data, SFR_DPH0, save_dph0); - ao_dbg_inst3(MOV_direct_data, SFR_DPL1, save_dpl1); - ao_dbg_inst3(MOV_direct_data, SFR_DPH1, save_dph1); - ao_dbg_inst3(MOV_direct_data, SFR_PSW, save_psw); - ao_dbg_inst2(MOV_A_data, save_acc); -} - -void -ao_dbg_write_byte(uint8_t byte) -{ - ao_dbg_inst2(MOV_A_data, byte); - ao_dbg_inst1(MOVX_atDPTR_A); - ao_dbg_inst1(INC_DPTR); -} - -uint8_t -ao_dbg_read_byte(void) -{ - ao_dbg_inst1(MOVX_A_atDPTR); - return ao_dbg_inst1(INC_DPTR); -} - -static void -ao_dbg_set_pins(void) -{ - /* Make the DBG pins GPIOs. On TeleMetrum, this will - * disable the SPI link, so don't expect SPI to work after - * using the debugger. - */ - DBG_PORT_SEL &= ~(DBG_CLOCK|DBG_DATA|DBG_RESET_N); - - /* make DBG_DATA tri-state */ - DBG_PORT_INP |= DBG_DATA; - - /* Raise RESET_N and CLOCK */ - DBG_PORT |= DBG_RESET_N | DBG_CLOCK; - - /* RESET_N and CLOCK are outputs now */ - DBG_PORT_DIR |= DBG_RESET_N | DBG_CLOCK; - DBG_PORT_DIR &= ~DBG_DATA; -} - -static void -ao_dbg_long_delay(void) -{ - uint8_t n; - - for (n = 0; n < 20; n++) - _asm nop _endasm; -} - -#define AO_RESET_LOW_DELAY AO_MS_TO_TICKS(100) -#define AO_RESET_HIGH_DELAY AO_MS_TO_TICKS(100) - -void -ao_dbg_debug_mode(void) -{ - ao_dbg_set_pins(); - ao_dbg_long_delay(); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N); - ao_dbg_long_delay(); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA| 0 ); - ao_delay(AO_RESET_LOW_DELAY); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); - ao_dbg_long_delay(); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA| 0 ); - ao_dbg_long_delay(); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); - ao_dbg_long_delay(); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA|DBG_RESET_N); - ao_delay(AO_RESET_HIGH_DELAY); -} - -void -ao_dbg_reset(void) -{ - ao_dbg_set_pins(); - ao_dbg_long_delay(); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N); - ao_dbg_long_delay(); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); - ao_delay(AO_RESET_LOW_DELAY); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); - ao_dbg_long_delay(); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); - ao_dbg_long_delay(); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); - ao_dbg_long_delay(); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N); - ao_delay(AO_RESET_HIGH_DELAY); -} - -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) -{ - __pdata uint16_t count; - __pdata uint16_t i; - __pdata 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) -{ - __pdata char 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) -{ - __pdata uint16_t count; - __pdata uint16_t addr; - __pdata uint8_t b; - __pdata 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) -{ - __pdata uint16_t count; - __pdata uint16_t addr; - __pdata 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] = { - { debug_enable, "D\0Enable debug" }, - { debug_get, "G \0Get data" }, - { debug_input, "I \0Input at " }, - { debug_output, "O \0Output at " }, - { debug_put, "P ...\0Put data" }, - { debug_reset, "R\0Reset" }, - { 0, NULL }, -}; - -void -ao_dbg_init(void) -{ - ao_cmd_register(&ao_dbg_cmds[0]); -} diff --git a/src/ao_dma.c b/src/ao_dma.c deleted file mode 100644 index 6052964a..00000000 --- a/src/ao_dma.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -#define NUM_DMA 5 - -/* - * The config address for DMA0 is programmed - * separately from that of DMA1-4, but for simplicity, - * we make them all contiguous. - */ - -static __xdata struct cc_dma_channel ao_dma_config[NUM_DMA]; -static __xdata uint8_t * __xdata ao_dma_done[NUM_DMA]; -static __data uint8_t ao_next_dma; - -uint8_t -ao_dma_alloc(__xdata uint8_t *done) -{ - uint8_t id; - - if (ao_next_dma == NUM_DMA) - ao_panic(AO_PANIC_DMA); - id = ao_next_dma++; - ao_dma_done[id] = done; - - /* When the first dma object is allocated, set up the DMA - * controller - */ - if (id == 0) { - DMAIRQ = 0; - DMAIF = 0; - IEN1 |= IEN1_DMAIE; - } - - return id; -} - -void -ao_dma_set_transfer(uint8_t id, - void __xdata *srcaddr, - void __xdata *dstaddr, - uint16_t count, - uint8_t cfg0, - uint8_t cfg1) -{ - if (DMAARM & (1 << id)) - ao_panic(AO_PANIC_DMA); - ao_dma_config[id].src_high = ((uint16_t) srcaddr) >> 8; - ao_dma_config[id].src_low = ((uint16_t) srcaddr); - ao_dma_config[id].dst_high = ((uint16_t) dstaddr) >> 8; - ao_dma_config[id].dst_low = ((uint16_t) dstaddr); - ao_dma_config[id].len_high = count >> 8; - ao_dma_config[id].len_low = count; - ao_dma_config[id].cfg0 = cfg0; - ao_dma_config[id].cfg1 = cfg1 | DMA_CFG1_IRQMASK; - if (id == 0) { - DMA0CFGH = ((uint16_t) (&ao_dma_config[0])) >> 8; - DMA0CFGL = ((uint16_t) (&ao_dma_config[0])); - } else { - DMA1CFGH = ((uint16_t) (&ao_dma_config[1])) >> 8; - DMA1CFGL = ((uint16_t) (&ao_dma_config[1])); - } -} - -#define nop() _asm nop _endasm; - -void -ao_dma_start(uint8_t id) -{ - uint8_t mask = (1 << id); - DMAIRQ &= ~mask; - 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(); -} - -void -ao_dma_trigger(uint8_t id) -{ - DMAREQ |= (1 << id); -} - -void -ao_dma_abort(uint8_t id) -{ - uint8_t mask = (1 << id); - DMAARM = 0x80 | mask; - DMAIRQ &= ~mask; -} - -void -ao_dma_isr(void) __interrupt 8 -{ - uint8_t id, mask; - - /* Find the first DMA channel which is done */ - mask = 1; - for (id = 0; id < ao_next_dma; id++) { - if (DMAIRQ & mask) { - /* Clear CPU interrupt flag */ - DMAIF = 0; - /* Clear the completed ID */ - DMAIRQ = ~mask; - *(ao_dma_done[id]) = 1; - ao_wakeup(ao_dma_done[id]); - break; - } - mask <<= 1; - } -} diff --git a/src/ao_ee.c b/src/ao_ee.c deleted file mode 100644 index a2fe8dc1..00000000 --- a/src/ao_ee.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" -#include "25lc1024.h" - -#define EE_BLOCK_SIZE ((uint16_t) (256)) -#define EE_BLOCK_SHIFT 8 -#define EE_DEVICE_SIZE ((uint32_t) 128 * (uint32_t) 1024) - -/* Total bytes of available storage */ -__pdata uint32_t ao_storage_total; - -/* Block size - device is erased in these units. At least 256 bytes */ -__pdata uint32_t ao_storage_block; - -/* Byte offset of config block. Will be ao_storage_block bytes long */ -__pdata uint32_t ao_storage_config; - -/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */ -__pdata uint16_t ao_storage_unit; - -/* - * Using SPI on USART 0, with P1_2 as the chip select - */ - -#define EE_CS P1_2 -#define EE_CS_INDEX 2 - -static __xdata uint8_t ao_ee_mutex; - -#define ao_ee_delay() do { \ - _asm nop _endasm; \ - _asm nop _endasm; \ - _asm nop _endasm; \ -} while(0) - -#define ao_ee_cs_low() ao_spi_get_bit(EE_CS) - -#define ao_ee_cs_high() ao_spi_put_bit(EE_CS) - -struct ao_ee_instruction { - uint8_t instruction; - uint8_t address[3]; -} __xdata ao_ee_instruction; - -static void -ao_ee_write_enable(void) -{ - ao_ee_cs_low(); - ao_ee_instruction.instruction = EE_WREN; - ao_spi_send(&ao_ee_instruction, 1); - ao_ee_cs_high(); -} - -static uint8_t -ao_ee_rdsr(void) -{ - ao_ee_cs_low(); - ao_ee_instruction.instruction = EE_RDSR; - ao_spi_send(&ao_ee_instruction, 1); - ao_spi_recv(&ao_ee_instruction, 1); - ao_ee_cs_high(); - return ao_ee_instruction.instruction; -} - -static void -ao_ee_wrsr(uint8_t status) -{ - ao_ee_cs_low(); - ao_ee_instruction.instruction = EE_WRSR; - ao_ee_instruction.address[0] = status; - ao_spi_send(&ao_ee_instruction, 2); - ao_ee_cs_high(); -} - -#define EE_BLOCK_NONE 0xffff - -static __xdata uint8_t ao_ee_data[EE_BLOCK_SIZE]; -static __pdata uint16_t ao_ee_block = EE_BLOCK_NONE; -static __pdata uint8_t ao_ee_block_dirty; - -/* Write the current block to the EEPROM */ -static void -ao_ee_write_block(void) -{ - uint8_t status; - - status = ao_ee_rdsr(); - if (status & (EE_STATUS_BP0|EE_STATUS_BP1|EE_STATUS_WPEN)) { - status &= ~(EE_STATUS_BP0|EE_STATUS_BP1|EE_STATUS_WPEN); - ao_ee_wrsr(status); - } - ao_ee_write_enable(); - ao_ee_cs_low(); - ao_ee_instruction.instruction = EE_WRITE; - ao_ee_instruction.address[0] = ao_ee_block >> 8; - ao_ee_instruction.address[1] = ao_ee_block; - ao_ee_instruction.address[2] = 0; - ao_spi_send(&ao_ee_instruction, 4); - ao_spi_send(ao_ee_data, EE_BLOCK_SIZE); - ao_ee_cs_high(); - for (;;) { - uint8_t status = ao_ee_rdsr(); - if ((status & EE_STATUS_WIP) == 0) - break; - } -} - -/* Read the current block from the EEPROM */ -static void -ao_ee_read_block(void) -{ - ao_ee_cs_low(); - ao_ee_instruction.instruction = EE_READ; - ao_ee_instruction.address[0] = ao_ee_block >> 8; - ao_ee_instruction.address[1] = ao_ee_block; - ao_ee_instruction.address[2] = 0; - ao_spi_send(&ao_ee_instruction, 4); - ao_spi_recv(ao_ee_data, EE_BLOCK_SIZE); - ao_ee_cs_high(); -} - -static void -ao_ee_flush_internal(void) -{ - if (ao_ee_block_dirty) { - ao_ee_write_block(); - ao_ee_block_dirty = 0; - } -} - -static void -ao_ee_fill(uint16_t block) -{ - if (block != ao_ee_block) { - ao_ee_flush_internal(); - ao_ee_block = block; - ao_ee_read_block(); - } -} - -uint8_t -ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant -{ - uint16_t block = (uint16_t) (pos >> EE_BLOCK_SHIFT); - - /* Transfer the data */ - ao_mutex_get(&ao_ee_mutex); { - if (len != EE_BLOCK_SIZE) - ao_ee_fill(block); - else { - ao_ee_flush_internal(); - ao_ee_block = block; - } - memcpy(ao_ee_data + (uint16_t) (pos & 0xff), buf, len); - ao_ee_block_dirty = 1; - } ao_mutex_put(&ao_ee_mutex); - return 1; -} - -uint8_t -ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant -{ - uint16_t block = (uint16_t) (pos >> EE_BLOCK_SHIFT); - - /* Transfer the data */ - ao_mutex_get(&ao_ee_mutex); { - ao_ee_fill(block); - memcpy(buf, ao_ee_data + (uint16_t) (pos & 0xff), len); - } ao_mutex_put(&ao_ee_mutex); - return 1; -} - -void -ao_storage_flush(void) __reentrant -{ - ao_mutex_get(&ao_ee_mutex); { - ao_ee_flush_internal(); - } ao_mutex_put(&ao_ee_mutex); -} - -uint8_t -ao_storage_erase(uint32_t pos) __reentrant -{ - ao_mutex_get(&ao_ee_mutex); { - ao_ee_flush_internal(); - ao_ee_block = (uint16_t) (pos >> EE_BLOCK_SHIFT); - memset(ao_ee_data, 0xff, EE_BLOCK_SIZE); - ao_ee_block_dirty = 1; - } ao_mutex_put(&ao_ee_mutex); - return 1; -} - -static void -ee_store(void) __reentrant -{ -} - -void -ao_storage_setup(void) -{ - if (ao_storage_total == 0) { - ao_storage_total = EE_DEVICE_SIZE; - ao_storage_block = EE_BLOCK_SIZE; - ao_storage_config = EE_DEVICE_SIZE - EE_BLOCK_SIZE; - ao_storage_unit = EE_BLOCK_SIZE; - } -} - -void -ao_storage_device_info(void) __reentrant -{ -} - -/* - * To initialize the chip, set up the CS line and - * the SPI interface - */ -void -ao_storage_device_init(void) -{ - /* set up CS */ - EE_CS = 1; - P1DIR |= (1 << EE_CS_INDEX); - P1SEL &= ~(1 << EE_CS_INDEX); -} diff --git a/src/ao_ee_fake.c b/src/ao_ee_fake.c deleted file mode 100644 index b0c1d61e..00000000 --- a/src/ao_ee_fake.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -/* - * For hardware without eeprom, the config code still - * wants to call these functions - */ -uint8_t -ao_ee_write_config(uint8_t *buf, uint16_t len) __reentrant -{ - (void) buf; - (void) len; - return 1; -} - -uint8_t -ao_ee_read_config(uint8_t *buf, uint16_t len) __reentrant -{ - memset(buf, '\0', len); - return 1; -} diff --git a/src/ao_flash.c b/src/ao_flash.c deleted file mode 100644 index bb40f6f7..00000000 --- a/src/ao_flash.c +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" -#include "at45db161d.h" - -/* Total bytes of available storage */ -__pdata uint32_t ao_storage_total; - -/* Block size - device is erased in these units. At least 256 bytes */ -__pdata uint32_t ao_storage_block; - -/* Byte offset of config block. Will be ao_storage_block bytes long */ -__pdata uint32_t ao_storage_config; - -/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */ -__pdata uint16_t ao_storage_unit; - -#define FLASH_CS P1_1 -#define FLASH_CS_INDEX 1 - -#define FLASH_BLOCK_SIZE_MAX 512 - -__xdata uint8_t ao_flash_mutex; - -#define ao_flash_delay() do { \ - _asm nop _endasm; \ - _asm nop _endasm; \ - _asm nop _endasm; \ -} while(0) - -#define ao_flash_cs_low() ao_spi_get_bit(FLASH_CS) - -#define ao_flash_cs_high() ao_spi_put_bit(FLASH_CS) - -struct ao_flash_instruction { - uint8_t instruction; - uint8_t address[3]; -} __xdata ao_flash_instruction; - -static void -ao_flash_set_pagesize_512(void) -{ - ao_flash_cs_low(); - ao_flash_instruction.instruction = FLASH_SET_CONFIG; - ao_flash_instruction.address[0] = FLASH_SET_512_BYTE_0; - ao_flash_instruction.address[1] = FLASH_SET_512_BYTE_1; - ao_flash_instruction.address[2] = FLASH_SET_512_BYTE_2; - ao_spi_send(&ao_flash_instruction, 4); - ao_flash_cs_high(); -} - - -static uint8_t -ao_flash_read_status(void) -{ - ao_flash_cs_low(); - ao_flash_instruction.instruction = FLASH_READ_STATUS; - ao_spi_send(&ao_flash_instruction, 1); - ao_spi_recv(&ao_flash_instruction, 1); - ao_flash_cs_high(); - return ao_flash_instruction.instruction; -} - -#define FLASH_BLOCK_NONE 0xffff - -static __xdata uint8_t ao_flash_data[FLASH_BLOCK_SIZE_MAX]; -static __pdata uint16_t ao_flash_block = FLASH_BLOCK_NONE; -static __pdata uint8_t ao_flash_block_dirty; -static __pdata uint8_t ao_flash_write_pending; -static __pdata uint8_t ao_flash_setup_done; -static __pdata uint8_t ao_flash_block_shift; -static __pdata uint16_t ao_flash_block_size; -static __pdata uint16_t ao_flash_block_mask; - -void -ao_storage_setup(void) __reentrant -{ - uint8_t status; - - if (ao_flash_setup_done) - return; - - ao_mutex_get(&ao_flash_mutex); - if (ao_flash_setup_done) { - ao_mutex_put(&ao_flash_mutex); - return; - } - - /* On first use, check to see if the flash chip has - * been programmed to use 512 byte pages. If not, do so. - * And then, because the flash part must be power cycled - * for that change to take effect, panic. - */ - status = ao_flash_read_status(); - - if (!(status & FLASH_STATUS_PAGESIZE_512)) { - ao_flash_set_pagesize_512(); - ao_panic(AO_PANIC_FLASH); - } - - switch (status & 0x3c) { - - /* AT45DB321D */ - case 0x34: - ao_flash_block_shift = 9; - ao_storage_total = ((uint32_t) 4 * (uint32_t) 1024 * (uint32_t) 1024); - break; - - /* AT45DB161D */ - case 0x2c: - ao_flash_block_shift = 9; - ao_storage_total = ((uint32_t) 2 * (uint32_t) 1024 * (uint32_t) 1024); - break; - - /* AT45DB081D */ - case 0x24: - ao_flash_block_shift = 8; - ao_storage_total = ((uint32_t) 1024 * (uint32_t) 1024); - break; - - /* AT45DB041D */ - case 0x1c: - ao_flash_block_shift = 8; - ao_storage_total = ((uint32_t) 512 * (uint32_t) 1024); - break; - - /* AT45DB021D */ - case 0x14: - ao_flash_block_shift = 8; - ao_storage_total = ((uint32_t) 256 * (uint32_t) 1024); - break; - - /* AT45DB011D */ - case 0x0c: - ao_flash_block_shift = 8; - ao_storage_total = ((uint32_t) 128 * (uint32_t) 1024); - break; - - default: - ao_panic(AO_PANIC_FLASH); - } - ao_flash_block_size = 1 << ao_flash_block_shift; - ao_flash_block_mask = ao_flash_block_size - 1; - - ao_storage_block = ao_flash_block_size; - ao_storage_config = ao_storage_total - ao_storage_block; - ao_storage_unit = ao_flash_block_size; - - ao_flash_setup_done = 1; - ao_mutex_put(&ao_flash_mutex); -} - -static void -ao_flash_wait_write(void) -{ - if (ao_flash_write_pending) { - for (;;) { - uint8_t status = ao_flash_read_status(); - if ((status & FLASH_STATUS_RDY)) - break; - } - ao_flash_write_pending = 0; - } -} - -/* Write the current block to the FLASHPROM */ -static void -ao_flash_write_block(void) -{ - ao_flash_wait_write(); - ao_flash_cs_low(); - ao_flash_instruction.instruction = FLASH_WRITE; - - /* 13/14 block bits + 9/8 byte bits (always 0) */ - ao_flash_instruction.address[0] = ao_flash_block >> (16 - ao_flash_block_shift); - ao_flash_instruction.address[1] = ao_flash_block << (ao_flash_block_shift - 8); - ao_flash_instruction.address[2] = 0; - ao_spi_send(&ao_flash_instruction, 4); - ao_spi_send(ao_flash_data, ao_storage_block); - ao_flash_cs_high(); - ao_flash_write_pending = 1; -} - -/* Read the current block from the FLASHPROM */ -static void -ao_flash_read_block(void) -{ - ao_flash_wait_write(); - ao_flash_cs_low(); - ao_flash_instruction.instruction = FLASH_READ; - - /* 13/14 block bits + 9/8 byte bits (always 0) */ - ao_flash_instruction.address[0] = ao_flash_block >> (16 - ao_flash_block_shift); - ao_flash_instruction.address[1] = ao_flash_block << (ao_flash_block_shift - 8); - ao_flash_instruction.address[2] = 0; - ao_spi_send(&ao_flash_instruction, 4); - ao_spi_recv(ao_flash_data, ao_flash_block_size); - ao_flash_cs_high(); -} - -static void -ao_flash_flush_internal(void) -{ - if (ao_flash_block_dirty) { - ao_flash_write_block(); - ao_flash_block_dirty = 0; - } -} - -static void -ao_flash_fill(uint16_t block) -{ - if (block != ao_flash_block) { - ao_flash_flush_internal(); - ao_flash_block = block; - ao_flash_read_block(); - } -} - -uint8_t -ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant -{ - uint16_t block = (uint16_t) (pos >> ao_flash_block_shift); - - /* Transfer the data */ - ao_mutex_get(&ao_flash_mutex); { - if (len != ao_flash_block_size) - ao_flash_fill(block); - else { - ao_flash_flush_internal(); - ao_flash_block = block; - } - memcpy(ao_flash_data + (uint16_t) (pos & ao_flash_block_mask), - buf, - len); - ao_flash_block_dirty = 1; - } ao_mutex_put(&ao_flash_mutex); - return 1; -} - -uint8_t -ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant -{ - uint16_t block = (uint16_t) (pos >> ao_flash_block_shift); - - /* Transfer the data */ - ao_mutex_get(&ao_flash_mutex); { - ao_flash_fill(block); - memcpy(buf, - ao_flash_data + (uint16_t) (pos & ao_flash_block_mask), - len); - } ao_mutex_put(&ao_flash_mutex); - return 1; -} - -void -ao_storage_flush(void) __reentrant -{ - ao_mutex_get(&ao_flash_mutex); { - ao_flash_flush_internal(); - } ao_mutex_put(&ao_flash_mutex); -} - -uint8_t -ao_storage_erase(uint32_t pos) __reentrant -{ - ao_mutex_get(&ao_flash_mutex); { - ao_flash_flush_internal(); - ao_flash_block = (uint16_t) (pos >> ao_flash_block_shift); - memset(ao_flash_data, 0xff, ao_flash_block_size); - ao_flash_block_dirty = 1; - } ao_mutex_put(&ao_flash_mutex); - return 1; -} - -void -ao_storage_device_info(void) __reentrant -{ - uint8_t status; - - ao_storage_setup(); - ao_mutex_get(&ao_flash_mutex); { - status = ao_flash_read_status(); - printf ("Flash status: 0x%02x\n", status); - printf ("Flash block shift: %d\n", ao_flash_block_shift); - printf ("Flash block size: %d\n", ao_flash_block_size); - printf ("Flash block mask: %d\n", ao_flash_block_mask); - printf ("Flash device size: %ld\n", ao_storage_total); - } ao_mutex_put(&ao_flash_mutex); -} - -/* - * To initialize the chip, set up the CS line and - * the SPI interface - */ -void -ao_storage_device_init(void) -{ - /* set up CS */ - FLASH_CS = 1; - P1DIR |= (1 << FLASH_CS_INDEX); - P1SEL &= ~(1 << FLASH_CS_INDEX); -} diff --git a/src/ao_flight.c b/src/ao_flight.c deleted file mode 100644 index 85c1825b..00000000 --- a/src/ao_flight.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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_FLIGHT_TEST -#include "ao.h" -#endif - -#ifndef HAS_ACCEL -#error Please define HAS_ACCEL -#endif - -#ifndef HAS_GPS -#error Please define HAS_GPS -#endif - -#ifndef HAS_USB -#error Please define HAS_USB -#endif - -/* Main flight thread. */ - -__pdata enum ao_flight_state ao_flight_state; /* current flight state */ -__pdata uint16_t ao_launch_tick; /* time of launch detect */ - -/* - * track min/max data over a long interval to detect - * resting - */ -__pdata uint16_t ao_interval_end; -__pdata int16_t ao_interval_min_height; -__pdata int16_t ao_interval_max_height; -__pdata uint8_t ao_flight_force_idle; - -/* We also have a clock, which can be used to sanity check things in - * case of other failures - */ - -#define BOOST_TICKS_MAX AO_SEC_TO_TICKS(15) - -/* Landing is detected by getting constant readings from both pressure and accelerometer - * for a fairly long time (AO_INTERVAL_TICKS) - */ -#define AO_INTERVAL_TICKS AO_SEC_TO_TICKS(10) - -#define abs(a) ((a) < 0 ? -(a) : (a)) - -void -ao_flight(void) -{ - ao_sample_init(); - ao_flight_state = ao_flight_startup; - for (;;) { - - /* - * Process ADC samples, just looping - * until the sensors are calibrated. - */ - if (!ao_sample()) - continue; - - switch (ao_flight_state) { - case ao_flight_startup: - - /* Check to see what mode we should go to. - * - Invalid mode if accel cal appears to be out - * - pad mode if we're upright, - * - idle mode otherwise - */ -#if HAS_ACCEL - if (ao_config.accel_plus_g == 0 || - ao_config.accel_minus_g == 0 || - ao_ground_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP || - ao_ground_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP) - { - /* Detected an accel value outside -1.5g to 1.5g - * (or uncalibrated values), so we go into invalid mode - */ - ao_flight_state = ao_flight_invalid; - - } else -#endif - if (!ao_flight_force_idle -#if HAS_ACCEL - && ao_ground_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP -#endif - ) - { - /* Set pad mode - we can fly! */ - ao_flight_state = ao_flight_pad; -#if HAS_USB - /* Disable the USB controller in flight mode - * to save power - */ - ao_usb_disable(); -#endif - - /* Disable packet mode in pad state */ - ao_packet_slave_stop(); - - /* Turn on telemetry system */ - ao_rdf_set(1); - ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD); - - /* signal successful initialization by turning off the LED */ - ao_led_off(AO_LED_RED); - } else { - /* Set idle mode */ - ao_flight_state = ao_flight_idle; - - /* signal successful initialization by turning off the LED */ - ao_led_off(AO_LED_RED); - } - /* wakeup threads due to state change */ - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - - break; - case ao_flight_pad: - - /* pad to boost: - * - * barometer: > 20m vertical motion - * OR - * accelerometer: > 2g AND velocity > 5m/s - * - * The accelerometer should always detect motion before - * the barometer, but we use both to make sure this - * transition is detected. If the device - * doesn't have an accelerometer, then ignore the - * speed and acceleration as they are quite noisy - * on the pad. - */ - if (ao_height > AO_M_TO_HEIGHT(20) -#if HAS_ACCEL - || (ao_accel > AO_MSS_TO_ACCEL(20) && - ao_speed > AO_MS_TO_SPEED(5)) -#endif - ) - { - ao_flight_state = ao_flight_boost; - ao_launch_tick = ao_sample_tick; - - /* start logging data */ - ao_log_start(); - - /* Increase telemetry rate */ - ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_FLIGHT); - - /* disable RDF beacon */ - ao_rdf_set(0); - -#if HAS_GPS - /* Record current GPS position by waking up GPS log tasks */ - ao_wakeup(&ao_gps_data); - ao_wakeup(&ao_gps_tracking_data); -#endif - - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - break; - case ao_flight_boost: - - /* boost to fast: - * - * accelerometer: start to fall at > 1/4 G - * OR - * time: boost for more than 15 seconds - * - * Detects motor burn out by the switch from acceleration to - * deceleration, or by waiting until the maximum burn duration - * (15 seconds) has past. - */ - if ((ao_accel < AO_MSS_TO_ACCEL(-2.5) && ao_height > AO_M_TO_HEIGHT(100)) || - (int16_t) (ao_sample_tick - ao_launch_tick) > BOOST_TICKS_MAX) - { -#if HAS_ACCEL - ao_flight_state = ao_flight_fast; -#else - ao_flight_state = ao_flight_coast; -#endif - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - break; -#if HAS_ACCEL - case ao_flight_fast: - /* - * This is essentially the same as coast, - * but the barometer is being ignored as - * it may be unreliable. - */ - if (ao_speed < AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) - { - ao_flight_state = ao_flight_coast; - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - break; -#endif - case ao_flight_coast: - - /* apogee detect: coast to drogue deploy: - * - * speed: < 0 - * - * Also make sure the model altitude is tracking - * the measured altitude reasonably closely; otherwise - * we're probably transsonic. - */ - if (ao_speed < 0 -#if !HAS_ACCEL - && (ao_sample_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 100) -#endif - ) - { - /* ignite the drogue charge */ - ao_ignite(ao_igniter_drogue); - - /* slow down the telemetry system */ - ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_RECOVER); - - /* Turn the RDF beacon back on */ - ao_rdf_set(1); - - /* and enter drogue state */ - ao_flight_state = ao_flight_drogue; - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - - break; - case ao_flight_drogue: - - /* drogue to main deploy: - * - * barometer: reach main deploy altitude - * - * Would like to use the accelerometer for this test, but - * the orientation of the flight computer is unknown after - * drogue deploy, so we ignore it. Could also detect - * high descent rate using the pressure sensor to - * recognize drogue deploy failure and eject the main - * at that point. Perhaps also use the drogue sense lines - * to notice continutity? - */ - if (ao_height <= ao_config.main_deploy) - { - ao_ignite(ao_igniter_main); - - /* - * Start recording min/max height - * to figure out when the rocket has landed - */ - - /* initialize interval values */ - ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; - - ao_interval_min_height = ao_interval_max_height = ao_avg_height; - - ao_flight_state = ao_flight_main; - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - break; - - /* fall through... */ - case ao_flight_main: - - /* main to land: - * - * barometer: altitude stable - */ - - if (ao_avg_height < ao_interval_min_height) - ao_interval_min_height = ao_avg_height; - if (ao_avg_height > ao_interval_max_height) - ao_interval_max_height = ao_avg_height; - - if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) { - if (ao_interval_max_height - ao_interval_min_height <= AO_M_TO_HEIGHT(4)) - { - ao_flight_state = ao_flight_landed; - - /* turn off the ADC capture */ - ao_timer_set_adc_interval(0); - - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - ao_interval_min_height = ao_interval_max_height = ao_avg_height; - ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; - } - break; - case ao_flight_landed: - break; - } - } -} - -static __xdata struct ao_task flight_task; - -void -ao_flight_init(void) -{ - ao_flight_state = ao_flight_startup; - ao_add_task(&flight_task, ao_flight, "flight"); -} diff --git a/src/ao_flight_nano.c b/src/ao_flight_nano.c deleted file mode 100644 index 2e332b12..00000000 --- a/src/ao_flight_nano.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -/* Main flight thread. */ - -__pdata enum ao_flight_state ao_flight_state; /* current flight state */ -__pdata uint16_t ao_launch_tick; /* time of launch detect */ - -/* - * track min/max data over a long interval to detect - * resting - */ -__pdata uint16_t ao_interval_end; -__pdata int16_t ao_interval_min_height; -__pdata int16_t ao_interval_max_height; - -__pdata uint8_t ao_flight_force_idle; - -/* Landing is detected by getting constant readings from both pressure and accelerometer - * for a fairly long time (AO_INTERVAL_TICKS) - */ -#define AO_INTERVAL_TICKS AO_SEC_TO_TICKS(5) - -static void -ao_flight_nano(void) -{ - ao_sample_init(); - ao_flight_state = ao_flight_startup; - - for (;;) { - /* - * Process ADC samples, just looping - * until the sensors are calibrated. - */ - if (!ao_sample()) - continue; - - switch (ao_flight_state) { - case ao_flight_startup: - if (ao_flight_force_idle) { - /* Set idle mode */ - ao_flight_state = ao_flight_idle; - } else { - ao_flight_state = ao_flight_pad; - /* Disable packet mode in pad state */ - ao_packet_slave_stop(); - - /* Turn on telemetry system */ - ao_rdf_set(1); - ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD); - } - /* signal successful initialization by turning off the LED */ - ao_led_off(AO_LED_RED); - - /* wakeup threads due to state change */ - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - break; - case ao_flight_pad: - if (ao_height> AO_M_TO_HEIGHT(20)) { - ao_flight_state = ao_flight_drogue; - ao_launch_tick = ao_sample_tick; - - /* start logging data */ - ao_log_start(); - - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - break; - case ao_flight_drogue: - /* drogue/main to land: - * - * barometer: altitude stable - */ - - if (ao_height < ao_interval_min_height) - ao_interval_min_height = ao_height; - if (ao_height > ao_interval_max_height) - ao_interval_max_height = ao_height; - - if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) { - if (ao_interval_max_height - ao_interval_min_height < AO_M_TO_HEIGHT(5)) - { - ao_flight_state = ao_flight_landed; - - /* turn off the ADC capture */ - ao_timer_set_adc_interval(0); - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - ao_interval_min_height = ao_interval_max_height = ao_height; - ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; - } - break; - } - } -} - -static __xdata struct ao_task flight_task; - -void -ao_flight_nano_init(void) -{ - ao_flight_state = ao_flight_startup; - ao_add_task(&flight_task, ao_flight_nano, "flight"); -} diff --git a/src/ao_flight_test.c b/src/ao_flight_test.c deleted file mode 100644 index 56733c89..00000000 --- a/src/ao_flight_test.c +++ /dev/null @@ -1,716 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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 _GNU_SOURCE - -#include -#include -#include -#include -#include -#include - -#define AO_HERTZ 100 - -#define AO_ADC_RING 64 -#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1)) -#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1)) - -#define AO_M_TO_HEIGHT(m) ((int16_t) (m)) -#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16)) -#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16)) - -/* - * One set of samples read from the A/D converter - */ -struct ao_adc { - uint16_t tick; /* tick when the sample was read */ - int16_t accel; /* accelerometer */ - int16_t pres; /* pressure sensor */ - int16_t pres_real; /* unclipped */ - int16_t temp; /* temperature sensor */ - int16_t v_batt; /* battery voltage */ - int16_t sense_d; /* drogue continuity sense */ - int16_t sense_m; /* main continuity sense */ -}; - -#define __pdata -#define __data -#define __xdata -#define __code -#define __reentrant - -#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5)) -#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5)) -#define from_fix(x) ((x) >> 16) - -/* - * Above this height, the baro sensor doesn't work - */ -#define AO_MAX_BARO_HEIGHT 12000 -#define AO_BARO_SATURATE 13000 -#define AO_MIN_BARO_VALUE ao_altitude_to_pres(AO_BARO_SATURATE) - -/* - * Above this speed, baro measurements are unreliable - */ -#define AO_MAX_BARO_SPEED 200 - -#define ACCEL_NOSE_UP (ao_accel_2g >> 2) - -enum ao_flight_state { - ao_flight_startup = 0, - ao_flight_idle = 1, - ao_flight_pad = 2, - ao_flight_boost = 3, - ao_flight_fast = 4, - ao_flight_coast = 5, - ao_flight_drogue = 6, - ao_flight_main = 7, - ao_flight_landed = 8, - ao_flight_invalid = 9 -}; - -extern enum ao_flight_state ao_flight_state; - -#define FALSE 0 -#define TRUE 1 - -struct ao_adc ao_adc_ring[AO_ADC_RING]; -uint8_t ao_adc_head; -int ao_summary = 0; - -#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_cmd_register(c) -#define ao_usb_disable() -#define ao_telemetry_set_interval(x) -#define ao_rdf_set(rdf) -#define ao_packet_slave_start() -#define ao_packet_slave_stop() - -enum ao_igniter { - ao_igniter_drogue = 0, - ao_igniter_main = 1 -}; - -struct ao_adc ao_adc_static; - -int drogue_height; -double drogue_time; -int main_height; -double main_time; - -int tick_offset; - -static int32_t ao_k_height; - -void -ao_ignite(enum ao_igniter igniter) -{ - double time = (double) (ao_adc_static.tick + tick_offset) / 100; - - if (igniter == ao_igniter_drogue) { - drogue_time = time; - drogue_height = ao_k_height >> 16; - } else { - main_time = time; - main_height = ao_k_height >> 16; - } -} - -struct ao_task { - int dummy; -}; - -#define ao_add_task(t,f,n) - -#define ao_log_start() -#define ao_log_stop() - -#define AO_MS_TO_TICKS(ms) ((ms) / 10) -#define AO_SEC_TO_TICKS(s) ((s) * 100) - -#define AO_FLIGHT_TEST - -int ao_flight_debug; - -FILE *emulator_in; -char *emulator_app; -char *emulator_name; -double emulator_error_max = 4; -double emulator_height_error_max = 20; /* noise in the baro sensor */ - -void -ao_dump_state(void); - -void -ao_sleep(void *wchan); - -const char const * const ao_state_names[] = { - "startup", "idle", "pad", "boost", "fast", - "coast", "drogue", "main", "landed", "invalid" -}; - -struct ao_cmds { - void (*func)(void); - const char *help; -}; - -#include "ao_convert.c" - -struct ao_config { - uint16_t main_deploy; - int16_t accel_plus_g; - int16_t accel_minus_g; - uint8_t pad_orientation; -}; - -#define AO_PAD_ORIENTATION_ANTENNA_UP 0 -#define AO_PAD_ORIENTATION_ANTENNA_DOWN 1 - -#define ao_config_get() - -struct ao_config ao_config; - -#define DATA_TO_XDATA(x) (x) - -#define HAS_FLIGHT 1 -#define HAS_ADC 1 -#define HAS_USB 1 -#define HAS_GPS 1 -#ifndef HAS_ACCEL -#define HAS_ACCEL 1 -#define HAS_ACCEL_REF 0 -#endif - -#define GRAVITY 9.80665 -extern int16_t ao_ground_accel, ao_flight_accel; -extern int16_t ao_accel_2g; - -extern uint16_t ao_sample_tick; - -extern int16_t ao_sample_height; -extern int16_t ao_sample_accel; -extern int32_t ao_accel_scale; -extern int16_t ao_ground_height; -extern int16_t ao_sample_alt; - -int ao_sample_prev_tick; -uint16_t prev_tick; - -#include "ao_kalman.c" -#include "ao_sample.c" -#include "ao_flight.c" - -#define to_double(f) ((f) / 65536.0) - -static int ao_records_read = 0; -static int ao_eof_read = 0; -static int ao_flight_ground_accel; -static int ao_flight_started = 0; -static int ao_test_max_height; -static double ao_test_max_height_time; -static int ao_test_main_height; -static double ao_test_main_height_time; -static double ao_test_landed_time; -static double ao_test_landed_height; -static double ao_test_landed_time; -static int landed_set; -static double landed_time; -static double landed_height; - -void -ao_test_exit(void) -{ - double drogue_error; - double main_error; - double landed_error; - double landed_time_error; - - if (!ao_test_main_height_time) { - ao_test_main_height_time = ao_test_max_height_time; - ao_test_main_height = ao_test_max_height; - } - drogue_error = fabs(ao_test_max_height_time - drogue_time); - main_error = fabs(ao_test_main_height_time - main_time); - landed_error = fabs(ao_test_landed_height - landed_height); - landed_time_error = ao_test_landed_time - landed_time; - if (drogue_error > emulator_error_max || main_error > emulator_error_max || - landed_time_error > emulator_error_max || landed_error > emulator_height_error_max) { - printf ("%s %s\n", - emulator_app, emulator_name); - printf ("\tApogee error %g\n", drogue_error); - printf ("\tMain error %g\n", main_error); - printf ("\tLanded height error %g\n", landed_error); - printf ("\tLanded time error %g\n", landed_time_error); - printf ("\tActual: apogee: %d at %7.2f main: %d at %7.2f landed %7.2f at %7.2f\n", - ao_test_max_height, ao_test_max_height_time, - ao_test_main_height, ao_test_main_height_time, - ao_test_landed_height, ao_test_landed_time); - printf ("\tComputed: apogee: %d at %7.2f main: %d at %7.2f landed %7.2f at %7.2f\n", - drogue_height, drogue_time, main_height, main_time, - landed_height, landed_time); - exit (1); - } - exit(0); -} - -void -ao_insert(void) -{ - double time; - - ao_adc_ring[ao_adc_head] = ao_adc_static; - ao_adc_head = ao_adc_ring_next(ao_adc_head); - if (ao_flight_state != ao_flight_startup) { - double height = ao_pres_to_altitude(ao_adc_static.pres_real) - ao_ground_height; - double accel = ((ao_flight_ground_accel - ao_adc_static.accel) * GRAVITY * 2.0) / - (ao_config.accel_minus_g - ao_config.accel_plus_g); - - if (!tick_offset) - tick_offset = -ao_adc_static.tick; - if ((prev_tick - ao_adc_static.tick) > 0x400) - tick_offset += 65536; - prev_tick = ao_adc_static.tick; - time = (double) (ao_adc_static.tick + tick_offset) / 100; - - if (ao_test_max_height < height) { - ao_test_max_height = height; - ao_test_max_height_time = time; - ao_test_landed_height = height; - ao_test_landed_time = time; - } - if (height > ao_config.main_deploy) { - ao_test_main_height_time = time; - ao_test_main_height = height; - } - - if (ao_test_landed_height > height) { - ao_test_landed_height = height; - ao_test_landed_time = time; - } - - if (ao_flight_state == ao_flight_landed && !landed_set) { - landed_set = 1; - landed_time = time; - landed_height = height; - } - - if (!ao_summary) { - printf("%7.2f height %8.2f accel %8.3f state %-8.8s k_height %8.2f k_speed %8.3f k_accel %8.3f avg_height %5d drogue %4d main %4d error %5d\n", - time, - height, - accel, - ao_state_names[ao_flight_state], - ao_k_height / 65536.0, - ao_k_speed / 65536.0 / 16.0, - ao_k_accel / 65536.0 / 16.0, - ao_avg_height, - drogue_height, - main_height, - ao_error_h_sq_avg); - -// if (ao_flight_state == ao_flight_landed) -// ao_test_exit(); - } - } -} - -#define AO_MAX_CALLSIGN 8 -#define AO_MAX_VERSION 8 -#define AO_MAX_TELEMETRY 128 - -struct ao_telemetry_generic { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - uint8_t payload[27]; /* 5 */ - /* 32 */ -}; - -#define AO_TELEMETRY_SENSOR_TELEMETRUM 0x01 -#define AO_TELEMETRY_SENSOR_TELEMINI 0x02 -#define AO_TELEMETRY_SENSOR_TELENANO 0x03 - -struct ao_telemetry_sensor { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - - uint8_t state; /* 5 flight state */ - int16_t accel; /* 6 accelerometer (TM only) */ - int16_t pres; /* 8 pressure sensor */ - int16_t temp; /* 10 temperature sensor */ - int16_t v_batt; /* 12 battery voltage */ - int16_t sense_d; /* 14 drogue continuity sense (TM/Tm) */ - int16_t sense_m; /* 16 main continuity sense (TM/Tm) */ - - int16_t acceleration; /* 18 m/s² * 16 */ - int16_t speed; /* 20 m/s * 16 */ - int16_t height; /* 22 m */ - - int16_t ground_pres; /* 24 average pres on pad */ - int16_t ground_accel; /* 26 average accel on pad */ - int16_t accel_plus_g; /* 28 accel calibration at +1g */ - int16_t accel_minus_g; /* 30 accel calibration at -1g */ - /* 32 */ -}; - -#define AO_TELEMETRY_CONFIGURATION 0x04 - -struct ao_telemetry_configuration { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - - uint8_t device; /* 5 device type */ - uint16_t flight; /* 6 flight number */ - uint8_t config_major; /* 8 Config major version */ - uint8_t config_minor; /* 9 Config minor version */ - uint16_t apogee_delay; /* 10 Apogee deploy delay in seconds */ - uint16_t main_deploy; /* 12 Main deploy alt in meters */ - uint16_t flight_log_max; /* 14 Maximum flight log size in kB */ - char callsign[AO_MAX_CALLSIGN]; /* 16 Radio operator identity */ - char version[AO_MAX_VERSION]; /* 24 Software version */ - /* 32 */ -}; - -#define AO_TELEMETRY_LOCATION 0x05 - -#define AO_GPS_MODE_NOT_VALID 'N' -#define AO_GPS_MODE_AUTONOMOUS 'A' -#define AO_GPS_MODE_DIFFERENTIAL 'D' -#define AO_GPS_MODE_ESTIMATED 'E' -#define AO_GPS_MODE_MANUAL 'M' -#define AO_GPS_MODE_SIMULATED 'S' - -struct ao_telemetry_location { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - - uint8_t flags; /* 5 Number of sats and other flags */ - int16_t altitude; /* 6 GPS reported altitude (m) */ - int32_t latitude; /* 8 latitude (degrees * 10⁷) */ - int32_t longitude; /* 12 longitude (degrees * 10⁷) */ - uint8_t year; /* 16 (- 2000) */ - uint8_t month; /* 17 (1-12) */ - uint8_t day; /* 18 (1-31) */ - uint8_t hour; /* 19 (0-23) */ - uint8_t minute; /* 20 (0-59) */ - uint8_t second; /* 21 (0-59) */ - uint8_t pdop; /* 22 (m * 5) */ - uint8_t hdop; /* 23 (m * 5) */ - uint8_t vdop; /* 24 (m * 5) */ - uint8_t mode; /* 25 */ - uint16_t ground_speed; /* 26 cm/s */ - int16_t climb_rate; /* 28 cm/s */ - uint8_t course; /* 30 degrees / 2 */ - uint8_t unused[1]; /* 31 */ - /* 32 */ -}; - -#define AO_TELEMETRY_SATELLITE 0x06 - -struct ao_telemetry_satellite_info { - uint8_t svid; - uint8_t c_n_1; -}; - -struct ao_telemetry_satellite { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - uint8_t channels; /* 5 number of reported sats */ - - struct ao_telemetry_satellite_info sats[12]; /* 6 */ - uint8_t unused[2]; /* 30 */ - /* 32 */ -}; - -union ao_telemetry_all { - struct ao_telemetry_generic generic; - struct ao_telemetry_sensor sensor; - struct ao_telemetry_configuration configuration; - struct ao_telemetry_location location; - struct ao_telemetry_satellite satellite; -}; - -uint16_t -uint16(uint8_t *bytes, int off) -{ - off++; - return (uint16_t) bytes[off] | (((uint16_t) bytes[off+1]) << 8); -} - -int16_t -int16(uint8_t *bytes, int off) -{ - return (int16_t) uint16(bytes, off); -} - -void -ao_sleep(void *wchan) -{ - if (wchan == &ao_adc_head) { - char type; - uint16_t tick; - uint16_t a, b; - int ret; - uint8_t bytes[1024]; - union ao_telemetry_all telem; - char line[1024]; - char *saveptr; - char *l; - char *words[64]; - int nword; - - for (;;) { - if (ao_records_read > 2 && ao_flight_state == ao_flight_startup) - { - ao_adc_static.accel = ao_flight_ground_accel; - ao_insert(); - return; - } - - if (!fgets(line, sizeof (line), emulator_in)) { - if (++ao_eof_read >= 1000) { - if (!ao_summary) - printf ("no more data, exiting simulation\n"); - ao_test_exit(); - } - ao_adc_static.tick += 10; - ao_insert(); - return; - } - l = line; - for (nword = 0; nword < 64; nword++) { - words[nword] = strtok_r(l, " \t\n", &saveptr); - l = NULL; - if (words[nword] == NULL) - break; - } - if (nword == 4) { - type = words[0][0]; - tick = strtoul(words[1], NULL, 16); - a = strtoul(words[2], NULL, 16); - b = strtoul(words[3], NULL, 16); - if (type == 'P') - type = 'A'; - } else if (nword >= 6 && strcmp(words[0], "Accel") == 0) { - ao_config.accel_plus_g = atoi(words[3]); - ao_config.accel_minus_g = atoi(words[5]); - } else if (nword >= 4 && strcmp(words[0], "Main") == 0) { - ao_config.main_deploy = atoi(words[2]); - } else if (nword >= 36 && strcmp(words[0], "CALL") == 0) { - tick = atoi(words[10]); - if (!ao_flight_started) { - type = 'F'; - a = atoi(words[26]); - ao_flight_started = 1; - } else { - type = 'A'; - a = atoi(words[12]); - b = atoi(words[14]); - } - } else if (nword == 3 && strcmp(words[0], "BARO") == 0) { - tick = strtol(words[1], NULL, 16); - a = 16384 - 328; - b = strtol(words[2], NULL, 10); - type = 'A'; - if (!ao_flight_started) { - ao_flight_ground_accel = 16384 - 328; - ao_config.accel_plus_g = 16384 - 328; - ao_config.accel_minus_g = 16384 + 328; - ao_flight_started = 1; - } - } else if (nword == 2 && strcmp(words[0], "TELEM") == 0) { - char *hex = words[1]; - char elt[3]; - int i, len; - uint8_t sum; - - len = strlen(hex); - if (len > sizeof (bytes) * 2) { - len = sizeof (bytes)*2; - hex[len] = '\0'; - } - for (i = 0; i < len; i += 2) { - elt[0] = hex[i]; - elt[1] = hex[i+1]; - elt[2] = '\0'; - bytes[i/2] = (uint8_t) strtol(elt, NULL, 16); - } - len = i/2; - if (bytes[0] != len - 2) { - printf ("bad length %d != %d\n", bytes[0], len - 2); - continue; - } - sum = 0x5a; - for (i = 1; i < len-1; i++) - sum += bytes[i]; - if (sum != bytes[len-1]) { - printf ("bad checksum\n"); - continue; - } - if ((bytes[len-2] & 0x80) == 0) { - continue; - } - if (len == 36) { - memcpy(&telem, bytes + 1, 32); - tick = telem.generic.tick; - switch (telem.generic.type) { - case AO_TELEMETRY_SENSOR_TELEMETRUM: - case AO_TELEMETRY_SENSOR_TELEMINI: - case AO_TELEMETRY_SENSOR_TELENANO: - if (!ao_flight_started) { - ao_flight_ground_accel = telem.sensor.ground_accel; - ao_config.accel_plus_g = telem.sensor.accel_plus_g; - ao_config.accel_minus_g = telem.sensor.accel_minus_g; - ao_flight_started = 1; - } - type = 'A'; - a = telem.sensor.accel; - b = telem.sensor.pres; - break; - } - } else if (len == 99) { - ao_flight_started = 1; - tick = uint16(bytes, 21); - ao_flight_ground_accel = int16(bytes, 7); - ao_config.accel_plus_g = int16(bytes, 17); - ao_config.accel_minus_g = int16(bytes, 19); - type = 'A'; - a = int16(bytes, 23); - b = int16(bytes, 25); - } else if (len == 98) { - ao_flight_started = 1; - tick = uint16(bytes, 20); - ao_flight_ground_accel = int16(bytes, 6); - ao_config.accel_plus_g = int16(bytes, 16); - ao_config.accel_minus_g = int16(bytes, 18); - type = 'A'; - a = int16(bytes, 22); - b = int16(bytes, 24); - } else { - printf("unknown len %d\n", len); - continue; - } - } - if (type != 'F' && !ao_flight_started) - continue; - - switch (type) { - case 'F': - ao_flight_ground_accel = a; - if (ao_config.accel_plus_g == 0) { - ao_config.accel_plus_g = a; - ao_config.accel_minus_g = a + 530; - } - if (ao_config.main_deploy == 0) - ao_config.main_deploy = 250; - ao_flight_started = 1; - break; - case 'S': - break; - case 'A': - ao_adc_static.tick = tick; - ao_adc_static.accel = a; - ao_adc_static.pres_real = b; - if (b < AO_MIN_BARO_VALUE) - b = AO_MIN_BARO_VALUE; - ao_adc_static.pres = b; - ao_records_read++; - ao_insert(); - return; - case 'T': - ao_adc_static.tick = tick; - ao_adc_static.temp = a; - ao_adc_static.v_batt = b; - break; - case 'D': - case 'G': - case 'N': - case 'W': - case 'H': - break; - } - } - - } -} -#define COUNTS_PER_G 264.8 - -void -ao_dump_state(void) -{ -} - -static const struct option options[] = { - { .name = "summary", .has_arg = 0, .val = 's' }, - { .name = "debug", .has_arg = 0, .val = 'd' }, - { 0, 0, 0, 0}, -}; - -void run_flight_fixed(char *name, FILE *f, int summary) -{ - emulator_name = name; - emulator_in = f; - ao_summary = summary; - ao_flight_init(); - ao_flight(); -} - -int -main (int argc, char **argv) -{ - int summary = 0; - int c; - int i; - -#if HAS_ACCEL - emulator_app="full"; -#else - emulator_app="baro"; -#endif - while ((c = getopt_long(argc, argv, "sd", options, NULL)) != -1) { - switch (c) { - case 's': - summary = 1; - break; - case 'd': - ao_flight_debug = 1; - break; - } - } - - if (optind == argc) - run_flight_fixed("", stdin, summary); - else - for (i = optind; i < argc; i++) { - FILE *f = fopen(argv[i], "r"); - if (!f) { - perror(argv[i]); - continue; - } - run_flight_fixed(argv[i], f, summary); - fclose(f); - } -} diff --git a/src/ao_gps_print.c b/src/ao_gps_print.c deleted file mode 100644 index fcdedd30..00000000 --- a/src/ao_gps_print.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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_GPS_TEST -#include "ao.h" -#endif -#include "ao_telem.h" - -void -ao_gps_print(__xdata struct ao_gps_orig *gps_data) __reentrant -{ - 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)) - 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); - - 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, - gps_data->climb_rate, - gps_data->ground_speed, - (int) gps_data->course * 2); - } -} - -void -ao_gps_tracking_print(__xdata struct ao_gps_tracking_orig *gps_tracking_data) __reentrant -{ - uint8_t c, n, v; - __xdata struct ao_gps_sat_orig *sat; - - n = gps_tracking_data->channels; - if (n == 0) - return; - - sat = gps_tracking_data->sats; - v = 0; - for (c = 0; c < n; c++) { - if (sat->svid) - v++; - sat++; - } - - printf (AO_TELEM_SAT_NUM " %d ", - v); - - sat = gps_tracking_data->sats; - v = 0; - for (c = 0; c < n; c++) { - 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++; - } -} diff --git a/src/ao_gps_report.c b/src/ao_gps_report.c deleted file mode 100644 index e57f8744..00000000 --- a/src/ao_gps_report.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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_report(void) -{ - static __xdata struct ao_log_record gps_log; - static __xdata struct ao_telemetry_location gps_data; - uint8_t date_reported = 0; - - for (;;) { - ao_sleep(&ao_gps_data); - ao_mutex_get(&ao_gps_mutex); - memcpy(&gps_data, &ao_gps_data, sizeof (ao_gps_data)); - ao_mutex_put(&ao_gps_mutex); - - if (!(gps_data.flags & AO_GPS_VALID)) - continue; - - gps_log.tick = ao_gps_tick; - 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 = gps_data.latitude; - ao_log_data(&gps_log); - gps_log.type = AO_LOG_GPS_LON; - gps_log.u.gps_longitude = gps_data.longitude; - 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); - if (!date_reported && (gps_data.flags & AO_GPS_DATE_VALID)) { - gps_log.type = AO_LOG_GPS_DATE; - gps_log.u.gps_date.year = gps_data.year; - gps_log.u.gps_date.month = gps_data.month; - gps_log.u.gps_date.day = gps_data.day; - gps_log.u.gps_date.extra = 0; - date_reported = ao_log_data(&gps_log); - } - } -} - -void -ao_gps_tracking_report(void) -{ - static __xdata struct ao_log_record gps_log; - static __xdata struct ao_telemetry_satellite gps_tracking_data; - uint8_t c, n; - - for (;;) { - ao_sleep(&ao_gps_tracking_data); - ao_mutex_get(&ao_gps_mutex); - gps_log.tick = ao_gps_tick; - memcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data)); - ao_mutex_put(&ao_gps_mutex); - - if (!(n = gps_tracking_data.channels)) - continue; - - 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.c_n = gps_tracking_data.sats[c].c_n_1; - 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"); -} diff --git a/src/ao_gps_sirf.c b/src/ao_gps_sirf.c deleted file mode 100644 index f2abbf84..00000000 --- a/src/ao_gps_sirf.c +++ /dev/null @@ -1,442 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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_GPS_TEST -#include "ao.h" -#endif - -__xdata uint8_t ao_gps_mutex; -__pdata uint16_t ao_gps_tick; -__xdata struct ao_telemetry_location ao_gps_data; -__xdata struct ao_telemetry_satellite ao_gps_tracking_data; - -static const char ao_gps_set_nmea[] = "\r\n$PSRF100,0,57600,8,1,0*37\r\n"; - -const char ao_gps_config[] = { - - 0xa0, 0xa2, 0x00, 0x0e, /* length: 14 bytes */ - 136, /* mode control */ - 0, 0, /* reserved */ - 0, /* degraded mode (allow 1-SV navigation) */ - 0, 0, /* reserved */ - 0, 0, /* user specified altitude */ - 2, /* alt hold mode (disabled, require 3d fixes) */ - 0, /* alt hold source (use last computed altitude) */ - 0, /* reserved */ - 10, /* Degraded time out (10 sec) */ - 10, /* Dead Reckoning time out (10 sec) */ - 0, /* Track smoothing (disabled) */ - 0x00, 0x8e, 0xb0, 0xb3, - - 0xa0, 0xa2, 0x00, 0x08, /* length: 8 bytes */ - 166, /* Set message rate */ - 2, /* enable/disable all messages */ - 0, /* message id (ignored) */ - 0, /* update rate (0 = disable) */ - 0, 0, 0, 0, /* reserved */ - 0x00, 0xa8, 0xb0, 0xb3, - - 0xa0, 0xa2, 0x00, 0x02, /* length: 2 bytes */ - 143, /* static navigation */ - 0, /* disable */ - 0x00, 0x8f, 0xb0, 0xb3, -}; - -#define NAV_TYPE_GPS_FIX_TYPE_MASK (7 << 0) -#define NAV_TYPE_NO_FIX (0 << 0) -#define NAV_TYPE_SV_KF (1 << 0) -#define NAV_TYPE_2_SV_KF (2 << 0) -#define NAV_TYPE_3_SV_KF (3 << 0) -#define NAV_TYPE_4_SV_KF (4 << 0) -#define NAV_TYPE_2D_LEAST_SQUARES (5 << 0) -#define NAV_TYPE_3D_LEAST_SQUARES (6 << 0) -#define NAV_TYPE_DR (7 << 0) -#define NAV_TYPE_TRICKLE_POWER (1 << 3) -#define NAV_TYPE_ALTITUDE_HOLD_MASK (3 << 4) -#define NAV_TYPE_ALTITUDE_HOLD_NONE (0 << 4) -#define NAV_TYPE_ALTITUDE_HOLD_KF (1 << 4) -#define NAV_TYPE_ALTITUDE_HOLD_USER (2 << 4) -#define NAV_TYPE_ALTITUDE_HOLD_ALWAYS (3 << 4) -#define NAV_TYPE_DOP_LIMIT_EXCEEDED (1 << 6) -#define NAV_TYPE_DGPS_APPLIED (1 << 7) -#define NAV_TYPE_SENSOR_DR (1 << 8) -#define NAV_TYPE_OVERDETERMINED (1 << 9) -#define NAV_TYPE_DR_TIMEOUT_EXCEEDED (1 << 10) -#define NAV_TYPE_FIX_MI_EDIT (1 << 11) -#define NAV_TYPE_INVALID_VELOCITY (1 << 12) -#define NAV_TYPE_ALTITUDE_HOLD_DISABLED (1 << 13) -#define NAV_TYPE_DR_ERROR_STATUS_MASK (3 << 14) -#define NAV_TYPE_DR_ERROR_STATUS_GPS_ONLY (0 << 14) -#define NAV_TYPE_DR_ERROR_STATUS_DR_FROM_GPS (1 << 14) -#define NAV_TYPE_DR_ERROR_STATUS_DR_SENSOR_ERROR (2 << 14) -#define NAV_TYPE_DR_ERROR_STATUS_DR_IN_TEST (3 << 14) - -struct sirf_geodetic_nav_data { - uint16_t nav_type; - uint16_t utc_year; - uint8_t utc_month; - uint8_t utc_day; - uint8_t utc_hour; - uint8_t utc_minute; - uint16_t utc_second; - int32_t lat; - int32_t lon; - int32_t alt_msl; - uint16_t ground_speed; - uint16_t course; - int16_t climb_rate; - uint32_t h_error; - uint32_t v_error; - uint8_t num_sv; - uint8_t hdop; -}; - -static __xdata struct sirf_geodetic_nav_data ao_sirf_data; - -struct sirf_measured_sat_data { - uint8_t svid; - 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; - -#define ao_sirf_byte() ((uint8_t) ao_serial_getchar()) - -static uint8_t data_byte(void) -{ - uint8_t c = ao_sirf_byte(); - --ao_sirf_len; - ao_sirf_cksum += c; - return c; -} - -static char __xdata *sirf_target; - -static void sirf_u16(uint8_t offset) -{ - uint16_t __xdata *ptr = (uint16_t __xdata *) (sirf_target + offset); - uint16_t val; - - val = data_byte() << 8; - val |= data_byte (); - *ptr = val; -} - -static void sirf_u8(uint8_t 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) __reentrant -{ - uint32_t __xdata *ptr = (uint32_t __xdata *) (sirf_target + offset); - uint32_t val; - - val = ((uint32_t) data_byte ()) << 24; - val |= ((uint32_t) data_byte ()) << 16; - val |= ((uint32_t) data_byte ()) << 8; - val |= ((uint32_t) data_byte ()); - *ptr = val; -} - -static void sirf_discard(uint8_t len) -{ - while (len--) - data_byte(); -} - -#define SIRF_END 0 -#define SIRF_DISCARD 1 -#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 */ - { SIRF_DISCARD, 6 }, /* 5 week number, time of week */ - { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, utc_year) }, /* 11 */ - { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_month) }, /* 13 */ - { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_day) }, /* 14 */ - { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_hour) }, /* 15 */ - { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_minute) }, /* 16 */ - { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, utc_second) }, /* 17 */ - { SIRF_DISCARD, 4 }, /* satellite id list */ /* 19 */ - { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, lat) }, /* 23 */ - { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, lon) }, /* 27 */ - { SIRF_DISCARD, 4 }, /* altitude from ellipsoid */ /* 31 */ - { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, alt_msl) }, /* 35 */ - { SIRF_DISCARD, 1 }, /* map datum */ /* 39 */ - { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, ground_speed) }, /* 40 */ - { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, course) }, /* 42 */ - { SIRF_DISCARD, 2 }, /* magnetic variation */ /* 44 */ - { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, climb_rate) }, /* 46 */ - { SIRF_DISCARD, 2 }, /* turn rate */ /* 48 */ - { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, h_error) }, /* 50 */ - { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, v_error) }, /* 54 */ - { SIRF_DISCARD, 30 }, /* time error, h_vel error, clock_bias, - clock bias error, clock drift, - clock drift error, distance, - distance error, heading error */ /* 58 */ - { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, num_sv) }, /* 88 */ - { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, hdop) }, /* 89 */ - { SIRF_DISCARD, 1 }, /* additional mode info */ /* 90 */ - { SIRF_END, 0 }, /* 91 */ -}; - -static void -ao_sirf_parse_41(void) __reentrant -{ - ao_sirf_parse(&ao_sirf_data, geodetic_nav_data_packet); -} - -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, 4 }, /* 1 azimuth, 2 elevation, 3 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 -ao_gps_setup(void) __reentrant -{ - uint8_t i, k; - ao_serial_set_speed(AO_SERIAL_SPEED_4800); - for (i = 0; i < 64; i++) - ao_serial_putchar(0x00); - for (k = 0; k < 3; k++) - for (i = 0; i < sizeof (ao_gps_set_nmea); i++) - ao_serial_putchar(ao_gps_set_nmea[i]); - ao_serial_set_speed(AO_SERIAL_SPEED_57600); - for (i = 0; i < 64; i++) - ao_serial_putchar(0x00); -} - -static const char ao_gps_set_message_rate[] = { - 0xa0, 0xa2, 0x00, 0x08, - 166, - 0, -}; - -void -ao_sirf_set_message_rate(uint8_t msg, uint8_t rate) __reentrant -{ - uint16_t cksum = 0x00a6; - uint8_t i; - - for (i = 0; i < sizeof (ao_gps_set_message_rate); i++) - ao_serial_putchar(ao_gps_set_message_rate[i]); - ao_serial_putchar(msg); - ao_serial_putchar(rate); - cksum = 0xa6 + msg + rate; - for (i = 0; i < 4; i++) - ao_serial_putchar(0); - ao_serial_putchar((cksum >> 8) & 0x7f); - ao_serial_putchar(cksum & 0xff); - ao_serial_putchar(0xb0); - ao_serial_putchar(0xb3); -} - -static const uint8_t sirf_disable[] = { - 2, - 9, - 10, - 27, - 50, - 52, -}; - -void -ao_gps(void) __reentrant -{ - uint8_t i, k; - uint16_t cksum; - - ao_gps_setup(); - for (k = 0; k < 5; k++) - { - for (i = 0; i < sizeof (ao_gps_config); i++) - ao_serial_putchar(ao_gps_config[i]); - 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 */ - while (ao_sirf_byte() != (uint8_t) 0xa0) - ; - if (ao_sirf_byte() != (uint8_t) 0xa2) - continue; - - /* Length */ - ao_sirf_len = ao_sirf_byte() << 8; - ao_sirf_len |= ao_sirf_byte(); - if (ao_sirf_len > 1023) - continue; - - ao_sirf_cksum = 0; - - /* message ID */ - i = data_byte (); /* 0 */ - - switch (i) { - case 41: - if (ao_sirf_len < 90) - 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; - - /* verify checksum and end sequence */ - ao_sirf_cksum &= 0x7fff; - cksum = ao_sirf_byte() << 8; - cksum |= ao_sirf_byte(); - if (ao_sirf_cksum != cksum) - continue; - if (ao_sirf_byte() != (uint8_t) 0xb0) - continue; - if (ao_sirf_byte() != (uint8_t) 0xb3) - continue; - - switch (i) { - case 41: - ao_mutex_get(&ao_gps_mutex); - ao_gps_tick = ao_time(); - ao_gps_data.hour = ao_sirf_data.utc_hour; - ao_gps_data.minute = ao_sirf_data.utc_minute; - ao_gps_data.second = ao_sirf_data.utc_second / 1000; - ao_gps_data.flags = ((ao_sirf_data.num_sv << AO_GPS_NUM_SAT_SHIFT) & AO_GPS_NUM_SAT_MASK) | AO_GPS_RUNNING; - if ((ao_sirf_data.nav_type & NAV_TYPE_GPS_FIX_TYPE_MASK) >= NAV_TYPE_4_SV_KF) - ao_gps_data.flags |= AO_GPS_VALID; - ao_gps_data.latitude = ao_sirf_data.lat; - ao_gps_data.longitude = ao_sirf_data.lon; - ao_gps_data.altitude = ao_sirf_data.alt_msl / 100; - ao_gps_data.ground_speed = ao_sirf_data.ground_speed; - 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 0 - if (ao_sirf_data.h_error > 6553500) - ao_gps_data.h_error = 65535; - else - ao_gps_data.h_error = ao_sirf_data.h_error / 100; - if (ao_sirf_data.v_error > 6553500) - ao_gps_data.v_error = 65535; - else - ao_gps_data.v_error = ao_sirf_data.v_error / 100; -#endif - 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].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; - } - } -} - -__xdata struct ao_task ao_gps_task; - -void -ao_gps_init(void) -{ - ao_add_task(&ao_gps_task, ao_gps, "gps"); -} diff --git a/src/ao_gps_skytraq.c b/src/ao_gps_skytraq.c deleted file mode 100644 index 7ac26946..00000000 --- a/src/ao_gps_skytraq.c +++ /dev/null @@ -1,490 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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_GPS_TEST -#include "ao.h" -#endif - -#define AO_GPS_LEADER 2 - -static __code char ao_gps_header[] = "GP"; - -__xdata uint8_t ao_gps_mutex; -static __data char ao_gps_char; -static __pdata uint8_t ao_gps_cksum; -static __pdata uint8_t ao_gps_error; - -__pdata uint16_t ao_gps_tick; -__xdata struct ao_telemetry_location ao_gps_data; -__xdata struct ao_telemetry_satellite ao_gps_tracking_data; - -static __pdata uint16_t ao_gps_next_tick; -static __xdata struct ao_telemetry_location ao_gps_next; -static __pdata uint8_t ao_gps_date_flags; -static __xdata struct ao_telemetry_satellite ao_gps_tracking_next; - -#define STQ_S 0xa0, 0xa1 -#define STQ_E 0x0d, 0x0a -#define SKYTRAQ_MSG_2(id,a,b) \ - STQ_S, 0, 3, id, a,b, (id^a^b), STQ_E -#define SKYTRAQ_MSG_3(id,a,b,c) \ - STQ_S, 0, 4, id, a,b,c, (id^a^b^c), STQ_E -#define SKYTRAQ_MSG_8(id,a,b,c,d,e,f,g,h) \ - STQ_S, 0, 9, id, a,b,c,d,e,f,g,h, (id^a^b^c^d^e^f^g^h), STQ_E -#define SKYTRAQ_MSG_14(id,a,b,c,d,e,f,g,h,i,j,k,l,m,n) \ - STQ_S, 0,15, id, a,b,c,d,e,f,g,h,i,j,k,l,m,n, \ - (id^a^b^c^d^e^f^g^h^i^j^k^l^m^n), STQ_E - -static __code uint8_t ao_gps_config[] = { - SKYTRAQ_MSG_8(0x08, 1, 1, 1, 1, 1, 1, 1, 0), /* configure nmea */ - /* gga interval */ - /* gsa interval */ - /* gsv interval */ - /* gll interval */ - /* rmc interval */ - /* vtg interval */ - /* zda interval */ - /* attributes (0 = update to sram, 1 = update flash too) */ - - SKYTRAQ_MSG_2(0x3c, 0x00, 0x00), /* configure navigation mode */ - /* 0 = car, 1 = pedestrian */ - /* 0 = update to sram, 1 = update sram + flash */ -}; - -static void -ao_gps_lexchar(void) -{ - if (ao_gps_error) - ao_gps_char = '\n'; - else - ao_gps_char = ao_serial_getchar(); - ao_gps_cksum ^= ao_gps_char; -} - -void -ao_gps_skip_field(void) -{ - while (ao_gps_char != ',' && ao_gps_char != '*' && ao_gps_char != '\n') - ao_gps_lexchar(); -} - -void -ao_gps_skip_sep(void) -{ - if (ao_gps_char == ',' || ao_gps_char == '.' || ao_gps_char == '*') - ao_gps_lexchar(); -} - -__pdata static uint8_t ao_gps_num_width; - -static int16_t -ao_gps_decimal(uint8_t max_width) -{ - int16_t v; - __pdata uint8_t neg = 0; - - ao_gps_skip_sep(); - if (ao_gps_char == '-') { - neg = 1; - ao_gps_lexchar(); - } - v = 0; - ao_gps_num_width = 0; - while (ao_gps_num_width < max_width) { - if (ao_gps_char < '0' || '9' < ao_gps_char) - break; - v = v * (int16_t) 10 + ao_gps_char - '0'; - ao_gps_num_width++; - ao_gps_lexchar(); - } - if (neg) - v = -v; - return v; -} - -static uint8_t -ao_gps_hex(uint8_t max_width) -{ - uint8_t v, d; - - ao_gps_skip_sep(); - v = 0; - ao_gps_num_width = 0; - while (ao_gps_num_width < max_width) { - if ('0' <= ao_gps_char && ao_gps_char <= '9') - d = ao_gps_char - '0'; - else if ('A' <= ao_gps_char && ao_gps_char <= 'F') - d = ao_gps_char - 'A' + 10; - else if ('a' <= ao_gps_char && ao_gps_char <= 'f') - d = ao_gps_char - 'a' + 10; - else - break; - v = (v << 4) | d; - ao_gps_num_width++; - ao_gps_lexchar(); - } - return v; -} - -static int32_t -ao_gps_parse_pos(uint8_t deg_width) __reentrant -{ - int32_t d; - int32_t m; - int32_t f; - - d = ao_gps_decimal(deg_width); - m = ao_gps_decimal(2); - if (ao_gps_char == '.') { - f = ao_gps_decimal(4); - while (ao_gps_num_width < 4) { - f *= 10; - ao_gps_num_width++; - } - } else { - f = 0; - if (ao_gps_char != ',') - ao_gps_error = 1; - } - d = d * 10000000l; - m = m * 10000l + f; - d = d + m * 50 / 3; - return d; -} - -static uint8_t -ao_gps_parse_flag(char no_c, char yes_c) __reentrant -{ - uint8_t ret = 0; - ao_gps_skip_sep(); - if (ao_gps_char == yes_c) - ret = 1; - else if (ao_gps_char == no_c) - ret = 0; - else - ao_gps_error = 1; - ao_gps_lexchar(); - return ret; -} - -static void -ao_nmea_gga() -{ - uint8_t i; - - /* Now read the data into the gps data record - * - * $GPGGA,025149.000,4528.1723,N,12244.2480,W,1,05,2.0,103.5,M,-19.5,M,,0000*66 - * - * Essential fix data - * - * 025149.000 time (02:51:49.000 GMT) - * 4528.1723,N Latitude 45°28.1723' N - * 12244.2480,W Longitude 122°44.2480' W - * 1 Fix quality: - * 0 = invalid - * 1 = GPS fix (SPS) - * 2 = DGPS fix - * 3 = PPS fix - * 4 = Real Time Kinematic - * 5 = Float RTK - * 6 = estimated (dead reckoning) - * 7 = Manual input mode - * 8 = Simulation mode - * 05 Number of satellites (5) - * 2.0 Horizontal dilution - * 103.5,M Altitude, 103.5M above msl - * -19.5,M Height of geoid above WGS84 ellipsoid - * ? time in seconds since last DGPS update - * 0000 DGPS station ID - * *66 checksum - */ - - ao_gps_next_tick = ao_time(); - ao_gps_next.flags = AO_GPS_RUNNING | ao_gps_date_flags; - ao_gps_next.hour = ao_gps_decimal(2); - ao_gps_next.minute = ao_gps_decimal(2); - ao_gps_next.second = ao_gps_decimal(2); - ao_gps_skip_field(); /* skip seconds fraction */ - - ao_gps_next.latitude = ao_gps_parse_pos(2); - if (ao_gps_parse_flag('N', 'S')) - ao_gps_next.latitude = -ao_gps_next.latitude; - ao_gps_next.longitude = ao_gps_parse_pos(3); - if (ao_gps_parse_flag('E', 'W')) - ao_gps_next.longitude = -ao_gps_next.longitude; - - i = ao_gps_decimal(0xff); - if (i == 1) - ao_gps_next.flags |= AO_GPS_VALID; - - i = ao_gps_decimal(0xff) << AO_GPS_NUM_SAT_SHIFT; - if (i > AO_GPS_NUM_SAT_MASK) - i = AO_GPS_NUM_SAT_MASK; - ao_gps_next.flags |= i; - - ao_gps_lexchar(); - i = ao_gps_decimal(0xff); - if (i <= 50) { - i = (uint8_t) 5 * i; - if (ao_gps_char == '.') - i = (i + ((uint8_t) ao_gps_decimal(1) >> 1)); - } else - i = 255; - ao_gps_next.hdop = i; - ao_gps_skip_field(); - - ao_gps_next.altitude = ao_gps_decimal(0xff); - ao_gps_skip_field(); /* skip any fractional portion */ - - /* Skip remaining fields */ - while (ao_gps_char != '*' && ao_gps_char != '\n' && ao_gps_char != '\r') { - ao_gps_lexchar(); - ao_gps_skip_field(); - } - if (ao_gps_char == '*') { - uint8_t cksum = ao_gps_cksum ^ '*'; - if (cksum != ao_gps_hex(2)) - ao_gps_error = 1; - } else - ao_gps_error = 1; - if (!ao_gps_error) { - ao_mutex_get(&ao_gps_mutex); - ao_gps_tick = ao_gps_next_tick; - memcpy(&ao_gps_data, &ao_gps_next, sizeof (ao_gps_data)); - ao_mutex_put(&ao_gps_mutex); - ao_wakeup(&ao_gps_data); - } -} - -static void -ao_nmea_gsv(void) -{ - char c; - uint8_t i; - uint8_t done; - /* Now read the data into the GPS tracking data record - * - * $GPGSV,3,1,12,05,54,069,45,12,44,061,44,21,07,184,46,22,78,289,47*72 - * - * Satellites in view data - * - * 3 Total number of GSV messages - * 1 Sequence number of current GSV message - * 12 Total sats in view (0-12) - * 05 SVID - * 54 Elevation - * 069 Azimuth - * 45 C/N0 in dB - * ... other SVIDs - * 72 checksum - */ - c = ao_gps_decimal(1); /* total messages */ - i = ao_gps_decimal(1); /* message sequence */ - if (i == 1) { - ao_gps_tracking_next.channels = 0; - } - done = (uint8_t) c == i; - ao_gps_lexchar(); - ao_gps_skip_field(); /* sats in view */ - while (ao_gps_char != '*' && ao_gps_char != '\n' && ao_gps_char != '\r') { - i = ao_gps_tracking_next.channels; - c = ao_gps_decimal(2); /* SVID */ - if (i < AO_MAX_GPS_TRACKING) - ao_gps_tracking_next.sats[i].svid = c; - ao_gps_lexchar(); - ao_gps_skip_field(); /* elevation */ - ao_gps_lexchar(); - ao_gps_skip_field(); /* azimuth */ - c = ao_gps_decimal(2); /* C/N0 */ - if (i < AO_MAX_GPS_TRACKING) { - if ((ao_gps_tracking_next.sats[i].c_n_1 = c) != 0) - ao_gps_tracking_next.channels = i + 1; - } - } - if (ao_gps_char == '*') { - uint8_t cksum = ao_gps_cksum ^ '*'; - if (cksum != ao_gps_hex(2)) - ao_gps_error = 1; - } - else - ao_gps_error = 1; - if (ao_gps_error) - ao_gps_tracking_next.channels = 0; - else if (done) { - ao_mutex_get(&ao_gps_mutex); - memcpy(&ao_gps_tracking_data, &ao_gps_tracking_next, - sizeof(ao_gps_tracking_data)); - ao_mutex_put(&ao_gps_mutex); - ao_wakeup(&ao_gps_tracking_data); - } -} - -static void -ao_nmea_rmc(void) -{ - char a, c; - uint8_t i; - /* Parse the RMC record to read out the current date */ - - /* $GPRMC,111636.932,A,2447.0949,N,12100.5223,E,000.0,000.0,030407,,,A*61 - * - * Recommended Minimum Specific GNSS Data - * - * 111636.932 UTC time 11:16:36.932 - * A Data Valid (V = receiver warning) - * 2447.0949 Latitude - * N North/south indicator - * 12100.5223 Longitude - * E East/west indicator - * 000.0 Speed over ground - * 000.0 Course over ground - * 030407 UTC date (ddmmyy format) - * A Mode indicator: - * N = data not valid - * A = autonomous mode - * D = differential mode - * E = estimated (dead reckoning) mode - * M = manual input mode - * S = simulator mode - * 61 checksum - */ - ao_gps_skip_field(); - for (i = 0; i < 8; i++) { - ao_gps_lexchar(); - ao_gps_skip_field(); - } - a = ao_gps_decimal(2); - c = ao_gps_decimal(2); - i = ao_gps_decimal(2); - /* Skip remaining fields */ - while (ao_gps_char != '*' && ao_gps_char != '\n' && ao_gps_char != '\r') { - ao_gps_lexchar(); - ao_gps_skip_field(); - } - if (ao_gps_char == '*') { - uint8_t cksum = ao_gps_cksum ^ '*'; - if (cksum != ao_gps_hex(2)) - ao_gps_error = 1; - } else - ao_gps_error = 1; - if (!ao_gps_error) { - ao_gps_next.year = i; - ao_gps_next.month = c; - ao_gps_next.day = a; - ao_gps_date_flags = AO_GPS_DATE_VALID; - } -} - -#define ao_skytraq_sendstruct(s) ao_skytraq_sendbytes((s), sizeof(s)) - -static void -ao_skytraq_sendbytes(__code uint8_t *b, uint8_t l) -{ - while (l--) { - uint8_t c = *b++; - if (c == 0xa0) - ao_delay(AO_MS_TO_TICKS(500)); - ao_serial_putchar(c); - } -} - -static void -ao_gps_nmea_parse(void) -{ - uint8_t a, b, c; - - ao_gps_cksum = 0; - ao_gps_error = 0; - - for (a = 0; a < AO_GPS_LEADER; a++) { - ao_gps_lexchar(); - if (ao_gps_char != ao_gps_header[a]) - return; - } - - ao_gps_lexchar(); - a = ao_gps_char; - ao_gps_lexchar(); - b = ao_gps_char; - ao_gps_lexchar(); - c = ao_gps_char; - ao_gps_lexchar(); - - if (ao_gps_char != ',') - return; - - if (a == (uint8_t) 'G' && b == (uint8_t) 'G' && c == (uint8_t) 'A') { - ao_nmea_gga(); - } else if (a == (uint8_t) 'G' && b == (uint8_t) 'S' && c == (uint8_t) 'V') { - ao_nmea_gsv(); - } else if (a == (uint8_t) 'R' && b == (uint8_t) 'M' && c == (uint8_t) 'C') { - ao_nmea_rmc(); - } -} - -void -ao_gps(void) __reentrant -{ - ao_serial_set_speed(AO_SERIAL_SPEED_9600); - - /* give skytraq time to boot in case of cold start */ - ao_delay(AO_MS_TO_TICKS(2000)); - - ao_skytraq_sendstruct(ao_gps_config); - - for (;;) { - /* Locate the begining of the next record */ - if (ao_serial_getchar() == '$') { - ao_gps_nmea_parse(); - } - - } -} - -__xdata struct ao_task ao_gps_task; - -static void -gps_dump(void) __reentrant -{ - uint8_t i; - ao_mutex_get(&ao_gps_mutex); - printf ("Date: %02d/%02d/%02d\n", ao_gps_data.year, ao_gps_data.month, ao_gps_data.day); - printf ("Time: %02d:%02d:%02d\n", ao_gps_data.hour, ao_gps_data.minute, ao_gps_data.second); - printf ("Lat/Lon: %ld %ld\n", ao_gps_data.latitude, ao_gps_data.longitude); - printf ("Alt: %d\n", ao_gps_data.altitude); - printf ("Flags: 0x%x\n", ao_gps_data.flags); - printf ("Sats: %d", ao_gps_tracking_data.channels); - for (i = 0; i < ao_gps_tracking_data.channels; i++) - printf (" %d %d", - ao_gps_tracking_data.sats[i].svid, - ao_gps_tracking_data.sats[i].c_n_1); - printf ("\ndone\n"); - ao_mutex_put(&ao_gps_mutex); -} - -__code struct ao_cmds ao_gps_cmds[] = { - { gps_dump, "g\0Display GPS" }, - { 0, NULL }, -}; - -void -ao_gps_init(void) -{ - ao_add_task(&ao_gps_task, ao_gps, "gps"); - ao_cmd_register(&ao_gps_cmds[0]); -} diff --git a/src/ao_gps_test.c b/src/ao_gps_test.c deleted file mode 100644 index 93d7a9ab..00000000 --- a/src/ao_gps_test.c +++ /dev/null @@ -1,508 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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_GPS_TEST -#include "ao_host.h" -#include -#include -#include -#include -#include -#define AO_GPS_NUM_SAT_MASK (0xf << 0) -#define AO_GPS_NUM_SAT_SHIFT (0) - -#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_orig { - uint8_t year; - uint8_t month; - uint8_t day; - uint8_t hour; - uint8_t minute; - uint8_t second; - uint8_t flags; - int32_t latitude; /* degrees * 10⁷ */ - int32_t longitude; /* degrees * 10⁷ */ - int16_t altitude; /* m */ - uint16_t ground_speed; /* cm/s */ - uint8_t course; /* degrees / 2 */ - uint8_t hdop; /* * 5 */ - int16_t climb_rate; /* cm/s */ - uint16_t h_error; /* m */ - 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_orig { - uint8_t svid; - uint8_t c_n_1; -}; - -#define AO_MAX_GPS_TRACKING 12 - -struct ao_gps_tracking_orig { - uint8_t channels; - struct ao_gps_sat_orig sats[AO_MAX_GPS_TRACKING]; -}; - -#define ao_telemetry_location ao_gps_orig -#define ao_telemetry_satellite ao_gps_tracking_orig -#define ao_telemetry_satellite_info ao_gps_sat_orig - -void -ao_mutex_get(uint8_t *mutex) -{ -} - -void -ao_mutex_put(uint8_t *mutex) -{ -} - -static int -ao_gps_fd; - -static void -ao_dbg_char(char c) -{ - char line[128]; - line[0] = '\0'; - if (c < ' ') { - if (c == '\n') - sprintf (line, "\n"); - else - sprintf (line, "\\%02x", ((int) c) & 0xff); - } else { - sprintf (line, "%c", c); - } - write(1, line, strlen(line)); -} - -#define QUEUE_LEN 4096 - -static char input_queue[QUEUE_LEN]; -int input_head, input_tail; - -#include - -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) -{ - uint16_t encoded_len, encoded_cksum; - uint16_t cksum; - uint8_t id; - int i; - - if (msg[0] != 0xa0 || msg[1] != 0xa2) { - printf ("bad header\n"); - return; - } - if (len < 7) { - printf("short\n"); - return; - } - if (msg[len-1] != 0xb3 || msg[len-2] != 0xb0) { - printf ("bad trailer\n"); - return; - } - encoded_len = (msg[2] << 8) | msg[3]; - id = msg[4]; -/* printf ("%9d: %3d\n", get_millis(), id); */ - if (encoded_len != len - 8) { - 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]; - cksum = 0; - for (i = 4; i < len - 4; i++) - cksum = (cksum + msg[i]) & 0x7fff; - if (encoded_cksum != cksum) { - printf ("cksum mismatch (got %04x wanted %04x)\n", - cksum, encoded_cksum); - return; - } - id = msg[4]; - switch (id) { - case 41:{ - int off = 4; - - uint8_t id; - uint16_t nav_valid; - uint16_t nav_type; - uint16_t week; - uint32_t tow; - uint16_t year; - uint8_t month; - uint8_t day; - uint8_t hour; - uint8_t minute; - uint16_t second; - uint32_t sat_list; - int32_t lat; - int32_t lon; - int32_t alt_ell; - int32_t alt_msl; - int8_t datum; - uint16_t sog; - uint16_t cog; - int16_t mag_var; - int16_t climb_rate; - int16_t heading_rate; - uint32_t h_error; - uint32_t v_error; - uint32_t t_error; - uint16_t h_v_error; - -#define get_u8(u) u = (msg[off]); off+= 1 -#define get_u16(u) u = (msg[off] << 8) | (msg[off + 1]); off+= 2 -#define get_u32(u) u = (msg[off] << 24) | (msg[off + 1] << 16) | (msg[off+2] << 8) | (msg[off+3]); off+= 4 - - get_u8(id); - get_u16(nav_valid); - get_u16(nav_type); - get_u16(week); - get_u32(tow); - get_u16(year); - get_u8(month); - get_u8(day); - get_u8(hour); - get_u8(minute); - get_u16(second); - get_u32(sat_list); - get_u32(lat); - get_u32(lon); - get_u32(alt_ell); - get_u32(alt_msl); - get_u8(datum); - get_u16(sog); - get_u16(cog); - get_u16(mag_var); - get_u16(climb_rate); - get_u16(heading_rate); - get_u32(h_error); - get_u32(v_error); - get_u32(t_error); - get_u16(h_v_error); - - - printf ("Geodetic Navigation Data (41):\n"); - printf ("\tNav valid %04x\n", nav_valid); - printf ("\tNav type %04x\n", nav_type); - 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", 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++) { - if (((i - 4) & 0xf) == 0) - printf("\n "); - printf (" %3d", msg[i]); - } - printf ("\n"); - } -} - -static uint8_t sirf_message[4096]; -static int sirf_message_len; -static uint8_t sirf_in_message[4096]; -static int sirf_in_len; - -char -ao_serial_getchar(void) -{ - char c; - uint8_t uc; - - while (input_head == input_tail) { - for (;;) { - input_tail = read(ao_gps_fd, input_queue, QUEUE_LEN); - if (input_tail < 0) { - if (errno == EINTR || errno == EAGAIN) - continue; - perror ("getchar"); - exit (1); - } - input_head = 0; - break; - } - } - c = input_queue[input_head]; - input_head = (input_head + 1) % QUEUE_LEN; - uc = c; - if (sirf_in_len || uc == 0xa0) { - if (sirf_in_len < 4096) - sirf_in_message[sirf_in_len++] = uc; - if (uc == 0xb3) { - check_sirf_message("recv", sirf_in_message, sirf_in_len); - sirf_in_len = 0; - } - } - return c; -} - - -void -ao_serial_putchar(char c) -{ - int i; - uint8_t uc = (uint8_t) c; - - if (sirf_message_len || uc == 0xa0) { - if (sirf_message_len < 4096) - sirf_message[sirf_message_len++] = uc; - if (uc == 0xb3) { - check_sirf_message("send", sirf_message, sirf_message_len); - sirf_message_len = 0; - } - } - for (;;) { - i = write(ao_gps_fd, &c, 1); - if (i == 1) { - if ((uint8_t) c == 0xb3 || c == '\r') { - static const struct timespec delay = { - .tv_sec = 0, - .tv_nsec = 100 * 1000 * 1000 - }; - tcdrain(ao_gps_fd); -// nanosleep(&delay, NULL); - } - break; - } - if (i < 0 && (errno == EINTR || errno == EAGAIN)) - continue; - perror("putchar"); - exit(1); - } -} - -#define AO_SERIAL_SPEED_4800 0 -#define AO_SERIAL_SPEED_57600 1 - -static void -ao_serial_set_speed(uint8_t speed) -{ - int fd = ao_gps_fd; - struct termios termios; - - tcdrain(fd); - tcgetattr(fd, &termios); - switch (speed) { - case AO_SERIAL_SPEED_4800: - cfsetspeed(&termios, B4800); - break; - case AO_SERIAL_SPEED_57600: - cfsetspeed(&termios, B57600); - break; - } - tcsetattr(fd, TCSAFLUSH, &termios); - tcflush(fd, TCIFLUSH); -} - -#define ao_time() 0 - -#include "ao_gps_print.c" -#include "ao_gps_sirf.c" - -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); - printf (" nsat %d %svalid", - ao_gps_data.flags & AO_GPS_NUM_SAT_MASK, - ao_gps_data.flags & AO_GPS_VALID ? "" : "not "); - printf (" lat %g lon %g alt %d", - ao_gps_data.latitude / 1.0e7, - ao_gps_data.longitude / 1.0e7, - ao_gps_data.altitude); - printf (" speed %g climb %g course %d", - ao_gps_data.ground_speed / 100.0, - ao_gps_data.climb_rate / 100.0, - ao_gps_data.course * 2); - printf (" hdop %g h_error %d v_error %d", - 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(%02d)", - ao_gps_tracking_data.sats[i].svid, - ao_gps_tracking_data.sats[i].c_n_1); - printf ("\n"); -} - -int -ao_gps_open(const char *tty) -{ - struct termios termios; - int fd; - - fd = open (tty, O_RDWR); - if (fd < 0) - return -1; - - tcgetattr(fd, &termios); - cfmakeraw(&termios); - cfsetspeed(&termios, B4800); - tcsetattr(fd, TCSAFLUSH, &termios); - - tcdrain(fd); - tcflush(fd, TCIFLUSH); - return fd; -} - -#include - -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 ]\n", program); - exit(1); -} - -int -main (int argc, char **argv) -{ - char *tty = "/dev/ttyUSB0"; - int c; - - 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 (tty); - exit (1); - } - ao_gps_setup(); - ao_gps(); -} diff --git a/src/ao_gps_test_skytraq.c b/src/ao_gps_test_skytraq.c deleted file mode 100644 index a78fae0f..00000000 --- a/src/ao_gps_test_skytraq.c +++ /dev/null @@ -1,490 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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_GPS_TEST -#include "ao_host.h" -#include -#include -#include -#include -#include -#define AO_GPS_NUM_SAT_MASK (0xf << 0) -#define AO_GPS_NUM_SAT_SHIFT (0) - -#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_orig { - uint8_t year; - uint8_t month; - uint8_t day; - uint8_t hour; - uint8_t minute; - uint8_t second; - uint8_t flags; - int32_t latitude; /* degrees * 10⁷ */ - int32_t longitude; /* degrees * 10⁷ */ - int16_t altitude; /* m */ - uint16_t ground_speed; /* cm/s */ - uint8_t course; /* degrees / 2 */ - uint8_t hdop; /* * 5 */ - int16_t climb_rate; /* cm/s */ - uint16_t h_error; /* m */ - 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_orig { - uint8_t svid; - uint8_t c_n_1; -}; - -#define AO_MAX_GPS_TRACKING 12 - -struct ao_gps_tracking_orig { - uint8_t channels; - struct ao_gps_sat_orig sats[AO_MAX_GPS_TRACKING]; -}; - -#define ao_telemetry_location ao_gps_orig -#define ao_telemetry_satellite ao_gps_tracking_orig -#define ao_telemetry_satellite_info ao_gps_sat_orig - -void -ao_mutex_get(uint8_t *mutex) -{ -} - -void -ao_mutex_put(uint8_t *mutex) -{ -} - -static int -ao_gps_fd; - -static void -ao_dbg_char(char c) -{ - char line[128]; - line[0] = '\0'; - if (c < ' ') { - if (c == '\n') - sprintf (line, "\n"); - else - sprintf (line, "\\%02x", ((int) c) & 0xff); - } else { - sprintf (line, "%c", c); - } - write(1, line, strlen(line)); -} - -#define QUEUE_LEN 4096 - -static char input_queue[QUEUE_LEN]; -int input_head, input_tail; - -#include - -int -get_millis(void) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000 + tv.tv_usec / 1000; -} - -static void -check_skytraq_message(char *from, uint8_t *msg, int len) -{ - uint16_t encoded_len, encoded_cksum; - uint16_t cksum; - uint8_t id; - int i; - -// fwrite(msg, 1, len, stdout); - return; - if (msg[0] != 0xa0 || msg[1] != 0xa2) { - printf ("bad header\n"); - return; - } - if (len < 7) { - printf("short\n"); - return; - } - if (msg[len-1] != 0xb3 || msg[len-2] != 0xb0) { - printf ("bad trailer\n"); - return; - } - encoded_len = (msg[2] << 8) | msg[3]; - id = msg[4]; -/* printf ("%9d: %3d\n", get_millis(), id); */ - if (encoded_len != len - 8) { - 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]; - cksum = 0; - for (i = 4; i < len - 4; i++) - cksum = (cksum + msg[i]) & 0x7fff; - if (encoded_cksum != cksum) { - printf ("cksum mismatch (got %04x wanted %04x)\n", - cksum, encoded_cksum); - return; - } - id = msg[4]; - switch (id) { - case 41:{ - int off = 4; - - uint8_t id; - uint16_t nav_valid; - uint16_t nav_type; - uint16_t week; - uint32_t tow; - uint16_t year; - uint8_t month; - uint8_t day; - uint8_t hour; - uint8_t minute; - uint16_t second; - uint32_t sat_list; - int32_t lat; - int32_t lon; - int32_t alt_ell; - int32_t alt_msl; - int8_t datum; - uint16_t sog; - uint16_t cog; - int16_t mag_var; - int16_t climb_rate; - int16_t heading_rate; - uint32_t h_error; - uint32_t v_error; - uint32_t t_error; - uint16_t h_v_error; - -#define get_u8(u) u = (msg[off]); off+= 1 -#define get_u16(u) u = (msg[off] << 8) | (msg[off + 1]); off+= 2 -#define get_u32(u) u = (msg[off] << 24) | (msg[off + 1] << 16) | (msg[off+2] << 8) | (msg[off+3]); off+= 4 - - get_u8(id); - get_u16(nav_valid); - get_u16(nav_type); - get_u16(week); - get_u32(tow); - get_u16(year); - get_u8(month); - get_u8(day); - get_u8(hour); - get_u8(minute); - get_u16(second); - get_u32(sat_list); - get_u32(lat); - get_u32(lon); - get_u32(alt_ell); - get_u32(alt_msl); - get_u8(datum); - get_u16(sog); - get_u16(cog); - get_u16(mag_var); - get_u16(climb_rate); - get_u16(heading_rate); - get_u32(h_error); - get_u32(v_error); - get_u32(t_error); - get_u16(h_v_error); - - - printf ("Geodetic Navigation Data (41):\n"); - printf ("\tNav valid %04x\n", nav_valid); - printf ("\tNav type %04x\n", nav_type); - 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", 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++) { - if (((i - 4) & 0xf) == 0) - printf("\n "); - printf (" %3d", msg[i]); - } - printf ("\n"); - } -} - -static uint8_t skytraq_message[4096]; -static int skytraq_message_len; -static uint8_t skytraq_in_message[4096]; -static int skytraq_in_len; - -char -ao_serial_getchar(void) -{ - char c; - uint8_t uc; - - while (input_head == input_tail) { - for (;;) { - input_tail = read(ao_gps_fd, input_queue, QUEUE_LEN); - if (input_tail < 0) { - if (errno == EINTR || errno == EAGAIN) - continue; - perror ("getchar"); - exit (1); - } - input_head = 0; - break; - } - } - c = input_queue[input_head]; - input_head = (input_head + 1) % QUEUE_LEN; - uc = c; -// printf ("c: %02x %c\n", uc, uc); - if (skytraq_in_len || uc == '$') { - if (skytraq_in_len < 4096) - skytraq_in_message[skytraq_in_len++] = uc; - if (uc == 0x0a) { - check_skytraq_message("recv", skytraq_in_message, skytraq_in_len); - skytraq_in_len = 0; - } - } - return c; -} - - -void -ao_serial_putchar(char c) -{ - int i; - uint8_t uc = (uint8_t) c; - - if (skytraq_message_len || uc == 0xa0) { - if (skytraq_message_len < 4096) - skytraq_message[skytraq_message_len++] = uc; - if (uc == 0x0a) { - check_skytraq_message("send", skytraq_message, skytraq_message_len); - skytraq_message_len = 0; - } - } - for (;;) { - i = write(ao_gps_fd, &c, 1); - if (i == 1) { - if ((uint8_t) c == 0xb3 || c == '\r') { - static const struct timespec delay = { - .tv_sec = 0, - .tv_nsec = 100 * 1000 * 1000 - }; - tcdrain(ao_gps_fd); -// nanosleep(&delay, NULL); - } - break; - } - if (i < 0 && (errno == EINTR || errno == EAGAIN)) - continue; - perror("putchar"); - exit(1); - } -} - -#define AO_SERIAL_SPEED_4800 0 -#define AO_SERIAL_SPEED_9600 1 -#define AO_SERIAL_SPEED_57600 2 - -static void -ao_serial_set_speed(uint8_t speed) -{ - int fd = ao_gps_fd; - struct termios termios; - - tcdrain(fd); - tcgetattr(fd, &termios); - switch (speed) { - case AO_SERIAL_SPEED_4800: - cfsetspeed(&termios, B4800); - break; - case AO_SERIAL_SPEED_9600: - cfsetspeed(&termios, B38400); - break; - case AO_SERIAL_SPEED_57600: - cfsetspeed(&termios, B57600); - break; - } - tcsetattr(fd, TCSAFLUSH, &termios); - tcflush(fd, TCIFLUSH); -} - -#define ao_time() 0 - -#include "ao_gps_print.c" -#include "ao_gps_skytraq.c" - -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; -} - -int -ao_gps_open(const char *tty) -{ - struct termios termios; - int fd; - - fd = open (tty, O_RDWR); - if (fd < 0) - return -1; - - tcgetattr(fd, &termios); - cfmakeraw(&termios); - cfsetspeed(&termios, B4800); - tcsetattr(fd, TCSAFLUSH, &termios); - - tcdrain(fd); - tcflush(fd, TCIFLUSH); - return fd; -} - -#include - -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 ]\n", program); - exit(1); -} - -int -main (int argc, char **argv) -{ - char *tty = "/dev/ttyUSB0"; - int c; - - 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 (tty); - exit (1); - } - ao_gps(); -} diff --git a/src/ao_host.h b/src/ao_host.h deleted file mode 100644 index 65c25fe5..00000000 --- a/src/ao_host.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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 _GNU_SOURCE - -#include -#include -#include -#include -#include - -#define AO_ADC_RING 64 -#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1)) -#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1)) - -/* - * One set of samples read from the A/D converter - */ -struct ao_adc { - uint16_t tick; /* tick when the sample was read */ - int16_t accel; /* accelerometer */ - int16_t pres; /* pressure sensor */ - int16_t temp; /* temperature sensor */ - int16_t v_batt; /* battery voltage */ - int16_t sense_d; /* drogue continuity sense */ - int16_t sense_m; /* main continuity sense */ -}; - -#define __pdata -#define __data -#define __xdata -#define __code -#define __reentrant - -enum ao_flight_state { - ao_flight_startup = 0, - ao_flight_idle = 1, - ao_flight_pad = 2, - ao_flight_boost = 3, - ao_flight_fast = 4, - ao_flight_coast = 5, - ao_flight_drogue = 6, - ao_flight_main = 7, - ao_flight_landed = 8, - ao_flight_invalid = 9 -}; - -struct ao_adc ao_adc_ring[AO_ADC_RING]; -uint8_t ao_adc_head; - -#define ao_led_on(l) -#define ao_led_off(l) -#define ao_timer_set_adc_interval(i) -#define ao_wakeup(wchan) ao_dump_state(wchan) -#define ao_cmd_register(c) -#define ao_usb_disable() -#define ao_telemetry_set_interval(x) -#define ao_delay(x) - -enum ao_igniter { - ao_igniter_drogue = 0, - ao_igniter_main = 1 -}; - -void -ao_ignite(enum ao_igniter igniter) -{ - printf ("ignite %s\n", igniter == ao_igniter_drogue ? "drogue" : "main"); -} - -struct ao_task { - int dummy; -}; - -#define ao_add_task(t,f,n) - -#define ao_log_start() -#define ao_log_stop() - -#define AO_MS_TO_TICKS(ms) ((ms) / 10) -#define AO_SEC_TO_TICKS(s) ((s) * 100) - -#define AO_FLIGHT_TEST - -struct ao_adc ao_adc_static; - -FILE *emulator_in; - -void -ao_dump_state(void *wchan); - -void -ao_sleep(void *wchan); - -const char const * const ao_state_names[] = { - "startup", "idle", "pad", "boost", "fast", - "coast", "drogue", "main", "landed", "invalid" -}; - -struct ao_cmds { - void (*func)(void); - const char *help; -}; - - -struct ao_config { - uint16_t main_deploy; - int16_t accel_zero_g; -}; - -#define ao_config_get() - -struct ao_config ao_config = { 250, 16000 }; diff --git a/src/ao_ignite.c b/src/ao_ignite.c deleted file mode 100644 index 5238beb4..00000000 --- a/src/ao_ignite.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -#if IGNITE_ON_P2 -#define AO_IGNITER_DROGUE P2_3 -#define AO_IGNITER_MAIN P2_4 -#define AO_IGNITER_DIR P2DIR -#define AO_IGNITER_DROGUE_BIT (1 << 3) -#define AO_IGNITER_MAIN_BIT (1 << 4) -#endif - -#if IGNITE_ON_P0 -#define AO_IGNITER_DROGUE P0_5 -#define AO_IGNITER_MAIN P0_4 -#define AO_IGNITER_DIR P0DIR -#define AO_IGNITER_DROGUE_BIT (1 << 5) -#define AO_IGNITER_MAIN_BIT (1 << 4) -#endif - -/* test these values with real igniters */ -#define AO_IGNITER_OPEN 1000 -#define AO_IGNITER_CLOSED 7000 -#define AO_IGNITER_FIRE_TIME AO_MS_TO_TICKS(50) -#define AO_IGNITER_CHARGE_TIME AO_MS_TO_TICKS(2000) - -struct ao_ignition { - uint8_t request; - uint8_t fired; - uint8_t firing; -}; - -__xdata struct ao_ignition ao_ignition[2]; - -void -ao_ignite(enum ao_igniter igniter) __critical -{ - ao_ignition[igniter].request = 1; - ao_wakeup(&ao_ignition); -} - -enum ao_igniter_status -ao_igniter_status(enum ao_igniter igniter) -{ - __xdata struct ao_adc adc; - __pdata int16_t value; - __pdata uint8_t request, firing, fired; - - __critical { - ao_adc_get(&adc); - request = ao_ignition[igniter].request; - fired = ao_ignition[igniter].fired; - firing = ao_ignition[igniter].firing; - } - if (firing || (request && !fired)) - return ao_igniter_active; - - value = (AO_IGNITER_CLOSED>>1); - switch (igniter) { - case ao_igniter_drogue: - value = adc.sense_d; - break; - case ao_igniter_main: - value = adc.sense_m; - break; - } - if (value < AO_IGNITER_OPEN) - return ao_igniter_open; - else if (value > AO_IGNITER_CLOSED) - return ao_igniter_ready; - else - return ao_igniter_unknown; -} - -void -ao_igniter_fire(enum ao_igniter igniter) __critical -{ - ao_ignition[igniter].firing = 1; - switch(ao_config.ignite_mode) { - case AO_IGNITE_MODE_DUAL: - switch (igniter) { - case ao_igniter_drogue: - AO_IGNITER_DROGUE = 1; - ao_delay(AO_IGNITER_FIRE_TIME); - AO_IGNITER_DROGUE = 0; - break; - case ao_igniter_main: - AO_IGNITER_MAIN = 1; - ao_delay(AO_IGNITER_FIRE_TIME); - AO_IGNITER_MAIN = 0; - break; - } - break; - case AO_IGNITE_MODE_APOGEE: - switch (igniter) { - case ao_igniter_drogue: - AO_IGNITER_DROGUE = 1; - ao_delay(AO_IGNITER_FIRE_TIME); - AO_IGNITER_DROGUE = 0; - ao_delay(AO_IGNITER_CHARGE_TIME); - AO_IGNITER_MAIN = 1; - ao_delay(AO_IGNITER_FIRE_TIME); - AO_IGNITER_MAIN = 0; - break; - } - break; - case AO_IGNITE_MODE_MAIN: - switch (igniter) { - case ao_igniter_main: - AO_IGNITER_DROGUE = 1; - ao_delay(AO_IGNITER_FIRE_TIME); - AO_IGNITER_DROGUE = 0; - ao_delay(AO_IGNITER_CHARGE_TIME); - AO_IGNITER_MAIN = 1; - ao_delay(AO_IGNITER_FIRE_TIME); - AO_IGNITER_MAIN = 0; - break; - } - break; - } - ao_ignition[igniter].firing = 0; -} - -void -ao_igniter(void) -{ - __xdata enum ao_ignter igniter; - - ao_config_get(); - for (;;) { - ao_sleep(&ao_ignition); - for (igniter = ao_igniter_drogue; igniter <= ao_igniter_main; igniter++) { - if (ao_ignition[igniter].request && !ao_ignition[igniter].fired) { - if (igniter == ao_igniter_drogue && ao_config.apogee_delay) - ao_delay(AO_SEC_TO_TICKS(ao_config.apogee_delay)); - - ao_igniter_fire(igniter); - ao_delay(AO_IGNITER_CHARGE_TIME); - ao_ignition[igniter].fired = 1; - } - } - } -} - -void -ao_ignite_manual(void) -{ - ao_cmd_white(); - if (!ao_match_word("DoIt")) - return; - ao_cmd_white(); - if (ao_cmd_lex_c == 'm') { - if(ao_match_word("main")) - ao_igniter_fire(ao_igniter_main); - } else { - if(ao_match_word("drogue")) - ao_igniter_fire(ao_igniter_drogue); - } -} - -static __code char * __code igniter_status_names[] = { - "unknown", "ready", "active", "open" -}; - -void -ao_ignite_print_status(enum ao_igniter igniter, __code char *name) __reentrant -{ - enum ao_igniter_status status = ao_igniter_status(igniter); - printf("Igniter: %6s Status: %s\n", - name, - igniter_status_names[status]); -} - -void -ao_ignite_test(void) -{ - ao_ignite_print_status(ao_igniter_drogue, "drogue"); - ao_ignite_print_status(ao_igniter_main, "main"); -} - -__code struct ao_cmds ao_ignite_cmds[] = { - { ao_ignite_manual, "i {main|drogue}\0Fire igniter. is doit with D&I" }, - { ao_ignite_test, "t\0Test igniter" }, - { 0, NULL }, -}; - -__xdata struct ao_task ao_igniter_task; - -void -ao_ignite_set_pins(void) -{ - AO_IGNITER_DROGUE = 0; - AO_IGNITER_MAIN = 0; - AO_IGNITER_DIR |= AO_IGNITER_DROGUE_BIT | AO_IGNITER_MAIN_BIT; -} - -void -ao_igniter_init(void) -{ - ao_ignite_set_pins(); - ao_cmd_register(&ao_ignite_cmds[0]); - ao_add_task(&ao_igniter_task, ao_igniter, "igniter"); -} diff --git a/src/ao_intflash.c b/src/ao_intflash.c deleted file mode 100644 index d76d954e..00000000 --- a/src/ao_intflash.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright © 2011 Anthony Towns - * - * 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" -#include "cc1111.h" - -#define ENDOFCODE (CODESIZE) -#define AO_INTFLASH_BLOCK 1024 -#define AO_INTFLASH_BLOCKS ((0x8000 - ENDOFCODE)/AO_INTFLASH_BLOCK) -#define AO_INTFLASH_SIZE (AO_INTFLASH_BLOCK * AO_INTFLASH_BLOCKS) -#define AO_INTFLASH_LOCATION (0x8000 - AO_INTFLASH_SIZE) - -/* - * 21000 * 24e6 - * FWT = ------------ - * 16e9 - * - * = 31.5 - * - * Round up and use 32 - */ - -#define FLASH_TIMING 0x20 - -#if AO_INTFLASH_BLOCKS < 2 -#error "Too few pages" -#endif - -#if AO_INFTLASH_LOCATION % 1024 != 0 -#error "Pages aren't aligned properly" -#endif - -__xdata __at(AO_INTFLASH_LOCATION) uint8_t ao_intflash[AO_INTFLASH_SIZE]; - -/* Total bytes of available storage */ -__pdata uint32_t ao_storage_total = sizeof(ao_intflash); - -/* Block size - device is erased in these units. */ -__pdata uint32_t ao_storage_block = AO_INTFLASH_BLOCK; - -/* Byte offset of config block. Will be ao_storage_block bytes long */ -__pdata uint32_t ao_storage_config = sizeof(ao_intflash) - AO_INTFLASH_BLOCK; - -/* Storage unit size - device reads and writes must be within blocks of this size. */ -__pdata uint16_t ao_storage_unit = AO_INTFLASH_BLOCK; - -__xdata static uint8_t ao_intflash_dma_done; -static uint8_t ao_intflash_dma; - -/* - * The internal flash chip is arranged in 1kB sectors; the - * chip cannot erase in units smaller than that. - * - * Writing happens in units of 2 bytes and - * can only change bits from 1 to 0. So, you can rewrite - * the same contents, or append to an existing page easily enough - */ - -/* - * Erase the specified sector - */ -uint8_t -ao_storage_erase(uint32_t pos) __reentrant -{ - uint16_t addr; - - if (pos >= ao_storage_total || pos + ao_storage_block > ao_storage_total) - return 0; - - addr = ((uint16_t)(ao_intflash + pos) >> 1); - - FADDRH = addr >> 8; - FADDRL = addr; - - __critical { - _asm - .even - orl _FCTL, #FCTL_ERASE; ; FCTL |= FCTL_ERASE - nop ; Required, see datasheet. - _endasm; - } - - return 1; -} - -/* - * Write to flash - */ - -static void -ao_intflash_write_aligned(uint16_t pos, __xdata void *d, uint16_t len) __reentrant -{ - pos = ((uint16_t) ao_intflash + pos) >> 1; - - ao_dma_set_transfer(ao_intflash_dma, - d, - &FWDATAXADDR, - len, - DMA_CFG0_WORDSIZE_8 | - DMA_CFG0_TMODE_SINGLE | - DMA_CFG0_TRIGGER_FLASH, - DMA_CFG1_SRCINC_1 | - DMA_CFG1_DESTINC_0 | - DMA_CFG1_PRIORITY_HIGH); - - FADDRH = pos >> 8; - FADDRL = pos; - - ao_dma_start(ao_intflash_dma); - - __critical { - _asm - .even - orl _FCTL, #FCTL_WRITE; ; FCTL |= FCTL_WRITE - nop - _endasm; - } -} - -static void -ao_intflash_write_byte(uint16_t pos, uint8_t byte) __reentrant -{ - static __xdata uint8_t b[2]; - - if (pos & 1) { - b[0] = 0xff; - b[1] = byte; - } else { - b[0] = byte; - b[1] = 0xff; - } - ao_intflash_write_aligned(pos, b, 2); -} - -uint8_t -ao_storage_device_write(uint32_t pos32, __xdata void *v, uint16_t len) __reentrant -{ - uint16_t pos = pos32; - __xdata uint8_t *d = v; - uint8_t oddlen; - - if (pos >= ao_storage_total || pos + len > ao_storage_total) - return 0; - if (len == 0) - return 1; - - if (pos & 1) { - ao_intflash_write_byte(pos++, *d++); - len--; - } - oddlen = len & 1; - len -= oddlen; - if (len) - ao_intflash_write_aligned(pos, d, len); - if (oddlen) - ao_intflash_write_byte(pos + len, d[len]); - - return 1; -} - -/* - * Read from flash - */ -uint8_t -ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant -{ - if (pos >= ao_storage_total || pos + len > ao_storage_total) - return 0; - memcpy(d, ao_intflash+pos, len); - return 1; -} - -void -ao_storage_flush(void) __reentrant -{ -} - -void -ao_storage_setup(void) -{ -} - -void -ao_storage_device_info(void) __reentrant -{ - printf ("Using internal flash, starting at 0x%04x\n", AO_INTFLASH_LOCATION); -} - -void -ao_storage_device_init(void) -{ - ao_intflash_dma = ao_dma_alloc(&ao_intflash_dma_done); - - FWT = FLASH_TIMING; -} diff --git a/src/ao_kalman.c b/src/ao_kalman.c deleted file mode 100644 index ee01949e..00000000 --- a/src/ao_kalman.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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_FLIGHT_TEST -#include "ao.h" -#endif - -#include "ao_kalman.h" - -static __pdata int32_t ao_k_height; -static __pdata int32_t ao_k_speed; -static __pdata int32_t ao_k_accel; - -#define AO_K_STEP_100 to_fix16(0.01) -#define AO_K_STEP_2_2_100 to_fix16(0.00005) - -#define AO_K_STEP_10 to_fix16(0.1) -#define AO_K_STEP_2_2_10 to_fix16(0.005) - -#define AO_K_STEP_1 to_fix16(1) -#define AO_K_STEP_2_2_1 to_fix16(0.5) - -__pdata int16_t ao_height; -__pdata int16_t ao_speed; -__pdata int16_t ao_accel; -__pdata int16_t ao_max_height; -static __pdata int32_t ao_avg_height_scaled; -__pdata int16_t ao_avg_height; - -__pdata int16_t ao_error_h; -__pdata int16_t ao_error_h_sq_avg; - -#if HAS_ACCEL -__pdata int16_t ao_error_a; -#endif - -static void -ao_kalman_predict(void) -{ -#ifdef AO_FLIGHT_TEST - if (ao_sample_tick - ao_sample_prev_tick > 50) { - ao_k_height += ((int32_t) ao_speed * AO_K_STEP_1 + - (int32_t) ao_accel * AO_K_STEP_2_2_1) >> 4; - ao_k_speed += (int32_t) ao_accel * AO_K_STEP_1; - - return; - } - if (ao_sample_tick - ao_sample_prev_tick > 5) { - ao_k_height += ((int32_t) ao_speed * AO_K_STEP_10 + - (int32_t) ao_accel * AO_K_STEP_2_2_10) >> 4; - ao_k_speed += (int32_t) ao_accel * AO_K_STEP_10; - - return; - } - if (ao_flight_debug) { - printf ("predict speed %g + (%g * %g) = %g\n", - ao_k_speed / (65536.0 * 16.0), ao_accel / 16.0, AO_K_STEP_100 / 65536.0, - (ao_k_speed + (int32_t) ao_accel * AO_K_STEP_100) / (65536.0 * 16.0)); - } -#endif - ao_k_height += ((int32_t) ao_speed * AO_K_STEP_100 + - (int32_t) ao_accel * AO_K_STEP_2_2_100) >> 4; - ao_k_speed += (int32_t) ao_accel * AO_K_STEP_100; -} - -static void -ao_kalman_err_height(void) -{ - int16_t e; - int16_t height_distrust; -#if HAS_ACCEL - int16_t speed_distrust; -#endif - - ao_error_h = ao_sample_height - (int16_t) (ao_k_height >> 16); - - e = ao_error_h; - if (e < 0) - e = -e; - if (e > 127) - e = 127; -#if HAS_ACCEL - ao_error_h_sq_avg -= ao_error_h_sq_avg >> 2; - ao_error_h_sq_avg += (e * e) >> 2; -#else - ao_error_h_sq_avg -= ao_error_h_sq_avg >> 4; - ao_error_h_sq_avg += (e * e) >> 4; -#endif - - if (ao_flight_state >= ao_flight_drogue) - return; - height_distrust = ao_sample_alt - AO_MAX_BARO_HEIGHT; -#if HAS_ACCEL - /* speed is stored * 16, but we need to ramp between 200 and 328, so - * we want to multiply by 2. The result is a shift by 3. - */ - speed_distrust = (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) >> (4 - 1); - if (speed_distrust <= 0) - speed_distrust = 0; - else if (speed_distrust > height_distrust) - height_distrust = speed_distrust; -#endif - if (height_distrust > 0) { -#ifdef AO_FLIGHT_TEST - int old_ao_error_h = ao_error_h; -#endif - if (height_distrust > 0x100) - height_distrust = 0x100; - ao_error_h = (int16_t) (((int32_t) ao_error_h * (0x100 - height_distrust)) >> 8); -#ifdef AO_FLIGHT_TEST - if (ao_flight_debug) { - printf("over height %g over speed %g distrust: %g height: error %d -> %d\n", - (double) (ao_sample_alt - AO_MAX_BARO_HEIGHT), - (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) / 16.0, - height_distrust / 256.0, - old_ao_error_h, ao_error_h); - } -#endif - } -} - -static void -ao_kalman_correct_baro(void) -{ - ao_kalman_err_height(); -#ifdef AO_FLIGHT_TEST - if (ao_sample_tick - ao_sample_prev_tick > 50) { - ao_k_height += (int32_t) AO_BARO_K0_1 * ao_error_h; - ao_k_speed += (int32_t) AO_BARO_K1_1 * ao_error_h; - ao_k_accel += (int32_t) AO_BARO_K2_1 * ao_error_h; - return; - } - if (ao_sample_tick - ao_sample_prev_tick > 5) { - ao_k_height += (int32_t) AO_BARO_K0_10 * ao_error_h; - ao_k_speed += (int32_t) AO_BARO_K1_10 * ao_error_h; - ao_k_accel += (int32_t) AO_BARO_K2_10 * ao_error_h; - return; - } -#endif - ao_k_height += (int32_t) AO_BARO_K0_100 * ao_error_h; - ao_k_speed += (int32_t) AO_BARO_K1_100 * ao_error_h; - ao_k_accel += (int32_t) AO_BARO_K2_100 * ao_error_h; -} - -#if HAS_ACCEL - -static void -ao_kalman_err_accel(void) -{ - int32_t accel; - - accel = (ao_ground_accel - ao_sample_accel) * ao_accel_scale; - - /* Can't use ao_accel here as it is the pre-prediction value still */ - ao_error_a = (accel - ao_k_accel) >> 16; -} - -static void -ao_kalman_correct_both(void) -{ - ao_kalman_err_height(); - ao_kalman_err_accel(); - -#ifdef AO_FLIGHT_TEST - if (ao_sample_tick - ao_sample_prev_tick > 50) { - if (ao_flight_debug) { - printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n", - ao_k_speed / (65536.0 * 16.0), - (double) ao_error_h, AO_BOTH_K10_1 / 65536.0, - (double) ao_error_a, AO_BOTH_K11_1 / 65536.0, - (ao_k_speed + - (int32_t) AO_BOTH_K10_1 * ao_error_h + - (int32_t) AO_BOTH_K11_1 * ao_error_a) / (65536.0 * 16.0)); - } - ao_k_height += - (int32_t) AO_BOTH_K00_1 * ao_error_h + - (int32_t) AO_BOTH_K01_1 * ao_error_a; - ao_k_speed += - (int32_t) AO_BOTH_K10_1 * ao_error_h + - (int32_t) AO_BOTH_K11_1 * ao_error_a; - ao_k_accel += - (int32_t) AO_BOTH_K20_1 * ao_error_h + - (int32_t) AO_BOTH_K21_1 * ao_error_a; - return; - } - if (ao_sample_tick - ao_sample_prev_tick > 5) { - if (ao_flight_debug) { - printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n", - ao_k_speed / (65536.0 * 16.0), - (double) ao_error_h, AO_BOTH_K10_10 / 65536.0, - (double) ao_error_a, AO_BOTH_K11_10 / 65536.0, - (ao_k_speed + - (int32_t) AO_BOTH_K10_10 * ao_error_h + - (int32_t) AO_BOTH_K11_10 * ao_error_a) / (65536.0 * 16.0)); - } - ao_k_height += - (int32_t) AO_BOTH_K00_10 * ao_error_h + - (int32_t) AO_BOTH_K01_10 * ao_error_a; - ao_k_speed += - (int32_t) AO_BOTH_K10_10 * ao_error_h + - (int32_t) AO_BOTH_K11_10 * ao_error_a; - ao_k_accel += - (int32_t) AO_BOTH_K20_10 * ao_error_h + - (int32_t) AO_BOTH_K21_10 * ao_error_a; - return; - } - if (ao_flight_debug) { - printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n", - ao_k_speed / (65536.0 * 16.0), - (double) ao_error_h, AO_BOTH_K10_100 / 65536.0, - (double) ao_error_a, AO_BOTH_K11_100 / 65536.0, - (ao_k_speed + - (int32_t) AO_BOTH_K10_100 * ao_error_h + - (int32_t) AO_BOTH_K11_100 * ao_error_a) / (65536.0 * 16.0)); - } -#endif - ao_k_height += - (int32_t) AO_BOTH_K00_100 * ao_error_h + - (int32_t) AO_BOTH_K01_100 * ao_error_a; - ao_k_speed += - (int32_t) AO_BOTH_K10_100 * ao_error_h + - (int32_t) AO_BOTH_K11_100 * ao_error_a; - ao_k_accel += - (int32_t) AO_BOTH_K20_100 * ao_error_h + - (int32_t) AO_BOTH_K21_100 * ao_error_a; -} - -#ifdef FORCE_ACCEL -static void -ao_kalman_correct_accel(void) -{ - ao_kalman_err_accel(); - - if (ao_sample_tick - ao_sample_prev_tick > 5) { - ao_k_height +=(int32_t) AO_ACCEL_K0_10 * ao_error_a; - ao_k_speed += (int32_t) AO_ACCEL_K1_10 * ao_error_a; - ao_k_accel += (int32_t) AO_ACCEL_K2_10 * ao_error_a; - return; - } - ao_k_height += (int32_t) AO_ACCEL_K0_100 * ao_error_a; - ao_k_speed += (int32_t) AO_ACCEL_K1_100 * ao_error_a; - ao_k_accel += (int32_t) AO_ACCEL_K2_100 * ao_error_a; -} -#endif -#endif /* HAS_ACCEL */ - -void -ao_kalman(void) -{ - ao_kalman_predict(); -#if HAS_ACCEL - if (ao_flight_state <= ao_flight_coast) { -#ifdef FORCE_ACCEL - ao_kalman_correct_accel(); -#else - ao_kalman_correct_both(); -#endif - } else -#endif - ao_kalman_correct_baro(); - ao_height = from_fix(ao_k_height); - ao_speed = from_fix(ao_k_speed); - ao_accel = from_fix(ao_k_accel); - if (ao_height > ao_max_height) - ao_max_height = ao_height; - ao_avg_height_scaled = ao_avg_height_scaled - ao_avg_height + ao_sample_height; -#ifdef AO_FLIGHT_TEST - if (ao_sample_tick - ao_sample_prev_tick > 50) - ao_avg_height = (ao_avg_height_scaled + 1) >> 1; - else if (ao_sample_tick - ao_sample_prev_tick > 5) - ao_avg_height = (ao_avg_height_scaled + 7) >> 4; - else -#endif - ao_avg_height = (ao_avg_height_scaled + 63) >> 7; -#ifdef AO_FLIGHT_TEST - ao_sample_prev_tick = ao_sample_tick; -#endif -} diff --git a/src/ao_led.c b/src/ao_led.c deleted file mode 100644 index 5beed58d..00000000 --- a/src/ao_led.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -__pdata uint8_t ao_led_enable; - -void -ao_led_on(uint8_t colors) -{ - P1 |= (colors & ao_led_enable); -} - -void -ao_led_off(uint8_t colors) -{ - P1 &= ~(colors & ao_led_enable); -} - -void -ao_led_set(uint8_t colors) -{ - P1 = (P1 & ~(ao_led_enable)) | (colors & ao_led_enable); -} - -void -ao_led_toggle(uint8_t colors) -{ - P1 ^= (colors & ao_led_enable); -} - -void -ao_led_for(uint8_t colors, uint16_t ticks) __reentrant -{ - ao_led_on(colors); - ao_delay(ticks); - ao_led_off(colors); -} - -void -ao_led_init(uint8_t enable) -{ - ao_led_enable = enable; - P1SEL &= ~enable; - P1 &= ~enable; - P1DIR |= enable; -} diff --git a/src/ao_log.c b/src/ao_log.c deleted file mode 100644 index 6d3ad535..00000000 --- a/src/ao_log.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -__pdata uint32_t ao_log_current_pos; -__pdata uint32_t ao_log_end_pos; -__pdata uint32_t ao_log_start_pos; -__xdata uint8_t ao_log_running; -__pdata enum flight_state ao_log_state; -__xdata uint16_t ao_flight_number; - -__code uint8_t ao_log_format = AO_LOG_FORMAT_FULL; - -void -ao_log_flush(void) -{ - ao_storage_flush(); -} - -/* - * When erasing a flight log, make sure the config block - * has an up-to-date version of the current flight number - */ - -struct ao_log_erase { - uint8_t unused; - uint16_t flight; -}; - -static __xdata struct ao_log_erase erase; - -#define LOG_MAX_ERASE 16 - -static uint32_t -ao_log_erase_pos(uint8_t i) -{ - return i * sizeof (struct ao_log_erase) + AO_STORAGE_ERASE_LOG; -} - -void -ao_log_write_erase(uint8_t pos) -{ - erase.unused = 0x00; - erase.flight = ao_flight_number; - ao_storage_write(ao_log_erase_pos(pos), &erase, sizeof (erase)); - ao_storage_flush(); -} - -static void -ao_log_read_erase(uint8_t pos) -{ - ao_storage_read(ao_log_erase_pos(pos), &erase, sizeof (erase)); -} - - -static void -ao_log_erase_mark(void) -{ - uint8_t i; - - for (i = 0; i < LOG_MAX_ERASE; i++) { - ao_log_read_erase(i); - if (erase.unused == 0 && erase.flight == ao_flight_number) - return; - if (erase.unused == 0xff) { - ao_log_write_erase(i); - return; - } - } - ao_config_put(); -} - -static uint8_t -ao_log_slots() -{ - return (uint8_t) (ao_storage_config / ao_config.flight_log_max); -} - -uint32_t -ao_log_pos(uint8_t slot) -{ - return ((slot) * ao_config.flight_log_max); -} - -static uint16_t -ao_log_max_flight(void) -{ - uint8_t log_slot; - uint8_t log_slots; - uint16_t log_flight; - uint16_t max_flight = 0; - - /* Scan the log space looking for the biggest flight number */ - log_slots = ao_log_slots(); - for (log_slot = 0; log_slot < log_slots; log_slot++) { - log_flight = ao_log_flight(log_slot); - if (!log_flight) - continue; - if (max_flight == 0 || (int16_t) (log_flight - max_flight) > 0) - max_flight = log_flight; - } - return max_flight; -} - -void -ao_log_scan(void) __reentrant -{ - uint8_t log_slot; - uint8_t log_slots; - uint8_t log_want; - - ao_config_get(); - - ao_flight_number = ao_log_max_flight(); - if (ao_flight_number) - if (++ao_flight_number == 0) - ao_flight_number = 1; - - /* Now look through the log of flight numbers from erase operations and - * see if the last one is bigger than what we found above - */ - for (log_slot = LOG_MAX_ERASE; log_slot-- > 0;) { - ao_log_read_erase(log_slot); - if (erase.unused == 0) { - if (ao_flight_number == 0 || - (int16_t) (erase.flight - ao_flight_number) > 0) - ao_flight_number = erase.flight; - break; - } - } - if (ao_flight_number == 0) - ao_flight_number = 1; - - /* With a flight number in hand, find a place to write a new log, - * use the target flight number to index the available log slots so - * that we write logs to each spot about the same number of times. - */ - - /* Find a log slot for the next flight, if available */ - ao_log_current_pos = ao_log_end_pos = 0; - log_slots = ao_log_slots(); - log_want = (ao_flight_number - 1) % log_slots; - log_slot = log_want; - do { - if (ao_log_flight(log_slot) == 0) { - ao_log_current_pos = ao_log_pos(log_slot); - ao_log_end_pos = ao_log_current_pos + ao_config.flight_log_max; - break; - } - if (++log_slot >= log_slots) - log_slot = 0; - } while (log_slot != log_want); - - ao_wakeup(&ao_flight_number); -} - -void -ao_log_start(void) -{ - /* start logging */ - ao_log_running = 1; - ao_wakeup(&ao_log_running); -} - -void -ao_log_stop(void) -{ - ao_log_running = 0; - ao_log_flush(); -} - -uint8_t -ao_log_present(void) -{ - return ao_log_max_flight() != 0; -} - -uint8_t -ao_log_full(void) -{ - return ao_log_current_pos == ao_log_end_pos; -} - -static __xdata struct ao_task ao_log_task; - -void -ao_log_list(void) __reentrant -{ - uint8_t slot; - uint8_t slots; - uint16_t flight; - - slots = ao_log_slots(); - for (slot = 0; slot < slots; slot++) - { - flight = ao_log_flight(slot); - if (flight) - printf ("flight %d start %x end %x\n", - flight, - (uint16_t) (ao_log_pos(slot) >> 8), - (uint16_t) (ao_log_pos(slot+1) >> 8)); - } - printf ("done\n"); -} - -void -ao_log_delete(void) __reentrant -{ - uint8_t slot; - uint8_t slots; - - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - - slots = ao_log_slots(); - /* Look for the flight log matching the requested flight */ - if (ao_cmd_lex_i) { - for (slot = 0; slot < slots; slot++) { - if (ao_log_flight(slot) == ao_cmd_lex_i) { - ao_log_erase_mark(); - ao_log_current_pos = ao_log_pos(slot); - ao_log_end_pos = ao_log_current_pos + ao_config.flight_log_max; - while (ao_log_current_pos < ao_log_end_pos) { - uint8_t i; - static __xdata uint8_t b; - - /* - * Check to see if we've reached the end of - * the used memory to avoid re-erasing the same - * memory over and over again - */ - for (i = 0; i < 16; i++) { - if (ao_storage_read(ao_log_current_pos + i, &b, 1)) - if (b != 0xff) - break; - } - if (i == 16) - break; - ao_storage_erase(ao_log_current_pos); - ao_log_current_pos += ao_storage_block; - } - puts("Erased"); - return; - } - } - } - printf("No such flight: %d\n", ao_cmd_lex_i); -} - -__code struct ao_cmds ao_log_cmds[] = { - { ao_log_list, "l\0List flight logs" }, - { ao_log_delete, "d \0Delete flight" }, - { 0, NULL }, -}; - -void -ao_log_init(void) -{ - ao_log_running = 0; - - /* For now, just log the flight starting at the begining of eeprom */ - ao_log_state = ao_flight_invalid; - - ao_cmd_register(&ao_log_cmds[0]); - - /* Create a task to log events to eeprom */ - ao_add_task(&ao_log_task, ao_log, "log"); -} diff --git a/src/ao_log_big.c b/src/ao_log_big.c deleted file mode 100644 index 74d94c4b..00000000 --- a/src/ao_log_big.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -static __xdata uint8_t ao_log_mutex; -static __xdata struct ao_log_record log; - -static uint8_t -ao_log_csum(__xdata uint8_t *b) __reentrant -{ - uint8_t sum = 0x5a; - uint8_t i; - - for (i = 0; i < sizeof (struct ao_log_record); i++) - sum += *b++; - return -sum; -} - -uint8_t -ao_log_data(__xdata struct ao_log_record *log) __reentrant -{ - uint8_t wrote = 0; - /* set checksum */ - log->csum = 0; - log->csum = ao_log_csum((__xdata uint8_t *) log); - ao_mutex_get(&ao_log_mutex); { - if (ao_log_current_pos >= ao_log_end_pos && ao_log_running) - ao_log_stop(); - if (ao_log_running) { - wrote = 1; - ao_storage_write(ao_log_current_pos, - log, - sizeof (struct ao_log_record)); - ao_log_current_pos += sizeof (struct ao_log_record); - } - } ao_mutex_put(&ao_log_mutex); - return wrote; -} - -static uint8_t -ao_log_dump_check_data(void) -{ - if (ao_log_csum((uint8_t *) &log) != 0) - return 0; - return 1; -} - -static __data uint8_t ao_log_adc_pos; - -/* a hack to make sure that ao_log_records fill the eeprom block in even units */ -typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_record))] ; - -#define AO_SENSOR_INTERVAL_ASCENT 1 -#define AO_SENSOR_INTERVAL_DESCENT 10 -#define AO_OTHER_INTERVAL 32 - -void -ao_log(void) -{ - __pdata uint16_t next_sensor, next_other; - - ao_storage_setup(); - - ao_log_scan(); - - while (!ao_log_running) - ao_sleep(&ao_log_running); - - log.type = AO_LOG_FLIGHT; - log.tick = ao_sample_tick; -#if HAS_ACCEL - log.u.flight.ground_accel = ao_ground_accel; -#endif - log.u.flight.flight = ao_flight_number; - ao_log_data(&log); - - /* Write the whole contents of the ring to the log - * when starting up. - */ - ao_log_adc_pos = ao_adc_ring_next(ao_sample_adc); - next_other = next_sensor = ao_adc_ring[ao_log_adc_pos].tick; - ao_log_state = ao_flight_startup; - for (;;) { - /* Write samples to EEPROM */ - while (ao_log_adc_pos != ao_sample_adc) { - log.tick = ao_adc_ring[ao_log_adc_pos].tick; - if ((int16_t) (log.tick - next_sensor) >= 0) { - log.type = AO_LOG_SENSOR; - log.u.sensor.accel = ao_adc_ring[ao_log_adc_pos].accel; - log.u.sensor.pres = ao_adc_ring[ao_log_adc_pos].pres; - ao_log_data(&log); - if (ao_log_state <= ao_flight_coast) - next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT; - else - next_sensor = log.tick + AO_SENSOR_INTERVAL_DESCENT; - } - if ((int16_t) (log.tick - next_other) >= 0) { - log.type = AO_LOG_TEMP_VOLT; - log.u.temp_volt.temp = ao_adc_ring[ao_log_adc_pos].temp; - log.u.temp_volt.v_batt = ao_adc_ring[ao_log_adc_pos].v_batt; - ao_log_data(&log); - log.type = AO_LOG_DEPLOY; - log.u.deploy.drogue = ao_adc_ring[ao_log_adc_pos].sense_d; - log.u.deploy.main = ao_adc_ring[ao_log_adc_pos].sense_m; - ao_log_data(&log); - next_other = log.tick + AO_OTHER_INTERVAL; - } - ao_log_adc_pos = ao_adc_ring_next(ao_log_adc_pos); - } - /* Write state change to EEPROM */ - if (ao_flight_state != ao_log_state) { - ao_log_state = ao_flight_state; - log.type = AO_LOG_STATE; - log.tick = ao_sample_tick; - log.u.state.state = ao_log_state; - log.u.state.reason = 0; - ao_log_data(&log); - - if (ao_log_state == ao_flight_landed) - ao_log_stop(); - } - - /* Wait for a while */ - ao_delay(AO_MS_TO_TICKS(100)); - - /* Stop logging when told to */ - while (!ao_log_running) - ao_sleep(&ao_log_running); - } -} - -uint16_t -ao_log_flight(uint8_t slot) -{ - if (!ao_storage_read(ao_log_pos(slot), - &log, - sizeof (struct ao_log_record))) - return 0; - - if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT) - return log.u.flight.flight; - return 0; -} diff --git a/src/ao_log_telem.c b/src/ao_log_telem.c deleted file mode 100644 index 1b472efe..00000000 --- a/src/ao_log_telem.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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_log_write_erase(uint8_t pos) -{ - (void) pos; -} - -uint8_t -ao_log_present(void) -{ - return 0; -} diff --git a/src/ao_log_tiny.c b/src/ao_log_tiny.c deleted file mode 100644 index d5a3b99f..00000000 --- a/src/ao_log_tiny.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -static __data uint16_t ao_log_tiny_interval; - -#define AO_LOG_TINY_INTERVAL_DEFAULT AO_MS_TO_TICKS(1000) -#if USE_FAST_ASCENT_LOG -#define AO_LOG_TINY_INTERVAL_ASCENT AO_MS_TO_TICKS(100) -#define AO_PAD_RING 8 -#else -#define AO_LOG_TINY_INTERVAL_ASCENT AO_LOG_TINY_INTERVAL_DEFAULT -#define AO_PAD_RING 2 -#endif - -__code uint8_t ao_log_format = AO_LOG_FORMAT_TINY; - -void -ao_log_tiny_set_interval(uint16_t ticks) -{ - ao_log_tiny_interval = ticks; -} - - -static void ao_log_tiny_data(uint16_t d) -{ - if (ao_log_current_pos >= ao_log_end_pos && ao_log_running) - ao_log_stop(); - if (ao_log_running) { - ao_storage_write(ao_log_current_pos, DATA_TO_XDATA(&d), 2); - ao_log_current_pos += 2; - } -} - -static __xdata uint16_t ao_log_pad_ring[AO_PAD_RING]; -static __pdata uint8_t ao_log_pad_ring_pos; - -#define ao_pad_ring_next(n) (((n) + 1) & (AO_PAD_RING - 1)) - -static void ao_log_tiny_queue(uint16_t d) -{ - ao_log_pad_ring[ao_log_pad_ring_pos] = d; - ao_log_pad_ring_pos = ao_pad_ring_next(ao_log_pad_ring_pos); -} - -static void ao_log_tiny_start(void) -{ - uint8_t p; - uint16_t d; - - ao_log_tiny_data(ao_flight_number); - ao_log_tiny_data(ao_ground_pres); - p = ao_log_pad_ring_pos; - do { - d = ao_log_pad_ring[p]; - /* - * ignore unwritten slots - */ - if (d) - ao_log_tiny_data(d); - p = ao_pad_ring_next(p); - } while (p != ao_log_pad_ring_pos); -} - -void -ao_log(void) -{ - uint16_t last_time; - uint16_t now; - enum ao_flight_state ao_log_tiny_state; - int32_t sum; - int16_t count; - uint8_t ao_log_adc; - uint8_t ao_log_started = 0; - - ao_storage_setup(); - - ao_log_scan(); - - ao_log_tiny_state = ao_flight_invalid; - ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_ASCENT; - sum = 0; - count = 0; - ao_log_adc = ao_sample_adc; - last_time = ao_time(); - for (;;) { - - /* - * Add in pending sample data - */ - ao_sleep(DATA_TO_XDATA(&ao_sample_adc)); - while (ao_log_adc != ao_sample_adc) { - sum += ao_adc_ring[ao_log_adc].pres; - count++; - ao_log_adc = ao_adc_ring_next(ao_log_adc); - } - if (ao_log_running) { - if (!ao_log_started) { - ao_log_tiny_start(); - ao_log_started = 1; - } - if (ao_flight_state != ao_log_tiny_state) { - ao_log_tiny_data(ao_flight_state | 0x8000); - ao_log_tiny_state = ao_flight_state; - ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_DEFAULT; -#if AO_LOG_TINY_INTERVAL_ASCENT != AO_LOG_TINY_INTERVAL_DEFAULT - if (ao_log_tiny_state <= ao_flight_coast) - ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_ASCENT; -#endif - if (ao_log_tiny_state == ao_flight_landed) - ao_log_stop(); - } - } - - /* Stop logging when told to */ - if (!ao_log_running && ao_log_started) - ao_exit(); - - /* - * Write out the sample when finished - */ - now = ao_time(); - if ((int16_t) (now - (last_time + ao_log_tiny_interval)) >= 0 && count) { - count = sum / count; - if (ao_log_started) - ao_log_tiny_data(count); - else - ao_log_tiny_queue(count); - sum = 0; - count = 0; - last_time = now; - } - } -} - -uint16_t -ao_log_flight(uint8_t slot) -{ - static __xdata uint16_t flight; - - (void) slot; - ao_storage_read(0, &flight, 2); - if (flight == 0xffff) - flight = 0; - return flight; -} diff --git a/src/ao_m25.c b/src/ao_m25.c deleted file mode 100644 index d7208273..00000000 --- a/src/ao_m25.c +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -/* Total bytes of available storage */ -__pdata uint32_t ao_storage_total; - -/* Block size - device is erased in these units. At least 256 bytes */ -__pdata uint32_t ao_storage_block; - -/* Byte offset of config block. Will be ao_storage_block bytes long */ -__pdata uint32_t ao_storage_config; - -/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */ -__pdata uint16_t ao_storage_unit; - -/* - * Each flash chip is arranged in 64kB sectors; the - * chip cannot erase in units smaller than that. - * - * Writing happens in units of 256 byte pages and - * can only change bits from 1 to 0. So, you can rewrite - * the same contents, or append to an existing page easily enough - */ - -#define M25_WREN 0x06 /* Write Enable */ -#define M25_WRDI 0x04 /* Write Disable */ -#define M25_RDID 0x9f /* Read Identification */ -#define M25_RDSR 0x05 /* Read Status Register */ -#define M25_WRSR 0x01 /* Write Status Register */ -#define M25_READ 0x03 /* Read Data Bytes */ -#define M25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ -#define M25_PP 0x02 /* Page Program */ -#define M25_SE 0xd8 /* Sector Erase */ -#define M25_BE 0xc7 /* Bulk Erase */ -#define M25_DP 0xb9 /* Deep Power-down */ - -/* RDID response */ -#define M25_MANUF_OFFSET 0 -#define M25_MEMORY_TYPE_OFFSET 1 -#define M25_CAPACITY_OFFSET 2 -#define M25_UID_OFFSET 3 -#define M25_CFI_OFFSET 4 -#define M25_RDID_LEN 4 /* that's all we need */ - -#define M25_CAPACITY_128KB 0x11 -#define M25_CAPACITY_256KB 0x12 -#define M25_CAPACITY_512KB 0x13 -#define M25_CAPACITY_1MB 0x14 -#define M25_CAPACITY_2MB 0x15 - -/* - * Status register bits - */ - -#define M25_STATUS_SRWD (1 << 7) /* Status register write disable */ -#define M25_STATUS_BP_MASK (7 << 2) /* Block protect bits */ -#define M25_STATUS_BP_SHIFT (2) -#define M25_STATUS_WEL (1 << 1) /* Write enable latch */ -#define M25_STATUS_WIP (1 << 0) /* Write in progress */ - -/* - * On teleterra, the m25 chip select pins are - * wired on P0_0 through P0_3. - */ - -#if M25_MAX_CHIPS > 1 -static uint8_t ao_m25_size[M25_MAX_CHIPS]; /* number of sectors in each chip */ -static uint8_t ao_m25_pin[M25_MAX_CHIPS]; /* chip select pin for each chip */ -static uint8_t ao_m25_numchips; /* number of chips detected */ -#endif -static uint8_t ao_m25_total; /* total sectors available */ -static uint8_t ao_m25_wip; /* write in progress */ - -static __xdata uint8_t ao_m25_mutex; - -/* - * This little array is abused to send and receive data. A particular - * caution -- the read and write addresses are written into the last - * three bytes of the array by ao_m25_set_page_address and then the - * first byte is used by ao_m25_wait_wip and ao_m25_write_enable, neither - * of which touch those last three bytes. - */ - -static __xdata uint8_t ao_m25_instruction[4]; - -#define M25_SELECT(cs) ao_spi_get_mask(SPI_CS_PORT,cs) -#define M25_DESELECT(cs) ao_spi_put_mask(SPI_CS_PORT,cs) - -#define M25_BLOCK_SHIFT 16 -#define M25_BLOCK 65536L -#define M25_POS_TO_SECTOR(pos) ((uint8_t) ((pos) >> M25_BLOCK_SHIFT)) -#define M25_SECTOR_TO_POS(sector) (((uint32_t) (sector)) << M25_BLOCK_SHIFT) - -/* - * Block until the specified chip is done writing - */ -static void -ao_m25_wait_wip(uint8_t cs) -{ - if (ao_m25_wip & cs) { - M25_SELECT(cs); - ao_m25_instruction[0] = M25_RDSR; - ao_spi_send(ao_m25_instruction, 1); - do { - ao_spi_recv(ao_m25_instruction, 1); - } while (ao_m25_instruction[0] & M25_STATUS_WIP); - M25_DESELECT(cs); - ao_m25_wip &= ~cs; - } -} - -/* - * Set the write enable latch so that page program and sector - * erase commands will work. Also mark the chip as busy writing - * so that future operations will block until the WIP bit goes off - */ -static void -ao_m25_write_enable(uint8_t cs) -{ - M25_SELECT(cs); - ao_m25_instruction[0] = M25_WREN; - ao_spi_send(&ao_m25_instruction, 1); - M25_DESELECT(cs); - ao_m25_wip |= cs; -} - - -/* - * Returns the number of 64kB sectors - */ -static uint8_t -ao_m25_read_capacity(uint8_t cs) -{ - uint8_t capacity; - M25_SELECT(cs); - ao_m25_instruction[0] = M25_RDID; - ao_spi_send(ao_m25_instruction, 1); - ao_spi_recv(ao_m25_instruction, M25_RDID_LEN); - M25_DESELECT(cs); - - /* Check to see if the chip is present */ - if (ao_m25_instruction[0] == 0xff) - return 0; - capacity = ao_m25_instruction[M25_CAPACITY_OFFSET]; - - /* Sanity check capacity number */ - if (capacity < 0x11 || 0x1f < capacity) - return 0; - return 1 << (capacity - 0x10); -} - -static uint8_t -ao_m25_set_address(uint32_t pos) -{ - uint8_t chip; -#if M25_MAX_CHIPS > 1 - uint8_t size; - - for (chip = 0; chip < ao_m25_numchips; chip++) { - size = ao_m25_size[chip]; - if (M25_POS_TO_SECTOR(pos) < size) - break; - pos -= M25_SECTOR_TO_POS(size); - } - if (chip == ao_m25_numchips) - return 0xff; - - chip = ao_m25_pin[chip]; -#else - chip = M25_CS_MASK; -#endif - ao_m25_wait_wip(chip); - - ao_m25_instruction[1] = pos >> 16; - ao_m25_instruction[2] = pos >> 8; - ao_m25_instruction[3] = pos; - return chip; -} - -/* - * Scan the possible chip select lines - * to see which flash chips are connected - */ -static uint8_t -ao_m25_scan(void) -{ -#if M25_MAX_CHIPS > 1 - uint8_t pin, size; -#endif - - if (ao_m25_total) - return 1; - -#if M25_MAX_CHIPS > 1 - ao_m25_numchips = 0; - for (pin = 1; pin != 0; pin <<= 1) { - if (M25_CS_MASK & pin) { - size = ao_m25_read_capacity(pin); - if (size != 0) { - ao_m25_size[ao_m25_numchips] = size; - ao_m25_pin[ao_m25_numchips] = pin; - ao_m25_total += size; - ao_m25_numchips++; - } - } - } -#else - ao_m25_total = ao_m25_read_capacity(M25_CS_MASK); -#endif - if (!ao_m25_total) - return 0; - ao_storage_total = M25_SECTOR_TO_POS(ao_m25_total); - ao_storage_block = M25_BLOCK; - ao_storage_config = ao_storage_total - M25_BLOCK; - ao_storage_unit = 256; - return 1; -} - -/* - * Erase the specified sector - */ -uint8_t -ao_storage_erase(uint32_t pos) __reentrant -{ - uint8_t cs; - - if (pos >= ao_storage_total || pos + ao_storage_block > ao_storage_total) - return 0; - - ao_mutex_get(&ao_m25_mutex); - ao_m25_scan(); - - cs = ao_m25_set_address(pos); - - ao_m25_wait_wip(cs); - ao_m25_write_enable(cs); - - ao_m25_instruction[0] = M25_SE; - M25_SELECT(cs); - ao_spi_send(ao_m25_instruction, 4); - M25_DESELECT(cs); - ao_m25_wip |= cs; - - ao_mutex_put(&ao_m25_mutex); - return 1; -} - -/* - * Write to flash - */ -uint8_t -ao_storage_device_write(uint32_t pos, __xdata void *d, uint16_t len) __reentrant -{ - uint8_t cs; - - if (pos >= ao_storage_total || pos + len > ao_storage_total) - return 0; - - ao_mutex_get(&ao_m25_mutex); - ao_m25_scan(); - - cs = ao_m25_set_address(pos); - ao_m25_write_enable(cs); - - ao_m25_instruction[0] = M25_PP; - M25_SELECT(cs); - ao_spi_send(ao_m25_instruction, 4); - ao_spi_send(d, len); - M25_DESELECT(cs); - - ao_mutex_put(&ao_m25_mutex); - return 1; -} - -/* - * Read from flash - */ -uint8_t -ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant -{ - uint8_t cs; - - if (pos >= ao_storage_total || pos + len > ao_storage_total) - return 0; - ao_mutex_get(&ao_m25_mutex); - ao_m25_scan(); - - cs = ao_m25_set_address(pos); - - /* No need to use the FAST_READ as we're running at only 8MHz */ - ao_m25_instruction[0] = M25_READ; - M25_SELECT(cs); - ao_spi_send(ao_m25_instruction, 4); - ao_spi_recv(d, len); - M25_DESELECT(cs); - - ao_mutex_put(&ao_m25_mutex); - return 1; -} - -void -ao_storage_flush(void) __reentrant -{ -} - -void -ao_storage_setup(void) -{ - ao_mutex_get(&ao_m25_mutex); - ao_m25_scan(); - ao_mutex_put(&ao_m25_mutex); -} - -void -ao_storage_device_info(void) __reentrant -{ - uint8_t cs; -#if M25_MAX_CHIPS > 1 - uint8_t chip; -#endif - - ao_mutex_get(&ao_m25_mutex); - ao_m25_scan(); - ao_mutex_put(&ao_m25_mutex); - -#if M25_MAX_CHIPS > 1 - printf ("Detected chips %d size %d\n", ao_m25_numchips, ao_m25_total); - for (chip = 0; chip < ao_m25_numchips; chip++) - printf ("Flash chip %d select %02x size %d\n", - chip, ao_m25_pin[chip], ao_m25_size[chip]); -#else - printf ("Detected chips 1 size %d\n", ao_m25_total); -#endif - - printf ("Available chips:\n"); - for (cs = 1; cs != 0; cs <<= 1) { - if ((M25_CS_MASK & cs) == 0) - continue; - - ao_mutex_get(&ao_m25_mutex); - M25_SELECT(cs); - ao_m25_instruction[0] = M25_RDID; - ao_spi_send(ao_m25_instruction, 1); - ao_spi_recv(ao_m25_instruction, M25_RDID_LEN); - M25_DESELECT(cs); - - printf ("Select %02x manf %02x type %02x cap %02x uid %02x\n", - cs, - ao_m25_instruction[M25_MANUF_OFFSET], - ao_m25_instruction[M25_MEMORY_TYPE_OFFSET], - ao_m25_instruction[M25_CAPACITY_OFFSET], - ao_m25_instruction[M25_UID_OFFSET]); - ao_mutex_put(&ao_m25_mutex); - } -} - -void -ao_storage_device_init(void) -{ - /* Set up chip select wires */ - SPI_CS_PORT |= M25_CS_MASK; /* raise all CS pins */ - SPI_CS_DIR |= M25_CS_MASK; /* set CS pins as outputs */ - SPI_CS_SEL &= ~M25_CS_MASK; /* set CS pins as GPIO */ -} diff --git a/src/ao_main.c b/src/ao_main.c deleted file mode 100644 index 25acccfc..00000000 --- a/src/ao_main.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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) -{ - ao_clock_init(); - - /* 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(); -} diff --git a/src/ao_monitor.c b/src/ao_monitor.c deleted file mode 100644 index 69eb58e8..00000000 --- a/src/ao_monitor.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" -#include "ao_telem.h" - -#if !HAS_MONITOR -#error Must define HAS_MONITOR to 1 -#endif - -__xdata uint8_t ao_monitoring; -__pdata uint8_t ao_monitor_led; - -#define AO_MONITOR_RING 8 - -__xdata union ao_monitor { - struct ao_telemetry_raw_recv raw; - struct ao_telemetry_orig_recv orig; - struct ao_telemetry_tiny_recv tiny; -} ao_monitor_ring[AO_MONITOR_RING]; - -#define ao_monitor_ring_next(n) (((n) + 1) & (AO_MONITOR_RING - 1)) - -__data uint8_t ao_monitor_head; - -void -ao_monitor_get(void) -{ - uint8_t size; - - for (;;) { - switch (ao_monitoring) { - case 0: - ao_sleep(&ao_monitoring); - continue; - case AO_MONITORING_ORIG: - size = sizeof (struct ao_telemetry_orig_recv); - break; - case AO_MONITORING_TINY: - size = sizeof (struct ao_telemetry_tiny_recv); - break; - default: - if (ao_monitoring > AO_MAX_TELEMETRY) - ao_monitoring = AO_MAX_TELEMETRY; - size = ao_monitoring; - break; - } - if (!ao_radio_recv(&ao_monitor_ring[ao_monitor_head], size + 2)) - continue; - ao_monitor_head = ao_monitor_ring_next(ao_monitor_head); - ao_wakeup(DATA_TO_XDATA(&ao_monitor_head)); - ao_led_toggle(ao_monitor_led); - } -} - -void -ao_monitor_put(void) -{ - __xdata char callsign[AO_MAX_CALLSIGN+1]; - - uint8_t ao_monitor_tail; - uint8_t state; - uint8_t sum, byte; - int16_t rssi; - __xdata union ao_monitor *m; - -#define recv_raw ((m->raw)) -#define recv_orig ((m->orig)) -#define recv_tiny ((m->tiny)) - - ao_monitor_tail = ao_monitor_head; - for (;;) { - while (ao_monitor_tail == ao_monitor_head) - ao_sleep(DATA_TO_XDATA(&ao_monitor_head)); - m = &ao_monitor_ring[ao_monitor_tail]; - ao_monitor_tail = ao_monitor_ring_next(ao_monitor_tail); - switch (ao_monitoring) { - case AO_MONITORING_ORIG: - state = recv_orig.telemetry_orig.flight_state; - - /* Typical RSSI offset for 38.4kBaud at 433 MHz is 74 */ - rssi = (int16_t) (recv_orig.rssi >> 1) - 74; - memcpy(callsign, recv_orig.telemetry_orig.callsign, AO_MAX_CALLSIGN); - if (state > ao_flight_invalid) - state = ao_flight_invalid; - if (recv_orig.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_orig.telemetry_orig.serial, - recv_orig.telemetry_orig.flight, - rssi, - ao_state_names[state], - recv_orig.telemetry_orig.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_orig.telemetry_orig.adc.accel, - recv_orig.telemetry_orig.adc.pres, - recv_orig.telemetry_orig.adc.temp, - recv_orig.telemetry_orig.adc.v_batt, - recv_orig.telemetry_orig.adc.sense_d, - recv_orig.telemetry_orig.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_orig.telemetry_orig.ground_accel, - recv_orig.telemetry_orig.ground_pres, - recv_orig.telemetry_orig.accel_plus_g, - recv_orig.telemetry_orig.accel_minus_g); - - if (recv_orig.telemetry_orig.u.k.unused == 0x8000) { - /* Kalman state values */ - printf(AO_TELEM_KALMAN_HEIGHT " %d " - AO_TELEM_KALMAN_SPEED " %d " - AO_TELEM_KALMAN_ACCEL " %d ", - recv_orig.telemetry_orig.height, - recv_orig.telemetry_orig.u.k.speed, - recv_orig.telemetry_orig.accel); - } else { - /* Ad-hoc flight values */ - printf(AO_TELEM_ADHOC_ACCEL " %d " - AO_TELEM_ADHOC_SPEED " %ld " - AO_TELEM_ADHOC_BARO " %d ", - recv_orig.telemetry_orig.accel, - recv_orig.telemetry_orig.u.flight_vel, - recv_orig.telemetry_orig.height); - } - ao_gps_print(&recv_orig.telemetry_orig.gps); - ao_gps_tracking_print(&recv_orig.telemetry_orig.gps_tracking); - putchar('\n'); - ao_rssi_set(rssi); - } else { - printf("CRC INVALID RSSI %3d\n", rssi); - } - break; - case AO_MONITORING_TINY: - 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); - } - break; - default: - printf ("TELEM %02x", ao_monitoring + 2); - sum = 0x5a; - for (state = 0; state < ao_monitoring + 2; state++) { - byte = recv_raw.packet[state]; - sum += byte; - printf("%02x", byte); - } - printf("%02x\n", sum); - break; - } - ao_usb_flush(); - } -} - -__xdata struct ao_task ao_monitor_get_task; -__xdata struct ao_task ao_monitor_put_task; - -void -ao_set_monitor(uint8_t monitoring) -{ - if (ao_monitoring) - ao_radio_recv_abort(); - ao_monitoring = monitoring; - ao_wakeup(&ao_monitoring); -} - -static void -set_monitor(void) -{ - ao_cmd_hex(); - ao_set_monitor(ao_cmd_lex_i); -} - -__code struct ao_cmds ao_monitor_cmds[] = { - { set_monitor, "m <0 off, 1 full, 2 tiny>\0Enable/disable radio monitoring" }, - { 0, NULL }, -}; - -void -ao_monitor_init(uint8_t monitor_led, uint8_t monitoring) __reentrant -{ - ao_monitor_led = monitor_led; - ao_monitoring = monitoring; - ao_cmd_register(&ao_monitor_cmds[0]); - ao_add_task(&ao_monitor_get_task, ao_monitor_get, "monitor_get"); - ao_add_task(&ao_monitor_put_task, ao_monitor_put, "monitor_put"); -} diff --git a/src/ao_mutex.c b/src/ao_mutex.c deleted file mode 100644 index c82a7d57..00000000 --- a/src/ao_mutex.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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_mutex_get(__xdata uint8_t *mutex) __reentrant -{ - if (*mutex == ao_cur_task->task_id) - ao_panic(AO_PANIC_MUTEX); - __critical { - while (*mutex) - ao_sleep(mutex); - *mutex = ao_cur_task->task_id; - } -} - -void -ao_mutex_put(__xdata uint8_t *mutex) __reentrant -{ - if (*mutex != ao_cur_task->task_id) - ao_panic(AO_PANIC_MUTEX); - __critical { - *mutex = 0; - ao_wakeup(mutex); - } -} diff --git a/src/ao_packet.c b/src/ao_packet.c deleted file mode 100644 index f627e02b..00000000 --- a/src/ao_packet.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -__xdata struct ao_packet_recv ao_rx_packet; -__xdata struct ao_packet ao_tx_packet; -__pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used; - -static __xdata char tx_data[AO_PACKET_MAX]; -static __xdata char rx_data[AO_PACKET_MAX]; -static __pdata uint8_t rx_seq; - -__xdata struct ao_task ao_packet_task; -__xdata uint8_t ao_packet_enable; -__xdata uint8_t ao_packet_master_sleeping; - -void -ao_packet_send(void) -{ - ao_led_on(AO_LED_RED); - /* If any tx data is pending then copy it into the tx packet */ - if (ao_packet_tx_used && ao_tx_packet.len == 0) { - memcpy(&ao_tx_packet.d, tx_data, ao_packet_tx_used); - ao_tx_packet.len = ao_packet_tx_used; - ao_tx_packet.seq++; - ao_packet_tx_used = 0; - ao_wakeup(&tx_data); - } - ao_radio_send(&ao_tx_packet, sizeof (ao_tx_packet)); - ao_led_off(AO_LED_RED); -} - -uint8_t -ao_packet_recv(void) -{ - uint8_t dma_done; - -#ifdef AO_LED_GREEN - ao_led_on(AO_LED_GREEN); -#endif - dma_done = ao_radio_recv(&ao_rx_packet, sizeof (struct ao_packet_recv)); -#ifdef AO_LED_GREEN - ao_led_off(AO_LED_GREEN); -#endif - - /* Check to see if we got a valid packet */ - if (!dma_done) - return 0; - if (!(ao_rx_packet.status & PKT_APPEND_STATUS_1_CRC_OK)) - return 0; - - /* SYN packets carry no data */ - if (ao_rx_packet.packet.len == AO_PACKET_SYN) { - rx_seq = ao_rx_packet.packet.seq; - ao_tx_packet.seq = ao_rx_packet.packet.ack; - ao_tx_packet.ack = rx_seq; - } else if (ao_rx_packet.packet.len) { - - /* Check for incoming data at the next sequence and - * for an empty data buffer - */ - if (ao_rx_packet.packet.seq == (uint8_t) (rx_seq + (uint8_t) 1) && - ao_packet_rx_used == ao_packet_rx_len) { - - /* Copy data to the receive data buffer and set up the - * offsets - */ - memcpy(rx_data, ao_rx_packet.packet.d, ao_rx_packet.packet.len); - ao_packet_rx_used = 0; - ao_packet_rx_len = ao_rx_packet.packet.len; - - /* Mark the sequence that we've received to - * let the sender know when we return a packet - */ - rx_seq = ao_rx_packet.packet.seq; - ao_tx_packet.ack = rx_seq; - - /* Poke anyone looking for received data */ - ao_wakeup(&ao_stdin_ready); - } - } - - /* If the other side has seen the latest data we queued, - * wake up any task waiting to send data and let them go again - */ - if (ao_rx_packet.packet.ack == ao_tx_packet.seq) { - ao_tx_packet.len = 0; - ao_wakeup(&ao_tx_packet); - } - return 1; -} - -#ifndef PACKET_HAS_MASTER -#define PACKET_HAS_MASTER 1 -#endif - -#if PACKET_HAS_MASTER -void -ao_packet_flush(void) -{ - /* If there is data to send, and this is the master, - * then poke the master to send all queued data - */ - if (ao_packet_tx_used && ao_packet_master_sleeping) - ao_wakeup(&ao_packet_master_sleeping); -} -#endif /* PACKET_HAS_MASTER */ - -void -ao_packet_putchar(char c) __reentrant -{ - while (ao_packet_tx_used == AO_PACKET_MAX && ao_packet_enable) { -#if PACKET_HAS_MASTER - ao_packet_flush(); -#endif - ao_sleep(&tx_data); - } - - if (ao_packet_enable) - tx_data[ao_packet_tx_used++] = c; -} - -char -ao_packet_pollchar(void) __critical -{ - if (!ao_packet_enable) - return AO_READ_AGAIN; - - if (ao_packet_rx_used == ao_packet_rx_len) - return AO_READ_AGAIN; - - return rx_data[ao_packet_rx_used++]; -} diff --git a/src/ao_packet_master.c b/src/ao_packet_master.c deleted file mode 100644 index b0fdf5a8..00000000 --- a/src/ao_packet_master.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -static char -ao_packet_getchar(void) __critical -{ - char c; - while ((c = ao_packet_pollchar()) == AO_READ_AGAIN) { - if (!ao_packet_enable) - break; - if (ao_packet_master_sleeping) - ao_wakeup(&ao_packet_master_sleeping); - flush(); - ao_sleep(&ao_stdin_ready); - } - return c; -} - -static void -ao_packet_echo(void) __reentrant -{ - char c; - while (ao_packet_enable) { - c = ao_packet_getchar(); - if (c != AO_READ_AGAIN) - putchar(c); - } - ao_exit(); -} - -static __xdata struct ao_task ao_packet_echo_task; -static __xdata uint16_t ao_packet_master_delay; -static __xdata uint16_t ao_packet_master_time; - -#define AO_PACKET_MASTER_DELAY_SHORT AO_MS_TO_TICKS(100) -#define AO_PACKET_MASTER_DELAY_LONG AO_MS_TO_TICKS(1000) -#define AO_PACKET_MASTER_DELAY_TIMEOUT AO_MS_TO_TICKS(2000) - -static void -ao_packet_master_busy(void) -{ - ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT; - ao_packet_master_time = ao_time(); -} - -static void -ao_packet_master_check_busy(void) -{ - int16_t idle; - if (ao_packet_master_delay != AO_PACKET_MASTER_DELAY_SHORT) - return; - idle = (int16_t) (ao_time() - ao_packet_master_time); - - if (idle > AO_PACKET_MASTER_DELAY_TIMEOUT) - ao_packet_master_delay = AO_PACKET_MASTER_DELAY_LONG; -} - -void -ao_packet_master(void) -{ - ao_config_get(); - ao_tx_packet.addr = ao_serial_number; - ao_tx_packet.len = AO_PACKET_SYN; - ao_packet_master_time = ao_time(); - ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT; - while (ao_packet_enable) { - memcpy(ao_tx_packet.callsign, ao_config.callsign, AO_MAX_CALLSIGN); - ao_packet_send(); - if (ao_tx_packet.len) - ao_packet_master_busy(); - ao_packet_master_check_busy(); - ao_alarm(ao_packet_master_delay); - if (ao_packet_recv()) { - /* if we can transmit data, do so */ - if (ao_packet_tx_used && ao_tx_packet.len == 0) - continue; - if (ao_rx_packet.packet.len) - ao_packet_master_busy(); - ao_packet_master_sleeping = 1; - ao_alarm(ao_packet_master_delay); - ao_sleep(&ao_packet_master_sleeping); - ao_packet_master_sleeping = 0; - } - } - ao_exit(); -} - -static void -ao_packet_forward(void) __reentrant -{ - char c; - ao_packet_enable = 1; - ao_cmd_white(); - - flush(); -#if HAS_MONITOR - ao_set_monitor(0); -#endif - ao_add_task(&ao_packet_task, ao_packet_master, "master"); - ao_add_task(&ao_packet_echo_task, ao_packet_echo, "echo"); - while ((c = getchar()) != '~') { - if (c == '\r') c = '\n'; - ao_packet_putchar(c); - } - - /* Wait for a second if there is any pending data */ - for (c = 0; (ao_packet_tx_used || ao_tx_packet.len) && c < 10; c++) - ao_delay(AO_MS_TO_TICKS(100)); - ao_packet_enable = 0; - while (ao_packet_echo_task.wchan || ao_packet_task.wchan) { - ao_radio_recv_abort(); - ao_wakeup(&ao_stdin_ready); - ao_delay(AO_MS_TO_TICKS(10)); - } -} - - - -__code struct ao_cmds ao_packet_master_cmds[] = { - { ao_packet_forward, "p\0Remote packet link." }, - { 0, NULL }, -}; - -void -ao_packet_master_init(void) -{ - ao_cmd_register(&ao_packet_master_cmds[0]); -} diff --git a/src/ao_packet_slave.c b/src/ao_packet_slave.c deleted file mode 100644 index 9f14052a..00000000 --- a/src/ao_packet_slave.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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_packet_slave(void) -{ - ao_tx_packet.addr = ao_serial_number; - ao_tx_packet.len = AO_PACKET_SYN; - while (ao_packet_enable) { - if (ao_packet_recv()) { - memcpy(&ao_tx_packet.callsign, &ao_rx_packet.packet.callsign, AO_MAX_CALLSIGN); -#if HAS_FLIGHT - ao_flight_force_idle = TRUE; -#endif - ao_packet_send(); - } - } - ao_exit(); -} - -void -ao_packet_slave_start(void) -{ - ao_packet_enable = 1; - ao_add_task(&ao_packet_task, ao_packet_slave, "slave"); -} - -void -ao_packet_slave_stop(void) -{ - if (ao_packet_enable) { - ao_packet_enable = 0; - while (ao_packet_task.wchan) { - ao_radio_recv_abort(); - ao_delay(AO_MS_TO_TICKS(10)); - } - } -} - -void -ao_packet_slave_init(uint8_t enable) -{ - ao_add_stdio(ao_packet_pollchar, - ao_packet_putchar, - NULL); - if (enable) - ao_packet_slave_start(); -} diff --git a/src/ao_panic.c b/src/ao_panic.c deleted file mode 100644 index fdada201..00000000 --- a/src/ao_panic.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -#ifndef HAS_BEEP -#error Please define HAS_BEEP -#endif - -#if !HAS_BEEP -#define ao_beep(x) -#endif - -static void -ao_panic_delay(uint8_t n) -{ - uint8_t i = 0, j = 0; - - while (n--) - while (--j) - while (--i) - _asm nop _endasm; -} - -void -ao_panic(uint8_t reason) -{ - 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_panic_delay(1); - ao_led_off(AO_LED_RED); - ao_beep(AO_BEEP_LOW); - ao_panic_delay(1); - } - 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_panic_delay(10); - ao_led_off(AO_LED_RED); - ao_beep(AO_BEEP_OFF); - ao_panic_delay(10); - } - } -} diff --git a/src/ao_pins.h b/src/ao_pins.h deleted file mode 100644 index e1f5459f..00000000 --- a/src/ao_pins.h +++ /dev/null @@ -1,408 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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_PINS_H_ -#define _AO_PINS_H_ - -#if defined(TELEMETRUM_V_1_0) - #define HAS_FLIGHT 1 - #define HAS_USB 1 - #define HAS_BEEP 1 - #define HAS_GPS 1 - #define HAS_SERIAL_1 1 - #define HAS_ADC 1 - #define USE_SERIAL_STDIN 0 - #define HAS_EEPROM 1 - #define USE_INTERNAL_FLASH 0 - #define HAS_DBG 1 - #define DBG_ON_P1 1 - #define DBG_ON_P0 0 - #define IGNITE_ON_P2 1 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 0 - #define PACKET_HAS_SLAVE 1 - - #define HAS_COMPANION 1 - #define COMPANION_CS_ON_P1 1 - #define COMPANION_CS_MASK 0x4 /* CS1 is P1_2 */ - #define COMPANION_CS P1_2 - - #define AO_LED_RED 1 - #define LEDS_AVAILABLE (AO_LED_RED) - #define HAS_EXTERNAL_TEMP 0 - #define HAS_ACCEL_REF 0 - #define HAS_ACCEL 1 - #define HAS_IGNITE 1 - #define HAS_MONITOR 0 -#endif - -#if defined(TELEMETRUM_V_1_1) - #define HAS_FLIGHT 1 - #define HAS_USB 1 - #define HAS_BEEP 1 - #define HAS_GPS 1 - #define HAS_SERIAL_1 1 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 1 - #define HAS_EEPROM 1 - #define USE_INTERNAL_FLASH 0 - #define HAS_DBG 1 - #define DBG_ON_P1 1 - #define DBG_ON_P0 0 - #define IGNITE_ON_P2 1 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 0 - #define PACKET_HAS_SLAVE 1 - - #define HAS_COMPANION 1 - #define COMPANION_CS_ON_P1 1 - #define COMPANION_CS_MASK 0x4 /* CS1 is P1_2 */ - #define COMPANION_CS P1_2 - - #define AO_LED_RED 1 - #define LEDS_AVAILABLE (AO_LED_RED) - #define HAS_EXTERNAL_TEMP 0 - #define HAS_ACCEL_REF 1 - #define SPI_CS_ON_P1 1 - #define SPI_CS_ON_P0 0 - #define M25_CS_MASK 0x02 /* CS0 is P1_1 */ - #define M25_MAX_CHIPS 1 - #define HAS_ACCEL 1 - #define HAS_IGNITE 1 - #define HAS_MONITOR 0 -#endif - -#if defined(TELEDONGLE_V_0_2) - #define HAS_FLIGHT 0 - #define HAS_USB 1 - #define HAS_BEEP 0 - #define HAS_SERIAL_1 0 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 0 - #define HAS_DBG 1 - #define HAS_EEPROM 0 - #define DBG_ON_P1 1 - #define DBG_ON_P0 0 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 1 - #define PACKET_HAS_SLAVE 0 - #define AO_LED_RED 1 - #define AO_LED_GREEN 2 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define SPI_CS_ON_P1 1 - #define SPI_CS_ON_P0 0 - #define HAS_IGNITE 0 - #define HAS_MONITOR 1 -#endif - -#if defined(TELEMINI_V_1_0) - #define HAS_FLIGHT 1 - #define HAS_USB 0 - #define HAS_BEEP 0 - #define HAS_GPS 0 - #define HAS_SERIAL_1 0 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 1 - #define HAS_EEPROM 1 - #define USE_INTERNAL_FLASH 1 - #define HAS_DBG 0 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 1 - #define PACKET_HAS_MASTER 0 - #define PACKET_HAS_SLAVE 1 - #define USE_FAST_ASCENT_LOG 1 - - #define AO_LED_GREEN 1 - #define AO_LED_RED 2 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define HAS_EXTERNAL_TEMP 0 - #define HAS_ACCEL 0 - #define HAS_IGNITE 1 - #define HAS_MONITOR 0 -#endif - -#if defined(TELENANO_V_0_1) - #define HAS_FLIGHT 1 - #define HAS_USB 0 - #define HAS_BEEP 0 - #define HAS_GPS 0 - #define HAS_SERIAL_1 0 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 1 - #define HAS_EEPROM 1 - #define USE_INTERNAL_FLASH 1 - #define HAS_DBG 0 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 1 - #define PACKET_HAS_MASTER 0 - #define PACKET_HAS_SLAVE 1 - - #define AO_LED_GREEN 1 - #define AO_LED_RED 2 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define HAS_EXTERNAL_TEMP 0 - #define HAS_ACCEL 0 - #define HAS_IGNITE 0 - #define HAS_MONITOR 0 -#endif - -#if defined(TELEMETRUM_V_0_1) - #define HAS_FLIGHT 1 - #define HAS_USB 1 - #define HAS_BEEP 1 - #define HAS_GPS 1 - #define HAS_SERIAL_1 1 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 1 - #define HAS_DBG 0 - #define HAS_EEPROM 1 - #define USE_INTERNAL_FLASH 0 - #define DBG_ON_P1 0 - #define DBG_ON_P0 1 - #define IGNITE_ON_P2 1 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 0 - #define PACKET_HAS_SLAVE 1 - #define AO_LED_RED 2 - #define AO_LED_GREEN 1 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define HAS_EXTERNAL_TEMP 1 - #define HAS_ACCEL_REF 0 - #define SPI_CS_ON_P1 1 - #define SPI_CS_ON_P0 0 - #define HAS_ACCEL 1 - #define HAS_IGNITE 1 - #define HAS_MONITOR 0 -#endif - -#if defined(TELEDONGLE_V_0_1) - #define HAS_FLIGHT 0 - #define HAS_USB 1 - #define HAS_BEEP 0 - #define HAS_SERIAL_1 0 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 0 - #define HAS_DBG 0 - #define HAS_EEPROM 0 - #define DBG_ON_P1 0 - #define DBG_ON_P0 1 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 1 - #define PACKET_HAS_SLAVE 0 - #define AO_LED_RED 2 - #define AO_LED_GREEN 1 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define SPI_CS_ON_P1 0 - #define SPI_CS_ON_P0 1 - #define HAS_IGNITE 0 - #define HAS_MONITOR 1 -#endif - -#if defined(TIDONGLE) - #define HAS_FLIGHT 0 - #define HAS_USB 1 - #define HAS_BEEP 0 - #define HAS_SERIAL_1 0 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 0 - #define HAS_DBG 1 - #define HAS_EEPROM 0 - #define DBG_ON_P1 0 - #define DBG_ON_P0 1 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 1 - #define PACKET_HAS_SLAVE 0 - #define AO_LED_RED 2 - #define LEDS_AVAILABLE (AO_LED_RED) - #define SPI_CS_ON_P1 0 - #define SPI_CS_ON_P0 1 - #define HAS_IGNITE 0 - #define HAS_MONITOR 1 -#endif - -#if defined(TELEBT_V_0_0) - #define HAS_FLIGHT 0 - #define HAS_USB 1 - #define HAS_BEEP 0 - #define HAS_SERIAL_1 1 - #define USE_SERIAL_STDIN 1 - #define HAS_ADC 0 - #define HAS_DBG 1 - #define HAS_EEPROM 0 - #define HAS_BTM 1 - #define DBG_ON_P1 0 - #define DBG_ON_P0 1 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 1 - #define PACKET_HAS_SLAVE 0 - #define AO_LED_RED 2 - #define AO_LED_GREEN 1 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define SPI_CS_ON_P1 1 - #define SPI_CS_ON_P0 0 - #define HAS_IGNITE 0 - #define BT_LINK_ON_P2 1 - #define BT_LINK_ON_P1 0 - #define BT_LINK_PIN_INDEX 7 - #define BT_LINK_PIN P2_1 - #define HAS_MONITOR 1 -#endif - -#if defined(TELEBT_V_0_1) - #define HAS_FLIGHT 0 - #define HAS_USB 1 - #define HAS_BEEP 1 - #define HAS_SERIAL_1 1 - #define HAS_SERIAL_1_ALT_1 1 - #define HAS_SERIAL_1_ALT_2 0 - #define HAS_SERIAL_1_HW_FLOW 1 - #define USE_SERIAL_STDIN 1 - #define HAS_ADC 0 - #define HAS_DBG 1 - #define HAS_EEPROM 1 - #define USE_INTERNAL_FLASH 0 - #define HAS_BTM 1 - #define DBG_ON_P1 1 - #define DBG_ON_P0 0 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 1 - #define PACKET_HAS_SLAVE 0 - #define AO_LED_RED 1 - #define AO_LED_GREEN 2 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define SPI_CS_ON_P1 1 - #define SPI_CS_ON_P0 0 - #define M25_CS_MASK 0x04 /* CS0 is P1_2 */ - #define M25_MAX_CHIPS 1 - #define HAS_ACCEL 0 - #define HAS_IGNITE 0 - #define BT_LINK_ON_P2 0 - #define BT_LINK_ON_P1 1 - #define BT_LINK_PIN_INDEX 7 - #define BT_LINK_PIN P1_7 - #define HAS_MONITOR 1 -#endif - -#if DBG_ON_P1 - - #define DBG_CLOCK (1 << 4) /* mi0 */ - #define DBG_DATA (1 << 5) /* mo0 */ - #define DBG_RESET_N (1 << 3) /* c0 */ - - #define DBG_CLOCK_PIN (P1_4) - #define DBG_DATA_PIN (P1_5) - #define DBG_RESET_N_PIN (P1_3) - - #define DBG_PORT_NUM 1 - #define DBG_PORT P1 - #define DBG_PORT_SEL P1SEL - #define DBG_PORT_INP P1INP - #define DBG_PORT_DIR P1DIR - -#endif /* DBG_ON_P1 */ - -#if DBG_ON_P0 - - #define DBG_CLOCK (1 << 3) - #define DBG_DATA (1 << 4) - #define DBG_RESET_N (1 << 5) - - #define DBG_CLOCK_PIN (P0_3) - #define DBG_DATA_PIN (P0_4) - #define DBG_RESET_N_PIN (P0_5) - - #define DBG_PORT_NUM 0 - #define DBG_PORT P0 - #define DBG_PORT_SEL P0SEL - #define DBG_PORT_INP P0INP - #define DBG_PORT_DIR P0DIR - -#endif /* DBG_ON_P0 */ - -#if COMPANION_CS_ON_P1 - #define COMPANION_CS_PORT P1 - #define COMPANION_CS_SEL P1SEL - #define COMPANION_CS_DIR P1DIR -#endif - -#if SPI_CS_ON_P1 - #define SPI_CS_PORT P1 - #define SPI_CS_SEL P1SEL - #define SPI_CS_DIR P1DIR -#endif - -#if SPI_CS_ON_P0 - #define SPI_CS_PORT P0 - #define SPI_CS_SEL P0SEL - #define SPI_CS_DIR P0DIR -#endif - -#ifndef IGNITE_ON_P2 -#error Please define IGNITE_ON_P2 -#endif - -#ifndef IGNITE_ON_P0 -#error Please define IGNITE_ON_P0 -#endif - -#ifndef HAS_SERIAL_1 -#error Please define HAS_SERIAL_1 -#endif - -#ifndef USE_SERIAL_STDIN -#error Please define USE_SERIAL_STDIN -#endif - -#ifndef HAS_ADC -#error Please define HAS_ADC -#endif - -#ifndef HAS_EEPROM -#error Please define HAS_EEPROM -#endif - -#if HAS_EEPROM -#ifndef USE_INTERNAL_FLASH -#error Please define USE_INTERNAL_FLASH -#endif -#endif - -#ifndef HAS_DBG -#error Please define HAS_DBG -#endif - -#ifndef HAS_IGNITE -#error Please define HAS_IGNITE -#endif - -#ifndef PACKET_HAS_MASTER -#error Please define PACKET_HAS_MASTER -#endif - -#ifndef PACKET_HAS_SLAVE -#error Please define PACKET_HAS_SLAVE -#endif - -#ifndef HAS_MONITOR -#error Please define HAS_MONITOR -#endif -#endif /* _AO_PINS_H_ */ diff --git a/src/ao_product.c b/src/ao_product.c deleted file mode 100644 index fb59580b..00000000 --- a/src/ao_product.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" -#include "ao_product.h" - -/* Defines which mark this particular AltOS product */ - -const char ao_version[AO_MAX_VERSION] = AO_iVersion_STRING; -const char ao_manufacturer[] = AO_iManufacturer_STRING; -const char ao_product[] = AO_iProduct_STRING; - -#define LE_WORD(x) ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8)) - -#if HAS_USB -#include "ao_usb.h" -/* USB descriptors in one giant block of bytes */ -__code __at(0x00aa) uint8_t ao_usb_descriptors [] = -{ - /* Device descriptor */ - 0x12, - AO_USB_DESC_DEVICE, - LE_WORD(0x0110), /* bcdUSB */ - 0x02, /* bDeviceClass */ - 0x00, /* bDeviceSubClass */ - 0x00, /* bDeviceProtocol */ - AO_USB_CONTROL_SIZE, /* bMaxPacketSize */ - LE_WORD(0xFFFE), /* idVendor */ - LE_WORD(AO_idProduct_NUMBER), /* idProduct */ - LE_WORD(0x0100), /* bcdDevice */ - 0x01, /* iManufacturer */ - 0x02, /* iProduct */ - 0x03, /* iSerialNumber */ - 0x01, /* bNumConfigurations */ - - /* Configuration descriptor */ - 0x09, - AO_USB_DESC_CONFIGURATION, - LE_WORD(67), /* wTotalLength */ - 0x02, /* bNumInterfaces */ - 0x01, /* bConfigurationValue */ - 0x00, /* iConfiguration */ - 0xC0, /* bmAttributes */ - 0x32, /* bMaxPower */ - - /* Control class interface */ - 0x09, - AO_USB_DESC_INTERFACE, - 0x00, /* bInterfaceNumber */ - 0x00, /* bAlternateSetting */ - 0x01, /* bNumEndPoints */ - 0x02, /* bInterfaceClass */ - 0x02, /* bInterfaceSubClass */ - 0x01, /* bInterfaceProtocol, linux requires value of 1 for the cdc_acm module */ - 0x00, /* iInterface */ - - /* Header functional descriptor */ - 0x05, - CS_INTERFACE, - 0x00, /* bDescriptor SubType Header */ - LE_WORD(0x0110), /* CDC version 1.1 */ - - /* Call management functional descriptor */ - 0x05, - CS_INTERFACE, - 0x01, /* bDescriptor SubType Call Management */ - 0x01, /* bmCapabilities = device handles call management */ - 0x01, /* bDataInterface call management interface number */ - - /* ACM functional descriptor */ - 0x04, - CS_INTERFACE, - 0x02, /* bDescriptor SubType Abstract Control Management */ - 0x02, /* bmCapabilities = D1 (Set_line_Coding, Set_Control_Line_State, Get_Line_Coding and Serial_State) */ - - /* Union functional descriptor */ - 0x05, - CS_INTERFACE, - 0x06, /* bDescriptor SubType Union Functional descriptor */ - 0x00, /* bMasterInterface */ - 0x01, /* bSlaveInterface0 */ - - /* Notification EP */ - 0x07, - AO_USB_DESC_ENDPOINT, - AO_USB_INT_EP|0x80, /* bEndpointAddress */ - 0x03, /* bmAttributes = intr */ - LE_WORD(8), /* wMaxPacketSize */ - 0x0A, /* bInterval */ - - /* Data class interface descriptor */ - 0x09, - AO_USB_DESC_INTERFACE, - 0x01, /* bInterfaceNumber */ - 0x00, /* bAlternateSetting */ - 0x02, /* bNumEndPoints */ - 0x0A, /* bInterfaceClass = data */ - 0x00, /* bInterfaceSubClass */ - 0x00, /* bInterfaceProtocol */ - 0x00, /* iInterface */ - - /* Data EP OUT */ - 0x07, - AO_USB_DESC_ENDPOINT, - AO_USB_OUT_EP, /* bEndpointAddress */ - 0x02, /* bmAttributes = bulk */ - LE_WORD(AO_USB_OUT_SIZE),/* wMaxPacketSize */ - 0x00, /* bInterval */ - - /* Data EP in */ - 0x07, - AO_USB_DESC_ENDPOINT, - AO_USB_IN_EP|0x80, /* bEndpointAddress */ - 0x02, /* bmAttributes = bulk */ - LE_WORD(AO_USB_IN_SIZE),/* wMaxPacketSize */ - 0x00, /* bInterval */ - - /* String descriptors */ - 0x04, - AO_USB_DESC_STRING, - LE_WORD(0x0409), - - /* iManufacturer */ - AO_iManufacturer_LEN, - AO_USB_DESC_STRING, - AO_iManufacturer_UCS2, - - /* iProduct */ - AO_iProduct_LEN, - AO_USB_DESC_STRING, - AO_iProduct_UCS2, - - /* iSerial */ - AO_iSerial_LEN, - AO_USB_DESC_STRING, - AO_iSerial_UCS2, - - /* Terminating zero */ - 0 -}; -#endif diff --git a/src/ao_radio.c b/src/ao_radio.c deleted file mode 100644 index 00816b33..00000000 --- a/src/ao_radio.c +++ /dev/null @@ -1,475 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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 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 - -/* - * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone), - * so the DRATE_E and DRATE_M values are: - * - * M is 94 and E is 6 - * - * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes - */ - -#define RDF_DRATE_E 6 -#define RDF_DRATE_M 94 -#define RDF_PACKET_LEN 50 - -/* - * RDF deviation should match the normal NFM value of 5kHz - * - * M is 6 and E is 1 - * - */ - -#define RDF_DEVIATION_M 6 -#define RDF_DEVIATION_E 1 - -/* 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_10_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_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_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, -}; - -static __code uint8_t rdf_setup[] = { - RF_MDMCFG4_OFF, ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) | - (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) | - (RDF_DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)), - RF_MDMCFG3_OFF, (RDF_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_DIS | - RF_MDMCFG1_NUM_PREAMBLE_2 | - (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)), - - RF_DEVIATN_OFF, ((RDF_DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) | - (RDF_DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)), - - /* packet length is set in-line */ - RF_PKTCTRL1_OFF, ((1 << PKTCTRL1_PQT_SHIFT)| - PKTCTRL1_ADR_CHK_NONE), - RF_PKTCTRL0_OFF, (RF_PKTCTRL0_PKT_FORMAT_NORMAL| - RF_PKTCTRL0_LENGTH_CONFIG_FIXED), -}; - -static __code uint8_t fixed_pkt_setup[] = { - 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_DEVIATN_OFF, ((DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) | - (DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)), - - /* max packet length -- now set inline */ - 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), -}; - -__xdata uint8_t ao_radio_dma; -__xdata uint8_t ao_radio_dma_done; -__xdata uint8_t ao_radio_done; -__xdata uint8_t ao_radio_abort; -__xdata uint8_t ao_radio_mutex; - -void -ao_radio_general_isr(void) __interrupt 16 -{ - S1CON &= ~0x03; - if (RFIF & RFIF_IM_TIMEOUT) { - ao_radio_recv_abort(); - RFIF &= ~ RFIF_IM_TIMEOUT; - } else if (RFIF & RFIF_IM_DONE) { - ao_radio_done = 1; - ao_wakeup(&ao_radio_done); - RFIF &= ~RFIF_IM_DONE; - } -} - -void -ao_radio_set_packet(void) -{ - uint8_t i; - for (i = 0; i < sizeof (fixed_pkt_setup); i += 2) - RF[fixed_pkt_setup[i]] = fixed_pkt_setup[i+1]; -} - -void -ao_radio_idle(void) -{ - if (RF_MARCSTATE != RF_MARCSTATE_IDLE) - { - do { - RFST = RFST_SIDLE; - ao_yield(); - } while (RF_MARCSTATE != RF_MARCSTATE_IDLE); - } -} - -void -ao_radio_get(uint8_t len) -{ - ao_config_get(); - ao_mutex_get(&ao_radio_mutex); - ao_radio_idle(); - RF_CHANNR = ao_config.radio_channel; - RF_FREQ2 = (uint8_t) (ao_config.radio_setting >> 16); - RF_FREQ1 = (uint8_t) (ao_config.radio_setting >> 8); - RF_FREQ0 = (uint8_t) (ao_config.radio_setting); - RF_PKTLEN = len; -} - - -void -ao_radio_send(__xdata void *packet, uint8_t size) __reentrant -{ - ao_radio_get(size); - ao_radio_done = 0; - ao_dma_set_transfer(ao_radio_dma, - packet, - &RFDXADDR, - size, - 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; - __critical while (!ao_radio_done) - ao_sleep(&ao_radio_done); - ao_radio_put(); -} - -uint8_t -ao_radio_recv(__xdata void *packet, uint8_t size) __reentrant -{ - ao_radio_abort = 0; - ao_radio_get(size - 2); - ao_dma_set_transfer(ao_radio_dma, - &RFDXADDR, - packet, - size, - 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; - - /* Wait for DMA to be done, for the radio receive process to - * get aborted or for a receive timeout to fire - */ - __critical while (!ao_radio_dma_done && !ao_radio_abort) - if (ao_sleep(&ao_radio_dma_done)) - break; - - /* If recv was aborted, clean up by stopping the DMA engine - * and idling the radio - */ - if (!ao_radio_dma_done) { - ao_dma_abort(ao_radio_dma); - ao_radio_idle(); - } - ao_radio_put(); - return ao_radio_dma_done; -} - -/* - * Wake up a task waiting to receive a radio packet - * and tell them to abort the transfer - */ - -void -ao_radio_recv_abort(void) -{ - ao_radio_abort = 1; - ao_wakeup(&ao_radio_dma_done); -} - -__xdata ao_radio_rdf_value = 0x55; - -void -ao_radio_rdf(int ms) -{ - uint8_t i; - uint8_t pkt_len; - - /* - * Compute the packet length as follows: - * - * 2000 bps (for a 1kHz tone) - * so, for 'ms' milliseconds, we need - * 2 * ms bits, or ms / 4 bytes - */ - if (ms > (255 * 4)) - ms = 255 * 4; - pkt_len = ms >> 2; - - ao_radio_abort = 0; - ao_radio_get(pkt_len); - ao_radio_done = 0; - for (i = 0; i < sizeof (rdf_setup); i += 2) - RF[rdf_setup[i]] = rdf_setup[i+1]; - - ao_dma_set_transfer(ao_radio_dma, - &ao_radio_rdf_value, - &RFDXADDR, - pkt_len, - DMA_CFG0_WORDSIZE_8 | - DMA_CFG0_TMODE_SINGLE | - DMA_CFG0_TRIGGER_RADIO, - DMA_CFG1_SRCINC_0 | - DMA_CFG1_DESTINC_0 | - DMA_CFG1_PRIORITY_HIGH); - ao_dma_start(ao_radio_dma); - RFST = RFST_STX; - __critical while (!ao_radio_done && !ao_radio_abort) - ao_sleep(&ao_radio_done); - if (!ao_radio_done) { - ao_dma_abort(ao_radio_dma); - ao_radio_idle(); - } - ao_radio_set_packet(); - ao_radio_put(); -} - -void -ao_radio_rdf_abort(void) -{ - ao_radio_abort = 1; - ao_wakeup(&ao_radio_done); -} - - -/* Output carrier */ -void -ao_radio_test(void) -{ - uint8_t mode = 2; - static __xdata radio_on; - ao_cmd_white(); - if (ao_cmd_lex_c != '\n') { - ao_cmd_decimal(); - mode = (uint8_t) ao_cmd_lex_u32; - } - mode++; - if ((mode & 2) && !radio_on) { -#if HAS_MONITOR - ao_set_monitor(0); -#endif -#if PACKET_HAS_SLAVE - ao_packet_slave_stop(); -#endif - ao_radio_get(0xff); - RFST = RFST_STX; - radio_on = 1; - } - if (mode == 3) { - printf ("Hit a character to stop..."); flush(); - getchar(); - putchar('\n'); - } - if ((mode & 1) && radio_on) { - ao_radio_idle(); - ao_radio_put(); - radio_on = 0; - } -} - -__code struct ao_cmds ao_radio_cmds[] = { - { ao_radio_test, "C <1 start, 0 stop, none both>\0Radio carrier test" }, - { 0, NULL }, -}; - -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_set_packet(); - ao_radio_dma_done = 1; - ao_radio_dma = ao_dma_alloc(&ao_radio_dma_done); - RFIF = 0; - RFIM = RFIM_IM_TIMEOUT|RFIM_IM_DONE; - IEN2 |= IEN2_RFIE; - ao_cmd_register(&ao_radio_cmds[0]); -} diff --git a/src/ao_reboot.c b/src/ao_reboot.c deleted file mode 100644 index 8c47b893..00000000 --- a/src/ao_reboot.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -/* Use the watchdog timer to force a complete reboot - */ -void -ao_reboot(void) -{ - WDCTL = WDCTL_EN | WDCTL_MODE_WATCHDOG | WDCTL_INT_32768; - ao_delay(AO_SEC_TO_TICKS(2)); - ao_panic(AO_PANIC_REBOOT); -} diff --git a/src/ao_report.c b/src/ao_report.c deleted file mode 100644 index 3cf558e1..00000000 --- a/src/ao_report.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -#define BIT(i,x) ((x) ? (1 << (i)) : 0) -#define MORSE1(a) (1 | BIT(3,a)) -#define MORSE2(a,b) (2 | BIT(3,a) | BIT(4,b)) -#define MORSE3(a,b,c) (3 | BIT(3,a) | BIT(4,b) | BIT(5,c)) -#define MORSE4(a,b,c,d) (4 | BIT(3,a) | BIT(4,b) | BIT(5,c) | BIT(6,d)) -#define MORSE5(a,b,c,d,e) (5 | BIT(3,a) | BIT(4,b) | BIT(5,c) | BIT(6,d) | BIT(7,e)) - -static const uint8_t flight_reports[] = { - MORSE3(0,0,0), /* startup, 'S' */ - MORSE2(0,0), /* idle 'I' */ - MORSE4(0,1,1,0), /* pad 'P' */ - MORSE4(1,0,0,0), /* boost 'B' */ - MORSE4(0,0,1,0), /* fast 'F' */ - MORSE4(1,0,1,0), /* coast 'C' */ - MORSE3(1,0,0), /* drogue 'D' */ - MORSE2(1,1), /* main 'M' */ - MORSE4(0,1,0,0), /* landed 'L' */ - MORSE4(1,0,0,1), /* invalid 'X' */ -}; - -#if HAS_BEEP -#define low(time) ao_beep_for(AO_BEEP_LOW, time) -#define mid(time) ao_beep_for(AO_BEEP_MID, time) -#define high(time) ao_beep_for(AO_BEEP_HIGH, time) -#else -#define low(time) ao_led_for(AO_LED_GREEN, time) -#define mid(time) ao_led_for(AO_LED_RED, time) -#define high(time) ao_led_for(AO_LED_GREEN|AO_LED_RED, time) -#endif -#define pause(time) ao_delay(time) - -static __pdata enum ao_flight_state ao_report_state; - -static void -ao_report_beep(void) __reentrant -{ - uint8_t r = flight_reports[ao_flight_state]; - uint8_t l = r & 7; - - if (!r) - return; - while (l--) { - if (r & 8) - mid(AO_MS_TO_TICKS(600)); - else - mid(AO_MS_TO_TICKS(200)); - pause(AO_MS_TO_TICKS(200)); - r >>= 1; - } - pause(AO_MS_TO_TICKS(400)); -} - -static void -ao_report_digit(uint8_t digit) __reentrant -{ - if (!digit) { - mid(AO_MS_TO_TICKS(500)); - pause(AO_MS_TO_TICKS(200)); - } else { - while (digit--) { - mid(AO_MS_TO_TICKS(200)); - pause(AO_MS_TO_TICKS(200)); - } - } - pause(AO_MS_TO_TICKS(300)); -} - -static void -ao_report_altitude(void) -{ - __pdata int16_t agl = ao_max_height; - __xdata uint8_t digits[10]; - __pdata uint8_t ndigits, i; - - if (agl < 0) - agl = 0; - ndigits = 0; - do { - digits[ndigits++] = agl % 10; - agl /= 10; - } while (agl); - - for (;;) { - ao_report_beep(); - i = ndigits; - do - ao_report_digit(digits[--i]); - while (i != 0); - pause(AO_SEC_TO_TICKS(5)); - } -} - -#if HAS_IGNITE -static uint8_t -ao_report_igniter_ready(enum ao_igniter igniter) -{ - return ao_igniter_status(igniter) == ao_igniter_ready ? 1 : 0; -} - -static void -ao_report_continuity(void) __reentrant -{ - uint8_t c = (ao_report_igniter_ready(ao_igniter_drogue) | - (ao_report_igniter_ready(ao_igniter_main) << 1)); - if (c) { - while (c--) { - high(AO_MS_TO_TICKS(25)); - pause(AO_MS_TO_TICKS(100)); - } - } else { - c = 10; - while (c--) { - high(AO_MS_TO_TICKS(20)); - low(AO_MS_TO_TICKS(20)); - } - } - if (ao_log_full()) { - pause(AO_MS_TO_TICKS(100)); - c = 2; - while (c--) { - low(AO_MS_TO_TICKS(100)); - mid(AO_MS_TO_TICKS(100)); - high(AO_MS_TO_TICKS(100)); - mid(AO_MS_TO_TICKS(100)); - } - } - c = 50; - while (c-- && ao_flight_state == ao_flight_pad) - pause(AO_MS_TO_TICKS(100)); -} -#endif - -void -ao_report(void) -{ - ao_report_state = ao_flight_state; - for(;;) { - if (ao_flight_state == ao_flight_landed) - ao_report_altitude(); - ao_report_beep(); -#if HAS_IGNITE - if (ao_flight_state == ao_flight_idle) - ao_report_continuity(); - while (ao_flight_state == ao_flight_pad) - ao_report_continuity(); -#endif - __critical { - while (ao_report_state == ao_flight_state) - ao_sleep(DATA_TO_XDATA(&ao_flight_state)); - ao_report_state = ao_flight_state; - } - } -} - -static __xdata struct ao_task ao_report_task; - -void -ao_report_init(void) -{ - ao_add_task(&ao_report_task, ao_report, "report"); -} diff --git a/src/ao_romconfig.c b/src/ao_romconfig.c deleted file mode 100644 index f3fe61b1..00000000 --- a/src/ao_romconfig.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -__code __at (0x00a0) uint16_t ao_romconfig_version = AO_ROMCONFIG_VERSION; -__code __at (0x00a2) uint16_t ao_romconfig_check = ~AO_ROMCONFIG_VERSION; -__code __at (0x00a4) uint16_t ao_serial_number = 0; -/* - * For 434.550MHz, the frequency value is: - * - * 434.550e6 / (24e6 / 2**16) = 1186611.2 - * - * This value is stored in a const variable so that - * ao-load can change it during programming for - * devices that have no eeprom for config data. - */ -__code __at (0x00a6) uint32_t ao_radio_cal = 1186611; diff --git a/src/ao_rssi.c b/src/ao_rssi.c deleted file mode 100644 index e3964d2d..00000000 --- a/src/ao_rssi.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -static __xdata volatile uint16_t ao_rssi_time; -static __pdata volatile uint16_t ao_rssi_delay; -static __pdata uint8_t ao_rssi_led; - -void -ao_rssi(void) -{ - for (;;) { - while ((int16_t) (ao_time() - ao_rssi_time) > AO_SEC_TO_TICKS(3)) - ao_sleep(&ao_rssi_time); - ao_led_for(ao_rssi_led, AO_MS_TO_TICKS(100)); - ao_delay(ao_rssi_delay); - } -} - -void -ao_rssi_set(int rssi_value) -{ - if (rssi_value > 0) - rssi_value = 0; - ao_rssi_delay = AO_MS_TO_TICKS((-rssi_value) * 5); - ao_rssi_time = ao_time(); - ao_wakeup(&ao_rssi_time); -} - -__xdata struct ao_task ao_rssi_task; - -void -ao_rssi_init(uint8_t rssi_led) -{ - ao_rssi_led = rssi_led; - ao_rssi_delay = 0; - ao_add_task(&ao_rssi_task, ao_rssi, "rssi"); -} diff --git a/src/ao_sample.c b/src/ao_sample.c deleted file mode 100644 index b2b8e9f6..00000000 --- a/src/ao_sample.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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_FLIGHT_TEST -#include "ao.h" -#endif - -/* - * Current sensor values - */ - -__pdata uint16_t ao_sample_tick; /* time of last data */ -__pdata int16_t ao_sample_pres; -__pdata int16_t ao_sample_alt; -__pdata int16_t ao_sample_height; -#if HAS_ACCEL -__pdata int16_t ao_sample_accel; -#endif - -__data uint8_t ao_sample_adc; - -/* - * Sensor calibration values - */ - -__pdata int16_t ao_ground_pres; /* startup pressure */ -__pdata int16_t ao_ground_height; /* MSL of ao_ground_pres */ - -#if HAS_ACCEL -__pdata int16_t ao_ground_accel; /* startup acceleration */ -__pdata int16_t ao_accel_2g; /* factory accel calibration */ -__pdata int32_t ao_accel_scale; /* sensor to m/s² conversion */ -#endif - -static __pdata uint8_t ao_preflight; /* in preflight mode */ - -static __pdata uint16_t nsamples; -__pdata int32_t ao_sample_pres_sum; -#if HAS_ACCEL -__pdata int32_t ao_sample_accel_sum; -#endif - -static void -ao_sample_preflight(void) -{ - /* startup state: - * - * Collect 512 samples of acceleration and pressure - * data and average them to find the resting values - */ - if (nsamples < 512) { -#if HAS_ACCEL - ao_sample_accel_sum += ao_sample_accel; -#endif - ao_sample_pres_sum += ao_sample_pres; - ++nsamples; - } else { - ao_config_get(); -#if HAS_ACCEL - ao_ground_accel = ao_sample_accel_sum >> 9; - ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g; - ao_accel_scale = to_fix32(GRAVITY * 2 * 16) / ao_accel_2g; -#endif - ao_ground_pres = ao_sample_pres_sum >> 9; - ao_ground_height = ao_pres_to_altitude(ao_ground_pres); - ao_preflight = FALSE; - } -} - -uint8_t -ao_sample(void) -{ - ao_wakeup(DATA_TO_XDATA(&ao_sample_adc)); - ao_sleep(DATA_TO_XDATA(&ao_adc_head)); - while (ao_sample_adc != ao_adc_head) { - __xdata struct ao_adc *ao_adc; - - /* Capture a sample */ - ao_adc = &ao_adc_ring[ao_sample_adc]; - ao_sample_tick = ao_adc->tick; - ao_sample_pres = ao_adc->pres; - ao_sample_alt = ao_pres_to_altitude(ao_sample_pres); - ao_sample_height = ao_sample_alt - ao_ground_height; -#if HAS_ACCEL - ao_sample_accel = ao_adc->accel; -#if HAS_ACCEL_REF - /* - * Ok, the math here is a bit tricky. - * - * ao_sample_accel: ADC output for acceleration - * ao_accel_ref: ADC output for the 5V reference. - * ao_cook_accel: Corrected acceleration value - * Vcc: 3.3V supply to the CC1111 - * Vac: 5V supply to the accelerometer - * accel: input voltage to accelerometer ADC pin - * ref: input voltage to 5V reference ADC pin - * - * - * Measured acceleration is ratiometric to Vcc: - * - * ao_sample_accel accel - * ------------ = ----- - * 32767 Vcc - * - * Measured 5v reference is also ratiometric to Vcc: - * - * ao_accel_ref ref - * ------------ = ----- - * 32767 Vcc - * - * - * ao_accel_ref = 32767 * (ref / Vcc) - * - * Acceleration is measured ratiometric to the 5V supply, - * so what we want is: - * - * ao_cook_accel accel - * ------------- = ----- - * 32767 ref - * - * - * accel Vcc - * = ----- * --- - * Vcc ref - * - * ao_sample_accel 32767 - * = ------------ * ------------ - * 32767 ao_accel_ref - * - * Multiply through by 32767: - * - * ao_sample_accel * 32767 - * ao_cook_accel = -------------------- - * ao_accel_ref - * - * Now, the tricky part. Getting this to compile efficiently - * and keeping all of the values in-range. - * - * First off, we need to use a shift of 16 instead of * 32767 as SDCC - * does the obvious optimizations for byte-granularity shifts: - * - * ao_cook_accel = (ao_sample_accel << 16) / ao_accel_ref - * - * Next, lets check our input ranges: - * - * 0 <= ao_sample_accel <= 0x7fff (singled ended ADC conversion) - * 0x7000 <= ao_accel_ref <= 0x7fff (the 5V ref value is close to 0x7fff) - * - * Plugging in our input ranges, we get an output range of 0 - 0x12490, - * which is 17 bits. That won't work. If we take the accel ref and shift - * by a bit, we'll change its range: - * - * 0xe000 <= ao_accel_ref<<1 <= 0xfffe - * - * ao_cook_accel = (ao_sample_accel << 16) / (ao_accel_ref << 1) - * - * Now the output range is 0 - 0x9248, which nicely fits in 16 bits. It - * is, however, one bit too large for our signed computations. So, we - * take the result and shift that by a bit: - * - * ao_cook_accel = ((ao_sample_accel << 16) / (ao_accel_ref << 1)) >> 1 - * - * This finally creates an output range of 0 - 0x4924. As the ADC only - * provides 11 bits of data, we haven't actually lost any precision, - * just dropped a bit of noise off the low end. - */ - ao_sample_accel = (uint16_t) ((((uint32_t) ao_sample_accel << 16) / (ao_accel_ref[ao_sample_adc] << 1))) >> 1; - if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP) - ao_sample_accel = 0x7fff - ao_sample_accel; - ao_adc->accel = ao_sample_accel; -#endif -#endif - - if (ao_preflight) - ao_sample_preflight(); - else - ao_kalman(); - ao_sample_adc = ao_adc_ring_next(ao_sample_adc); - } - return !ao_preflight; -} - -void -ao_sample_init(void) -{ - nsamples = 0; - ao_sample_pres_sum = 0; - ao_sample_pres = 0; -#if HAS_ACCEL - ao_sample_accel_sum = 0; - ao_sample_accel = 0; -#endif - ao_sample_adc = ao_adc_head; - ao_preflight = TRUE; -} diff --git a/src/ao_serial.c b/src/ao_serial.c deleted file mode 100644 index 82370c64..00000000 --- a/src/ao_serial.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -volatile __xdata struct ao_fifo ao_usart1_rx_fifo; -volatile __xdata struct ao_fifo ao_usart1_tx_fifo; - -void -ao_serial_rx1_isr(void) __interrupt 3 -{ - if (!ao_fifo_full(ao_usart1_rx_fifo)) - ao_fifo_insert(ao_usart1_rx_fifo, U1DBUF); - ao_wakeup(&ao_usart1_rx_fifo); -#if USE_SERIAL_STDIN - ao_wakeup(&ao_stdin_ready); -#endif -} - -static __xdata uint8_t ao_serial_tx1_started; - -static void -ao_serial_tx1_start(void) -{ - if (!ao_fifo_empty(ao_usart1_tx_fifo) && - !ao_serial_tx1_started) - { - ao_serial_tx1_started = 1; - ao_fifo_remove(ao_usart1_tx_fifo, U1DBUF); - } -} - -void -ao_serial_tx1_isr(void) __interrupt 14 -{ - UTX1IF = 0; - ao_serial_tx1_started = 0; - ao_serial_tx1_start(); - ao_wakeup(&ao_usart1_tx_fifo); -} - -char -ao_serial_getchar(void) __critical -{ - char c; - while (ao_fifo_empty(ao_usart1_rx_fifo)) - ao_sleep(&ao_usart1_rx_fifo); - ao_fifo_remove(ao_usart1_rx_fifo, c); - return c; -} - -#if USE_SERIAL_STDIN -char -ao_serial_pollchar(void) __critical -{ - char c; - if (ao_fifo_empty(ao_usart1_rx_fifo)) - return AO_READ_AGAIN; - ao_fifo_remove(ao_usart1_rx_fifo,c); - return c; -} -#endif - -void -ao_serial_putchar(char c) __critical -{ - while (ao_fifo_full(ao_usart1_tx_fifo)) - ao_sleep(&ao_usart1_tx_fifo); - ao_fifo_insert(ao_usart1_tx_fifo, c); - ao_serial_tx1_start(); -} - -void -ao_serial_drain(void) __critical -{ - while (!ao_fifo_empty(ao_usart1_tx_fifo)) - ao_sleep(&ao_usart1_tx_fifo); -} - -static __code struct { - uint8_t baud; - uint8_t gcr; -} ao_serial_speeds[] = { - /* [AO_SERIAL_SPEED_4800] = */ { - /* .baud = */ 163, - /* .gcr = */ (7 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB - }, - /* [AO_SERIAL_SPEED_9600] = */ { - /* .baud = */ 163, - /* .gcr = */ (8 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB - }, - /* [AO_SERIAL_SPEED_19200] = */ { - /* .baud = */ 163, - /* .gcr = */ (9 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB - }, - /* [AO_SERIAL_SPEED_57600] = */ { - /* .baud = */ 59, - /* .gcr = */ (11 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB - }, -}; - -void -ao_serial_set_speed(uint8_t speed) -{ - ao_serial_drain(); - if (speed > AO_SERIAL_SPEED_57600) - return; - U1UCR |= UxUCR_FLUSH; - U1BAUD = ao_serial_speeds[speed].baud; - U1GCR = ao_serial_speeds[speed].gcr; -} - -void -ao_serial_init(void) -{ -#if HAS_SERIAL_1_ALT_1 - /* Set up the USART pin assignment */ - PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_1; - - P2DIR = (P2DIR & ~P2DIR_PRIP0_MASK) | P2DIR_PRIP0_USART1_USART0; - - /* Make the USART pins be controlled by the USART */ - P0SEL |= (1 << 5) | (1 << 4); -#if HAS_SERIAL_1_HW_FLOW - P0SEL |= (1 << 3) | (1 << 2); -#endif -#else - /* Set up the USART pin assignment */ - PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_2; - - P2SEL = (P2SEL & ~(P2SEL_PRI3P1_MASK | P2SEL_PRI2P1_MASK)) | - (P2SEL_PRI3P1_USART1 | P2SEL_PRI2P1_USART1); - - /* Make the USART pins be controlled by the USART */ - P1SEL |= (1 << 6) | (1 << 7); - P1SEL |= (1 << 5) | (1 << 4); -#endif - - /* UART mode with receiver enabled */ - U1CSR = (UxCSR_MODE_UART | UxCSR_RE); - - /* Pick a 4800 baud rate */ - ao_serial_set_speed(AO_SERIAL_SPEED_4800); - - /* Reasonable serial parameters */ - U1UCR = (UxUCR_FLUSH | -#if HAS_SERIAL_1_HW_FLOW - UxUCR_FLOW_ENABLE | -#else - UxUCR_FLOW_DISABLE | -#endif - UxUCR_D9_EVEN_PARITY | - UxUCR_BIT9_8_BITS | - UxUCR_PARITY_DISABLE | - UxUCR_SPB_1_STOP_BIT | - UxUCR_STOP_HIGH | - UxUCR_START_LOW); - - IEN0 |= IEN0_URX1IE; - IEN2 |= IEN2_UTX1IE; -} diff --git a/src/ao_spi.c b/src/ao_spi.c deleted file mode 100644 index fbe613c7..00000000 --- a/src/ao_spi.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -/* Shared mutex to protect SPI bus, must cover the entire - * operation, from CS low to CS high. This means that any SPI - * user must protect the SPI bus with this mutex - */ -__xdata uint8_t ao_spi_mutex; -__xdata uint8_t ao_spi_dma_in_done; -__xdata uint8_t ao_spi_dma_out_done; - -uint8_t ao_spi_dma_out_id; -uint8_t ao_spi_dma_in_id; - -static __xdata uint8_t ao_spi_const = 0xff; - -/* Send bytes over SPI. - * - * This sets up two DMA engines, one writing the data and another reading - * bytes coming back. We use the bytes coming back to tell when the transfer - * is complete, as the transmit register is double buffered and hence signals - * completion one byte before the transfer is actually complete - */ -void -ao_spi_send(void __xdata *block, uint16_t len) __reentrant -{ - ao_dma_set_transfer(ao_spi_dma_in_id, - &U0DBUFXADDR, - &ao_spi_const, - len, - DMA_CFG0_WORDSIZE_8 | - DMA_CFG0_TMODE_SINGLE | - DMA_CFG0_TRIGGER_URX0, - DMA_CFG1_SRCINC_0 | - DMA_CFG1_DESTINC_0 | - DMA_CFG1_PRIORITY_NORMAL); - - ao_dma_set_transfer(ao_spi_dma_out_id, - block, - &U0DBUFXADDR, - len, - DMA_CFG0_WORDSIZE_8 | - DMA_CFG0_TMODE_SINGLE | - DMA_CFG0_TRIGGER_UTX0, - DMA_CFG1_SRCINC_1 | - DMA_CFG1_DESTINC_0 | - DMA_CFG1_PRIORITY_NORMAL); - - ao_dma_start(ao_spi_dma_in_id); - ao_dma_start(ao_spi_dma_out_id); - ao_dma_trigger(ao_spi_dma_out_id); - __critical while (!ao_spi_dma_in_done) - ao_sleep(&ao_spi_dma_in_done); -} - -/* Receive bytes over SPI. - * - * This sets up tow DMA engines, one reading the data and another - * writing constant values to the SPI transmitter as that is what - * clocks the data coming in. - */ -void -ao_spi_recv(void __xdata *block, uint16_t len) __reentrant -{ - ao_dma_set_transfer(ao_spi_dma_in_id, - &U0DBUFXADDR, - block, - len, - DMA_CFG0_WORDSIZE_8 | - DMA_CFG0_TMODE_SINGLE | - DMA_CFG0_TRIGGER_URX0, - DMA_CFG1_SRCINC_0 | - DMA_CFG1_DESTINC_1 | - DMA_CFG1_PRIORITY_NORMAL); - - ao_dma_set_transfer(ao_spi_dma_out_id, - &ao_spi_const, - &U0DBUFXADDR, - len, - DMA_CFG0_WORDSIZE_8 | - DMA_CFG0_TMODE_SINGLE | - DMA_CFG0_TRIGGER_UTX0, - DMA_CFG1_SRCINC_0 | - DMA_CFG1_DESTINC_0 | - DMA_CFG1_PRIORITY_NORMAL); - - ao_dma_start(ao_spi_dma_in_id); - ao_dma_start(ao_spi_dma_out_id); - ao_dma_trigger(ao_spi_dma_out_id); - __critical while (!ao_spi_dma_in_done) - ao_sleep(&ao_spi_dma_in_done); -} - -/* - * Initialize USART0 for SPI using config alt 2 - * - * MO P1_5 - * MI P1_4 - * CLK P1_3 - * - * Chip select is the responsibility of the caller - */ - -void -ao_spi_init(void) -{ - /* Set up the USART pin assignment */ - PERCFG = (PERCFG & ~PERCFG_U0CFG_ALT_MASK) | PERCFG_U0CFG_ALT_2; - - /* Ensure that USART0 takes precidence over USART1 for pins that - * they share - */ - P2SEL = (P2SEL & ~P2SEL_PRI3P1_MASK) | P2SEL_PRI3P1_USART0; - - /* Make the SPI pins be controlled by the USART peripheral */ - P1SEL |= ((1 << 5) | (1 << 4) | (1 << 3)); - - /* Set up OUT DMA */ - ao_spi_dma_out_id = ao_dma_alloc(&ao_spi_dma_out_done); - - /* Set up IN DMA */ - ao_spi_dma_in_id = ao_dma_alloc(&ao_spi_dma_in_done); - - /* Set up the USART. - * - * SPI master mode - */ - U0CSR = (UxCSR_MODE_SPI | UxCSR_RE | UxCSR_MASTER); - - /* Set the baud rate and signal parameters - * - * The cc1111 is limited to a 24/8 MHz SPI clock. - * Every peripheral I've ever seen goes faster than that, - * so set the clock to 3MHz (BAUD_E 17, BAUD_M 0) - */ - U0BAUD = 0; - U0GCR = (UxGCR_CPOL_NEGATIVE | - UxGCR_CPHA_FIRST_EDGE | - UxGCR_ORDER_MSB | - (17 << UxGCR_BAUD_E_SHIFT)); -} diff --git a/src/ao_state.c b/src/ao_state.c deleted file mode 100644 index ed197aa5..00000000 --- a/src/ao_state.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -const char const * const ao_state_names[] = { - "startup", "idle", "pad", "boost", "fast", - "coast", "drogue", "main", "landed", "invalid" -}; diff --git a/src/ao_stdio.c b/src/ao_stdio.c deleted file mode 100644 index c0138a30..00000000 --- a/src/ao_stdio.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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 - */ - -#define AO_NUM_STDIOS (HAS_USB + PACKET_HAS_SLAVE + USE_SERIAL_STDIN) - -__xdata struct ao_stdio ao_stdios[AO_NUM_STDIOS]; -__pdata int8_t ao_cur_stdio; -__pdata int8_t ao_num_stdios; - -void -putchar(char c) -{ - if (c == '\n') - (*ao_stdios[ao_cur_stdio].putchar)('\r'); - (*ao_stdios[ao_cur_stdio].putchar)(c); -} - -void -flush(void) -{ - if (ao_stdios[ao_cur_stdio].flush) - ao_stdios[ao_cur_stdio].flush(); -} - -__xdata uint8_t ao_stdin_ready; - -char -getchar(void) __reentrant __critical -{ - char c; - int8_t stdio = ao_cur_stdio; - - for (;;) { - c = ao_stdios[stdio].pollchar(); - if (c != AO_READ_AGAIN) - break; - if (++stdio == ao_num_stdios) - stdio = 0; - if (stdio == ao_cur_stdio) - ao_sleep(&ao_stdin_ready); - } - ao_cur_stdio = stdio; - return c; -} - -uint8_t -ao_echo(void) -{ - return ao_stdios[ao_cur_stdio].echo; -} - -int8_t -ao_add_stdio(char (*pollchar)(void), - void (*putchar)(char), - void (*flush)(void)) __reentrant -{ - if (ao_num_stdios == AO_NUM_STDIOS) - ao_panic(AO_PANIC_STDIO); - ao_stdios[ao_num_stdios].pollchar = pollchar; - ao_stdios[ao_num_stdios].putchar = putchar; - ao_stdios[ao_num_stdios].flush = flush; - ao_stdios[ao_num_stdios].echo = 1; - return ao_num_stdios++; -} diff --git a/src/ao_storage.c b/src/ao_storage.c deleted file mode 100644 index 6ffca0e5..00000000 --- a/src/ao_storage.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -uint8_t -ao_storage_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant -{ - uint16_t this_len; - uint16_t this_off; - - ao_storage_setup(); - if (pos >= ao_storage_total || pos + len > ao_storage_total) - return 0; - while (len) { - - /* Compute portion of transfer within - * a single block - */ - this_off = (uint16_t) pos & (ao_storage_unit - 1); - this_len = ao_storage_unit - this_off; - if (this_len > len) - this_len = len; - - if (!ao_storage_device_read(pos, buf, this_len)) - return 0; - - /* See how much is left */ - buf += this_len; - len -= this_len; - pos += this_len; - } - return 1; -} - -uint8_t -ao_storage_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant -{ - uint16_t this_len; - uint16_t this_off; - - ao_storage_setup(); - if (pos >= ao_storage_total || pos + len > ao_storage_total) - return 0; - while (len) { - - /* Compute portion of transfer within - * a single block - */ - this_off = (uint16_t) pos & (ao_storage_unit - 1); - this_len = ao_storage_unit - this_off; - if (this_len > len) - this_len = len; - - if (!ao_storage_device_write(pos, buf, this_len)) - return 0; - - /* See how much is left */ - buf += this_len; - len -= this_len; - pos += this_len; - } - return 1; -} - -static __xdata uint8_t storage_data[8]; - -static void -ao_storage_dump(void) __reentrant -{ - uint8_t i, j; - - ao_cmd_hex(); - if (ao_cmd_status != ao_cmd_success) - return; - for (i = 0; ; i += 8) { - if (ao_storage_read(((uint32_t) (ao_cmd_lex_i) << 8) + i, - storage_data, - 8)) { - ao_cmd_put16((uint16_t) i); - for (j = 0; j < 8; j++) { - putchar(' '); - ao_cmd_put8(storage_data[j]); - } - putchar ('\n'); - } - if (i == 248) - break; - } -} - -#if 0 - -/* not enough space for this today - */ -static void -ao_storage_store(void) __reentrant -{ - uint16_t block; - uint8_t i; - uint16_t len; - static __xdata uint8_t b; - 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_storage_write(addr, &b, 1); - addr++; - } -} -#endif - -void -ao_storage_zap(void) __reentrant -{ - ao_cmd_hex(); - if (ao_cmd_status != ao_cmd_success) - return; - ao_storage_erase((uint32_t) ao_cmd_lex_i << 8); -} - -void -ao_storage_zapall(void) __reentrant -{ - uint32_t pos; - - ao_cmd_white(); - if (!ao_match_word("DoIt")) - return; - for (pos = 0; pos < ao_storage_config; pos += ao_storage_block) - ao_storage_erase(pos); -} - -void -ao_storage_info(void) __reentrant -{ - printf("Storage size: %ld\n", ao_storage_total); - printf("Storage erase unit: %ld\n", ao_storage_block); - ao_storage_device_info(); -} - -__code struct ao_cmds ao_storage_cmds[] = { - { ao_storage_info, "f\0Show storage" }, - { ao_storage_dump, "e \0Dump flash" }, -#ifdef HAS_STORAGE_DBG - { ao_storage_store, "w ...\0Write data to flash" }, -#endif - { ao_storage_zap, "z \0Erase " }, - { ao_storage_zapall,"Z \0Erase all. is doit with D&I" }, - { 0, NULL }, -}; - -void -ao_storage_init(void) -{ - ao_storage_device_init(); - ao_cmd_register(&ao_storage_cmds[0]); -} diff --git a/src/ao_task.c b/src/ao_task.c deleted file mode 100644 index f5850fa4..00000000 --- a/src/ao_task.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -#define AO_NO_TASK_INDEX 0xff - -__xdata struct ao_task * __xdata ao_tasks[AO_NUM_TASKS]; -__data uint8_t ao_num_tasks; -__data uint8_t ao_cur_task_index; -__xdata struct ao_task *__data ao_cur_task; - -void -ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant -{ - uint8_t __xdata *stack; - uint8_t task_id; - uint8_t t; - if (ao_num_tasks == AO_NUM_TASKS) - ao_panic(AO_PANIC_NO_TASK); - for (task_id = 1; task_id != 0; task_id++) { - for (t = 0; t < ao_num_tasks; t++) - if (ao_tasks[t]->task_id == task_id) - break; - if (t == ao_num_tasks) - break; - } - ao_tasks[ao_num_tasks++] = task; - task->task_id = task_id; - task->name = name; - /* - * Construct a stack frame so that it will 'return' - * to the start of the task - */ - stack = task->stack; - - *stack++ = ((uint16_t) start); /* 0 */ - *stack++ = ((uint16_t) start) >> 8; /* 1 */ - - /* and the stuff saved by ao_switch */ - *stack++ = 0; /* 2 acc */ - *stack++ = 0x80; /* 3 IE */ - - /* 4 DPL - * 5 DPH - * 6 B - * 7 R2 - * 8 R3 - * 9 R4 - * 10 R5 - * 11 R6 - * 12 R7 - * 13 R0 - * 14 R1 - * 15 PSW - * 16 BP - */ - for (t = 0; t < 13; t++) - *stack++ = 0; - - task->stack_count = 17; - task->wchan = NULL; -} - -/* Task switching function. This must not use any stack variables */ -void -ao_yield(void) __naked -{ - - /* Save current context */ - _asm - /* Push ACC first, as when restoring the context it must be restored - * last (it is used to set the IE register). */ - push ACC - /* Store the IE register then enable interrupts. */ - push _IEN0 - setb _EA - push DPL - push DPH - push b - push ar2 - push ar3 - push ar4 - push ar5 - push ar6 - push ar7 - push ar0 - push ar1 - push PSW - _endasm; - PSW = 0; - _asm - push _bp - _endasm; - - if (ao_cur_task_index == AO_NO_TASK_INDEX) - ao_cur_task_index = ao_num_tasks-1; - else - { - uint8_t stack_len; - __data uint8_t *stack_ptr; - __xdata uint8_t *save_ptr; - /* Save the current stack */ - stack_len = SP - (AO_STACK_START - 1); - ao_cur_task->stack_count = stack_len; - stack_ptr = (uint8_t __data *) AO_STACK_START; - save_ptr = (uint8_t __xdata *) ao_cur_task->stack; - do - *save_ptr++ = *stack_ptr++; - while (--stack_len); - } - - /* Empty the stack; might as well let interrupts have the whole thing */ - SP = AO_STACK_START - 1; - - /* Find a task to run. If there isn't any runnable task, - * this loop will run forever, which is just fine - */ - { - __pdata uint8_t ao_next_task_index = ao_cur_task_index; - for (;;) { - ++ao_next_task_index; - if (ao_next_task_index == ao_num_tasks) - ao_next_task_index = 0; - - ao_cur_task = ao_tasks[ao_next_task_index]; - if (ao_cur_task->wchan == NULL) { - ao_cur_task_index = ao_next_task_index; - break; - } - - /* Check if the alarm is set for a time which has passed */ - if (ao_cur_task->alarm && - (int16_t) (ao_time() - ao_cur_task->alarm) >= 0) { - ao_cur_task_index = ao_next_task_index; - break; - } - - /* Enter lower power mode when there isn't anything to do */ - if (ao_next_task_index == ao_cur_task_index) - PCON = PCON_IDLE; - } - } - - { - uint8_t stack_len; - __data uint8_t *stack_ptr; - __xdata uint8_t *save_ptr; - - /* Restore the old stack */ - stack_len = ao_cur_task->stack_count; - SP = AO_STACK_START - 1 + stack_len; - - stack_ptr = (uint8_t __data *) AO_STACK_START; - save_ptr = (uint8_t __xdata *) ao_cur_task->stack; - do - *stack_ptr++ = *save_ptr++; - while (--stack_len); - } - - _asm - pop _bp - pop PSW - pop ar1 - pop ar0 - pop ar7 - pop ar6 - pop ar5 - pop ar4 - pop ar3 - pop ar2 - pop b - pop DPH - pop DPL - /* The next byte of the stack is the IE register. Only the global - enable bit forms part of the task context. Pop off the IE then set - the global enable bit to match that of the stored IE register. */ - pop ACC - JB ACC.7,0098$ - CLR _EA - LJMP 0099$ - 0098$: - SETB _EA - 0099$: - /* Finally pop off the ACC, which was the first register saved. */ - pop ACC - ret - _endasm; -} - -uint8_t -ao_sleep(__xdata void *wchan) -{ - __critical { - ao_cur_task->wchan = wchan; - } - ao_yield(); - ao_cur_task->alarm = 0; - if (ao_cur_task->wchan) { - ao_cur_task->wchan = NULL; - return 1; - } - return 0; -} - -void -ao_wakeup(__xdata void *wchan) -{ - uint8_t i; - - for (i = 0; i < ao_num_tasks; i++) - if (ao_tasks[i]->wchan == wchan) - ao_tasks[i]->wchan = NULL; -} - -void -ao_alarm(uint16_t delay) -{ - /* Make sure we sleep *at least* delay ticks, which means adding - * one to account for the fact that we may be close to the next tick - */ - if (!(ao_cur_task->alarm = ao_time() + delay + 1)) - ao_cur_task->alarm = 1; -} - -void -ao_exit(void) __critical -{ - uint8_t i; - ao_num_tasks--; - for (i = ao_cur_task_index; i < ao_num_tasks; i++) - ao_tasks[i] = ao_tasks[i+1]; - ao_cur_task_index = AO_NO_TASK_INDEX; - ao_yield(); - /* we'll never get back here */ -} - -void -ao_task_info(void) -{ - uint8_t i; - uint8_t pc_loc; - __xdata struct ao_task *task; - - for (i = 0; i < ao_num_tasks; i++) { - task = ao_tasks[i]; - pc_loc = task->stack_count - 17; - printf("%12s: wchan %04x pc %04x\n", - task->name, - (int16_t) task->wchan, - (task->stack[pc_loc]) | (task->stack[pc_loc+1] << 8)); - } -} - -void -ao_start_scheduler(void) -{ - ao_cur_task_index = AO_NO_TASK_INDEX; - ao_cur_task = NULL; - ao_yield(); -} diff --git a/src/ao_telebt.c b/src/ao_telebt.c deleted file mode 100644 index 85565172..00000000 --- a/src/ao_telebt.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -__code uint8_t ao_log_format = AO_LOG_FORMAT_NONE; /* until we actually log stuff */ - -void -main(void) -{ - ao_clock_init(); - - /* Turn on the LED until the system is stable */ - ao_led_init(LEDS_AVAILABLE); - ao_led_on(AO_LED_RED); - ao_timer_init(); -#if HAS_BEEP - ao_beep_init(); -#endif - ao_cmd_init(); -#if HAS_EEPROM - ao_spi_init(); - ao_storage_init(); -#endif - ao_usb_init(); - ao_monitor_init(AO_LED_GREEN, TRUE); - ao_rssi_init(AO_LED_RED); - ao_radio_init(); - ao_packet_master_init(); - ao_btm_init(); -#if HAS_DBG - ao_dbg_init(); -#endif - ao_config_init(); - ao_start_scheduler(); -} diff --git a/src/ao_teledongle.c b/src/ao_teledongle.c deleted file mode 100644 index 008b200a..00000000 --- a/src/ao_teledongle.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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) -{ - ao_clock_init(); - - /* Turn on the LED until the system is stable */ - ao_led_init(LEDS_AVAILABLE); - ao_led_on(AO_LED_RED); - ao_timer_init(); - ao_cmd_init(); - ao_usb_init(); - ao_monitor_init(AO_LED_GREEN, TRUE); - ao_rssi_init(AO_LED_RED); - ao_radio_init(); - ao_packet_master_init(); -#if HAS_DBG - ao_dbg_init(); -#endif - ao_config_init(); - ao_start_scheduler(); -} diff --git a/src/ao_telem.h b/src/ao_telem.h deleted file mode 100644 index 1a8da291..00000000 --- a/src/ao_telem.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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 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_g 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" -#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_g" -#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_ */ diff --git a/src/ao_telemetrum.c b/src/ao_telemetrum.c deleted file mode 100644 index f560740a..00000000 --- a/src/ao_telemetrum.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" -#include "ao_pins.h" - -void -main(void) -{ - /* - * Reduce the transient on the ignite pins at startup by - * pulling the pins low as soon as possible at power up - */ - ao_ignite_set_pins(); - - ao_clock_init(); - - /* Turn on the red LED until the system is stable */ - ao_led_init(LEDS_AVAILABLE); - ao_led_on(AO_LED_RED); - - /* A hack -- look at the SPI clock pin, if it's sitting at - * ground, then we force the computer to idle mode instead of - * flight mode - */ - if (P1_3 == 0) { - ao_flight_force_idle = 1; - while (P1_3 == 0) - ; - } - ao_timer_init(); - ao_adc_init(); - ao_beep_init(); - ao_cmd_init(); - ao_spi_init(); - ao_storage_init(); - ao_flight_init(); - ao_log_init(); - ao_report_init(); - ao_usb_init(); - ao_serial_init(); - ao_gps_init(); - ao_gps_report_init(); - ao_telemetry_init(); - ao_radio_init(); - ao_packet_slave_init(TRUE); - ao_igniter_init(); -#if HAS_DBG - ao_dbg_init(); -#endif -#if HAS_COMPANION - ao_companion_init(); -#endif - ao_config_init(); - ao_start_scheduler(); -} diff --git a/src/ao_telemetry.c b/src/ao_telemetry.c deleted file mode 100644 index c7338a58..00000000 --- a/src/ao_telemetry.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" -#include "ao_product.h" - -static __pdata uint16_t ao_telemetry_interval; -static __pdata int8_t ao_telemetry_config_max; -static __pdata int8_t ao_telemetry_config_cur; -#if HAS_GPS -static __pdata int8_t ao_telemetry_loc_cur; -static __pdata int8_t ao_telemetry_sat_cur; -#endif -#if HAS_COMPANION -static __pdata int8_t ao_telemetry_companion_max; -static __pdata int8_t ao_telemetry_companion_cur; -#endif -static __pdata uint8_t ao_rdf = 0; -static __pdata uint16_t ao_rdf_time; - -#define AO_RDF_INTERVAL_TICKS AO_SEC_TO_TICKS(5) -#define AO_RDF_LENGTH_MS 500 - -#if defined(TELEMETRUM_V_0_1) || defined(TELEMETRUM_V_0_2) || defined(TELEMETRUM_V_1_0) || defined(TELEMETRUM_V_1_1) -#define AO_TELEMETRY_SENSOR AO_TELEMETRY_SENSOR_TELEMETRUM -#endif - -#if defined(TELEMINI_V_1_0) -#define AO_TELEMETRY_SENSOR AO_TELEMETRY_SENSOR_TELEMINI -#endif - -#if defined(TELENANO_V_0_1) -#define AO_TELEMETRY_SENSOR AO_TELEMETRY_SENSOR_TELENANO -#endif - -static __xdata union ao_telemetry_all telemetry; - -/* Send sensor packet */ -static void -ao_send_sensor(void) -{ - uint8_t sample; - sample = ao_sample_adc; - - telemetry.generic.tick = ao_adc_ring[sample].tick; - telemetry.generic.type = AO_TELEMETRY_SENSOR; - - telemetry.sensor.state = ao_flight_state; -#if HAS_ACCEL - telemetry.sensor.accel = ao_adc_ring[sample].accel; -#else - telemetry.sensor.accel = 0; -#endif - telemetry.sensor.pres = ao_adc_ring[sample].pres; - telemetry.sensor.temp = ao_adc_ring[sample].temp; - telemetry.sensor.v_batt = ao_adc_ring[sample].v_batt; -#if HAS_IGNITE - telemetry.sensor.sense_d = ao_adc_ring[sample].sense_d; - telemetry.sensor.sense_m = ao_adc_ring[sample].sense_m; -#else - telemetry.sensor.sense_d = 0; - telemetry.sensor.sense_m = 0; -#endif - - telemetry.sensor.acceleration = ao_accel; - telemetry.sensor.speed = ao_speed; - telemetry.sensor.height = ao_height; - - telemetry.sensor.ground_pres = ao_ground_pres; -#if HAS_ACCEL - telemetry.sensor.ground_accel = ao_ground_accel; - telemetry.sensor.accel_plus_g = ao_config.accel_plus_g; - telemetry.sensor.accel_minus_g = ao_config.accel_minus_g; -#else - telemetry.sensor.ground_accel = 0; - telemetry.sensor.accel_plus_g = 0; - telemetry.sensor.accel_minus_g = 0; -#endif - - ao_radio_send(&telemetry, sizeof (telemetry)); -} - -static void -ao_send_configuration(void) -{ - if (--ao_telemetry_config_cur <= 0) - { - telemetry.generic.type = AO_TELEMETRY_CONFIGURATION; - telemetry.configuration.device = AO_idProduct_NUMBER; - telemetry.configuration.flight = ao_log_full() ? 0 : ao_flight_number; - telemetry.configuration.config_major = AO_CONFIG_MAJOR; - telemetry.configuration.config_minor = AO_CONFIG_MINOR; - telemetry.configuration.apogee_delay = ao_config.apogee_delay; - telemetry.configuration.main_deploy = ao_config.main_deploy; - telemetry.configuration.flight_log_max = ao_config.flight_log_max >> 10; - memcpy (telemetry.configuration.callsign, - ao_config.callsign, - AO_MAX_CALLSIGN); - memcpy (telemetry.configuration.version, - ao_version, - AO_MAX_VERSION); - ao_radio_send(&telemetry, sizeof (telemetry)); - ao_telemetry_config_cur = ao_telemetry_config_max; - } -} - -#if HAS_GPS -static void -ao_send_location(void) -{ - if (--ao_telemetry_loc_cur <= 0) - { - telemetry.generic.type = AO_TELEMETRY_LOCATION; - ao_mutex_get(&ao_gps_mutex); - memcpy(&telemetry.location.flags, - &ao_gps_data.flags, - 26); - ao_mutex_put(&ao_gps_mutex); - ao_radio_send(&telemetry, sizeof (telemetry)); - ao_telemetry_loc_cur = ao_telemetry_config_max; - } -} - -static void -ao_send_satellite(void) -{ - if (--ao_telemetry_sat_cur <= 0) - { - telemetry.generic.type = AO_TELEMETRY_SATELLITE; - ao_mutex_get(&ao_gps_mutex); - telemetry.satellite.channels = ao_gps_tracking_data.channels; - memcpy(&telemetry.satellite.sats, - &ao_gps_tracking_data.sats, - AO_MAX_GPS_TRACKING * sizeof (struct ao_telemetry_satellite_info)); - ao_mutex_put(&ao_gps_mutex); - ao_radio_send(&telemetry, sizeof (telemetry)); - ao_telemetry_sat_cur = ao_telemetry_config_max; - } -} -#endif - -#if HAS_COMPANION -static void -ao_send_companion(void) -{ - if (--ao_telemetry_companion_cur <= 0) { - telemetry.generic.type = AO_TELEMETRY_COMPANION; - telemetry.companion.board_id = ao_companion_setup.board_id; - telemetry.companion.update_period = ao_companion_setup.update_period; - telemetry.companion.channels = ao_companion_setup.channels; - ao_mutex_get(&ao_companion_mutex); - memcpy(&telemetry.companion.companion_data, - ao_companion_data, - ao_companion_setup.channels * 2); - ao_mutex_put(&ao_companion_mutex); - ao_radio_send(&telemetry, sizeof (telemetry)); - ao_telemetry_companion_cur = ao_telemetry_companion_max; - } -} -#endif - -void -ao_telemetry(void) -{ - uint16_t time; - int16_t delay; - - ao_config_get(); - if (!ao_config.radio_enable) - ao_exit(); - while (!ao_flight_number) - ao_sleep(&ao_flight_number); - - telemetry.generic.serial = ao_serial_number; - for (;;) { - while (ao_telemetry_interval == 0) - ao_sleep(&telemetry); - time = ao_rdf_time = ao_time(); - while (ao_telemetry_interval) { - - - ao_send_sensor(); -#if HAS_COMPANION - if (ao_companion_running) - ao_send_companion(); -#endif - ao_send_configuration(); -#if HAS_GPS - ao_send_location(); - ao_send_satellite(); -#endif - if (ao_rdf && - (int16_t) (ao_time() - ao_rdf_time) >= 0) - { - ao_rdf_time = ao_time() + AO_RDF_INTERVAL_TICKS; - ao_radio_rdf(AO_RDF_LENGTH_MS); - } - time += ao_telemetry_interval; - delay = time - ao_time(); - if (delay > 0) - ao_delay(delay); - else - time = ao_time(); - } - } -} - -void -ao_telemetry_set_interval(uint16_t interval) -{ - ao_telemetry_interval = interval; - -#if HAS_COMPANION - if (!ao_companion_setup.update_period) - ao_companion_setup.update_period = AO_SEC_TO_TICKS(1); - ao_telemetry_companion_max = ao_companion_setup.update_period / interval; - ao_telemetry_companion_cur = 1; -#endif - - ao_telemetry_config_max = AO_SEC_TO_TICKS(1) / interval; -#if HAS_COMPANION - ao_telemetry_config_cur = ao_telemetry_companion_cur; - if (ao_telemetry_config_max > ao_telemetry_config_cur) - ao_telemetry_config_cur++; -#else - ao_telemetry_config_cur = 1; -#endif - -#if HAS_GPS - ao_telemetry_loc_cur = ao_telemetry_config_cur; - if (ao_telemetry_config_max > ao_telemetry_loc_cur) - ao_telemetry_loc_cur++; - ao_telemetry_sat_cur = ao_telemetry_loc_cur; - if (ao_telemetry_config_max > ao_telemetry_sat_cur) - ao_telemetry_sat_cur++; -#endif - ao_wakeup(&telemetry); -} - -void -ao_rdf_set(uint8_t rdf) -{ - ao_rdf = rdf; - if (rdf == 0) - ao_radio_rdf_abort(); - else - ao_rdf_time = ao_time(); -} - -__xdata struct ao_task ao_telemetry_task; - -void -ao_telemetry_init() -{ - ao_add_task(&ao_telemetry_task, ao_telemetry, "telemetry"); -} diff --git a/src/ao_telemini.c b/src/ao_telemini.c deleted file mode 100644 index fa23de01..00000000 --- a/src/ao_telemini.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" -#include "ao_pins.h" - -void -main(void) -{ - /* - * Reduce the transient on the ignite pins at startup by - * pulling the pins low as soon as possible at power up - */ - ao_ignite_set_pins(); - - ao_clock_init(); - - /* Turn on the red LED until the system is stable */ - ao_led_init(LEDS_AVAILABLE); - ao_led_on(AO_LED_RED); - - ao_timer_init(); - ao_adc_init(); - ao_cmd_init(); - ao_storage_init(); - ao_flight_init(); - ao_log_init(); - ao_report_init(); - ao_telemetry_init(); - ao_radio_init(); - ao_packet_slave_init(TRUE); - ao_igniter_init(); - ao_config_init(); - ao_start_scheduler(); -} diff --git a/src/ao_telenano.c b/src/ao_telenano.c deleted file mode 100644 index d91983d0..00000000 --- a/src/ao_telenano.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" -#include "ao_pins.h" - -void -main(void) -{ - ao_clock_init(); - - - /* Turn on the red LED until the system is stable */ - ao_led_init(LEDS_AVAILABLE); - ao_led_on(AO_LED_RED); - - ao_timer_init(); - ao_adc_init(); - ao_cmd_init(); - ao_storage_init(); - ao_flight_nano_init(); - ao_log_init(); - ao_report_init(); - ao_telemetry_init(); - ao_radio_init(); - ao_packet_slave_init(TRUE); - ao_config_init(); - ao_start_scheduler(); -} diff --git a/src/ao_teleterra.c b/src/ao_teleterra.c deleted file mode 100644 index d696b914..00000000 --- a/src/ao_teleterra.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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_ADC_ISR 1 -#include "ao.h" - -void -main(void) -{ - ao_clock_init(); - - /* Turn on the red LED until the system is stable */ - ao_led_init(AO_LED_RED|AO_LED_GREEN); - ao_led_on(AO_LED_RED); - ao_timer_init(); - ao_beep_init(); - ao_cmd_init(); - ao_usb_init(); - ao_serial_init(); - ao_monitor_init(AO_LED_GREEN, TRUE); - ao_radio_init(); - ao_config_init(); - ao_start_scheduler(); -} diff --git a/src/ao_test.c b/src/ao_test.c deleted file mode 100644 index 14c2eb75..00000000 --- a/src/ao_test.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -struct ao_task __xdata blink_0_task; -struct ao_task __xdata blink_1_task; -struct ao_task __xdata wakeup_task; -struct ao_task __xdata beep_task; -struct ao_task __xdata echo_task; - -void delay(int n) __reentrant -{ - uint8_t j = 0; - while (--n) - while (--j) - ao_yield(); -} - -static __xdata uint8_t blink_chan; - -void -blink_0(void) -{ - uint8_t b = 0; - for (;;) { - b = 1 - b; - if (b) - ao_led_on(AO_LED_GREEN); - else - ao_led_off(AO_LED_GREEN); - ao_sleep(&blink_chan); - } -} - -void -blink_1(void) -{ - static __xdata struct ao_adc adc; - - for (;;) { - ao_sleep(&ao_adc_head); - ao_adc_get(&adc); - if (adc.accel < 15900) - ao_led_on(AO_LED_RED); - else - ao_led_off(AO_LED_RED); - } -} - -void -wakeup(void) -{ - for (;;) { - ao_delay(AO_MS_TO_TICKS(100)); - ao_wakeup(&blink_chan); - } -} - -void -beep(void) -{ - static __xdata struct ao_adc adc; - - for (;;) { - ao_delay(AO_SEC_TO_TICKS(1)); - ao_adc_get(&adc); - if (adc.temp > 7400) - ao_beep_for(AO_BEEP_LOW, AO_MS_TO_TICKS(50)); - } -} - -void -echo(void) -{ - char c; - for (;;) { - ao_usb_flush(); - c = ao_usb_getchar(); - ao_usb_putchar(c); - if (c == '\r') - ao_usb_putchar('\n'); - } -} - -void -main(void) -{ - ao_clock_init(); - -// ao_add_task(&blink_0_task, blink_0); -// ao_add_task(&blink_1_task, blink_1); -// ao_add_task(&wakeup_task, wakeup); -// ao_add_task(&beep_task, beep); - ao_add_task(&echo_task, echo); - ao_timer_init(); - ao_adc_init(); - ao_beep_init(); - ao_led_init(); - ao_usb_init(); - - ao_start_scheduler(); -} diff --git a/src/ao_tidongle.c b/src/ao_tidongle.c deleted file mode 100644 index 3b7c2733..00000000 --- a/src/ao_tidongle.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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) -{ - ao_clock_init(); - - /* Turn on the LED until the system is stable */ - ao_led_init(AO_LED_RED); - ao_led_on(AO_LED_RED); - ao_timer_init(); - ao_cmd_init(); - ao_usb_init(); - ao_monitor_init(AO_LED_RED, TRUE); - ao_rssi_init(AO_LED_RED); - ao_radio_init(); - ao_dbg_init(); - ao_config_init(); - /* Bring up the USB link */ - P1DIR |= 1; - P1 |= 1; - ao_start_scheduler(); -} diff --git a/src/ao_timer.c b/src/ao_timer.c deleted file mode 100644 index c977fbc8..00000000 --- a/src/ao_timer.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" - -static volatile __data uint16_t ao_tick_count; - -uint16_t ao_time(void) __critical -{ - return ao_tick_count; -} - -static __xdata uint8_t ao_forever; - -void -ao_delay(uint16_t ticks) -{ - ao_alarm(ticks); - ao_sleep(&ao_forever); -} - -#define T1_CLOCK_DIVISOR 8 /* 24e6/8 = 3e6 */ -#define T1_SAMPLE_TIME 30000 /* 3e6/30000 = 100 */ - -#if HAS_ADC -volatile __data uint8_t ao_adc_interval = 1; -volatile __data uint8_t ao_adc_count; -#endif - -void ao_timer_isr(void) __interrupt 9 -{ - ++ao_tick_count; -#if HAS_ADC - if (++ao_adc_count == ao_adc_interval) { - ao_adc_count = 0; - ao_adc_poll(); - } -#endif -} - -#if HAS_ADC -void -ao_timer_set_adc_interval(uint8_t interval) __critical -{ - ao_adc_interval = interval; - ao_adc_count = 0; -} -#endif - -void -ao_timer_init(void) -{ - /* NOTE: This uses a timer only present on cc1111 architecture. */ - - /* disable timer 1 */ - T1CTL = 0; - - /* set the sample rate */ - T1CC0H = T1_SAMPLE_TIME >> 8; - T1CC0L = (uint8_t) T1_SAMPLE_TIME; - - T1CCTL0 = T1CCTL_MODE_COMPARE; - T1CCTL1 = 0; - T1CCTL2 = 0; - - /* clear timer value */ - T1CNTL = 0; - - /* enable overflow interrupt */ - OVFIM = 1; - /* enable timer 1 interrupt */ - T1IE = 1; - - /* enable timer 1 in module mode, dividing by 8 */ - T1CTL = T1CTL_MODE_MODULO | T1CTL_DIV_8; -} - -/* - * AltOS always cranks the clock to the max frequency - */ -void -ao_clock_init(void) -{ - /* Switch system clock to crystal oscilator */ - CLKCON = (CLKCON & ~CLKCON_OSC_MASK) | (CLKCON_OSC_XTAL); - - while (!(SLEEP & SLEEP_XOSC_STB)) - ; - - /* Crank up the timer tick and system clock speed */ - CLKCON = ((CLKCON & ~(CLKCON_TICKSPD_MASK | CLKCON_CLKSPD_MASK)) | - (CLKCON_TICKSPD_1 | CLKCON_CLKSPD_1)); - - while ((CLKCON & (CLKCON_TICKSPD_MASK|CLKCON_CLKSPD_MASK)) != - (CLKCON_TICKSPD_1 | CLKCON_CLKSPD_1)) - ; -} diff --git a/src/ao_usb.c b/src/ao_usb.c deleted file mode 100644 index 08cb7390..00000000 --- a/src/ao_usb.c +++ /dev/null @@ -1,460 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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" -#include "ao_usb.h" - -struct ao_task __xdata ao_usb_task; - -static __xdata uint16_t ao_usb_in_bytes; -static __pdata uint16_t ao_usb_in_bytes_last; -static __xdata uint16_t ao_usb_out_bytes; -static __pdata uint8_t ao_usb_iif; -static __pdata uint8_t ao_usb_running; - -static void -ao_usb_set_interrupts(void) -{ - /* IN interrupts on the control an IN endpoints */ - USBIIE = (1 << AO_USB_CONTROL_EP) | (1 << AO_USB_IN_EP); - - /* OUT interrupts on the OUT endpoint */ - USBOIE = (1 << AO_USB_OUT_EP); - - /* Only care about reset */ - USBCIE = USBCIE_RSTIE; -} - -/* This interrupt is shared with port 2, - * so when we hook that up, fix this - */ -void -ao_usb_isr(void) __interrupt 6 -{ - USBIF = 0; - ao_usb_iif |= USBIIF; - if (ao_usb_iif & 1) - ao_wakeup(&ao_usb_task); - if (ao_usb_iif & (1 << AO_USB_IN_EP)) - ao_wakeup(&ao_usb_in_bytes); - - if (USBOIF & (1 << AO_USB_OUT_EP)) - ao_wakeup(&ao_stdin_ready); - - if (USBCIF & USBCIF_RSTIF) - ao_usb_set_interrupts(); -#if HAS_BTM -#if BT_LINK_ON_P2 - ao_btm_isr(); -#endif -#endif -} - -struct ao_usb_setup { - uint8_t dir_type_recip; - uint8_t request; - uint16_t value; - uint16_t index; - uint16_t length; -} __xdata ao_usb_setup; - -__pdata uint8_t ao_usb_ep0_state; -uint8_t * __pdata ao_usb_ep0_in_data; -__pdata uint8_t ao_usb_ep0_in_len; -__pdata uint8_t ao_usb_ep0_in_buf[2]; -__pdata uint8_t ao_usb_ep0_out_len; -__xdata uint8_t *__pdata ao_usb_ep0_out_data; -__pdata uint8_t ao_usb_configuration; - -/* Send an IN data packet */ -static void -ao_usb_ep0_flush(void) -{ - __pdata uint8_t this_len; - __pdata uint8_t cs0; - - /* If the IN packet hasn't been picked up, just return */ - USBINDEX = 0; - cs0 = USBCS0; - if (cs0 & USBCS0_INPKT_RDY) - return; - - this_len = ao_usb_ep0_in_len; - if (this_len > AO_USB_CONTROL_SIZE) - this_len = AO_USB_CONTROL_SIZE; - cs0 = USBCS0_INPKT_RDY; - if (this_len != AO_USB_CONTROL_SIZE) { - cs0 = USBCS0_INPKT_RDY | USBCS0_DATA_END; - ao_usb_ep0_state = AO_USB_EP0_IDLE; - } - ao_usb_ep0_in_len -= this_len; - while (this_len--) - USBFIFO[0] = *ao_usb_ep0_in_data++; - USBINDEX = 0; - USBCS0 = cs0; -} - -__xdata static struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8}; - -/* Walk through the list of descriptors and find a match - */ -static void -ao_usb_get_descriptor(uint16_t value) -{ - __code uint8_t *__pdata descriptor; - __pdata uint8_t type = value >> 8; - __pdata uint8_t index = value; - - descriptor = ao_usb_descriptors; - while (descriptor[0] != 0) { - if (descriptor[1] == type && index-- == 0) { - if (type == AO_USB_DESC_CONFIGURATION) - ao_usb_ep0_in_len = descriptor[2]; - else - ao_usb_ep0_in_len = descriptor[0]; - ao_usb_ep0_in_data = descriptor; - break; - } - descriptor += descriptor[0]; - } -} - -/* Read data from the ep0 OUT fifo - */ -static void -ao_usb_ep0_fill(void) -{ - __pdata uint8_t len; - - USBINDEX = 0; - len = USBCNT0; - if (len > ao_usb_ep0_out_len) - len = ao_usb_ep0_out_len; - ao_usb_ep0_out_len -= len; - while (len--) - *ao_usb_ep0_out_data++ = USBFIFO[0]; -} - -void -ao_usb_ep0_queue_byte(uint8_t a) -{ - ao_usb_ep0_in_buf[ao_usb_ep0_in_len++] = a; -} - -void -ao_usb_set_address(uint8_t address) -{ - ao_usb_running = 1; - USBADDR = address | 0x80; - while (USBADDR & 0x80) - ; -} - -static void -ao_usb_set_configuration(void) -{ - /* Set the IN max packet size, double buffered */ - USBINDEX = AO_USB_IN_EP; - USBMAXI = AO_USB_IN_SIZE >> 3; - USBCSIH |= USBCSIH_IN_DBL_BUF; - - /* Set the OUT max packet size, double buffered */ - USBINDEX = AO_USB_OUT_EP; - USBMAXO = AO_USB_OUT_SIZE >> 3; - USBCSOH = USBCSOH_OUT_DBL_BUF; -} - -static void -ao_usb_ep0_setup(void) -{ - /* Pull the setup packet out of the fifo */ - ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_setup; - ao_usb_ep0_out_len = 8; - ao_usb_ep0_fill(); - if (ao_usb_ep0_out_len != 0) - return; - - /* Figure out how to ACK the setup packet */ - if (ao_usb_setup.dir_type_recip & AO_USB_DIR_IN) { - if (ao_usb_setup.length) - ao_usb_ep0_state = AO_USB_EP0_DATA_IN; - else - ao_usb_ep0_state = AO_USB_EP0_IDLE; - } else { - if (ao_usb_setup.length) - ao_usb_ep0_state = AO_USB_EP0_DATA_OUT; - else - ao_usb_ep0_state = AO_USB_EP0_IDLE; - } - USBINDEX = 0; - if (ao_usb_ep0_state == AO_USB_EP0_IDLE) - USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END; - else - USBCS0 = USBCS0_CLR_OUTPKT_RDY; - - ao_usb_ep0_in_data = ao_usb_ep0_in_buf; - ao_usb_ep0_in_len = 0; - switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_TYPE_MASK) { - case AO_USB_TYPE_STANDARD: - switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_RECIP_MASK) { - case AO_USB_RECIP_DEVICE: - switch(ao_usb_setup.request) { - case AO_USB_REQ_GET_STATUS: - ao_usb_ep0_queue_byte(0); - ao_usb_ep0_queue_byte(0); - break; - case AO_USB_REQ_SET_ADDRESS: - ao_usb_set_address(ao_usb_setup.value); - break; - case AO_USB_REQ_GET_DESCRIPTOR: - ao_usb_get_descriptor(ao_usb_setup.value); - break; - case AO_USB_REQ_GET_CONFIGURATION: - ao_usb_ep0_queue_byte(ao_usb_configuration); - break; - case AO_USB_REQ_SET_CONFIGURATION: - ao_usb_configuration = ao_usb_setup.value; - ao_usb_set_configuration(); - break; - } - 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); - ao_usb_ep0_queue_byte(0); - break; - case AO_USB_REQ_GET_INTERFACE: - ao_usb_ep0_queue_byte(0); - break; - case AO_USB_REQ_SET_INTERFACE: - break; - } - break; - case AO_USB_RECIP_ENDPOINT: - switch(ao_usb_setup.request) { - case AO_USB_REQ_GET_STATUS: - ao_usb_ep0_queue_byte(0); - ao_usb_ep0_queue_byte(0); - break; - } - break; - } - break; - case AO_USB_TYPE_CLASS: - switch (ao_usb_setup.request) { - case SET_LINE_CODING: - ao_usb_ep0_out_len = 7; - ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_line_coding; - break; - case GET_LINE_CODING: - ao_usb_ep0_in_len = 7; - ao_usb_ep0_in_data = (uint8_t *) &ao_usb_line_coding; - break; - case SET_CONTROL_LINE_STATE: - break; - } - break; - } - if (ao_usb_ep0_state != AO_USB_EP0_DATA_OUT) { - if (ao_usb_setup.length < ao_usb_ep0_in_len) - ao_usb_ep0_in_len = ao_usb_setup.length; - ao_usb_ep0_flush(); - } -} - -/* End point 0 receives all of the control messages. */ -static void -ao_usb_ep0(void) -{ - __pdata uint8_t cs0; - - ao_usb_ep0_state = AO_USB_EP0_IDLE; - for (;;) { - __critical for (;;) { - if (ao_usb_iif & 1) { - ao_usb_iif &= ~1; - break; - } - ao_sleep(&ao_usb_task); - } - USBINDEX = 0; - cs0 = USBCS0; - if (cs0 & USBCS0_SETUP_END) { - ao_usb_ep0_state = AO_USB_EP0_IDLE; - USBCS0 = USBCS0_CLR_SETUP_END; - } - if (cs0 & USBCS0_SENT_STALL) { - ao_usb_ep0_state = AO_USB_EP0_IDLE; - USBCS0 &= ~USBCS0_SENT_STALL; - } - if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN && - (cs0 & USBCS0_INPKT_RDY) == 0) - { - ao_usb_ep0_flush(); - } - if (cs0 & USBCS0_OUTPKT_RDY) { - switch (ao_usb_ep0_state) { - case AO_USB_EP0_IDLE: - ao_usb_ep0_setup(); - break; - case AO_USB_EP0_DATA_OUT: - ao_usb_ep0_fill(); - if (ao_usb_ep0_out_len == 0) - ao_usb_ep0_state = AO_USB_EP0_IDLE; - USBINDEX = 0; - if (ao_usb_ep0_state == AO_USB_EP0_IDLE) - USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END; - else - USBCS0 = USBCS0_CLR_OUTPKT_RDY; - break; - } - } - } -} - -/* Wait for a free IN buffer */ -static void -ao_usb_in_wait(void) -{ - for (;;) { - USBINDEX = AO_USB_IN_EP; - if ((USBCSIL & USBCSIL_INPKT_RDY) == 0) - break; - ao_sleep(&ao_usb_in_bytes); - } -} - -/* Send the current IN packet */ -static void -ao_usb_in_send(void) -{ - USBINDEX = AO_USB_IN_EP; - USBCSIL |= USBCSIL_INPKT_RDY; - ao_usb_in_bytes_last = ao_usb_in_bytes; - ao_usb_in_bytes = 0; -} - -void -ao_usb_flush(void) __critical -{ - if (!ao_usb_running) - return; - - /* If there are pending bytes, or if the last packet was full, - * send another IN packet - */ - if (ao_usb_in_bytes || (ao_usb_in_bytes_last == AO_USB_IN_SIZE)) { - ao_usb_in_wait(); - ao_usb_in_send(); - } -} - -void -ao_usb_putchar(char c) __critical __reentrant -{ - if (!ao_usb_running) - return; - - ao_usb_in_wait(); - - /* Queue a byte, sending the packet when full */ - USBFIFO[AO_USB_IN_EP << 1] = c; - if (++ao_usb_in_bytes == AO_USB_IN_SIZE) - ao_usb_in_send(); -} - -char -ao_usb_pollchar(void) __critical -{ - char c; - if (ao_usb_out_bytes == 0) { - USBINDEX = AO_USB_OUT_EP; - if ((USBCSOL & USBCSOL_OUTPKT_RDY) == 0) - return AO_READ_AGAIN; - ao_usb_out_bytes = (USBCNTH << 8) | USBCNTL; - if (ao_usb_out_bytes == 0) { - USBINDEX = AO_USB_OUT_EP; - USBCSOL &= ~USBCSOL_OUTPKT_RDY; - return AO_READ_AGAIN; - } - } - --ao_usb_out_bytes; - c = USBFIFO[AO_USB_OUT_EP << 1]; - if (ao_usb_out_bytes == 0) { - USBINDEX = AO_USB_OUT_EP; - USBCSOL &= ~USBCSOL_OUTPKT_RDY; - } - return c; -} - -char -ao_usb_getchar(void) __critical -{ - char c; - - while ((c = ao_usb_pollchar()) == AO_READ_AGAIN) - ao_sleep(&ao_stdin_ready); - return c; -} - -void -ao_usb_enable(void) -{ - /* Turn on the USB controller */ - SLEEP |= SLEEP_USB_EN; - - ao_usb_set_configuration(); - - ao_usb_set_interrupts(); - - /* enable USB interrupts */ - IEN2 |= IEN2_USBIE; - - /* Clear any pending interrupts */ - USBCIF = 0; - USBOIF = 0; - USBIIF = 0; -} - -void -ao_usb_disable(void) -{ - /* Disable USB interrupts */ - USBIIE = 0; - USBOIE = 0; - USBCIE = 0; - IEN2 &= ~IEN2_USBIE; - - /* Clear any pending interrupts */ - USBCIF = 0; - USBOIF = 0; - USBIIF = 0; - - /* Turn off the USB controller */ - SLEEP &= ~SLEEP_USB_EN; -} - -void -ao_usb_init(void) -{ - ao_usb_enable(); - - ao_add_task(&ao_usb_task, ao_usb_ep0, "usb"); - ao_add_stdio(ao_usb_pollchar, ao_usb_putchar, ao_usb_flush); -} diff --git a/src/ao_usb.h b/src/ao_usb.h deleted file mode 100644 index 6633dafc..00000000 --- a/src/ao_usb.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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_USB_H_ -#define _AO_USB_H_ - -#define AO_USB_SETUP_DIR_MASK (0x01 << 7) -#define AO_USB_SETUP_TYPE_MASK (0x03 << 5) -#define AO_USB_SETUP_RECIP_MASK (0x1f) - -#define AO_USB_DIR_OUT 0 -#define AO_USB_DIR_IN (1 << 7) - -#define AO_USB_TYPE_STANDARD 0 -#define AO_USB_TYPE_CLASS (1 << 5) -#define AO_USB_TYPE_VENDOR (2 << 5) -#define AO_USB_TYPE_RESERVED (3 << 5) - -#define AO_USB_RECIP_DEVICE 0 -#define AO_USB_RECIP_INTERFACE 1 -#define AO_USB_RECIP_ENDPOINT 2 -#define AO_USB_RECIP_OTHER 3 - -/* standard requests */ -#define AO_USB_REQ_GET_STATUS 0x00 -#define AO_USB_REQ_CLEAR_FEATURE 0x01 -#define AO_USB_REQ_SET_FEATURE 0x03 -#define AO_USB_REQ_SET_ADDRESS 0x05 -#define AO_USB_REQ_GET_DESCRIPTOR 0x06 -#define AO_USB_REQ_SET_DESCRIPTOR 0x07 -#define AO_USB_REQ_GET_CONFIGURATION 0x08 -#define AO_USB_REQ_SET_CONFIGURATION 0x09 -#define AO_USB_REQ_GET_INTERFACE 0x0A -#define AO_USB_REQ_SET_INTERFACE 0x0B -#define AO_USB_REQ_SYNCH_FRAME 0x0C - -#define AO_USB_DESC_DEVICE 1 -#define AO_USB_DESC_CONFIGURATION 2 -#define AO_USB_DESC_STRING 3 -#define AO_USB_DESC_INTERFACE 4 -#define AO_USB_DESC_ENDPOINT 5 -#define AO_USB_DESC_DEVICE_QUALIFIER 6 -#define AO_USB_DESC_OTHER_SPEED 7 -#define AO_USB_DESC_INTERFACE_POWER 8 - -#define AO_USB_GET_DESC_TYPE(x) (((x)>>8)&0xFF) -#define AO_USB_GET_DESC_INDEX(x) ((x)&0xFF) - -#define AO_USB_CONTROL_EP 0 -#define AO_USB_INT_EP 1 -#define AO_USB_OUT_EP 4 -#define AO_USB_IN_EP 5 -#define AO_USB_CONTROL_SIZE 32 -/* - * Double buffer IN and OUT EPs, so each - * gets half of the available space - * - * Ah, but USB bulk packets can only come in 8, 16, 32 and 64 - * byte sizes, so we'll use 64 for everything - */ -#define AO_USB_IN_SIZE 64 -#define AO_USB_OUT_SIZE 64 - -#define AO_USB_EP0_IDLE 0 -#define AO_USB_EP0_DATA_IN 1 -#define AO_USB_EP0_DATA_OUT 2 - -#define LE_WORD(x) ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8)) - -/* CDC definitions */ -#define CS_INTERFACE 0x24 -#define CS_ENDPOINT 0x25 - -#define SET_LINE_CODING 0x20 -#define GET_LINE_CODING 0x21 -#define SET_CONTROL_LINE_STATE 0x22 - -/* Data structure for GET_LINE_CODING / SET_LINE_CODING class requests */ -struct ao_usb_line_coding { - uint32_t rate; - uint8_t char_format; - uint8_t parity; - uint8_t data_bits; -} ; - -#endif /* _AO_USB_H_ */ diff --git a/src/at45db161d.h b/src/at45db161d.h deleted file mode 100644 index 9ee6f1b6..00000000 --- a/src/at45db161d.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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. - */ - -/* Defines for the Atmel AT45DB161D 16Mbit SPI Bus DataFlash® */ - -#ifndef _AT45DB161D_H_ -#define _AT45DB161D_H_ - -/* - * We reserve the last block on the device for - * configuration space. Writes and reads in this - * area return errors. - */ - - -#define FLASH_READ 0x03 -#define FLASH_WRITE 0x82 -#define FLASH_PAGE_ERASE 0x81 -#define FLASH_READ_STATUS 0xd7 -#define FLASH_SET_CONFIG 0x3d - -#define FLASH_SET_512_BYTE_0 0x2a -#define FLASH_SET_512_BYTE_1 0x80 -#define FLASH_SET_512_BYTE_2 0xa6 - -#define FLASH_STATUS_RDY (1 << 7) -#define FLASH_STATUS_COMP (1 << 6) -#define FLASH_STATUS_PROTECT (1 << 1) -#define FLASH_STATUS_PAGESIZE_512 (1 << 0) - -#endif /* _AT45DB161D_H_ */ diff --git a/src/cc1111.h b/src/cc1111.h deleted file mode 100644 index e52aa79f..00000000 --- a/src/cc1111.h +++ /dev/null @@ -1,1306 +0,0 @@ -/*------------------------------------------------------------------------- - Register Declarations for the ChipCon CC1111 Processor Range - - Copyright © 2008 Keith Packard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; 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. - - Adapted from the Cygnal C8051F12x config file which is: - - Copyright (C) 2003 - Maarten Brock, sourceforge.brock@dse.nl - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --------------------------------------------------------------------------*/ - -#ifndef _CC1111_H_ -#define _CC1111_H_ -#include -#include - -__sfr __at 0xA8 IEN0; /* Interrupt Enable 0 Register */ - -sbit __at 0xA8 RFTXRXIE; /* RF TX/RX done interrupt enable */ -sbit __at 0xA9 ADCIE; /* ADC interrupt enable */ -sbit __at 0xAA URX0IE; /* USART0 RX interrupt enable */ -sbit __at 0xAB URX1IE; /* USART1 RX interrupt enable (shared with I2S RX) */ -sbit __at 0xAB I2SRXIE; /* I2S RX interrupt enable (shared with USART1 RX) */ -sbit __at 0xAC ENCIE; /* AES encryption/decryption interrupt enable */ -sbit __at 0xAD STIE; /* Sleep Timer interrupt enable */ -sbit __at 0xAF EA; /* Enable All */ - -#define IEN0_EA (1 << 7) -#define IEN0_STIE (1 << 5) -#define IEN0_ENCIE (1 << 4) -#define IEN0_URX1IE (1 << 3) -#define IEN0_I2SRXIE (1 << 3) -#define IEN0_URX0IE (1 << 2) -#define IEN0_ADCIE (1 << 1) -#define IEN0_RFTXRXIE (1 << 0) - -__sfr __at 0xB8 IEN1; /* Interrupt Enable 1 Register */ - -#define IEN1_P0IE (1 << 5) /* Port 0 interrupt enable */ -#define IEN1_T4IE (1 << 4) /* Timer 4 interrupt enable */ -#define IEN1_T3IE (1 << 3) /* Timer 3 interrupt enable */ -#define IEN1_T2IE (1 << 2) /* Timer 2 interrupt enable */ -#define IEN1_T1IE (1 << 1) /* Timer 1 interrupt enable */ -#define IEN1_DMAIE (1 << 0) /* DMA transfer interrupt enable */ - -/* IEN2 */ -__sfr __at 0x9A IEN2; /* Interrupt Enable 2 Register */ - -#define IEN2_WDTIE (1 << 5) /* Watchdog timer interrupt enable */ -#define IEN2_P1IE (1 << 4) /* Port 1 interrupt enable */ -#define IEN2_UTX1IE (1 << 3) /* USART1 TX interrupt enable */ -#define IEN2_I2STXIE (1 << 3) /* I2S TX interrupt enable */ -#define IEN2_UTX0IE (1 << 2) /* USART0 TX interrupt enable */ -#define IEN2_P2IE (1 << 1) /* Port 2 interrupt enable */ -#define IEN2_USBIE (1 << 1) /* USB interrupt enable */ -#define IEN2_RFIE (1 << 0) /* RF general interrupt enable */ - -/* CLKCON 0xC6 */ -__sfr __at 0xC6 CLKCON; /* Clock Control */ - -#define CLKCON_OSC32K_RC (1 << 7) -#define CLKCON_OSC32K_XTAL (0 << 7) -#define CLKCON_OSC32K_MASK (1 << 7) -#define CLKCON_OSC_RC (1 << 6) -#define CLKCON_OSC_XTAL (0 << 6) -#define CLKCON_OSC_MASK (1 << 6) -#define CLKCON_TICKSPD_MASK (7 << 3) -# define CLKCON_TICKSPD_1 (0 << 3) -# define CLKCON_TICKSPD_1_2 (1 << 3) -# define CLKCON_TICKSPD_1_4 (2 << 3) -# define CLKCON_TICKSPD_1_8 (3 << 3) -# define CLKCON_TICKSPD_1_16 (4 << 3) -# define CLKCON_TICKSPD_1_32 (5 << 3) -# define CLKCON_TICKSPD_1_64 (6 << 3) -# define CLKCON_TICKSPD_1_128 (7 << 3) - -#define CLKCON_CLKSPD_MASK (7 << 0) -# define CLKCON_CLKSPD_1 (0 << 0) -# define CLKCON_CLKSPD_1_2 (1 << 0) -# define CLKCON_CLKSPD_1_4 (2 << 0) -# define CLKCON_CLKSPD_1_8 (3 << 0) -# define CLKCON_CLKSPD_1_16 (4 << 0) -# define CLKCON_CLKSPD_1_32 (5 << 0) -# define CLKCON_CLKSPD_1_64 (6 << 0) -# define CLKCON_CLKSPD_1_128 (7 << 0) - -/* SLEEP 0xBE */ -#define SLEEP_USB_EN (1 << 7) -#define SLEEP_XOSC_STB (1 << 6) -#define SLEEP_HFRC_STB (1 << 5) -#define SLEEP_RST_POWER (0 << 3) -#define SLEEP_RST_EXTERNAL (1 << 3) -#define SLEEP_RST_WATCHDOG (2 << 3) -#define SLEEP_RST_MASK (3 << 3) -#define SLEEP_OSC_PD (1 << 2) -#define SLEEP_MODE_PM0 (0 << 0) -#define SLEEP_MODE_PM1 (1 << 0) -#define SLEEP_MODE_PM2 (2 << 0) -#define SLEEP_MODE_PM3 (3 << 0) -#define SLEEP_MODE_MASK (3 << 0) - -/* PCON 0x87 */ -__sfr __at 0x87 PCON; /* Power Mode Control Register */ - -#define PCON_IDLE (1 << 0) - -/* - * TCON - */ -__sfr __at 0x88 TCON; /* CPU Interrupt Flag 1 */ - -sbit __at 0x8F URX1IF; /* USART1 RX interrupt flag. Automatically cleared */ -sbit __at 0x8F I2SRXIF; /* I2S RX interrupt flag. Automatically cleared */ -sbit __at 0x8D ADCIF; /* ADC interrupt flag. Automatically cleared */ -sbit __at 0x8B URX0IF; /* USART0 RX interrupt flag. Automatically cleared */ -sbit __at 0x89 RFTXRXIF; /* RF TX/RX complete interrupt flag. Automatically cleared */ - -#define TCON_URX1IF (1 << 7) -#define TCON_I2SRXIF (1 << 7) -#define TCON_ADCIF (1 << 5) -#define TCON_URX0IF (1 << 3) -#define TCON_RFTXRXIF (1 << 1) - -/* - * S0CON - */ -__sfr __at 0x98 S0CON; /* CPU Interrupt Flag 2 */ - -sbit __at 0x98 ENCIF_0; /* AES interrupt 0. */ -sbit __at 0x99 ENCIF_1; /* AES interrupt 1. */ - -#define S0CON_ENCIF_1 (1 << 1) -#define S0CON_ENCIF_0 (1 << 0) - -/* - * S1CON - */ -__sfr __at 0x9B S1CON; /* CPU Interrupt Flag 3 */ - -#define S1CON_RFIF_1 (1 << 1) -#define S1CON_RFIF_0 (1 << 0) - -/* - * IRCON - */ -__sfr __at 0xC0 IRCON; /* CPU Interrupt Flag 4 */ - -sbit __at 0xC0 DMAIF; /* DMA complete interrupt flag */ -sbit __at 0xC1 T1IF; /* Timer 1 interrupt flag. Automatically cleared */ -sbit __at 0xC2 T2IF; /* Timer 2 interrupt flag. Automatically cleared */ -sbit __at 0xC3 T3IF; /* Timer 3 interrupt flag. Automatically cleared */ -sbit __at 0xC4 T4IF; /* Timer 4 interrupt flag. Automatically cleared */ -sbit __at 0xC5 P0IF; /* Port0 interrupt flag */ -sbit __at 0xC7 STIF; /* Sleep Timer interrupt flag */ - -#define IRCON_DMAIF (1 << 0) /* DMA complete interrupt flag */ -#define IRCON_T1IF (1 << 1) /* Timer 1 interrupt flag. Automatically cleared */ -#define IRCON_T2IF (1 << 2) /* Timer 2 interrupt flag. Automatically cleared */ -#define IRCON_T3IF (1 << 3) /* Timer 3 interrupt flag. Automatically cleared */ -#define IRCON_T4IF (1 << 4) /* Timer 4 interrupt flag. Automatically cleared */ -#define IRCON_P0IF (1 << 5) /* Port0 interrupt flag */ -#define IRCON_STIF (1 << 7) /* Sleep Timer interrupt flag */ - -/* - * IRCON2 - */ -__sfr __at 0xE8 IRCON2; /* CPU Interrupt Flag 5 */ - -sbit __at 0xE8 USBIF; /* USB interrupt flag (shared with Port2) */ -sbit __at 0xE8 P2IF; /* Port2 interrupt flag (shared with USB) */ -sbit __at 0xE9 UTX0IF; /* USART0 TX interrupt flag */ -sbit __at 0xEA UTX1IF; /* USART1 TX interrupt flag (shared with I2S TX) */ -sbit __at 0xEA I2STXIF; /* I2S TX interrupt flag (shared with USART1 TX) */ -sbit __at 0xEB P1IF; /* Port1 interrupt flag */ -sbit __at 0xEC WDTIF; /* Watchdog timer interrupt flag */ - -#define IRCON2_USBIF (1 << 0) /* USB interrupt flag (shared with Port2) */ -#define IRCON2_P2IF (1 << 0) /* Port2 interrupt flag (shared with USB) */ -#define IRCON2_UTX0IF (1 << 1) /* USART0 TX interrupt flag */ -#define IRCON2_UTX1IF (1 << 2) /* USART1 TX interrupt flag (shared with I2S TX) */ -#define IRCON2_I2STXIF (1 << 2) /* I2S TX interrupt flag (shared with USART1 TX) */ -#define IRCON2_P1IF (1 << 3) /* Port1 interrupt flag */ -#define IRCON2_WDTIF (1 << 4) /* Watchdog timer interrupt flag */ - -/* - * IP1 - Interrupt Priority 1 - */ - -/* - * Interrupt priority groups: - * - * IPG0 RFTXRX RF DMA - * IPG1 ADC T1 P2INT/USB - * IPG2 URX0 T2 UTX0 - * IPG3 URX1/I2SRX T3 UTX1 / I2STX - * IPG4 ENC T4 P1INT - * IPG5 ST P0INT WDT - * - * Priority = (IP1 << 1) | IP0. Higher priority interrupts served first - */ - -__sfr __at 0xB9 IP1; /* Interrupt Priority 1 */ -__sfr __at 0xA9 IP0; /* Interrupt Priority 0 */ - -#define IP1_IPG5 (1 << 5) -#define IP1_IPG4 (1 << 4) -#define IP1_IPG3 (1 << 3) -#define IP1_IPG2 (1 << 2) -#define IP1_IPG1 (1 << 1) -#define IP1_IPG0 (1 << 0) - -#define IP0_IPG5 (1 << 5) -#define IP0_IPG4 (1 << 4) -#define IP0_IPG3 (1 << 3) -#define IP0_IPG2 (1 << 2) -#define IP0_IPG1 (1 << 1) -#define IP0_IPG0 (1 << 0) - -/* - * Timer 1 - */ -#define T1CTL_MODE_SUSPENDED (0 << 0) -#define T1CTL_MODE_FREE (1 << 0) -#define T1CTL_MODE_MODULO (2 << 0) -#define T1CTL_MODE_UP_DOWN (3 << 0) -#define T1CTL_MODE_MASK (3 << 0) -#define T1CTL_DIV_1 (0 << 2) -#define T1CTL_DIV_8 (1 << 2) -#define T1CTL_DIV_32 (2 << 2) -#define T1CTL_DIV_128 (3 << 2) -#define T1CTL_DIV_MASK (3 << 2) -#define T1CTL_OVFIF (1 << 4) -#define T1CTL_CH0IF (1 << 5) -#define T1CTL_CH1IF (1 << 6) -#define T1CTL_CH2IF (1 << 7) - -#define T1CCTL_NO_CAPTURE (0 << 0) -#define T1CCTL_CAPTURE_RISING (1 << 0) -#define T1CCTL_CAPTURE_FALLING (2 << 0) -#define T1CCTL_CAPTURE_BOTH (3 << 0) -#define T1CCTL_CAPTURE_MASK (3 << 0) - -#define T1CCTL_MODE_CAPTURE (0 << 2) -#define T1CCTL_MODE_COMPARE (1 << 2) - -#define T1CTL_CMP_SET (0 << 3) -#define T1CTL_CMP_CLEAR (1 << 3) -#define T1CTL_CMP_TOGGLE (2 << 3) -#define T1CTL_CMP_SET_CLEAR (3 << 3) -#define T1CTL_CMP_CLEAR_SET (4 << 3) - -#define T1CTL_IM_DISABLED (0 << 6) -#define T1CTL_IM_ENABLED (1 << 6) - -#define T1CTL_CPSEL_NORMAL (0 << 7) -#define T1CTL_CPSEL_RF (1 << 7) - -/* - * Timer 3 and Timer 4 - */ - -/* Timer count */ -__sfr __at 0xCA T3CNT; -__sfr __at 0xEA T4CNT; - -/* Timer control */ - -__sfr __at 0xCB T3CTL; -__sfr __at 0xEB T4CTL; - -#define TxCTL_DIV_1 (0 << 5) -#define TxCTL_DIV_2 (1 << 5) -#define TxCTL_DIV_4 (2 << 5) -#define TxCTL_DIV_8 (3 << 5) -#define TxCTL_DIV_16 (4 << 5) -#define TxCTL_DIV_32 (5 << 5) -#define TxCTL_DIV_64 (6 << 5) -#define TxCTL_DIV_128 (7 << 5) -#define TxCTL_START (1 << 4) -#define TxCTL_OVFIM (1 << 3) -#define TxCTL_CLR (1 << 2) -#define TxCTL_MODE_FREE (0 << 0) -#define TxCTL_MODE_DOWN (1 << 0) -#define TxCTL_MODE_MODULO (2 << 0) -#define TxCTL_MODE_UP_DOWN (3 << 0) - -/* Timer 4 channel 0 compare control */ - -__sfr __at 0xCC T3CCTL0; -__sfr __at 0xCE T3CCTL1; -__sfr __at 0xEC T4CCTL0; -__sfr __at 0xEE T4CCTL1; - -#define TxCCTLy_IM (1 << 6) -#define TxCCTLy_CMP_SET (0 << 3) -#define TxCCTLy_CMP_CLEAR (1 << 3) -#define TxCCTLy_CMP_TOGGLE (2 << 3) -#define TxCCTLy_CMP_SET_UP_CLEAR_DOWN (3 << 3) -#define TxCCTLy_CMP_CLEAR_UP_SET_DOWN (4 << 3) -#define TxCCTLy_CMP_SET_CLEAR_FF (5 << 3) -#define TxCCTLy_CMP_CLEAR_SET_00 (6 << 3) -#define TxCCTLy_CMP_MODE_ENABLE (1 << 2) - -/* Timer compare value */ -__sfr __at 0xCD T3CC0; -__sfr __at 0xCF T3CC1; -__sfr __at 0xED T4CC0; -__sfr __at 0xEF T4CC1; - -/* - * Peripheral control - */ - -__sfr __at 0xf1 PERCFG; -#define PERCFG_T1CFG_ALT_1 (0 << 6) -#define PERCFG_T1CFG_ALT_2 (1 << 6) -#define PERCFG_T1CFG_ALT_MASK (1 << 6) - -#define PERCFG_T3CFG_ALT_1 (0 << 5) -#define PERCFG_T3CFG_ALT_2 (1 << 5) -#define PERCFG_T3CFG_ALT_MASK (1 << 5) - -#define PERCFG_T4CFG_ALT_1 (0 << 4) -#define PERCFG_T4CFG_ALT_2 (1 << 4) -#define PERCFG_T4CFG_ALT_MASK (1 << 4) - -#define PERCFG_U1CFG_ALT_1 (0 << 1) -#define PERCFG_U1CFG_ALT_2 (1 << 1) -#define PERCFG_U1CFG_ALT_MASK (1 << 1) - -#define PERCFG_U0CFG_ALT_1 (0 << 0) -#define PERCFG_U0CFG_ALT_2 (1 << 0) -#define PERCFG_U0CFG_ALT_MASK (1 << 0) - -/* directly addressed USB registers */ -__xdata __at (0xde00) volatile uint8_t USBADDR; -__xdata __at (0xde01) volatile uint8_t USBPOW; -__xdata __at (0xde02) volatile uint8_t USBIIF; - -__xdata __at (0xde04) volatile uint8_t USBOIF; - -__xdata __at (0xde06) volatile uint8_t USBCIF; - -# define USBCIF_SOFIF (1 << 3) -# define USBCIF_RSTIF (1 << 2) -# define USBCIF_RESUMEIF (1 << 1) -# define USBCIF_SUSPENDIF (1 << 0) - -__xdata __at (0xde07) volatile uint8_t USBIIE; - -__xdata __at (0xde09) volatile uint8_t USBOIE; - -__xdata __at (0xde0b) volatile uint8_t USBCIE; - -# define USBCIE_SOFIE (1 << 3) -# define USBCIE_RSTIE (1 << 2) -# define USBCIE_RESUMEIE (1 << 1) -# define USBCIE_SUSPENDIE (1 << 0) - -__xdata __at (0xde0c) volatile uint8_t USBFRML; -__xdata __at (0xde0d) volatile uint8_t USBFRMH; -__xdata __at (0xde0e) volatile uint8_t USBINDEX; - -/* indexed USB registers, must set USBINDEX to 0-5 */ -__xdata __at (0xde10) volatile uint8_t USBMAXI; -__xdata __at (0xde11) volatile uint8_t USBCS0; - -# define USBCS0_CLR_SETUP_END (1 << 7) -# define USBCS0_CLR_OUTPKT_RDY (1 << 6) -# define USBCS0_SEND_STALL (1 << 5) -# define USBCS0_SETUP_END (1 << 4) -# define USBCS0_DATA_END (1 << 3) -# define USBCS0_SENT_STALL (1 << 2) -# define USBCS0_INPKT_RDY (1 << 1) -# define USBCS0_OUTPKT_RDY (1 << 0) - -__xdata __at (0xde11) volatile uint8_t USBCSIL; - -# define USBCSIL_CLR_DATA_TOG (1 << 6) -# define USBCSIL_SENT_STALL (1 << 5) -# define USBCSIL_SEND_STALL (1 << 4) -# define USBCSIL_FLUSH_PACKET (1 << 3) -# define USBCSIL_UNDERRUN (1 << 2) -# define USBCSIL_PKT_PRESENT (1 << 1) -# define USBCSIL_INPKT_RDY (1 << 0) - -__xdata __at (0xde12) volatile uint8_t USBCSIH; - -# define USBCSIH_AUTOSET (1 << 7) -# define USBCSIH_ISO (1 << 6) -# define USBCSIH_FORCE_DATA_TOG (1 << 3) -# define USBCSIH_IN_DBL_BUF (1 << 0) - -__xdata __at (0xde13) volatile uint8_t USBMAXO; -__xdata __at (0xde14) volatile uint8_t USBCSOL; - -# define USBCSOL_CLR_DATA_TOG (1 << 7) -# define USBCSOL_SENT_STALL (1 << 6) -# define USBCSOL_SEND_STALL (1 << 5) -# define USBCSOL_FLUSH_PACKET (1 << 4) -# define USBCSOL_DATA_ERROR (1 << 3) -# define USBCSOL_OVERRUN (1 << 2) -# define USBCSOL_FIFO_FULL (1 << 1) -# define USBCSOL_OUTPKT_RDY (1 << 0) - -__xdata __at (0xde15) volatile uint8_t USBCSOH; - -# define USBCSOH_AUTOCLEAR (1 << 7) -# define USBCSOH_ISO (1 << 6) -# define USBCSOH_OUT_DBL_BUF (1 << 0) - -__xdata __at (0xde16) volatile uint8_t USBCNT0; -__xdata __at (0xde16) volatile uint8_t USBCNTL; -__xdata __at (0xde17) volatile uint8_t USBCNTH; - -__xdata __at (0xde20) volatile uint8_t USBFIFO[12]; - -/* ADC Data register, low and high */ -__sfr at 0xBA ADCL; -__sfr at 0xBB ADCH; -__xdata __at (0xDFBA) volatile uint16_t ADCXDATA; - -/* ADC Control Register 1 */ -__sfr at 0xB4 ADCCON1; - -# define ADCCON1_EOC (1 << 7) /* conversion complete */ -# define ADCCON1_ST (1 << 6) /* start conversion */ - -# define ADCCON1_STSEL_MASK (3 << 4) /* start select */ -# define ADCCON1_STSEL_EXTERNAL (0 << 4) /* P2_0 pin triggers */ -# define ADCCON1_STSEL_FULLSPEED (1 << 4) /* full speed, no waiting */ -# define ADCCON1_STSEL_TIMER1 (2 << 4) /* timer 1 channel 0 */ -# define ADCCON1_STSEL_START (3 << 4) /* set start bit */ - -# define ADCCON1_RCTRL_MASK (3 << 2) /* random number control */ -# define ADCCON1_RCTRL_COMPLETE (0 << 2) /* operation completed */ -# define ADCCON1_RCTRL_CLOCK_LFSR (1 << 2) /* Clock the LFSR once */ - -/* ADC Control Register 2 */ -__sfr at 0xB5 ADCCON2; - -# define ADCCON2_SREF_MASK (3 << 6) /* reference voltage */ -# define ADCCON2_SREF_1_25V (0 << 6) /* internal 1.25V */ -# define ADCCON2_SREF_EXTERNAL (1 << 6) /* external on AIN7 cc1110 */ -# define ADCCON2_SREF_VDD (2 << 6) /* VDD on the AVDD pin */ -# define ADCCON2_SREF_EXTERNAL_DIFF (3 << 6) /* external on AIN6-7 cc1110 */ - -# define ADCCON2_SDIV_MASK (3 << 4) /* decimation rate */ -# define ADCCON2_SDIV_64 (0 << 4) /* 7 bits */ -# define ADCCON2_SDIV_128 (1 << 4) /* 9 bits */ -# define ADCCON2_SDIV_256 (2 << 4) /* 10 bits */ -# define ADCCON2_SDIV_512 (3 << 4) /* 12 bits */ - -# define ADCCON2_SCH_MASK (0xf << 0) /* Sequence channel select */ -# define ADCCON2_SCH_SHIFT 0 -# define ADCCON2_SCH_AIN0 (0 << 0) -# define ADCCON2_SCH_AIN1 (1 << 0) -# define ADCCON2_SCH_AIN2 (2 << 0) -# define ADCCON2_SCH_AIN3 (3 << 0) -# define ADCCON2_SCH_AIN4 (4 << 0) -# define ADCCON2_SCH_AIN5 (5 << 0) -# define ADCCON2_SCH_AIN6 (6 << 0) -# define ADCCON2_SCH_AIN7 (7 << 0) -# define ADCCON2_SCH_AIN0_AIN1 (8 << 0) -# define ADCCON2_SCH_AIN2_AIN3 (9 << 0) -# define ADCCON2_SCH_AIN4_AIN5 (0xa << 0) -# define ADCCON2_SCH_AIN6_AIN7 (0xb << 0) -# define ADCCON2_SCH_GND (0xc << 0) -# define ADCCON2_SCH_VREF (0xd << 0) -# define ADCCON2_SCH_TEMP (0xe << 0) -# define ADCCON2_SCH_VDD_3 (0xf << 0) - - -/* ADC Control Register 3 */ -__sfr at 0xB6 ADCCON3; - -# define ADCCON3_EREF_MASK (3 << 6) /* extra conversion reference */ -# define ADCCON3_EREF_1_25 (0 << 6) /* internal 1.25V */ -# define ADCCON3_EREF_EXTERNAL (1 << 6) /* external AIN7 cc1110 */ -# define ADCCON3_EREF_VDD (2 << 6) /* VDD on the AVDD pin */ -# define ADCCON3_EREF_EXTERNAL_DIFF (3 << 6) /* external AIN6-7 cc1110 */ -# define ADCCON3_EDIV_MASK (3 << 4) /* extral decimation */ -# define ADCCON3_EDIV_64 (0 << 4) /* 7 bits */ -# define ADCCON3_EDIV_128 (1 << 4) /* 9 bits */ -# define ADCCON3_EDIV_256 (2 << 4) /* 10 bits */ -# define ADCCON3_EDIV_512 (3 << 4) /* 12 bits */ -# define ADCCON3_ECH_MASK (0xf << 0) /* Sequence channel select */ -# define ADCCON3_ECH_SHIFT 0 -# define ADCCON3_ECH_AIN0 (0 << 0) -# define ADCCON3_ECH_AIN1 (1 << 0) -# define ADCCON3_ECH_AIN2 (2 << 0) -# define ADCCON3_ECH_AIN3 (3 << 0) -# define ADCCON3_ECH_AIN4 (4 << 0) -# define ADCCON3_ECH_AIN5 (5 << 0) -# define ADCCON3_ECH_AIN6 (6 << 0) -# define ADCCON3_ECH_AIN7 (7 << 0) -# define ADCCON3_ECH_AIN0_AIN1 (8 << 0) -# define ADCCON3_ECH_AIN2_AIN3 (9 << 0) -# define ADCCON3_ECH_AIN4_AIN5 (0xa << 0) -# define ADCCON3_ECH_AIN6_AIN7 (0xb << 0) -# define ADCCON3_ECH_GND (0xc << 0) -# define ADCCON3_ECH_VREF (0xd << 0) -# define ADCCON3_ECH_TEMP (0xe << 0) -# define ADCCON3_ECH_VDD_3 (0xf << 0) - -/* - * ADC configuration register, this selects which - * GPIO pins are to be used as ADC inputs - */ -__sfr at 0xF2 ADCCFG; - -/* - * Watchdog timer - */ - -__sfr at 0xc9 WDCTL; - -#define WDCTL_CLEAR_FIRST (0xa << 4) -#define WDCTL_CLEAR_SECOND (0x5 << 4) -#define WDCTL_EN (1 << 3) -#define WDCTL_MODE_WATCHDOG (0 << 2) -#define WDCTL_MODE_TIMER (1 << 2) -#define WDCTL_MODE_MASK (1 << 2) -#define WDCTL_INT_32768 (0 << 0) -#define WDCTL_INT_8192 (1 << 0) -#define WDCTL_INT_512 (2 << 0) -#define WDCTL_INT_64 (3 << 0) - -/* - * Pin selectors, these set which pins are - * using their peripheral function - */ -__sfr at 0xF3 P0SEL; -__sfr at 0xF4 P1SEL; -__sfr at 0xF5 P2SEL; - -#define P2SEL_PRI3P1_USART0 (0 << 6) -#define P2SEL_PRI3P1_USART1 (1 << 6) -#define P2SEL_PRI3P1_MASK (1 << 6) -#define P2SEL_PRI2P1_USART1 (0 << 5) -#define P2SEL_PRI2P1_TIMER3 (1 << 5) -#define P2SEL_PRI2P1_MASK (1 << 5) -#define P2SEL_PRI1P1_TIMER1 (0 << 4) -#define P2SEL_PRI1P1_TIMER4 (1 << 4) -#define P2SEL_PRI1P1_MASK (1 << 4) -#define P2SEL_PRI0P1_USART0 (0 << 3) -#define P2SEL_PRI0P1_TIMER1 (1 << 3) -#define P2SEL_PRI0P1_MASK (1 << 3) -#define P2SEL_SELP2_4_GPIO (0 << 2) -#define P2SEL_SELP2_4_PERIPHERAL (1 << 2) -#define P2SEL_SELP2_4_MASK (1 << 2) -#define P2SEL_SELP2_3_GPIO (0 << 1) -#define P2SEL_SELP2_3_PERIPHERAL (1 << 1) -#define P2SEL_SELP2_3_MASK (1 << 1) -#define P2SEL_SELP2_0_GPIO (0 << 0) -#define P2SEL_SELP2_0_PERIPHERAL (1 << 0) -#define P2SEL_SELP2_0_MASK (1 << 0) - -/* - * For pins used as GPIOs, these set which are used as outputs - */ -__sfr at 0xFD P0DIR; -__sfr at 0xFE P1DIR; -__sfr at 0xFF P2DIR; - -#define P2DIR_PRIP0_USART0_USART1 (0 << 6) -#define P2DIR_PRIP0_USART1_USART0 (1 << 6) -#define P2DIR_PRIP0_TIMER1_01_USART1 (2 << 6) -#define P2DIR_PRIP0_TIMER1_2_USART0 (3 << 6) -#define P2DIR_PRIP0_MASK (3 << 6) - -__sfr at 0x8F P0INP; - -/* Select between tri-state and pull up/down - * for pins P0_0 - P0_7. - */ -#define P0INP_MDP0_7_PULL (0 << 7) -#define P0INP_MDP0_7_TRISTATE (1 << 7) -#define P0INP_MDP0_6_PULL (0 << 6) -#define P0INP_MDP0_6_TRISTATE (1 << 6) -#define P0INP_MDP0_5_PULL (0 << 5) -#define P0INP_MDP0_5_TRISTATE (1 << 5) -#define P0INP_MDP0_4_PULL (0 << 4) -#define P0INP_MDP0_4_TRISTATE (1 << 4) -#define P0INP_MDP0_3_PULL (0 << 3) -#define P0INP_MDP0_3_TRISTATE (1 << 3) -#define P0INP_MDP0_2_PULL (0 << 2) -#define P0INP_MDP0_2_TRISTATE (1 << 2) -#define P0INP_MDP0_1_PULL (0 << 1) -#define P0INP_MDP0_1_TRISTATE (1 << 1) -#define P0INP_MDP0_0_PULL (0 << 0) -#define P0INP_MDP0_0_TRISTATE (1 << 0) - -__sfr at 0xF6 P1INP; - -/* Select between tri-state and pull up/down - * for pins P1_2 - P1_7. Pins P1_0 and P1_1 are - * always tri-stated - */ -#define P1INP_MDP1_7_PULL (0 << 7) -#define P1INP_MDP1_7_TRISTATE (1 << 7) -#define P1INP_MDP1_6_PULL (0 << 6) -#define P1INP_MDP1_6_TRISTATE (1 << 6) -#define P1INP_MDP1_5_PULL (0 << 5) -#define P1INP_MDP1_5_TRISTATE (1 << 5) -#define P1INP_MDP1_4_PULL (0 << 4) -#define P1INP_MDP1_4_TRISTATE (1 << 4) -#define P1INP_MDP1_3_PULL (0 << 3) -#define P1INP_MDP1_3_TRISTATE (1 << 3) -#define P1INP_MDP1_2_PULL (0 << 2) -#define P1INP_MDP1_2_TRISTATE (1 << 2) - -__sfr at 0xF7 P2INP; -/* P2INP has three extra bits which are used to choose - * between pull-up and pull-down when they are not tri-stated - */ -#define P2INP_PDUP2_PULL_UP (0 << 7) -#define P2INP_PDUP2_PULL_DOWN (1 << 7) -#define P2INP_PDUP1_PULL_UP (0 << 6) -#define P2INP_PDUP1_PULL_DOWN (1 << 6) -#define P2INP_PDUP0_PULL_UP (0 << 5) -#define P2INP_PDUP0_PULL_DOWN (1 << 5) - -/* For the P2 pins, choose between tri-state and pull up/down - * mode - */ -#define P2INP_MDP2_4_PULL (0 << 4) -#define P2INP_MDP2_4_TRISTATE (1 << 4) -#define P2INP_MDP2_3_PULL (0 << 3) -#define P2INP_MDP2_3_TRISTATE (1 << 3) -#define P2INP_MDP2_2_PULL (0 << 2) -#define P2INP_MDP2_2_TRISTATE (1 << 2) -#define P2INP_MDP2_1_PULL (0 << 1) -#define P2INP_MDP2_1_TRISTATE (1 << 1) -#define P2INP_MDP2_0_PULL (0 << 0) -#define P2INP_MDP2_0_TRISTATE (1 << 0) - -/* GPIO interrupt status flags */ -__sfr at 0x89 P0IFG; -__sfr at 0x8A P1IFG; -__sfr at 0x8B P2IFG; - -#define P0IFG_USB_RESUME (1 << 7) - -__sfr at 0x8C PICTL; -#define PICTL_P2IEN (1 << 5) -#define PICTL_P0IENH (1 << 4) -#define PICTL_P0IENL (1 << 3) -#define PICTL_P2ICON (1 << 2) -#define PICTL_P1ICON (1 << 1) -#define PICTL_P0ICON (1 << 0) - -/* GPIO pins */ -__sfr at 0x80 P0; - -sbit at 0x80 P0_0; -sbit at 0x81 P0_1; -sbit at 0x82 P0_2; -sbit at 0x83 P0_3; -sbit at 0x84 P0_4; -sbit at 0x85 P0_5; -sbit at 0x86 P0_6; -sbit at 0x87 P0_7; - -__sfr at 0x90 P1; - -sbit at 0x90 P1_0; -sbit at 0x91 P1_1; -sbit at 0x92 P1_2; -sbit at 0x93 P1_3; -sbit at 0x94 P1_4; -sbit at 0x95 P1_5; -sbit at 0x96 P1_6; -sbit at 0x97 P1_7; - -__sfr at 0xa0 P2; - -sbit at 0xa0 P2_0; -sbit at 0xa1 P2_1; -sbit at 0xa2 P2_2; -sbit at 0xa3 P2_3; -sbit at 0xa4 P2_4; - -/* DMA controller */ -struct cc_dma_channel { - uint8_t src_high; - uint8_t src_low; - uint8_t dst_high; - uint8_t dst_low; - uint8_t len_high; - uint8_t len_low; - uint8_t cfg0; - uint8_t cfg1; -}; - -# define DMA_LEN_HIGH_VLEN_MASK (7 << 5) -# define DMA_LEN_HIGH_VLEN_LEN (0 << 5) -# define DMA_LEN_HIGH_VLEN_PLUS_1 (1 << 5) -# define DMA_LEN_HIGH_VLEN (2 << 5) -# define DMA_LEN_HIGH_VLEN_PLUS_2 (3 << 5) -# define DMA_LEN_HIGH_VLEN_PLUS_3 (4 << 5) -# define DMA_LEN_HIGH_MASK (0x1f) - -# define DMA_CFG0_WORDSIZE_8 (0 << 7) -# define DMA_CFG0_WORDSIZE_16 (1 << 7) -# define DMA_CFG0_TMODE_MASK (3 << 5) -# define DMA_CFG0_TMODE_SINGLE (0 << 5) -# define DMA_CFG0_TMODE_BLOCK (1 << 5) -# define DMA_CFG0_TMODE_REPEATED_SINGLE (2 << 5) -# define DMA_CFG0_TMODE_REPEATED_BLOCK (3 << 5) - -/* - * DMA triggers - */ -# define DMA_CFG0_TRIGGER_NONE 0 -# define DMA_CFG0_TRIGGER_PREV 1 -# define DMA_CFG0_TRIGGER_T1_CH0 2 -# define DMA_CFG0_TRIGGER_T1_CH1 3 -# define DMA_CFG0_TRIGGER_T1_CH2 4 -# define DMA_CFG0_TRIGGER_T2_OVFL 6 -# define DMA_CFG0_TRIGGER_T3_CH0 7 -# define DMA_CFG0_TRIGGER_T3_CH1 8 -# define DMA_CFG0_TRIGGER_T4_CH0 9 -# define DMA_CFG0_TRIGGER_T4_CH1 10 -# define DMA_CFG0_TRIGGER_IOC_0 12 -# define DMA_CFG0_TRIGGER_IOC_1 13 -# define DMA_CFG0_TRIGGER_URX0 14 -# define DMA_CFG0_TRIGGER_UTX0 15 -# define DMA_CFG0_TRIGGER_URX1 16 -# define DMA_CFG0_TRIGGER_UTX1 17 -# define DMA_CFG0_TRIGGER_FLASH 18 -# define DMA_CFG0_TRIGGER_RADIO 19 -# define DMA_CFG0_TRIGGER_ADC_CHALL 20 -# define DMA_CFG0_TRIGGER_ADC_CH0 21 -# define DMA_CFG0_TRIGGER_ADC_CH1 22 -# define DMA_CFG0_TRIGGER_ADC_CH2 23 -# define DMA_CFG0_TRIGGER_ADC_CH3 24 -# define DMA_CFG0_TRIGGER_ADC_CH4 25 -# define DMA_CFG0_TRIGGER_ADC_CH5 26 -# define DMA_CFG0_TRIGGER_ADC_CH6 27 -# define DMA_CFG0_TRIGGER_I2SRX 27 -# define DMA_CFG0_TRIGGER_ADC_CH7 28 -# define DMA_CFG0_TRIGGER_I2STX 28 -# define DMA_CFG0_TRIGGER_ENC_DW 29 -# define DMA_CFG0_TRIGGER_DNC_UP 30 - -# define DMA_CFG1_SRCINC_MASK (3 << 6) -# define DMA_CFG1_SRCINC_0 (0 << 6) -# define DMA_CFG1_SRCINC_1 (1 << 6) -# define DMA_CFG1_SRCINC_2 (2 << 6) -# define DMA_CFG1_SRCINC_MINUS_1 (3 << 6) - -# define DMA_CFG1_DESTINC_MASK (3 << 4) -# define DMA_CFG1_DESTINC_0 (0 << 4) -# define DMA_CFG1_DESTINC_1 (1 << 4) -# define DMA_CFG1_DESTINC_2 (2 << 4) -# define DMA_CFG1_DESTINC_MINUS_1 (3 << 4) - -# define DMA_CFG1_IRQMASK (1 << 3) -# define DMA_CFG1_M8 (1 << 2) - -# define DMA_CFG1_PRIORITY_MASK (3 << 0) -# define DMA_CFG1_PRIORITY_LOW (0 << 0) -# define DMA_CFG1_PRIORITY_NORMAL (1 << 0) -# define DMA_CFG1_PRIORITY_HIGH (2 << 0) - -/* - * DMAARM - DMA Channel Arm - */ - -__sfr at 0xD6 DMAARM; - -# define DMAARM_ABORT (1 << 7) -# define DMAARM_DMAARM4 (1 << 4) -# define DMAARM_DMAARM3 (1 << 3) -# define DMAARM_DMAARM2 (1 << 2) -# define DMAARM_DMAARM1 (1 << 1) -# define DMAARM_DMAARM0 (1 << 0) - -/* - * DMAREQ - DMA Channel Start Request and Status - */ - -__sfr at 0xD7 DMAREQ; - -# define DMAREQ_DMAREQ4 (1 << 4) -# define DMAREQ_DMAREQ3 (1 << 3) -# define DMAREQ_DMAREQ2 (1 << 2) -# define DMAREQ_DMAREQ1 (1 << 1) -# define DMAREQ_DMAREQ0 (1 << 0) - -/* - * DMA configuration 0 address - */ - -__sfr at 0xD5 DMA0CFGH; -__sfr at 0xD4 DMA0CFGL; - -/* - * DMA configuration 1-4 address - */ - -__sfr at 0xD3 DMA1CFGH; -__sfr at 0xD2 DMA1CFGL; - -/* - * DMAIRQ - DMA Interrupt Flag - */ - -__sfr at 0xD1 DMAIRQ; - -# define DMAIRQ_DMAIF4 (1 << 4) -# define DMAIRQ_DMAIF3 (1 << 3) -# define DMAIRQ_DMAIF2 (1 << 2) -# define DMAIRQ_DMAIF1 (1 << 1) -# define DMAIRQ_DMAIF0 (1 << 0) - -/* - * UART registers - */ - -/* USART config/status registers */ -__sfr at 0x86 U0CSR; -__sfr at 0xF8 U1CSR; - -# define UxCSR_MODE_UART (1 << 7) -# define UxCSR_MODE_SPI (0 << 7) -# define UxCSR_RE (1 << 6) -# define UxCSR_SLAVE (1 << 5) -# define UxCSR_MASTER (0 << 5) -# define UxCSR_FE (1 << 4) -# define UxCSR_ERR (1 << 3) -# define UxCSR_RX_BYTE (1 << 2) -# define UxCSR_TX_BYTE (1 << 1) -# define UxCSR_ACTIVE (1 << 0) - -/* UART configuration registers */ -__sfr at 0xc4 U0UCR; -__sfr at 0xfb U1UCR; - -# define UxUCR_FLUSH (1 << 7) -# define UxUCR_FLOW_DISABLE (0 << 6) -# define UxUCR_FLOW_ENABLE (1 << 6) -# define UxUCR_D9_EVEN_PARITY (0 << 5) -# define UxUCR_D9_ODD_PARITY (1 << 5) -# define UxUCR_BIT9_8_BITS (0 << 4) -# define UxUCR_BIT9_9_BITS (1 << 4) -# define UxUCR_PARITY_DISABLE (0 << 3) -# define UxUCR_PARITY_ENABLE (1 << 3) -# define UxUCR_SPB_1_STOP_BIT (0 << 2) -# define UxUCR_SPB_2_STOP_BITS (1 << 2) -# define UxUCR_STOP_LOW (0 << 1) -# define UxUCR_STOP_HIGH (1 << 1) -# define UxUCR_START_LOW (0 << 0) -# define UxUCR_START_HIGH (1 << 0) - -/* USART General configuration registers (mostly SPI) */ -__sfr at 0xc5 U0GCR; -__sfr at 0xfc U1GCR; - -# define UxGCR_CPOL_NEGATIVE (0 << 7) -# define UxGCR_CPOL_POSITIVE (1 << 7) -# define UxGCR_CPHA_FIRST_EDGE (0 << 6) -# define UxGCR_CPHA_SECOND_EDGE (1 << 6) -# define UxGCR_ORDER_LSB (0 << 5) -# define UxGCR_ORDER_MSB (1 << 5) -# define UxGCR_BAUD_E_MASK (0x1f) -# define UxGCR_BAUD_E_SHIFT 0 - -/* USART data registers */ -__sfr at 0xc1 U0DBUF; -__xdata __at (0xDFC1) volatile uint8_t U0DBUFXADDR; -__sfr at 0xf9 U1DBUF; -__xdata __at (0xDFF9) volatile uint8_t U1DBUFXADDR; - -/* USART baud rate registers, M value */ -__sfr at 0xc2 U0BAUD; -__sfr at 0xfa U1BAUD; - -/* Flash controller */ - -__sfr at 0xAE FCTL; -#define FCTL_BUSY (1 << 7) -#define FCTL_SWBSY (1 << 6) -#define FCTL_CONTRD_ENABLE (1 << 4) -#define FCTL_WRITE (1 << 1) -#define FCTL_ERASE (1 << 0) - -/* Flash write data. Write two bytes here */ -__sfr at 0xAF FWDATA; -__xdata __at (0xDFAF) volatile uint8_t FWDATAXADDR; - -/* Flash write/erase address */ -__sfr at 0xAD FADDRH; -__sfr at 0xAC FADDRL; - -/* Flash timing */ -__sfr at 0xAB FWT; - -/* 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 0x91 RFIM; -#define RFIM_IM_TXUNF (1 << 7) -#define RFIM_IM_RXOVF (1 << 6) -#define RFIM_IM_TIMEOUT (1 << 5) -#define RFIM_IM_DONE (1 << 4) -#define RFIM_IM_CS (1 << 3) -#define RFIM_IM_PQT (1 << 2) -#define RFIM_IM_CCA (1 << 1) -#define RFIM_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 diff --git a/src/cc1111/Makefile.cc1111 b/src/cc1111/Makefile.cc1111 new file mode 100644 index 00000000..8de4a9b2 --- /dev/null +++ b/src/cc1111/Makefile.cc1111 @@ -0,0 +1,27 @@ +CC=sdcc + +CFLAGS=--model-small --debug --opt-code-speed -DCODESIZE=$(CODESIZE) + +CFLAGS += $(PRODUCT_DEF) -I. -I.. -I../core -I../cc1111 -I../driver -I../product + +CODESIZE ?= 0x8000 + +LDFLAGS=--out-fmt-ihx --code-loc 0x0000 --code-size $(CODESIZE) \ + --xram-loc 0xf000 --xram-size 0xda2 --iram-size 0xff + +REL=$(SRC:.c=.rel) ao_product.rel +ADB=$(REL:.rel=.adb) +ASM=$(REL:.rel=.asm) +LNK=$(REL:.rel=.lnk) +LST=$(REL:.rel=.lst) +RST=$(REL:.rel=.rst) +SYM=$(REL:.rel=.sym) + +PCDB=$(PROG:.ihx=.cdb) +PLNK=$(PROG:.ihx=.lnk) +PMAP=$(PROG:.ihx=.map) +PMEM=$(PROG:.ihx=.mem) +PAOM=$(PROG:.ihx=) + +%.rel : %.c $(INC) + $(call quiet,CC,$(PRODUCT_DEF)) $(CFLAGS) -c -o$@ $< diff --git a/src/cc1111/_bp.c b/src/cc1111/_bp.c new file mode 100644 index 00000000..6bf135bc --- /dev/null +++ b/src/cc1111/_bp.c @@ -0,0 +1,26 @@ +/*------------------------------------------------------------------------- + + _bp.c :- just declares bp as a variable + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999) + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ + +__data unsigned char bp ; diff --git a/src/cc1111/ao_adc.c b/src/cc1111/ao_adc.c new file mode 100644 index 00000000..786dfd11 --- /dev/null +++ b/src/cc1111/ao_adc.c @@ -0,0 +1,196 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" +#include "ao_pins.h" + +volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING]; +#if HAS_ACCEL_REF +volatile __xdata uint16_t ao_accel_ref[AO_ADC_RING]; +#endif +volatile __data uint8_t ao_adc_head; + +void +ao_adc_poll(void) +{ +#if HAS_ACCEL_REF + ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 2; +#else +# ifdef TELENANO_V_0_1 + ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 1; +# else + ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 0; +# endif +#endif +} + +void +ao_adc_get(__xdata struct ao_adc *packet) +{ + uint8_t i = ao_adc_ring_prev(ao_sample_adc); + memcpy(packet, &ao_adc_ring[i], sizeof (struct ao_adc)); +} + +void +ao_adc_isr(void) __interrupt 1 +{ + uint8_t sequence; + uint8_t __xdata *a; + + sequence = (ADCCON2 & ADCCON2_SCH_MASK) >> ADCCON2_SCH_SHIFT; +#if IGNITE_ON_P2 + /* TeleMetrum readings */ +#if HAS_ACCEL_REF + if (sequence == 2) { + a = (uint8_t __xdata *) (&ao_accel_ref[ao_adc_head]); + sequence = 0; + } else +#endif + { + if (sequence == ADCCON3_ECH_TEMP) + sequence = 2; + a = (uint8_t __xdata *) (&ao_adc_ring[ao_adc_head].accel + sequence); + sequence++; + } +#define GOT_ADC + a[0] = ADCL; + a[1] = ADCH; + if (sequence < 6) { +#if HAS_EXTERNAL_TEMP == 0 + /* start next channel conversion */ + /* v0.2 replaces external temp sensor with internal one */ + if (sequence == 2) + ADCCON3 = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP; + else +#endif + ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | sequence; + } +#endif + +#if IGNITE_ON_P0 + /* TeleMini readings */ + a = (uint8_t __xdata *) (&ao_adc_ring[ao_adc_head].pres); +#ifdef TELEMINI_V_1_0 + switch (sequence) { + case 0: + /* pressure */ + a += 0; + sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 1; + break; + case 1: + /* drogue sense */ + a += 6; + sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 2; + break; + case 2: + /* main sense */ + a += 8; + sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 3; + break; + case 3: + /* battery */ + a += 4; + sequence = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP; + break; + case ADCCON3_ECH_TEMP: + a += 2; + sequence = 0; + break; + } +#define GOT_ADC +#endif +#ifdef TELENANO_V_0_1 + switch (sequence) { + case 1: + /* pressure */ + a += 0; + sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 3; + break; + case 3: + /* battery */ + a += 4; + sequence = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP; + break; + case ADCCON3_ECH_TEMP: + a += 2; + sequence = 0; + break; + } +#define GOT_ADC +#endif + a[0] = ADCL; + a[1] = ADCH; + if (sequence) { + /* Start next conversion */ + ADCCON3 = sequence; + } +#endif +#ifndef GOT_ADC +#error No known ADC configuration set +#endif + + else { + /* record this conversion series */ + ao_adc_ring[ao_adc_head].tick = ao_time(); + ao_adc_head = ao_adc_ring_next(ao_adc_head); + ao_wakeup(DATA_TO_XDATA(&ao_adc_head)); + } +} + +static void +ao_adc_dump(void) __reentrant +{ + static __xdata struct ao_adc packet; + ao_adc_get(&packet); + printf("tick: %5u accel: %5d pres: %5d temp: %5d batt: %5d drogue: %5d main: %5d\n", + packet.tick, packet.accel, packet.pres, packet.temp, + packet.v_batt, packet.sense_d, packet.sense_m); +} + +__code struct ao_cmds ao_adc_cmds[] = { + { ao_adc_dump, "a\0Current ADC" }, + { 0, NULL }, +}; + +void +ao_adc_init(void) +{ +#if IGNITE_ON_P2 + /* TeleMetrum configuration */ + ADCCFG = ((1 << 0) | /* acceleration */ + (1 << 1) | /* pressure */ +#if HAS_EXTERNAL_TEMP + (1 << 2) | /* v0.1 temperature */ +#endif + (1 << 3) | /* battery voltage */ + (1 << 4) | /* drogue sense */ + (1 << 5)); /* main sense */ +#endif + +#if IGNITE_ON_P0 + /* TeleMini configuration */ + ADCCFG = ((1 << 0) | /* pressure */ + (1 << 1) | /* drogue sense */ + (1 << 2) | /* main sense */ + (1 << 3)); /* battery voltage */ +#endif + + /* enable interrupts */ + ADCIF = 0; + IEN0 |= IEN0_ADCIE; + ao_cmd_register(&ao_adc_cmds[0]); +} diff --git a/src/cc1111/ao_beep.c b/src/cc1111/ao_beep.c new file mode 100644 index 00000000..3642f4c6 --- /dev/null +++ b/src/cc1111/ao_beep.c @@ -0,0 +1,52 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_beep(uint8_t beep) +{ + if (beep == 0) { + P2_0 = 0; + P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_GPIO; + T4CTL = 0; + } else { + P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_PERIPHERAL; + T4CC0 = beep; + T4CTL = TxCTL_DIV_32 | TxCTL_MODE_MODULO | TxCTL_START; + } +} + +void +ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant +{ + ao_beep(beep); + ao_delay(ticks); + ao_beep(0); +} + +void +ao_beep_init(void) +{ + /* Our beeper is on P2_0, which is hooked to timer 4 using + * configuration alternative 2 + */ + P2_0 = 0; + P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_GPIO; + PERCFG = (PERCFG & ~PERCFG_T4CFG_ALT_MASK) | PERCFG_T4CFG_ALT_2; + T4CCTL0 = TxCCTLy_CMP_TOGGLE|TxCCTLy_CMP_MODE_ENABLE; +} diff --git a/src/cc1111/ao_dbg.c b/src/cc1111/ao_dbg.c new file mode 100644 index 00000000..d4c9567f --- /dev/null +++ b/src/cc1111/ao_dbg.c @@ -0,0 +1,364 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" +#include "ao_pins.h" + +static void +ao_dbg_send_bits(uint8_t msk, uint8_t val) __reentrant +{ + DBG_PORT = (DBG_PORT & ~msk) | (val & msk); + _asm + nop + nop + _endasm; +} + +void +ao_dbg_send_byte(uint8_t byte) +{ + __pdata uint8_t b, d; + + DBG_PORT |= DBG_DATA; + DBG_PORT_DIR |= DBG_DATA; + for (b = 0; b < 8; b++) { + d = 0; + if (byte & 0x80) + d = DBG_DATA; + byte <<= 1; + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA, DBG_CLOCK|d); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA, 0 |d); + } + DBG_PORT_DIR &= ~DBG_DATA; +} + +uint8_t +ao_dbg_recv_byte(void) +{ + __pdata uint8_t byte, b; + + byte = 0; + for (b = 0; b < 8; b++) { + byte = byte << 1; + ao_dbg_send_bits(DBG_CLOCK, DBG_CLOCK); + if (DBG_DATA_PIN) + byte |= 1; + ao_dbg_send_bits(DBG_CLOCK, 0); + } + return byte; +} + +/* 8051 instructions + */ +#define NOP 0x00 +#define MOV_direct_data 0x75 +#define LJMP 0x02 +#define MOV_Rn_data(n) (0x78 | (n)) +#define DJNZ_Rn_rel(n) (0xd8 | (n)) +#define MOV_A_direct 0xe5 +#define MOV_direct1_direct2 0x85 +#define MOV_direct_A 0xf5 +#define MOV_DPTR_data16 0x90 +#define MOV_A_data 0x74 +#define MOVX_atDPTR_A 0xf0 +#define MOVX_A_atDPTR 0xe0 +#define INC_DPTR 0xa3 +#define TRAP 0xa5 +#define SJMP 0x80 +#define JB 0x20 + +#define DEBUG_INSTR(l) (0x54 | (l)) + +#define SFR_PSW 0xD0 +#define SFR_DPL0 0x82 +#define SFR_DPH0 0x83 +#define SFR_DPL1 0x84 +#define SFR_DPH1 0x85 + +__pdata uint8_t save_acc; +__pdata uint8_t save_psw; +__pdata uint8_t save_dpl0; +__pdata uint8_t save_dph0; +__pdata uint8_t save_dpl1; +__pdata uint8_t save_dph1; + +static uint8_t +ao_dbg_inst1(uint8_t a) __reentrant +{ + ao_dbg_send_byte(DEBUG_INSTR(1)); + ao_dbg_send_byte(a); + return ao_dbg_recv_byte(); +} + +static uint8_t +ao_dbg_inst2(uint8_t a, uint8_t b) __reentrant +{ + ao_dbg_send_byte(DEBUG_INSTR(2)); + ao_dbg_send_byte(a); + ao_dbg_send_byte(b); + return ao_dbg_recv_byte(); +} + +static uint8_t +ao_dbg_inst3(uint8_t a, uint8_t b, uint8_t c) __reentrant +{ + ao_dbg_send_byte(DEBUG_INSTR(3)); + ao_dbg_send_byte(a); + ao_dbg_send_byte(b); + ao_dbg_send_byte(c); + return ao_dbg_recv_byte(); +} + +void +ao_dbg_start_transfer(uint16_t addr) +{ + save_acc = ao_dbg_inst1(NOP); + save_psw = ao_dbg_inst2(MOV_A_direct, SFR_PSW); + save_dpl0 = ao_dbg_inst2(MOV_A_direct, SFR_DPL0); + save_dph0 = ao_dbg_inst2(MOV_A_direct, SFR_DPH0); + save_dpl1 = ao_dbg_inst2(MOV_A_direct, SFR_DPL1); + save_dph1 = ao_dbg_inst2(MOV_A_direct, SFR_DPH1); + ao_dbg_inst3(MOV_DPTR_data16, addr >> 8, addr); +} + +void +ao_dbg_end_transfer(void) +{ + ao_dbg_inst3(MOV_direct_data, SFR_DPL0, save_dpl0); + ao_dbg_inst3(MOV_direct_data, SFR_DPH0, save_dph0); + ao_dbg_inst3(MOV_direct_data, SFR_DPL1, save_dpl1); + ao_dbg_inst3(MOV_direct_data, SFR_DPH1, save_dph1); + ao_dbg_inst3(MOV_direct_data, SFR_PSW, save_psw); + ao_dbg_inst2(MOV_A_data, save_acc); +} + +void +ao_dbg_write_byte(uint8_t byte) +{ + ao_dbg_inst2(MOV_A_data, byte); + ao_dbg_inst1(MOVX_atDPTR_A); + ao_dbg_inst1(INC_DPTR); +} + +uint8_t +ao_dbg_read_byte(void) +{ + ao_dbg_inst1(MOVX_A_atDPTR); + return ao_dbg_inst1(INC_DPTR); +} + +static void +ao_dbg_set_pins(void) +{ + /* Make the DBG pins GPIOs. On TeleMetrum, this will + * disable the SPI link, so don't expect SPI to work after + * using the debugger. + */ + DBG_PORT_SEL &= ~(DBG_CLOCK|DBG_DATA|DBG_RESET_N); + + /* make DBG_DATA tri-state */ + DBG_PORT_INP |= DBG_DATA; + + /* Raise RESET_N and CLOCK */ + DBG_PORT |= DBG_RESET_N | DBG_CLOCK; + + /* RESET_N and CLOCK are outputs now */ + DBG_PORT_DIR |= DBG_RESET_N | DBG_CLOCK; + DBG_PORT_DIR &= ~DBG_DATA; +} + +static void +ao_dbg_long_delay(void) +{ + uint8_t n; + + for (n = 0; n < 20; n++) + _asm nop _endasm; +} + +#define AO_RESET_LOW_DELAY AO_MS_TO_TICKS(100) +#define AO_RESET_HIGH_DELAY AO_MS_TO_TICKS(100) + +void +ao_dbg_debug_mode(void) +{ + ao_dbg_set_pins(); + ao_dbg_long_delay(); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N); + ao_dbg_long_delay(); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA| 0 ); + ao_delay(AO_RESET_LOW_DELAY); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); + ao_dbg_long_delay(); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA| 0 ); + ao_dbg_long_delay(); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); + ao_dbg_long_delay(); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA|DBG_RESET_N); + ao_delay(AO_RESET_HIGH_DELAY); +} + +void +ao_dbg_reset(void) +{ + ao_dbg_set_pins(); + ao_dbg_long_delay(); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N); + ao_dbg_long_delay(); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); + ao_delay(AO_RESET_LOW_DELAY); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); + ao_dbg_long_delay(); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); + ao_dbg_long_delay(); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); + ao_dbg_long_delay(); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N); + ao_delay(AO_RESET_HIGH_DELAY); +} + +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) +{ + __pdata uint16_t count; + __pdata uint16_t i; + __pdata 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) +{ + __pdata char 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) +{ + __pdata uint16_t count; + __pdata uint16_t addr; + __pdata uint8_t b; + __pdata 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) +{ + __pdata uint16_t count; + __pdata uint16_t addr; + __pdata 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] = { + { debug_enable, "D\0Enable debug" }, + { debug_get, "G \0Get data" }, + { debug_input, "I \0Input at " }, + { debug_output, "O \0Output at " }, + { debug_put, "P ...\0Put data" }, + { debug_reset, "R\0Reset" }, + { 0, NULL }, +}; + +void +ao_dbg_init(void) +{ + ao_cmd_register(&ao_dbg_cmds[0]); +} diff --git a/src/cc1111/ao_dma.c b/src/cc1111/ao_dma.c new file mode 100644 index 00000000..6052964a --- /dev/null +++ b/src/cc1111/ao_dma.c @@ -0,0 +1,131 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +#define NUM_DMA 5 + +/* + * The config address for DMA0 is programmed + * separately from that of DMA1-4, but for simplicity, + * we make them all contiguous. + */ + +static __xdata struct cc_dma_channel ao_dma_config[NUM_DMA]; +static __xdata uint8_t * __xdata ao_dma_done[NUM_DMA]; +static __data uint8_t ao_next_dma; + +uint8_t +ao_dma_alloc(__xdata uint8_t *done) +{ + uint8_t id; + + if (ao_next_dma == NUM_DMA) + ao_panic(AO_PANIC_DMA); + id = ao_next_dma++; + ao_dma_done[id] = done; + + /* When the first dma object is allocated, set up the DMA + * controller + */ + if (id == 0) { + DMAIRQ = 0; + DMAIF = 0; + IEN1 |= IEN1_DMAIE; + } + + return id; +} + +void +ao_dma_set_transfer(uint8_t id, + void __xdata *srcaddr, + void __xdata *dstaddr, + uint16_t count, + uint8_t cfg0, + uint8_t cfg1) +{ + if (DMAARM & (1 << id)) + ao_panic(AO_PANIC_DMA); + ao_dma_config[id].src_high = ((uint16_t) srcaddr) >> 8; + ao_dma_config[id].src_low = ((uint16_t) srcaddr); + ao_dma_config[id].dst_high = ((uint16_t) dstaddr) >> 8; + ao_dma_config[id].dst_low = ((uint16_t) dstaddr); + ao_dma_config[id].len_high = count >> 8; + ao_dma_config[id].len_low = count; + ao_dma_config[id].cfg0 = cfg0; + ao_dma_config[id].cfg1 = cfg1 | DMA_CFG1_IRQMASK; + if (id == 0) { + DMA0CFGH = ((uint16_t) (&ao_dma_config[0])) >> 8; + DMA0CFGL = ((uint16_t) (&ao_dma_config[0])); + } else { + DMA1CFGH = ((uint16_t) (&ao_dma_config[1])) >> 8; + DMA1CFGL = ((uint16_t) (&ao_dma_config[1])); + } +} + +#define nop() _asm nop _endasm; + +void +ao_dma_start(uint8_t id) +{ + uint8_t mask = (1 << id); + DMAIRQ &= ~mask; + 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(); +} + +void +ao_dma_trigger(uint8_t id) +{ + DMAREQ |= (1 << id); +} + +void +ao_dma_abort(uint8_t id) +{ + uint8_t mask = (1 << id); + DMAARM = 0x80 | mask; + DMAIRQ &= ~mask; +} + +void +ao_dma_isr(void) __interrupt 8 +{ + uint8_t id, mask; + + /* Find the first DMA channel which is done */ + mask = 1; + for (id = 0; id < ao_next_dma; id++) { + if (DMAIRQ & mask) { + /* Clear CPU interrupt flag */ + DMAIF = 0; + /* Clear the completed ID */ + DMAIRQ = ~mask; + *(ao_dma_done[id]) = 1; + ao_wakeup(ao_dma_done[id]); + break; + } + mask <<= 1; + } +} diff --git a/src/cc1111/ao_ignite.c b/src/cc1111/ao_ignite.c new file mode 100644 index 00000000..5238beb4 --- /dev/null +++ b/src/cc1111/ao_ignite.c @@ -0,0 +1,218 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +#if IGNITE_ON_P2 +#define AO_IGNITER_DROGUE P2_3 +#define AO_IGNITER_MAIN P2_4 +#define AO_IGNITER_DIR P2DIR +#define AO_IGNITER_DROGUE_BIT (1 << 3) +#define AO_IGNITER_MAIN_BIT (1 << 4) +#endif + +#if IGNITE_ON_P0 +#define AO_IGNITER_DROGUE P0_5 +#define AO_IGNITER_MAIN P0_4 +#define AO_IGNITER_DIR P0DIR +#define AO_IGNITER_DROGUE_BIT (1 << 5) +#define AO_IGNITER_MAIN_BIT (1 << 4) +#endif + +/* test these values with real igniters */ +#define AO_IGNITER_OPEN 1000 +#define AO_IGNITER_CLOSED 7000 +#define AO_IGNITER_FIRE_TIME AO_MS_TO_TICKS(50) +#define AO_IGNITER_CHARGE_TIME AO_MS_TO_TICKS(2000) + +struct ao_ignition { + uint8_t request; + uint8_t fired; + uint8_t firing; +}; + +__xdata struct ao_ignition ao_ignition[2]; + +void +ao_ignite(enum ao_igniter igniter) __critical +{ + ao_ignition[igniter].request = 1; + ao_wakeup(&ao_ignition); +} + +enum ao_igniter_status +ao_igniter_status(enum ao_igniter igniter) +{ + __xdata struct ao_adc adc; + __pdata int16_t value; + __pdata uint8_t request, firing, fired; + + __critical { + ao_adc_get(&adc); + request = ao_ignition[igniter].request; + fired = ao_ignition[igniter].fired; + firing = ao_ignition[igniter].firing; + } + if (firing || (request && !fired)) + return ao_igniter_active; + + value = (AO_IGNITER_CLOSED>>1); + switch (igniter) { + case ao_igniter_drogue: + value = adc.sense_d; + break; + case ao_igniter_main: + value = adc.sense_m; + break; + } + if (value < AO_IGNITER_OPEN) + return ao_igniter_open; + else if (value > AO_IGNITER_CLOSED) + return ao_igniter_ready; + else + return ao_igniter_unknown; +} + +void +ao_igniter_fire(enum ao_igniter igniter) __critical +{ + ao_ignition[igniter].firing = 1; + switch(ao_config.ignite_mode) { + case AO_IGNITE_MODE_DUAL: + switch (igniter) { + case ao_igniter_drogue: + AO_IGNITER_DROGUE = 1; + ao_delay(AO_IGNITER_FIRE_TIME); + AO_IGNITER_DROGUE = 0; + break; + case ao_igniter_main: + AO_IGNITER_MAIN = 1; + ao_delay(AO_IGNITER_FIRE_TIME); + AO_IGNITER_MAIN = 0; + break; + } + break; + case AO_IGNITE_MODE_APOGEE: + switch (igniter) { + case ao_igniter_drogue: + AO_IGNITER_DROGUE = 1; + ao_delay(AO_IGNITER_FIRE_TIME); + AO_IGNITER_DROGUE = 0; + ao_delay(AO_IGNITER_CHARGE_TIME); + AO_IGNITER_MAIN = 1; + ao_delay(AO_IGNITER_FIRE_TIME); + AO_IGNITER_MAIN = 0; + break; + } + break; + case AO_IGNITE_MODE_MAIN: + switch (igniter) { + case ao_igniter_main: + AO_IGNITER_DROGUE = 1; + ao_delay(AO_IGNITER_FIRE_TIME); + AO_IGNITER_DROGUE = 0; + ao_delay(AO_IGNITER_CHARGE_TIME); + AO_IGNITER_MAIN = 1; + ao_delay(AO_IGNITER_FIRE_TIME); + AO_IGNITER_MAIN = 0; + break; + } + break; + } + ao_ignition[igniter].firing = 0; +} + +void +ao_igniter(void) +{ + __xdata enum ao_ignter igniter; + + ao_config_get(); + for (;;) { + ao_sleep(&ao_ignition); + for (igniter = ao_igniter_drogue; igniter <= ao_igniter_main; igniter++) { + if (ao_ignition[igniter].request && !ao_ignition[igniter].fired) { + if (igniter == ao_igniter_drogue && ao_config.apogee_delay) + ao_delay(AO_SEC_TO_TICKS(ao_config.apogee_delay)); + + ao_igniter_fire(igniter); + ao_delay(AO_IGNITER_CHARGE_TIME); + ao_ignition[igniter].fired = 1; + } + } + } +} + +void +ao_ignite_manual(void) +{ + ao_cmd_white(); + if (!ao_match_word("DoIt")) + return; + ao_cmd_white(); + if (ao_cmd_lex_c == 'm') { + if(ao_match_word("main")) + ao_igniter_fire(ao_igniter_main); + } else { + if(ao_match_word("drogue")) + ao_igniter_fire(ao_igniter_drogue); + } +} + +static __code char * __code igniter_status_names[] = { + "unknown", "ready", "active", "open" +}; + +void +ao_ignite_print_status(enum ao_igniter igniter, __code char *name) __reentrant +{ + enum ao_igniter_status status = ao_igniter_status(igniter); + printf("Igniter: %6s Status: %s\n", + name, + igniter_status_names[status]); +} + +void +ao_ignite_test(void) +{ + ao_ignite_print_status(ao_igniter_drogue, "drogue"); + ao_ignite_print_status(ao_igniter_main, "main"); +} + +__code struct ao_cmds ao_ignite_cmds[] = { + { ao_ignite_manual, "i {main|drogue}\0Fire igniter. is doit with D&I" }, + { ao_ignite_test, "t\0Test igniter" }, + { 0, NULL }, +}; + +__xdata struct ao_task ao_igniter_task; + +void +ao_ignite_set_pins(void) +{ + AO_IGNITER_DROGUE = 0; + AO_IGNITER_MAIN = 0; + AO_IGNITER_DIR |= AO_IGNITER_DROGUE_BIT | AO_IGNITER_MAIN_BIT; +} + +void +ao_igniter_init(void) +{ + ao_ignite_set_pins(); + ao_cmd_register(&ao_ignite_cmds[0]); + ao_add_task(&ao_igniter_task, ao_igniter, "igniter"); +} diff --git a/src/cc1111/ao_intflash.c b/src/cc1111/ao_intflash.c new file mode 100644 index 00000000..d76d954e --- /dev/null +++ b/src/cc1111/ao_intflash.c @@ -0,0 +1,209 @@ +/* + * Copyright © 2011 Anthony Towns + * + * 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" +#include "cc1111.h" + +#define ENDOFCODE (CODESIZE) +#define AO_INTFLASH_BLOCK 1024 +#define AO_INTFLASH_BLOCKS ((0x8000 - ENDOFCODE)/AO_INTFLASH_BLOCK) +#define AO_INTFLASH_SIZE (AO_INTFLASH_BLOCK * AO_INTFLASH_BLOCKS) +#define AO_INTFLASH_LOCATION (0x8000 - AO_INTFLASH_SIZE) + +/* + * 21000 * 24e6 + * FWT = ------------ + * 16e9 + * + * = 31.5 + * + * Round up and use 32 + */ + +#define FLASH_TIMING 0x20 + +#if AO_INTFLASH_BLOCKS < 2 +#error "Too few pages" +#endif + +#if AO_INFTLASH_LOCATION % 1024 != 0 +#error "Pages aren't aligned properly" +#endif + +__xdata __at(AO_INTFLASH_LOCATION) uint8_t ao_intflash[AO_INTFLASH_SIZE]; + +/* Total bytes of available storage */ +__pdata uint32_t ao_storage_total = sizeof(ao_intflash); + +/* Block size - device is erased in these units. */ +__pdata uint32_t ao_storage_block = AO_INTFLASH_BLOCK; + +/* Byte offset of config block. Will be ao_storage_block bytes long */ +__pdata uint32_t ao_storage_config = sizeof(ao_intflash) - AO_INTFLASH_BLOCK; + +/* Storage unit size - device reads and writes must be within blocks of this size. */ +__pdata uint16_t ao_storage_unit = AO_INTFLASH_BLOCK; + +__xdata static uint8_t ao_intflash_dma_done; +static uint8_t ao_intflash_dma; + +/* + * The internal flash chip is arranged in 1kB sectors; the + * chip cannot erase in units smaller than that. + * + * Writing happens in units of 2 bytes and + * can only change bits from 1 to 0. So, you can rewrite + * the same contents, or append to an existing page easily enough + */ + +/* + * Erase the specified sector + */ +uint8_t +ao_storage_erase(uint32_t pos) __reentrant +{ + uint16_t addr; + + if (pos >= ao_storage_total || pos + ao_storage_block > ao_storage_total) + return 0; + + addr = ((uint16_t)(ao_intflash + pos) >> 1); + + FADDRH = addr >> 8; + FADDRL = addr; + + __critical { + _asm + .even + orl _FCTL, #FCTL_ERASE; ; FCTL |= FCTL_ERASE + nop ; Required, see datasheet. + _endasm; + } + + return 1; +} + +/* + * Write to flash + */ + +static void +ao_intflash_write_aligned(uint16_t pos, __xdata void *d, uint16_t len) __reentrant +{ + pos = ((uint16_t) ao_intflash + pos) >> 1; + + ao_dma_set_transfer(ao_intflash_dma, + d, + &FWDATAXADDR, + len, + DMA_CFG0_WORDSIZE_8 | + DMA_CFG0_TMODE_SINGLE | + DMA_CFG0_TRIGGER_FLASH, + DMA_CFG1_SRCINC_1 | + DMA_CFG1_DESTINC_0 | + DMA_CFG1_PRIORITY_HIGH); + + FADDRH = pos >> 8; + FADDRL = pos; + + ao_dma_start(ao_intflash_dma); + + __critical { + _asm + .even + orl _FCTL, #FCTL_WRITE; ; FCTL |= FCTL_WRITE + nop + _endasm; + } +} + +static void +ao_intflash_write_byte(uint16_t pos, uint8_t byte) __reentrant +{ + static __xdata uint8_t b[2]; + + if (pos & 1) { + b[0] = 0xff; + b[1] = byte; + } else { + b[0] = byte; + b[1] = 0xff; + } + ao_intflash_write_aligned(pos, b, 2); +} + +uint8_t +ao_storage_device_write(uint32_t pos32, __xdata void *v, uint16_t len) __reentrant +{ + uint16_t pos = pos32; + __xdata uint8_t *d = v; + uint8_t oddlen; + + if (pos >= ao_storage_total || pos + len > ao_storage_total) + return 0; + if (len == 0) + return 1; + + if (pos & 1) { + ao_intflash_write_byte(pos++, *d++); + len--; + } + oddlen = len & 1; + len -= oddlen; + if (len) + ao_intflash_write_aligned(pos, d, len); + if (oddlen) + ao_intflash_write_byte(pos + len, d[len]); + + return 1; +} + +/* + * Read from flash + */ +uint8_t +ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant +{ + if (pos >= ao_storage_total || pos + len > ao_storage_total) + return 0; + memcpy(d, ao_intflash+pos, len); + return 1; +} + +void +ao_storage_flush(void) __reentrant +{ +} + +void +ao_storage_setup(void) +{ +} + +void +ao_storage_device_info(void) __reentrant +{ + printf ("Using internal flash, starting at 0x%04x\n", AO_INTFLASH_LOCATION); +} + +void +ao_storage_device_init(void) +{ + ao_intflash_dma = ao_dma_alloc(&ao_intflash_dma_done); + + FWT = FLASH_TIMING; +} diff --git a/src/cc1111/ao_led.c b/src/cc1111/ao_led.c new file mode 100644 index 00000000..5beed58d --- /dev/null +++ b/src/cc1111/ao_led.c @@ -0,0 +1,61 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +__pdata uint8_t ao_led_enable; + +void +ao_led_on(uint8_t colors) +{ + P1 |= (colors & ao_led_enable); +} + +void +ao_led_off(uint8_t colors) +{ + P1 &= ~(colors & ao_led_enable); +} + +void +ao_led_set(uint8_t colors) +{ + P1 = (P1 & ~(ao_led_enable)) | (colors & ao_led_enable); +} + +void +ao_led_toggle(uint8_t colors) +{ + P1 ^= (colors & ao_led_enable); +} + +void +ao_led_for(uint8_t colors, uint16_t ticks) __reentrant +{ + ao_led_on(colors); + ao_delay(ticks); + ao_led_off(colors); +} + +void +ao_led_init(uint8_t enable) +{ + ao_led_enable = enable; + P1SEL &= ~enable; + P1 &= ~enable; + P1DIR |= enable; +} diff --git a/src/cc1111/ao_packet.c b/src/cc1111/ao_packet.c new file mode 100644 index 00000000..f627e02b --- /dev/null +++ b/src/cc1111/ao_packet.c @@ -0,0 +1,148 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +__xdata struct ao_packet_recv ao_rx_packet; +__xdata struct ao_packet ao_tx_packet; +__pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used; + +static __xdata char tx_data[AO_PACKET_MAX]; +static __xdata char rx_data[AO_PACKET_MAX]; +static __pdata uint8_t rx_seq; + +__xdata struct ao_task ao_packet_task; +__xdata uint8_t ao_packet_enable; +__xdata uint8_t ao_packet_master_sleeping; + +void +ao_packet_send(void) +{ + ao_led_on(AO_LED_RED); + /* If any tx data is pending then copy it into the tx packet */ + if (ao_packet_tx_used && ao_tx_packet.len == 0) { + memcpy(&ao_tx_packet.d, tx_data, ao_packet_tx_used); + ao_tx_packet.len = ao_packet_tx_used; + ao_tx_packet.seq++; + ao_packet_tx_used = 0; + ao_wakeup(&tx_data); + } + ao_radio_send(&ao_tx_packet, sizeof (ao_tx_packet)); + ao_led_off(AO_LED_RED); +} + +uint8_t +ao_packet_recv(void) +{ + uint8_t dma_done; + +#ifdef AO_LED_GREEN + ao_led_on(AO_LED_GREEN); +#endif + dma_done = ao_radio_recv(&ao_rx_packet, sizeof (struct ao_packet_recv)); +#ifdef AO_LED_GREEN + ao_led_off(AO_LED_GREEN); +#endif + + /* Check to see if we got a valid packet */ + if (!dma_done) + return 0; + if (!(ao_rx_packet.status & PKT_APPEND_STATUS_1_CRC_OK)) + return 0; + + /* SYN packets carry no data */ + if (ao_rx_packet.packet.len == AO_PACKET_SYN) { + rx_seq = ao_rx_packet.packet.seq; + ao_tx_packet.seq = ao_rx_packet.packet.ack; + ao_tx_packet.ack = rx_seq; + } else if (ao_rx_packet.packet.len) { + + /* Check for incoming data at the next sequence and + * for an empty data buffer + */ + if (ao_rx_packet.packet.seq == (uint8_t) (rx_seq + (uint8_t) 1) && + ao_packet_rx_used == ao_packet_rx_len) { + + /* Copy data to the receive data buffer and set up the + * offsets + */ + memcpy(rx_data, ao_rx_packet.packet.d, ao_rx_packet.packet.len); + ao_packet_rx_used = 0; + ao_packet_rx_len = ao_rx_packet.packet.len; + + /* Mark the sequence that we've received to + * let the sender know when we return a packet + */ + rx_seq = ao_rx_packet.packet.seq; + ao_tx_packet.ack = rx_seq; + + /* Poke anyone looking for received data */ + ao_wakeup(&ao_stdin_ready); + } + } + + /* If the other side has seen the latest data we queued, + * wake up any task waiting to send data and let them go again + */ + if (ao_rx_packet.packet.ack == ao_tx_packet.seq) { + ao_tx_packet.len = 0; + ao_wakeup(&ao_tx_packet); + } + return 1; +} + +#ifndef PACKET_HAS_MASTER +#define PACKET_HAS_MASTER 1 +#endif + +#if PACKET_HAS_MASTER +void +ao_packet_flush(void) +{ + /* If there is data to send, and this is the master, + * then poke the master to send all queued data + */ + if (ao_packet_tx_used && ao_packet_master_sleeping) + ao_wakeup(&ao_packet_master_sleeping); +} +#endif /* PACKET_HAS_MASTER */ + +void +ao_packet_putchar(char c) __reentrant +{ + while (ao_packet_tx_used == AO_PACKET_MAX && ao_packet_enable) { +#if PACKET_HAS_MASTER + ao_packet_flush(); +#endif + ao_sleep(&tx_data); + } + + if (ao_packet_enable) + tx_data[ao_packet_tx_used++] = c; +} + +char +ao_packet_pollchar(void) __critical +{ + if (!ao_packet_enable) + return AO_READ_AGAIN; + + if (ao_packet_rx_used == ao_packet_rx_len) + return AO_READ_AGAIN; + + return rx_data[ao_packet_rx_used++]; +} diff --git a/src/cc1111/ao_packet_master.c b/src/cc1111/ao_packet_master.c new file mode 100644 index 00000000..b0fdf5a8 --- /dev/null +++ b/src/cc1111/ao_packet_master.c @@ -0,0 +1,144 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +static char +ao_packet_getchar(void) __critical +{ + char c; + while ((c = ao_packet_pollchar()) == AO_READ_AGAIN) { + if (!ao_packet_enable) + break; + if (ao_packet_master_sleeping) + ao_wakeup(&ao_packet_master_sleeping); + flush(); + ao_sleep(&ao_stdin_ready); + } + return c; +} + +static void +ao_packet_echo(void) __reentrant +{ + char c; + while (ao_packet_enable) { + c = ao_packet_getchar(); + if (c != AO_READ_AGAIN) + putchar(c); + } + ao_exit(); +} + +static __xdata struct ao_task ao_packet_echo_task; +static __xdata uint16_t ao_packet_master_delay; +static __xdata uint16_t ao_packet_master_time; + +#define AO_PACKET_MASTER_DELAY_SHORT AO_MS_TO_TICKS(100) +#define AO_PACKET_MASTER_DELAY_LONG AO_MS_TO_TICKS(1000) +#define AO_PACKET_MASTER_DELAY_TIMEOUT AO_MS_TO_TICKS(2000) + +static void +ao_packet_master_busy(void) +{ + ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT; + ao_packet_master_time = ao_time(); +} + +static void +ao_packet_master_check_busy(void) +{ + int16_t idle; + if (ao_packet_master_delay != AO_PACKET_MASTER_DELAY_SHORT) + return; + idle = (int16_t) (ao_time() - ao_packet_master_time); + + if (idle > AO_PACKET_MASTER_DELAY_TIMEOUT) + ao_packet_master_delay = AO_PACKET_MASTER_DELAY_LONG; +} + +void +ao_packet_master(void) +{ + ao_config_get(); + ao_tx_packet.addr = ao_serial_number; + ao_tx_packet.len = AO_PACKET_SYN; + ao_packet_master_time = ao_time(); + ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT; + while (ao_packet_enable) { + memcpy(ao_tx_packet.callsign, ao_config.callsign, AO_MAX_CALLSIGN); + ao_packet_send(); + if (ao_tx_packet.len) + ao_packet_master_busy(); + ao_packet_master_check_busy(); + ao_alarm(ao_packet_master_delay); + if (ao_packet_recv()) { + /* if we can transmit data, do so */ + if (ao_packet_tx_used && ao_tx_packet.len == 0) + continue; + if (ao_rx_packet.packet.len) + ao_packet_master_busy(); + ao_packet_master_sleeping = 1; + ao_alarm(ao_packet_master_delay); + ao_sleep(&ao_packet_master_sleeping); + ao_packet_master_sleeping = 0; + } + } + ao_exit(); +} + +static void +ao_packet_forward(void) __reentrant +{ + char c; + ao_packet_enable = 1; + ao_cmd_white(); + + flush(); +#if HAS_MONITOR + ao_set_monitor(0); +#endif + ao_add_task(&ao_packet_task, ao_packet_master, "master"); + ao_add_task(&ao_packet_echo_task, ao_packet_echo, "echo"); + while ((c = getchar()) != '~') { + if (c == '\r') c = '\n'; + ao_packet_putchar(c); + } + + /* Wait for a second if there is any pending data */ + for (c = 0; (ao_packet_tx_used || ao_tx_packet.len) && c < 10; c++) + ao_delay(AO_MS_TO_TICKS(100)); + ao_packet_enable = 0; + while (ao_packet_echo_task.wchan || ao_packet_task.wchan) { + ao_radio_recv_abort(); + ao_wakeup(&ao_stdin_ready); + ao_delay(AO_MS_TO_TICKS(10)); + } +} + + + +__code struct ao_cmds ao_packet_master_cmds[] = { + { ao_packet_forward, "p\0Remote packet link." }, + { 0, NULL }, +}; + +void +ao_packet_master_init(void) +{ + ao_cmd_register(&ao_packet_master_cmds[0]); +} diff --git a/src/cc1111/ao_packet_slave.c b/src/cc1111/ao_packet_slave.c new file mode 100644 index 00000000..9f14052a --- /dev/null +++ b/src/cc1111/ao_packet_slave.c @@ -0,0 +1,64 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_packet_slave(void) +{ + ao_tx_packet.addr = ao_serial_number; + ao_tx_packet.len = AO_PACKET_SYN; + while (ao_packet_enable) { + if (ao_packet_recv()) { + memcpy(&ao_tx_packet.callsign, &ao_rx_packet.packet.callsign, AO_MAX_CALLSIGN); +#if HAS_FLIGHT + ao_flight_force_idle = TRUE; +#endif + ao_packet_send(); + } + } + ao_exit(); +} + +void +ao_packet_slave_start(void) +{ + ao_packet_enable = 1; + ao_add_task(&ao_packet_task, ao_packet_slave, "slave"); +} + +void +ao_packet_slave_stop(void) +{ + if (ao_packet_enable) { + ao_packet_enable = 0; + while (ao_packet_task.wchan) { + ao_radio_recv_abort(); + ao_delay(AO_MS_TO_TICKS(10)); + } + } +} + +void +ao_packet_slave_init(uint8_t enable) +{ + ao_add_stdio(ao_packet_pollchar, + ao_packet_putchar, + NULL); + if (enable) + ao_packet_slave_start(); +} diff --git a/src/cc1111/ao_radio.c b/src/cc1111/ao_radio.c new file mode 100644 index 00000000..00816b33 --- /dev/null +++ b/src/cc1111/ao_radio.c @@ -0,0 +1,475 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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 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 + +/* + * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone), + * so the DRATE_E and DRATE_M values are: + * + * M is 94 and E is 6 + * + * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes + */ + +#define RDF_DRATE_E 6 +#define RDF_DRATE_M 94 +#define RDF_PACKET_LEN 50 + +/* + * RDF deviation should match the normal NFM value of 5kHz + * + * M is 6 and E is 1 + * + */ + +#define RDF_DEVIATION_M 6 +#define RDF_DEVIATION_E 1 + +/* 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_10_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_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_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, +}; + +static __code uint8_t rdf_setup[] = { + RF_MDMCFG4_OFF, ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) | + (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) | + (RDF_DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)), + RF_MDMCFG3_OFF, (RDF_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_DIS | + RF_MDMCFG1_NUM_PREAMBLE_2 | + (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)), + + RF_DEVIATN_OFF, ((RDF_DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) | + (RDF_DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)), + + /* packet length is set in-line */ + RF_PKTCTRL1_OFF, ((1 << PKTCTRL1_PQT_SHIFT)| + PKTCTRL1_ADR_CHK_NONE), + RF_PKTCTRL0_OFF, (RF_PKTCTRL0_PKT_FORMAT_NORMAL| + RF_PKTCTRL0_LENGTH_CONFIG_FIXED), +}; + +static __code uint8_t fixed_pkt_setup[] = { + 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_DEVIATN_OFF, ((DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) | + (DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)), + + /* max packet length -- now set inline */ + 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), +}; + +__xdata uint8_t ao_radio_dma; +__xdata uint8_t ao_radio_dma_done; +__xdata uint8_t ao_radio_done; +__xdata uint8_t ao_radio_abort; +__xdata uint8_t ao_radio_mutex; + +void +ao_radio_general_isr(void) __interrupt 16 +{ + S1CON &= ~0x03; + if (RFIF & RFIF_IM_TIMEOUT) { + ao_radio_recv_abort(); + RFIF &= ~ RFIF_IM_TIMEOUT; + } else if (RFIF & RFIF_IM_DONE) { + ao_radio_done = 1; + ao_wakeup(&ao_radio_done); + RFIF &= ~RFIF_IM_DONE; + } +} + +void +ao_radio_set_packet(void) +{ + uint8_t i; + for (i = 0; i < sizeof (fixed_pkt_setup); i += 2) + RF[fixed_pkt_setup[i]] = fixed_pkt_setup[i+1]; +} + +void +ao_radio_idle(void) +{ + if (RF_MARCSTATE != RF_MARCSTATE_IDLE) + { + do { + RFST = RFST_SIDLE; + ao_yield(); + } while (RF_MARCSTATE != RF_MARCSTATE_IDLE); + } +} + +void +ao_radio_get(uint8_t len) +{ + ao_config_get(); + ao_mutex_get(&ao_radio_mutex); + ao_radio_idle(); + RF_CHANNR = ao_config.radio_channel; + RF_FREQ2 = (uint8_t) (ao_config.radio_setting >> 16); + RF_FREQ1 = (uint8_t) (ao_config.radio_setting >> 8); + RF_FREQ0 = (uint8_t) (ao_config.radio_setting); + RF_PKTLEN = len; +} + + +void +ao_radio_send(__xdata void *packet, uint8_t size) __reentrant +{ + ao_radio_get(size); + ao_radio_done = 0; + ao_dma_set_transfer(ao_radio_dma, + packet, + &RFDXADDR, + size, + 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; + __critical while (!ao_radio_done) + ao_sleep(&ao_radio_done); + ao_radio_put(); +} + +uint8_t +ao_radio_recv(__xdata void *packet, uint8_t size) __reentrant +{ + ao_radio_abort = 0; + ao_radio_get(size - 2); + ao_dma_set_transfer(ao_radio_dma, + &RFDXADDR, + packet, + size, + 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; + + /* Wait for DMA to be done, for the radio receive process to + * get aborted or for a receive timeout to fire + */ + __critical while (!ao_radio_dma_done && !ao_radio_abort) + if (ao_sleep(&ao_radio_dma_done)) + break; + + /* If recv was aborted, clean up by stopping the DMA engine + * and idling the radio + */ + if (!ao_radio_dma_done) { + ao_dma_abort(ao_radio_dma); + ao_radio_idle(); + } + ao_radio_put(); + return ao_radio_dma_done; +} + +/* + * Wake up a task waiting to receive a radio packet + * and tell them to abort the transfer + */ + +void +ao_radio_recv_abort(void) +{ + ao_radio_abort = 1; + ao_wakeup(&ao_radio_dma_done); +} + +__xdata ao_radio_rdf_value = 0x55; + +void +ao_radio_rdf(int ms) +{ + uint8_t i; + uint8_t pkt_len; + + /* + * Compute the packet length as follows: + * + * 2000 bps (for a 1kHz tone) + * so, for 'ms' milliseconds, we need + * 2 * ms bits, or ms / 4 bytes + */ + if (ms > (255 * 4)) + ms = 255 * 4; + pkt_len = ms >> 2; + + ao_radio_abort = 0; + ao_radio_get(pkt_len); + ao_radio_done = 0; + for (i = 0; i < sizeof (rdf_setup); i += 2) + RF[rdf_setup[i]] = rdf_setup[i+1]; + + ao_dma_set_transfer(ao_radio_dma, + &ao_radio_rdf_value, + &RFDXADDR, + pkt_len, + DMA_CFG0_WORDSIZE_8 | + DMA_CFG0_TMODE_SINGLE | + DMA_CFG0_TRIGGER_RADIO, + DMA_CFG1_SRCINC_0 | + DMA_CFG1_DESTINC_0 | + DMA_CFG1_PRIORITY_HIGH); + ao_dma_start(ao_radio_dma); + RFST = RFST_STX; + __critical while (!ao_radio_done && !ao_radio_abort) + ao_sleep(&ao_radio_done); + if (!ao_radio_done) { + ao_dma_abort(ao_radio_dma); + ao_radio_idle(); + } + ao_radio_set_packet(); + ao_radio_put(); +} + +void +ao_radio_rdf_abort(void) +{ + ao_radio_abort = 1; + ao_wakeup(&ao_radio_done); +} + + +/* Output carrier */ +void +ao_radio_test(void) +{ + uint8_t mode = 2; + static __xdata radio_on; + ao_cmd_white(); + if (ao_cmd_lex_c != '\n') { + ao_cmd_decimal(); + mode = (uint8_t) ao_cmd_lex_u32; + } + mode++; + if ((mode & 2) && !radio_on) { +#if HAS_MONITOR + ao_set_monitor(0); +#endif +#if PACKET_HAS_SLAVE + ao_packet_slave_stop(); +#endif + ao_radio_get(0xff); + RFST = RFST_STX; + radio_on = 1; + } + if (mode == 3) { + printf ("Hit a character to stop..."); flush(); + getchar(); + putchar('\n'); + } + if ((mode & 1) && radio_on) { + ao_radio_idle(); + ao_radio_put(); + radio_on = 0; + } +} + +__code struct ao_cmds ao_radio_cmds[] = { + { ao_radio_test, "C <1 start, 0 stop, none both>\0Radio carrier test" }, + { 0, NULL }, +}; + +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_set_packet(); + ao_radio_dma_done = 1; + ao_radio_dma = ao_dma_alloc(&ao_radio_dma_done); + RFIF = 0; + RFIM = RFIM_IM_TIMEOUT|RFIM_IM_DONE; + IEN2 |= IEN2_RFIE; + ao_cmd_register(&ao_radio_cmds[0]); +} diff --git a/src/cc1111/ao_reboot.c b/src/cc1111/ao_reboot.c new file mode 100644 index 00000000..8c47b893 --- /dev/null +++ b/src/cc1111/ao_reboot.c @@ -0,0 +1,28 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +/* Use the watchdog timer to force a complete reboot + */ +void +ao_reboot(void) +{ + WDCTL = WDCTL_EN | WDCTL_MODE_WATCHDOG | WDCTL_INT_32768; + ao_delay(AO_SEC_TO_TICKS(2)); + ao_panic(AO_PANIC_REBOOT); +} diff --git a/src/cc1111/ao_romconfig.c b/src/cc1111/ao_romconfig.c new file mode 100644 index 00000000..f3fe61b1 --- /dev/null +++ b/src/cc1111/ao_romconfig.c @@ -0,0 +1,32 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +__code __at (0x00a0) uint16_t ao_romconfig_version = AO_ROMCONFIG_VERSION; +__code __at (0x00a2) uint16_t ao_romconfig_check = ~AO_ROMCONFIG_VERSION; +__code __at (0x00a4) uint16_t ao_serial_number = 0; +/* + * For 434.550MHz, the frequency value is: + * + * 434.550e6 / (24e6 / 2**16) = 1186611.2 + * + * This value is stored in a const variable so that + * ao-load can change it during programming for + * devices that have no eeprom for config data. + */ +__code __at (0x00a6) uint32_t ao_radio_cal = 1186611; diff --git a/src/cc1111/ao_serial.c b/src/cc1111/ao_serial.c new file mode 100644 index 00000000..82370c64 --- /dev/null +++ b/src/cc1111/ao_serial.c @@ -0,0 +1,175 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +volatile __xdata struct ao_fifo ao_usart1_rx_fifo; +volatile __xdata struct ao_fifo ao_usart1_tx_fifo; + +void +ao_serial_rx1_isr(void) __interrupt 3 +{ + if (!ao_fifo_full(ao_usart1_rx_fifo)) + ao_fifo_insert(ao_usart1_rx_fifo, U1DBUF); + ao_wakeup(&ao_usart1_rx_fifo); +#if USE_SERIAL_STDIN + ao_wakeup(&ao_stdin_ready); +#endif +} + +static __xdata uint8_t ao_serial_tx1_started; + +static void +ao_serial_tx1_start(void) +{ + if (!ao_fifo_empty(ao_usart1_tx_fifo) && + !ao_serial_tx1_started) + { + ao_serial_tx1_started = 1; + ao_fifo_remove(ao_usart1_tx_fifo, U1DBUF); + } +} + +void +ao_serial_tx1_isr(void) __interrupt 14 +{ + UTX1IF = 0; + ao_serial_tx1_started = 0; + ao_serial_tx1_start(); + ao_wakeup(&ao_usart1_tx_fifo); +} + +char +ao_serial_getchar(void) __critical +{ + char c; + while (ao_fifo_empty(ao_usart1_rx_fifo)) + ao_sleep(&ao_usart1_rx_fifo); + ao_fifo_remove(ao_usart1_rx_fifo, c); + return c; +} + +#if USE_SERIAL_STDIN +char +ao_serial_pollchar(void) __critical +{ + char c; + if (ao_fifo_empty(ao_usart1_rx_fifo)) + return AO_READ_AGAIN; + ao_fifo_remove(ao_usart1_rx_fifo,c); + return c; +} +#endif + +void +ao_serial_putchar(char c) __critical +{ + while (ao_fifo_full(ao_usart1_tx_fifo)) + ao_sleep(&ao_usart1_tx_fifo); + ao_fifo_insert(ao_usart1_tx_fifo, c); + ao_serial_tx1_start(); +} + +void +ao_serial_drain(void) __critical +{ + while (!ao_fifo_empty(ao_usart1_tx_fifo)) + ao_sleep(&ao_usart1_tx_fifo); +} + +static __code struct { + uint8_t baud; + uint8_t gcr; +} ao_serial_speeds[] = { + /* [AO_SERIAL_SPEED_4800] = */ { + /* .baud = */ 163, + /* .gcr = */ (7 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB + }, + /* [AO_SERIAL_SPEED_9600] = */ { + /* .baud = */ 163, + /* .gcr = */ (8 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB + }, + /* [AO_SERIAL_SPEED_19200] = */ { + /* .baud = */ 163, + /* .gcr = */ (9 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB + }, + /* [AO_SERIAL_SPEED_57600] = */ { + /* .baud = */ 59, + /* .gcr = */ (11 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB + }, +}; + +void +ao_serial_set_speed(uint8_t speed) +{ + ao_serial_drain(); + if (speed > AO_SERIAL_SPEED_57600) + return; + U1UCR |= UxUCR_FLUSH; + U1BAUD = ao_serial_speeds[speed].baud; + U1GCR = ao_serial_speeds[speed].gcr; +} + +void +ao_serial_init(void) +{ +#if HAS_SERIAL_1_ALT_1 + /* Set up the USART pin assignment */ + PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_1; + + P2DIR = (P2DIR & ~P2DIR_PRIP0_MASK) | P2DIR_PRIP0_USART1_USART0; + + /* Make the USART pins be controlled by the USART */ + P0SEL |= (1 << 5) | (1 << 4); +#if HAS_SERIAL_1_HW_FLOW + P0SEL |= (1 << 3) | (1 << 2); +#endif +#else + /* Set up the USART pin assignment */ + PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_2; + + P2SEL = (P2SEL & ~(P2SEL_PRI3P1_MASK | P2SEL_PRI2P1_MASK)) | + (P2SEL_PRI3P1_USART1 | P2SEL_PRI2P1_USART1); + + /* Make the USART pins be controlled by the USART */ + P1SEL |= (1 << 6) | (1 << 7); + P1SEL |= (1 << 5) | (1 << 4); +#endif + + /* UART mode with receiver enabled */ + U1CSR = (UxCSR_MODE_UART | UxCSR_RE); + + /* Pick a 4800 baud rate */ + ao_serial_set_speed(AO_SERIAL_SPEED_4800); + + /* Reasonable serial parameters */ + U1UCR = (UxUCR_FLUSH | +#if HAS_SERIAL_1_HW_FLOW + UxUCR_FLOW_ENABLE | +#else + UxUCR_FLOW_DISABLE | +#endif + UxUCR_D9_EVEN_PARITY | + UxUCR_BIT9_8_BITS | + UxUCR_PARITY_DISABLE | + UxUCR_SPB_1_STOP_BIT | + UxUCR_STOP_HIGH | + UxUCR_START_LOW); + + IEN0 |= IEN0_URX1IE; + IEN2 |= IEN2_UTX1IE; +} diff --git a/src/cc1111/ao_spi.c b/src/cc1111/ao_spi.c new file mode 100644 index 00000000..fbe613c7 --- /dev/null +++ b/src/cc1111/ao_spi.c @@ -0,0 +1,157 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +/* Shared mutex to protect SPI bus, must cover the entire + * operation, from CS low to CS high. This means that any SPI + * user must protect the SPI bus with this mutex + */ +__xdata uint8_t ao_spi_mutex; +__xdata uint8_t ao_spi_dma_in_done; +__xdata uint8_t ao_spi_dma_out_done; + +uint8_t ao_spi_dma_out_id; +uint8_t ao_spi_dma_in_id; + +static __xdata uint8_t ao_spi_const = 0xff; + +/* Send bytes over SPI. + * + * This sets up two DMA engines, one writing the data and another reading + * bytes coming back. We use the bytes coming back to tell when the transfer + * is complete, as the transmit register is double buffered and hence signals + * completion one byte before the transfer is actually complete + */ +void +ao_spi_send(void __xdata *block, uint16_t len) __reentrant +{ + ao_dma_set_transfer(ao_spi_dma_in_id, + &U0DBUFXADDR, + &ao_spi_const, + len, + DMA_CFG0_WORDSIZE_8 | + DMA_CFG0_TMODE_SINGLE | + DMA_CFG0_TRIGGER_URX0, + DMA_CFG1_SRCINC_0 | + DMA_CFG1_DESTINC_0 | + DMA_CFG1_PRIORITY_NORMAL); + + ao_dma_set_transfer(ao_spi_dma_out_id, + block, + &U0DBUFXADDR, + len, + DMA_CFG0_WORDSIZE_8 | + DMA_CFG0_TMODE_SINGLE | + DMA_CFG0_TRIGGER_UTX0, + DMA_CFG1_SRCINC_1 | + DMA_CFG1_DESTINC_0 | + DMA_CFG1_PRIORITY_NORMAL); + + ao_dma_start(ao_spi_dma_in_id); + ao_dma_start(ao_spi_dma_out_id); + ao_dma_trigger(ao_spi_dma_out_id); + __critical while (!ao_spi_dma_in_done) + ao_sleep(&ao_spi_dma_in_done); +} + +/* Receive bytes over SPI. + * + * This sets up tow DMA engines, one reading the data and another + * writing constant values to the SPI transmitter as that is what + * clocks the data coming in. + */ +void +ao_spi_recv(void __xdata *block, uint16_t len) __reentrant +{ + ao_dma_set_transfer(ao_spi_dma_in_id, + &U0DBUFXADDR, + block, + len, + DMA_CFG0_WORDSIZE_8 | + DMA_CFG0_TMODE_SINGLE | + DMA_CFG0_TRIGGER_URX0, + DMA_CFG1_SRCINC_0 | + DMA_CFG1_DESTINC_1 | + DMA_CFG1_PRIORITY_NORMAL); + + ao_dma_set_transfer(ao_spi_dma_out_id, + &ao_spi_const, + &U0DBUFXADDR, + len, + DMA_CFG0_WORDSIZE_8 | + DMA_CFG0_TMODE_SINGLE | + DMA_CFG0_TRIGGER_UTX0, + DMA_CFG1_SRCINC_0 | + DMA_CFG1_DESTINC_0 | + DMA_CFG1_PRIORITY_NORMAL); + + ao_dma_start(ao_spi_dma_in_id); + ao_dma_start(ao_spi_dma_out_id); + ao_dma_trigger(ao_spi_dma_out_id); + __critical while (!ao_spi_dma_in_done) + ao_sleep(&ao_spi_dma_in_done); +} + +/* + * Initialize USART0 for SPI using config alt 2 + * + * MO P1_5 + * MI P1_4 + * CLK P1_3 + * + * Chip select is the responsibility of the caller + */ + +void +ao_spi_init(void) +{ + /* Set up the USART pin assignment */ + PERCFG = (PERCFG & ~PERCFG_U0CFG_ALT_MASK) | PERCFG_U0CFG_ALT_2; + + /* Ensure that USART0 takes precidence over USART1 for pins that + * they share + */ + P2SEL = (P2SEL & ~P2SEL_PRI3P1_MASK) | P2SEL_PRI3P1_USART0; + + /* Make the SPI pins be controlled by the USART peripheral */ + P1SEL |= ((1 << 5) | (1 << 4) | (1 << 3)); + + /* Set up OUT DMA */ + ao_spi_dma_out_id = ao_dma_alloc(&ao_spi_dma_out_done); + + /* Set up IN DMA */ + ao_spi_dma_in_id = ao_dma_alloc(&ao_spi_dma_in_done); + + /* Set up the USART. + * + * SPI master mode + */ + U0CSR = (UxCSR_MODE_SPI | UxCSR_RE | UxCSR_MASTER); + + /* Set the baud rate and signal parameters + * + * The cc1111 is limited to a 24/8 MHz SPI clock. + * Every peripheral I've ever seen goes faster than that, + * so set the clock to 3MHz (BAUD_E 17, BAUD_M 0) + */ + U0BAUD = 0; + U0GCR = (UxGCR_CPOL_NEGATIVE | + UxGCR_CPHA_FIRST_EDGE | + UxGCR_ORDER_MSB | + (17 << UxGCR_BAUD_E_SHIFT)); +} diff --git a/src/cc1111/ao_timer.c b/src/cc1111/ao_timer.c new file mode 100644 index 00000000..c977fbc8 --- /dev/null +++ b/src/cc1111/ao_timer.c @@ -0,0 +1,111 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +static volatile __data uint16_t ao_tick_count; + +uint16_t ao_time(void) __critical +{ + return ao_tick_count; +} + +static __xdata uint8_t ao_forever; + +void +ao_delay(uint16_t ticks) +{ + ao_alarm(ticks); + ao_sleep(&ao_forever); +} + +#define T1_CLOCK_DIVISOR 8 /* 24e6/8 = 3e6 */ +#define T1_SAMPLE_TIME 30000 /* 3e6/30000 = 100 */ + +#if HAS_ADC +volatile __data uint8_t ao_adc_interval = 1; +volatile __data uint8_t ao_adc_count; +#endif + +void ao_timer_isr(void) __interrupt 9 +{ + ++ao_tick_count; +#if HAS_ADC + if (++ao_adc_count == ao_adc_interval) { + ao_adc_count = 0; + ao_adc_poll(); + } +#endif +} + +#if HAS_ADC +void +ao_timer_set_adc_interval(uint8_t interval) __critical +{ + ao_adc_interval = interval; + ao_adc_count = 0; +} +#endif + +void +ao_timer_init(void) +{ + /* NOTE: This uses a timer only present on cc1111 architecture. */ + + /* disable timer 1 */ + T1CTL = 0; + + /* set the sample rate */ + T1CC0H = T1_SAMPLE_TIME >> 8; + T1CC0L = (uint8_t) T1_SAMPLE_TIME; + + T1CCTL0 = T1CCTL_MODE_COMPARE; + T1CCTL1 = 0; + T1CCTL2 = 0; + + /* clear timer value */ + T1CNTL = 0; + + /* enable overflow interrupt */ + OVFIM = 1; + /* enable timer 1 interrupt */ + T1IE = 1; + + /* enable timer 1 in module mode, dividing by 8 */ + T1CTL = T1CTL_MODE_MODULO | T1CTL_DIV_8; +} + +/* + * AltOS always cranks the clock to the max frequency + */ +void +ao_clock_init(void) +{ + /* Switch system clock to crystal oscilator */ + CLKCON = (CLKCON & ~CLKCON_OSC_MASK) | (CLKCON_OSC_XTAL); + + while (!(SLEEP & SLEEP_XOSC_STB)) + ; + + /* Crank up the timer tick and system clock speed */ + CLKCON = ((CLKCON & ~(CLKCON_TICKSPD_MASK | CLKCON_CLKSPD_MASK)) | + (CLKCON_TICKSPD_1 | CLKCON_CLKSPD_1)); + + while ((CLKCON & (CLKCON_TICKSPD_MASK|CLKCON_CLKSPD_MASK)) != + (CLKCON_TICKSPD_1 | CLKCON_CLKSPD_1)) + ; +} diff --git a/src/cc1111/ao_usb.c b/src/cc1111/ao_usb.c new file mode 100644 index 00000000..08cb7390 --- /dev/null +++ b/src/cc1111/ao_usb.c @@ -0,0 +1,460 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" +#include "ao_usb.h" + +struct ao_task __xdata ao_usb_task; + +static __xdata uint16_t ao_usb_in_bytes; +static __pdata uint16_t ao_usb_in_bytes_last; +static __xdata uint16_t ao_usb_out_bytes; +static __pdata uint8_t ao_usb_iif; +static __pdata uint8_t ao_usb_running; + +static void +ao_usb_set_interrupts(void) +{ + /* IN interrupts on the control an IN endpoints */ + USBIIE = (1 << AO_USB_CONTROL_EP) | (1 << AO_USB_IN_EP); + + /* OUT interrupts on the OUT endpoint */ + USBOIE = (1 << AO_USB_OUT_EP); + + /* Only care about reset */ + USBCIE = USBCIE_RSTIE; +} + +/* This interrupt is shared with port 2, + * so when we hook that up, fix this + */ +void +ao_usb_isr(void) __interrupt 6 +{ + USBIF = 0; + ao_usb_iif |= USBIIF; + if (ao_usb_iif & 1) + ao_wakeup(&ao_usb_task); + if (ao_usb_iif & (1 << AO_USB_IN_EP)) + ao_wakeup(&ao_usb_in_bytes); + + if (USBOIF & (1 << AO_USB_OUT_EP)) + ao_wakeup(&ao_stdin_ready); + + if (USBCIF & USBCIF_RSTIF) + ao_usb_set_interrupts(); +#if HAS_BTM +#if BT_LINK_ON_P2 + ao_btm_isr(); +#endif +#endif +} + +struct ao_usb_setup { + uint8_t dir_type_recip; + uint8_t request; + uint16_t value; + uint16_t index; + uint16_t length; +} __xdata ao_usb_setup; + +__pdata uint8_t ao_usb_ep0_state; +uint8_t * __pdata ao_usb_ep0_in_data; +__pdata uint8_t ao_usb_ep0_in_len; +__pdata uint8_t ao_usb_ep0_in_buf[2]; +__pdata uint8_t ao_usb_ep0_out_len; +__xdata uint8_t *__pdata ao_usb_ep0_out_data; +__pdata uint8_t ao_usb_configuration; + +/* Send an IN data packet */ +static void +ao_usb_ep0_flush(void) +{ + __pdata uint8_t this_len; + __pdata uint8_t cs0; + + /* If the IN packet hasn't been picked up, just return */ + USBINDEX = 0; + cs0 = USBCS0; + if (cs0 & USBCS0_INPKT_RDY) + return; + + this_len = ao_usb_ep0_in_len; + if (this_len > AO_USB_CONTROL_SIZE) + this_len = AO_USB_CONTROL_SIZE; + cs0 = USBCS0_INPKT_RDY; + if (this_len != AO_USB_CONTROL_SIZE) { + cs0 = USBCS0_INPKT_RDY | USBCS0_DATA_END; + ao_usb_ep0_state = AO_USB_EP0_IDLE; + } + ao_usb_ep0_in_len -= this_len; + while (this_len--) + USBFIFO[0] = *ao_usb_ep0_in_data++; + USBINDEX = 0; + USBCS0 = cs0; +} + +__xdata static struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8}; + +/* Walk through the list of descriptors and find a match + */ +static void +ao_usb_get_descriptor(uint16_t value) +{ + __code uint8_t *__pdata descriptor; + __pdata uint8_t type = value >> 8; + __pdata uint8_t index = value; + + descriptor = ao_usb_descriptors; + while (descriptor[0] != 0) { + if (descriptor[1] == type && index-- == 0) { + if (type == AO_USB_DESC_CONFIGURATION) + ao_usb_ep0_in_len = descriptor[2]; + else + ao_usb_ep0_in_len = descriptor[0]; + ao_usb_ep0_in_data = descriptor; + break; + } + descriptor += descriptor[0]; + } +} + +/* Read data from the ep0 OUT fifo + */ +static void +ao_usb_ep0_fill(void) +{ + __pdata uint8_t len; + + USBINDEX = 0; + len = USBCNT0; + if (len > ao_usb_ep0_out_len) + len = ao_usb_ep0_out_len; + ao_usb_ep0_out_len -= len; + while (len--) + *ao_usb_ep0_out_data++ = USBFIFO[0]; +} + +void +ao_usb_ep0_queue_byte(uint8_t a) +{ + ao_usb_ep0_in_buf[ao_usb_ep0_in_len++] = a; +} + +void +ao_usb_set_address(uint8_t address) +{ + ao_usb_running = 1; + USBADDR = address | 0x80; + while (USBADDR & 0x80) + ; +} + +static void +ao_usb_set_configuration(void) +{ + /* Set the IN max packet size, double buffered */ + USBINDEX = AO_USB_IN_EP; + USBMAXI = AO_USB_IN_SIZE >> 3; + USBCSIH |= USBCSIH_IN_DBL_BUF; + + /* Set the OUT max packet size, double buffered */ + USBINDEX = AO_USB_OUT_EP; + USBMAXO = AO_USB_OUT_SIZE >> 3; + USBCSOH = USBCSOH_OUT_DBL_BUF; +} + +static void +ao_usb_ep0_setup(void) +{ + /* Pull the setup packet out of the fifo */ + ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_setup; + ao_usb_ep0_out_len = 8; + ao_usb_ep0_fill(); + if (ao_usb_ep0_out_len != 0) + return; + + /* Figure out how to ACK the setup packet */ + if (ao_usb_setup.dir_type_recip & AO_USB_DIR_IN) { + if (ao_usb_setup.length) + ao_usb_ep0_state = AO_USB_EP0_DATA_IN; + else + ao_usb_ep0_state = AO_USB_EP0_IDLE; + } else { + if (ao_usb_setup.length) + ao_usb_ep0_state = AO_USB_EP0_DATA_OUT; + else + ao_usb_ep0_state = AO_USB_EP0_IDLE; + } + USBINDEX = 0; + if (ao_usb_ep0_state == AO_USB_EP0_IDLE) + USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END; + else + USBCS0 = USBCS0_CLR_OUTPKT_RDY; + + ao_usb_ep0_in_data = ao_usb_ep0_in_buf; + ao_usb_ep0_in_len = 0; + switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_TYPE_MASK) { + case AO_USB_TYPE_STANDARD: + switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_RECIP_MASK) { + case AO_USB_RECIP_DEVICE: + switch(ao_usb_setup.request) { + case AO_USB_REQ_GET_STATUS: + ao_usb_ep0_queue_byte(0); + ao_usb_ep0_queue_byte(0); + break; + case AO_USB_REQ_SET_ADDRESS: + ao_usb_set_address(ao_usb_setup.value); + break; + case AO_USB_REQ_GET_DESCRIPTOR: + ao_usb_get_descriptor(ao_usb_setup.value); + break; + case AO_USB_REQ_GET_CONFIGURATION: + ao_usb_ep0_queue_byte(ao_usb_configuration); + break; + case AO_USB_REQ_SET_CONFIGURATION: + ao_usb_configuration = ao_usb_setup.value; + ao_usb_set_configuration(); + break; + } + 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); + ao_usb_ep0_queue_byte(0); + break; + case AO_USB_REQ_GET_INTERFACE: + ao_usb_ep0_queue_byte(0); + break; + case AO_USB_REQ_SET_INTERFACE: + break; + } + break; + case AO_USB_RECIP_ENDPOINT: + switch(ao_usb_setup.request) { + case AO_USB_REQ_GET_STATUS: + ao_usb_ep0_queue_byte(0); + ao_usb_ep0_queue_byte(0); + break; + } + break; + } + break; + case AO_USB_TYPE_CLASS: + switch (ao_usb_setup.request) { + case SET_LINE_CODING: + ao_usb_ep0_out_len = 7; + ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_line_coding; + break; + case GET_LINE_CODING: + ao_usb_ep0_in_len = 7; + ao_usb_ep0_in_data = (uint8_t *) &ao_usb_line_coding; + break; + case SET_CONTROL_LINE_STATE: + break; + } + break; + } + if (ao_usb_ep0_state != AO_USB_EP0_DATA_OUT) { + if (ao_usb_setup.length < ao_usb_ep0_in_len) + ao_usb_ep0_in_len = ao_usb_setup.length; + ao_usb_ep0_flush(); + } +} + +/* End point 0 receives all of the control messages. */ +static void +ao_usb_ep0(void) +{ + __pdata uint8_t cs0; + + ao_usb_ep0_state = AO_USB_EP0_IDLE; + for (;;) { + __critical for (;;) { + if (ao_usb_iif & 1) { + ao_usb_iif &= ~1; + break; + } + ao_sleep(&ao_usb_task); + } + USBINDEX = 0; + cs0 = USBCS0; + if (cs0 & USBCS0_SETUP_END) { + ao_usb_ep0_state = AO_USB_EP0_IDLE; + USBCS0 = USBCS0_CLR_SETUP_END; + } + if (cs0 & USBCS0_SENT_STALL) { + ao_usb_ep0_state = AO_USB_EP0_IDLE; + USBCS0 &= ~USBCS0_SENT_STALL; + } + if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN && + (cs0 & USBCS0_INPKT_RDY) == 0) + { + ao_usb_ep0_flush(); + } + if (cs0 & USBCS0_OUTPKT_RDY) { + switch (ao_usb_ep0_state) { + case AO_USB_EP0_IDLE: + ao_usb_ep0_setup(); + break; + case AO_USB_EP0_DATA_OUT: + ao_usb_ep0_fill(); + if (ao_usb_ep0_out_len == 0) + ao_usb_ep0_state = AO_USB_EP0_IDLE; + USBINDEX = 0; + if (ao_usb_ep0_state == AO_USB_EP0_IDLE) + USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END; + else + USBCS0 = USBCS0_CLR_OUTPKT_RDY; + break; + } + } + } +} + +/* Wait for a free IN buffer */ +static void +ao_usb_in_wait(void) +{ + for (;;) { + USBINDEX = AO_USB_IN_EP; + if ((USBCSIL & USBCSIL_INPKT_RDY) == 0) + break; + ao_sleep(&ao_usb_in_bytes); + } +} + +/* Send the current IN packet */ +static void +ao_usb_in_send(void) +{ + USBINDEX = AO_USB_IN_EP; + USBCSIL |= USBCSIL_INPKT_RDY; + ao_usb_in_bytes_last = ao_usb_in_bytes; + ao_usb_in_bytes = 0; +} + +void +ao_usb_flush(void) __critical +{ + if (!ao_usb_running) + return; + + /* If there are pending bytes, or if the last packet was full, + * send another IN packet + */ + if (ao_usb_in_bytes || (ao_usb_in_bytes_last == AO_USB_IN_SIZE)) { + ao_usb_in_wait(); + ao_usb_in_send(); + } +} + +void +ao_usb_putchar(char c) __critical __reentrant +{ + if (!ao_usb_running) + return; + + ao_usb_in_wait(); + + /* Queue a byte, sending the packet when full */ + USBFIFO[AO_USB_IN_EP << 1] = c; + if (++ao_usb_in_bytes == AO_USB_IN_SIZE) + ao_usb_in_send(); +} + +char +ao_usb_pollchar(void) __critical +{ + char c; + if (ao_usb_out_bytes == 0) { + USBINDEX = AO_USB_OUT_EP; + if ((USBCSOL & USBCSOL_OUTPKT_RDY) == 0) + return AO_READ_AGAIN; + ao_usb_out_bytes = (USBCNTH << 8) | USBCNTL; + if (ao_usb_out_bytes == 0) { + USBINDEX = AO_USB_OUT_EP; + USBCSOL &= ~USBCSOL_OUTPKT_RDY; + return AO_READ_AGAIN; + } + } + --ao_usb_out_bytes; + c = USBFIFO[AO_USB_OUT_EP << 1]; + if (ao_usb_out_bytes == 0) { + USBINDEX = AO_USB_OUT_EP; + USBCSOL &= ~USBCSOL_OUTPKT_RDY; + } + return c; +} + +char +ao_usb_getchar(void) __critical +{ + char c; + + while ((c = ao_usb_pollchar()) == AO_READ_AGAIN) + ao_sleep(&ao_stdin_ready); + return c; +} + +void +ao_usb_enable(void) +{ + /* Turn on the USB controller */ + SLEEP |= SLEEP_USB_EN; + + ao_usb_set_configuration(); + + ao_usb_set_interrupts(); + + /* enable USB interrupts */ + IEN2 |= IEN2_USBIE; + + /* Clear any pending interrupts */ + USBCIF = 0; + USBOIF = 0; + USBIIF = 0; +} + +void +ao_usb_disable(void) +{ + /* Disable USB interrupts */ + USBIIE = 0; + USBOIE = 0; + USBCIE = 0; + IEN2 &= ~IEN2_USBIE; + + /* Clear any pending interrupts */ + USBCIF = 0; + USBOIF = 0; + USBIIF = 0; + + /* Turn off the USB controller */ + SLEEP &= ~SLEEP_USB_EN; +} + +void +ao_usb_init(void) +{ + ao_usb_enable(); + + ao_add_task(&ao_usb_task, ao_usb_ep0, "usb"); + ao_add_stdio(ao_usb_pollchar, ao_usb_putchar, ao_usb_flush); +} diff --git a/src/cc1111/ao_usb.h b/src/cc1111/ao_usb.h new file mode 100644 index 00000000..6633dafc --- /dev/null +++ b/src/cc1111/ao_usb.h @@ -0,0 +1,100 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_USB_H_ +#define _AO_USB_H_ + +#define AO_USB_SETUP_DIR_MASK (0x01 << 7) +#define AO_USB_SETUP_TYPE_MASK (0x03 << 5) +#define AO_USB_SETUP_RECIP_MASK (0x1f) + +#define AO_USB_DIR_OUT 0 +#define AO_USB_DIR_IN (1 << 7) + +#define AO_USB_TYPE_STANDARD 0 +#define AO_USB_TYPE_CLASS (1 << 5) +#define AO_USB_TYPE_VENDOR (2 << 5) +#define AO_USB_TYPE_RESERVED (3 << 5) + +#define AO_USB_RECIP_DEVICE 0 +#define AO_USB_RECIP_INTERFACE 1 +#define AO_USB_RECIP_ENDPOINT 2 +#define AO_USB_RECIP_OTHER 3 + +/* standard requests */ +#define AO_USB_REQ_GET_STATUS 0x00 +#define AO_USB_REQ_CLEAR_FEATURE 0x01 +#define AO_USB_REQ_SET_FEATURE 0x03 +#define AO_USB_REQ_SET_ADDRESS 0x05 +#define AO_USB_REQ_GET_DESCRIPTOR 0x06 +#define AO_USB_REQ_SET_DESCRIPTOR 0x07 +#define AO_USB_REQ_GET_CONFIGURATION 0x08 +#define AO_USB_REQ_SET_CONFIGURATION 0x09 +#define AO_USB_REQ_GET_INTERFACE 0x0A +#define AO_USB_REQ_SET_INTERFACE 0x0B +#define AO_USB_REQ_SYNCH_FRAME 0x0C + +#define AO_USB_DESC_DEVICE 1 +#define AO_USB_DESC_CONFIGURATION 2 +#define AO_USB_DESC_STRING 3 +#define AO_USB_DESC_INTERFACE 4 +#define AO_USB_DESC_ENDPOINT 5 +#define AO_USB_DESC_DEVICE_QUALIFIER 6 +#define AO_USB_DESC_OTHER_SPEED 7 +#define AO_USB_DESC_INTERFACE_POWER 8 + +#define AO_USB_GET_DESC_TYPE(x) (((x)>>8)&0xFF) +#define AO_USB_GET_DESC_INDEX(x) ((x)&0xFF) + +#define AO_USB_CONTROL_EP 0 +#define AO_USB_INT_EP 1 +#define AO_USB_OUT_EP 4 +#define AO_USB_IN_EP 5 +#define AO_USB_CONTROL_SIZE 32 +/* + * Double buffer IN and OUT EPs, so each + * gets half of the available space + * + * Ah, but USB bulk packets can only come in 8, 16, 32 and 64 + * byte sizes, so we'll use 64 for everything + */ +#define AO_USB_IN_SIZE 64 +#define AO_USB_OUT_SIZE 64 + +#define AO_USB_EP0_IDLE 0 +#define AO_USB_EP0_DATA_IN 1 +#define AO_USB_EP0_DATA_OUT 2 + +#define LE_WORD(x) ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8)) + +/* CDC definitions */ +#define CS_INTERFACE 0x24 +#define CS_ENDPOINT 0x25 + +#define SET_LINE_CODING 0x20 +#define GET_LINE_CODING 0x21 +#define SET_CONTROL_LINE_STATE 0x22 + +/* Data structure for GET_LINE_CODING / SET_LINE_CODING class requests */ +struct ao_usb_line_coding { + uint32_t rate; + uint8_t char_format; + uint8_t parity; + uint8_t data_bits; +} ; + +#endif /* _AO_USB_H_ */ diff --git a/src/cc1111/cc1111.h b/src/cc1111/cc1111.h new file mode 100644 index 00000000..e52aa79f --- /dev/null +++ b/src/cc1111/cc1111.h @@ -0,0 +1,1306 @@ +/*------------------------------------------------------------------------- + Register Declarations for the ChipCon CC1111 Processor Range + + Copyright © 2008 Keith Packard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; 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. + + Adapted from the Cygnal C8051F12x config file which is: + + Copyright (C) 2003 - Maarten Brock, sourceforge.brock@dse.nl + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-------------------------------------------------------------------------*/ + +#ifndef _CC1111_H_ +#define _CC1111_H_ +#include +#include + +__sfr __at 0xA8 IEN0; /* Interrupt Enable 0 Register */ + +sbit __at 0xA8 RFTXRXIE; /* RF TX/RX done interrupt enable */ +sbit __at 0xA9 ADCIE; /* ADC interrupt enable */ +sbit __at 0xAA URX0IE; /* USART0 RX interrupt enable */ +sbit __at 0xAB URX1IE; /* USART1 RX interrupt enable (shared with I2S RX) */ +sbit __at 0xAB I2SRXIE; /* I2S RX interrupt enable (shared with USART1 RX) */ +sbit __at 0xAC ENCIE; /* AES encryption/decryption interrupt enable */ +sbit __at 0xAD STIE; /* Sleep Timer interrupt enable */ +sbit __at 0xAF EA; /* Enable All */ + +#define IEN0_EA (1 << 7) +#define IEN0_STIE (1 << 5) +#define IEN0_ENCIE (1 << 4) +#define IEN0_URX1IE (1 << 3) +#define IEN0_I2SRXIE (1 << 3) +#define IEN0_URX0IE (1 << 2) +#define IEN0_ADCIE (1 << 1) +#define IEN0_RFTXRXIE (1 << 0) + +__sfr __at 0xB8 IEN1; /* Interrupt Enable 1 Register */ + +#define IEN1_P0IE (1 << 5) /* Port 0 interrupt enable */ +#define IEN1_T4IE (1 << 4) /* Timer 4 interrupt enable */ +#define IEN1_T3IE (1 << 3) /* Timer 3 interrupt enable */ +#define IEN1_T2IE (1 << 2) /* Timer 2 interrupt enable */ +#define IEN1_T1IE (1 << 1) /* Timer 1 interrupt enable */ +#define IEN1_DMAIE (1 << 0) /* DMA transfer interrupt enable */ + +/* IEN2 */ +__sfr __at 0x9A IEN2; /* Interrupt Enable 2 Register */ + +#define IEN2_WDTIE (1 << 5) /* Watchdog timer interrupt enable */ +#define IEN2_P1IE (1 << 4) /* Port 1 interrupt enable */ +#define IEN2_UTX1IE (1 << 3) /* USART1 TX interrupt enable */ +#define IEN2_I2STXIE (1 << 3) /* I2S TX interrupt enable */ +#define IEN2_UTX0IE (1 << 2) /* USART0 TX interrupt enable */ +#define IEN2_P2IE (1 << 1) /* Port 2 interrupt enable */ +#define IEN2_USBIE (1 << 1) /* USB interrupt enable */ +#define IEN2_RFIE (1 << 0) /* RF general interrupt enable */ + +/* CLKCON 0xC6 */ +__sfr __at 0xC6 CLKCON; /* Clock Control */ + +#define CLKCON_OSC32K_RC (1 << 7) +#define CLKCON_OSC32K_XTAL (0 << 7) +#define CLKCON_OSC32K_MASK (1 << 7) +#define CLKCON_OSC_RC (1 << 6) +#define CLKCON_OSC_XTAL (0 << 6) +#define CLKCON_OSC_MASK (1 << 6) +#define CLKCON_TICKSPD_MASK (7 << 3) +# define CLKCON_TICKSPD_1 (0 << 3) +# define CLKCON_TICKSPD_1_2 (1 << 3) +# define CLKCON_TICKSPD_1_4 (2 << 3) +# define CLKCON_TICKSPD_1_8 (3 << 3) +# define CLKCON_TICKSPD_1_16 (4 << 3) +# define CLKCON_TICKSPD_1_32 (5 << 3) +# define CLKCON_TICKSPD_1_64 (6 << 3) +# define CLKCON_TICKSPD_1_128 (7 << 3) + +#define CLKCON_CLKSPD_MASK (7 << 0) +# define CLKCON_CLKSPD_1 (0 << 0) +# define CLKCON_CLKSPD_1_2 (1 << 0) +# define CLKCON_CLKSPD_1_4 (2 << 0) +# define CLKCON_CLKSPD_1_8 (3 << 0) +# define CLKCON_CLKSPD_1_16 (4 << 0) +# define CLKCON_CLKSPD_1_32 (5 << 0) +# define CLKCON_CLKSPD_1_64 (6 << 0) +# define CLKCON_CLKSPD_1_128 (7 << 0) + +/* SLEEP 0xBE */ +#define SLEEP_USB_EN (1 << 7) +#define SLEEP_XOSC_STB (1 << 6) +#define SLEEP_HFRC_STB (1 << 5) +#define SLEEP_RST_POWER (0 << 3) +#define SLEEP_RST_EXTERNAL (1 << 3) +#define SLEEP_RST_WATCHDOG (2 << 3) +#define SLEEP_RST_MASK (3 << 3) +#define SLEEP_OSC_PD (1 << 2) +#define SLEEP_MODE_PM0 (0 << 0) +#define SLEEP_MODE_PM1 (1 << 0) +#define SLEEP_MODE_PM2 (2 << 0) +#define SLEEP_MODE_PM3 (3 << 0) +#define SLEEP_MODE_MASK (3 << 0) + +/* PCON 0x87 */ +__sfr __at 0x87 PCON; /* Power Mode Control Register */ + +#define PCON_IDLE (1 << 0) + +/* + * TCON + */ +__sfr __at 0x88 TCON; /* CPU Interrupt Flag 1 */ + +sbit __at 0x8F URX1IF; /* USART1 RX interrupt flag. Automatically cleared */ +sbit __at 0x8F I2SRXIF; /* I2S RX interrupt flag. Automatically cleared */ +sbit __at 0x8D ADCIF; /* ADC interrupt flag. Automatically cleared */ +sbit __at 0x8B URX0IF; /* USART0 RX interrupt flag. Automatically cleared */ +sbit __at 0x89 RFTXRXIF; /* RF TX/RX complete interrupt flag. Automatically cleared */ + +#define TCON_URX1IF (1 << 7) +#define TCON_I2SRXIF (1 << 7) +#define TCON_ADCIF (1 << 5) +#define TCON_URX0IF (1 << 3) +#define TCON_RFTXRXIF (1 << 1) + +/* + * S0CON + */ +__sfr __at 0x98 S0CON; /* CPU Interrupt Flag 2 */ + +sbit __at 0x98 ENCIF_0; /* AES interrupt 0. */ +sbit __at 0x99 ENCIF_1; /* AES interrupt 1. */ + +#define S0CON_ENCIF_1 (1 << 1) +#define S0CON_ENCIF_0 (1 << 0) + +/* + * S1CON + */ +__sfr __at 0x9B S1CON; /* CPU Interrupt Flag 3 */ + +#define S1CON_RFIF_1 (1 << 1) +#define S1CON_RFIF_0 (1 << 0) + +/* + * IRCON + */ +__sfr __at 0xC0 IRCON; /* CPU Interrupt Flag 4 */ + +sbit __at 0xC0 DMAIF; /* DMA complete interrupt flag */ +sbit __at 0xC1 T1IF; /* Timer 1 interrupt flag. Automatically cleared */ +sbit __at 0xC2 T2IF; /* Timer 2 interrupt flag. Automatically cleared */ +sbit __at 0xC3 T3IF; /* Timer 3 interrupt flag. Automatically cleared */ +sbit __at 0xC4 T4IF; /* Timer 4 interrupt flag. Automatically cleared */ +sbit __at 0xC5 P0IF; /* Port0 interrupt flag */ +sbit __at 0xC7 STIF; /* Sleep Timer interrupt flag */ + +#define IRCON_DMAIF (1 << 0) /* DMA complete interrupt flag */ +#define IRCON_T1IF (1 << 1) /* Timer 1 interrupt flag. Automatically cleared */ +#define IRCON_T2IF (1 << 2) /* Timer 2 interrupt flag. Automatically cleared */ +#define IRCON_T3IF (1 << 3) /* Timer 3 interrupt flag. Automatically cleared */ +#define IRCON_T4IF (1 << 4) /* Timer 4 interrupt flag. Automatically cleared */ +#define IRCON_P0IF (1 << 5) /* Port0 interrupt flag */ +#define IRCON_STIF (1 << 7) /* Sleep Timer interrupt flag */ + +/* + * IRCON2 + */ +__sfr __at 0xE8 IRCON2; /* CPU Interrupt Flag 5 */ + +sbit __at 0xE8 USBIF; /* USB interrupt flag (shared with Port2) */ +sbit __at 0xE8 P2IF; /* Port2 interrupt flag (shared with USB) */ +sbit __at 0xE9 UTX0IF; /* USART0 TX interrupt flag */ +sbit __at 0xEA UTX1IF; /* USART1 TX interrupt flag (shared with I2S TX) */ +sbit __at 0xEA I2STXIF; /* I2S TX interrupt flag (shared with USART1 TX) */ +sbit __at 0xEB P1IF; /* Port1 interrupt flag */ +sbit __at 0xEC WDTIF; /* Watchdog timer interrupt flag */ + +#define IRCON2_USBIF (1 << 0) /* USB interrupt flag (shared with Port2) */ +#define IRCON2_P2IF (1 << 0) /* Port2 interrupt flag (shared with USB) */ +#define IRCON2_UTX0IF (1 << 1) /* USART0 TX interrupt flag */ +#define IRCON2_UTX1IF (1 << 2) /* USART1 TX interrupt flag (shared with I2S TX) */ +#define IRCON2_I2STXIF (1 << 2) /* I2S TX interrupt flag (shared with USART1 TX) */ +#define IRCON2_P1IF (1 << 3) /* Port1 interrupt flag */ +#define IRCON2_WDTIF (1 << 4) /* Watchdog timer interrupt flag */ + +/* + * IP1 - Interrupt Priority 1 + */ + +/* + * Interrupt priority groups: + * + * IPG0 RFTXRX RF DMA + * IPG1 ADC T1 P2INT/USB + * IPG2 URX0 T2 UTX0 + * IPG3 URX1/I2SRX T3 UTX1 / I2STX + * IPG4 ENC T4 P1INT + * IPG5 ST P0INT WDT + * + * Priority = (IP1 << 1) | IP0. Higher priority interrupts served first + */ + +__sfr __at 0xB9 IP1; /* Interrupt Priority 1 */ +__sfr __at 0xA9 IP0; /* Interrupt Priority 0 */ + +#define IP1_IPG5 (1 << 5) +#define IP1_IPG4 (1 << 4) +#define IP1_IPG3 (1 << 3) +#define IP1_IPG2 (1 << 2) +#define IP1_IPG1 (1 << 1) +#define IP1_IPG0 (1 << 0) + +#define IP0_IPG5 (1 << 5) +#define IP0_IPG4 (1 << 4) +#define IP0_IPG3 (1 << 3) +#define IP0_IPG2 (1 << 2) +#define IP0_IPG1 (1 << 1) +#define IP0_IPG0 (1 << 0) + +/* + * Timer 1 + */ +#define T1CTL_MODE_SUSPENDED (0 << 0) +#define T1CTL_MODE_FREE (1 << 0) +#define T1CTL_MODE_MODULO (2 << 0) +#define T1CTL_MODE_UP_DOWN (3 << 0) +#define T1CTL_MODE_MASK (3 << 0) +#define T1CTL_DIV_1 (0 << 2) +#define T1CTL_DIV_8 (1 << 2) +#define T1CTL_DIV_32 (2 << 2) +#define T1CTL_DIV_128 (3 << 2) +#define T1CTL_DIV_MASK (3 << 2) +#define T1CTL_OVFIF (1 << 4) +#define T1CTL_CH0IF (1 << 5) +#define T1CTL_CH1IF (1 << 6) +#define T1CTL_CH2IF (1 << 7) + +#define T1CCTL_NO_CAPTURE (0 << 0) +#define T1CCTL_CAPTURE_RISING (1 << 0) +#define T1CCTL_CAPTURE_FALLING (2 << 0) +#define T1CCTL_CAPTURE_BOTH (3 << 0) +#define T1CCTL_CAPTURE_MASK (3 << 0) + +#define T1CCTL_MODE_CAPTURE (0 << 2) +#define T1CCTL_MODE_COMPARE (1 << 2) + +#define T1CTL_CMP_SET (0 << 3) +#define T1CTL_CMP_CLEAR (1 << 3) +#define T1CTL_CMP_TOGGLE (2 << 3) +#define T1CTL_CMP_SET_CLEAR (3 << 3) +#define T1CTL_CMP_CLEAR_SET (4 << 3) + +#define T1CTL_IM_DISABLED (0 << 6) +#define T1CTL_IM_ENABLED (1 << 6) + +#define T1CTL_CPSEL_NORMAL (0 << 7) +#define T1CTL_CPSEL_RF (1 << 7) + +/* + * Timer 3 and Timer 4 + */ + +/* Timer count */ +__sfr __at 0xCA T3CNT; +__sfr __at 0xEA T4CNT; + +/* Timer control */ + +__sfr __at 0xCB T3CTL; +__sfr __at 0xEB T4CTL; + +#define TxCTL_DIV_1 (0 << 5) +#define TxCTL_DIV_2 (1 << 5) +#define TxCTL_DIV_4 (2 << 5) +#define TxCTL_DIV_8 (3 << 5) +#define TxCTL_DIV_16 (4 << 5) +#define TxCTL_DIV_32 (5 << 5) +#define TxCTL_DIV_64 (6 << 5) +#define TxCTL_DIV_128 (7 << 5) +#define TxCTL_START (1 << 4) +#define TxCTL_OVFIM (1 << 3) +#define TxCTL_CLR (1 << 2) +#define TxCTL_MODE_FREE (0 << 0) +#define TxCTL_MODE_DOWN (1 << 0) +#define TxCTL_MODE_MODULO (2 << 0) +#define TxCTL_MODE_UP_DOWN (3 << 0) + +/* Timer 4 channel 0 compare control */ + +__sfr __at 0xCC T3CCTL0; +__sfr __at 0xCE T3CCTL1; +__sfr __at 0xEC T4CCTL0; +__sfr __at 0xEE T4CCTL1; + +#define TxCCTLy_IM (1 << 6) +#define TxCCTLy_CMP_SET (0 << 3) +#define TxCCTLy_CMP_CLEAR (1 << 3) +#define TxCCTLy_CMP_TOGGLE (2 << 3) +#define TxCCTLy_CMP_SET_UP_CLEAR_DOWN (3 << 3) +#define TxCCTLy_CMP_CLEAR_UP_SET_DOWN (4 << 3) +#define TxCCTLy_CMP_SET_CLEAR_FF (5 << 3) +#define TxCCTLy_CMP_CLEAR_SET_00 (6 << 3) +#define TxCCTLy_CMP_MODE_ENABLE (1 << 2) + +/* Timer compare value */ +__sfr __at 0xCD T3CC0; +__sfr __at 0xCF T3CC1; +__sfr __at 0xED T4CC0; +__sfr __at 0xEF T4CC1; + +/* + * Peripheral control + */ + +__sfr __at 0xf1 PERCFG; +#define PERCFG_T1CFG_ALT_1 (0 << 6) +#define PERCFG_T1CFG_ALT_2 (1 << 6) +#define PERCFG_T1CFG_ALT_MASK (1 << 6) + +#define PERCFG_T3CFG_ALT_1 (0 << 5) +#define PERCFG_T3CFG_ALT_2 (1 << 5) +#define PERCFG_T3CFG_ALT_MASK (1 << 5) + +#define PERCFG_T4CFG_ALT_1 (0 << 4) +#define PERCFG_T4CFG_ALT_2 (1 << 4) +#define PERCFG_T4CFG_ALT_MASK (1 << 4) + +#define PERCFG_U1CFG_ALT_1 (0 << 1) +#define PERCFG_U1CFG_ALT_2 (1 << 1) +#define PERCFG_U1CFG_ALT_MASK (1 << 1) + +#define PERCFG_U0CFG_ALT_1 (0 << 0) +#define PERCFG_U0CFG_ALT_2 (1 << 0) +#define PERCFG_U0CFG_ALT_MASK (1 << 0) + +/* directly addressed USB registers */ +__xdata __at (0xde00) volatile uint8_t USBADDR; +__xdata __at (0xde01) volatile uint8_t USBPOW; +__xdata __at (0xde02) volatile uint8_t USBIIF; + +__xdata __at (0xde04) volatile uint8_t USBOIF; + +__xdata __at (0xde06) volatile uint8_t USBCIF; + +# define USBCIF_SOFIF (1 << 3) +# define USBCIF_RSTIF (1 << 2) +# define USBCIF_RESUMEIF (1 << 1) +# define USBCIF_SUSPENDIF (1 << 0) + +__xdata __at (0xde07) volatile uint8_t USBIIE; + +__xdata __at (0xde09) volatile uint8_t USBOIE; + +__xdata __at (0xde0b) volatile uint8_t USBCIE; + +# define USBCIE_SOFIE (1 << 3) +# define USBCIE_RSTIE (1 << 2) +# define USBCIE_RESUMEIE (1 << 1) +# define USBCIE_SUSPENDIE (1 << 0) + +__xdata __at (0xde0c) volatile uint8_t USBFRML; +__xdata __at (0xde0d) volatile uint8_t USBFRMH; +__xdata __at (0xde0e) volatile uint8_t USBINDEX; + +/* indexed USB registers, must set USBINDEX to 0-5 */ +__xdata __at (0xde10) volatile uint8_t USBMAXI; +__xdata __at (0xde11) volatile uint8_t USBCS0; + +# define USBCS0_CLR_SETUP_END (1 << 7) +# define USBCS0_CLR_OUTPKT_RDY (1 << 6) +# define USBCS0_SEND_STALL (1 << 5) +# define USBCS0_SETUP_END (1 << 4) +# define USBCS0_DATA_END (1 << 3) +# define USBCS0_SENT_STALL (1 << 2) +# define USBCS0_INPKT_RDY (1 << 1) +# define USBCS0_OUTPKT_RDY (1 << 0) + +__xdata __at (0xde11) volatile uint8_t USBCSIL; + +# define USBCSIL_CLR_DATA_TOG (1 << 6) +# define USBCSIL_SENT_STALL (1 << 5) +# define USBCSIL_SEND_STALL (1 << 4) +# define USBCSIL_FLUSH_PACKET (1 << 3) +# define USBCSIL_UNDERRUN (1 << 2) +# define USBCSIL_PKT_PRESENT (1 << 1) +# define USBCSIL_INPKT_RDY (1 << 0) + +__xdata __at (0xde12) volatile uint8_t USBCSIH; + +# define USBCSIH_AUTOSET (1 << 7) +# define USBCSIH_ISO (1 << 6) +# define USBCSIH_FORCE_DATA_TOG (1 << 3) +# define USBCSIH_IN_DBL_BUF (1 << 0) + +__xdata __at (0xde13) volatile uint8_t USBMAXO; +__xdata __at (0xde14) volatile uint8_t USBCSOL; + +# define USBCSOL_CLR_DATA_TOG (1 << 7) +# define USBCSOL_SENT_STALL (1 << 6) +# define USBCSOL_SEND_STALL (1 << 5) +# define USBCSOL_FLUSH_PACKET (1 << 4) +# define USBCSOL_DATA_ERROR (1 << 3) +# define USBCSOL_OVERRUN (1 << 2) +# define USBCSOL_FIFO_FULL (1 << 1) +# define USBCSOL_OUTPKT_RDY (1 << 0) + +__xdata __at (0xde15) volatile uint8_t USBCSOH; + +# define USBCSOH_AUTOCLEAR (1 << 7) +# define USBCSOH_ISO (1 << 6) +# define USBCSOH_OUT_DBL_BUF (1 << 0) + +__xdata __at (0xde16) volatile uint8_t USBCNT0; +__xdata __at (0xde16) volatile uint8_t USBCNTL; +__xdata __at (0xde17) volatile uint8_t USBCNTH; + +__xdata __at (0xde20) volatile uint8_t USBFIFO[12]; + +/* ADC Data register, low and high */ +__sfr at 0xBA ADCL; +__sfr at 0xBB ADCH; +__xdata __at (0xDFBA) volatile uint16_t ADCXDATA; + +/* ADC Control Register 1 */ +__sfr at 0xB4 ADCCON1; + +# define ADCCON1_EOC (1 << 7) /* conversion complete */ +# define ADCCON1_ST (1 << 6) /* start conversion */ + +# define ADCCON1_STSEL_MASK (3 << 4) /* start select */ +# define ADCCON1_STSEL_EXTERNAL (0 << 4) /* P2_0 pin triggers */ +# define ADCCON1_STSEL_FULLSPEED (1 << 4) /* full speed, no waiting */ +# define ADCCON1_STSEL_TIMER1 (2 << 4) /* timer 1 channel 0 */ +# define ADCCON1_STSEL_START (3 << 4) /* set start bit */ + +# define ADCCON1_RCTRL_MASK (3 << 2) /* random number control */ +# define ADCCON1_RCTRL_COMPLETE (0 << 2) /* operation completed */ +# define ADCCON1_RCTRL_CLOCK_LFSR (1 << 2) /* Clock the LFSR once */ + +/* ADC Control Register 2 */ +__sfr at 0xB5 ADCCON2; + +# define ADCCON2_SREF_MASK (3 << 6) /* reference voltage */ +# define ADCCON2_SREF_1_25V (0 << 6) /* internal 1.25V */ +# define ADCCON2_SREF_EXTERNAL (1 << 6) /* external on AIN7 cc1110 */ +# define ADCCON2_SREF_VDD (2 << 6) /* VDD on the AVDD pin */ +# define ADCCON2_SREF_EXTERNAL_DIFF (3 << 6) /* external on AIN6-7 cc1110 */ + +# define ADCCON2_SDIV_MASK (3 << 4) /* decimation rate */ +# define ADCCON2_SDIV_64 (0 << 4) /* 7 bits */ +# define ADCCON2_SDIV_128 (1 << 4) /* 9 bits */ +# define ADCCON2_SDIV_256 (2 << 4) /* 10 bits */ +# define ADCCON2_SDIV_512 (3 << 4) /* 12 bits */ + +# define ADCCON2_SCH_MASK (0xf << 0) /* Sequence channel select */ +# define ADCCON2_SCH_SHIFT 0 +# define ADCCON2_SCH_AIN0 (0 << 0) +# define ADCCON2_SCH_AIN1 (1 << 0) +# define ADCCON2_SCH_AIN2 (2 << 0) +# define ADCCON2_SCH_AIN3 (3 << 0) +# define ADCCON2_SCH_AIN4 (4 << 0) +# define ADCCON2_SCH_AIN5 (5 << 0) +# define ADCCON2_SCH_AIN6 (6 << 0) +# define ADCCON2_SCH_AIN7 (7 << 0) +# define ADCCON2_SCH_AIN0_AIN1 (8 << 0) +# define ADCCON2_SCH_AIN2_AIN3 (9 << 0) +# define ADCCON2_SCH_AIN4_AIN5 (0xa << 0) +# define ADCCON2_SCH_AIN6_AIN7 (0xb << 0) +# define ADCCON2_SCH_GND (0xc << 0) +# define ADCCON2_SCH_VREF (0xd << 0) +# define ADCCON2_SCH_TEMP (0xe << 0) +# define ADCCON2_SCH_VDD_3 (0xf << 0) + + +/* ADC Control Register 3 */ +__sfr at 0xB6 ADCCON3; + +# define ADCCON3_EREF_MASK (3 << 6) /* extra conversion reference */ +# define ADCCON3_EREF_1_25 (0 << 6) /* internal 1.25V */ +# define ADCCON3_EREF_EXTERNAL (1 << 6) /* external AIN7 cc1110 */ +# define ADCCON3_EREF_VDD (2 << 6) /* VDD on the AVDD pin */ +# define ADCCON3_EREF_EXTERNAL_DIFF (3 << 6) /* external AIN6-7 cc1110 */ +# define ADCCON3_EDIV_MASK (3 << 4) /* extral decimation */ +# define ADCCON3_EDIV_64 (0 << 4) /* 7 bits */ +# define ADCCON3_EDIV_128 (1 << 4) /* 9 bits */ +# define ADCCON3_EDIV_256 (2 << 4) /* 10 bits */ +# define ADCCON3_EDIV_512 (3 << 4) /* 12 bits */ +# define ADCCON3_ECH_MASK (0xf << 0) /* Sequence channel select */ +# define ADCCON3_ECH_SHIFT 0 +# define ADCCON3_ECH_AIN0 (0 << 0) +# define ADCCON3_ECH_AIN1 (1 << 0) +# define ADCCON3_ECH_AIN2 (2 << 0) +# define ADCCON3_ECH_AIN3 (3 << 0) +# define ADCCON3_ECH_AIN4 (4 << 0) +# define ADCCON3_ECH_AIN5 (5 << 0) +# define ADCCON3_ECH_AIN6 (6 << 0) +# define ADCCON3_ECH_AIN7 (7 << 0) +# define ADCCON3_ECH_AIN0_AIN1 (8 << 0) +# define ADCCON3_ECH_AIN2_AIN3 (9 << 0) +# define ADCCON3_ECH_AIN4_AIN5 (0xa << 0) +# define ADCCON3_ECH_AIN6_AIN7 (0xb << 0) +# define ADCCON3_ECH_GND (0xc << 0) +# define ADCCON3_ECH_VREF (0xd << 0) +# define ADCCON3_ECH_TEMP (0xe << 0) +# define ADCCON3_ECH_VDD_3 (0xf << 0) + +/* + * ADC configuration register, this selects which + * GPIO pins are to be used as ADC inputs + */ +__sfr at 0xF2 ADCCFG; + +/* + * Watchdog timer + */ + +__sfr at 0xc9 WDCTL; + +#define WDCTL_CLEAR_FIRST (0xa << 4) +#define WDCTL_CLEAR_SECOND (0x5 << 4) +#define WDCTL_EN (1 << 3) +#define WDCTL_MODE_WATCHDOG (0 << 2) +#define WDCTL_MODE_TIMER (1 << 2) +#define WDCTL_MODE_MASK (1 << 2) +#define WDCTL_INT_32768 (0 << 0) +#define WDCTL_INT_8192 (1 << 0) +#define WDCTL_INT_512 (2 << 0) +#define WDCTL_INT_64 (3 << 0) + +/* + * Pin selectors, these set which pins are + * using their peripheral function + */ +__sfr at 0xF3 P0SEL; +__sfr at 0xF4 P1SEL; +__sfr at 0xF5 P2SEL; + +#define P2SEL_PRI3P1_USART0 (0 << 6) +#define P2SEL_PRI3P1_USART1 (1 << 6) +#define P2SEL_PRI3P1_MASK (1 << 6) +#define P2SEL_PRI2P1_USART1 (0 << 5) +#define P2SEL_PRI2P1_TIMER3 (1 << 5) +#define P2SEL_PRI2P1_MASK (1 << 5) +#define P2SEL_PRI1P1_TIMER1 (0 << 4) +#define P2SEL_PRI1P1_TIMER4 (1 << 4) +#define P2SEL_PRI1P1_MASK (1 << 4) +#define P2SEL_PRI0P1_USART0 (0 << 3) +#define P2SEL_PRI0P1_TIMER1 (1 << 3) +#define P2SEL_PRI0P1_MASK (1 << 3) +#define P2SEL_SELP2_4_GPIO (0 << 2) +#define P2SEL_SELP2_4_PERIPHERAL (1 << 2) +#define P2SEL_SELP2_4_MASK (1 << 2) +#define P2SEL_SELP2_3_GPIO (0 << 1) +#define P2SEL_SELP2_3_PERIPHERAL (1 << 1) +#define P2SEL_SELP2_3_MASK (1 << 1) +#define P2SEL_SELP2_0_GPIO (0 << 0) +#define P2SEL_SELP2_0_PERIPHERAL (1 << 0) +#define P2SEL_SELP2_0_MASK (1 << 0) + +/* + * For pins used as GPIOs, these set which are used as outputs + */ +__sfr at 0xFD P0DIR; +__sfr at 0xFE P1DIR; +__sfr at 0xFF P2DIR; + +#define P2DIR_PRIP0_USART0_USART1 (0 << 6) +#define P2DIR_PRIP0_USART1_USART0 (1 << 6) +#define P2DIR_PRIP0_TIMER1_01_USART1 (2 << 6) +#define P2DIR_PRIP0_TIMER1_2_USART0 (3 << 6) +#define P2DIR_PRIP0_MASK (3 << 6) + +__sfr at 0x8F P0INP; + +/* Select between tri-state and pull up/down + * for pins P0_0 - P0_7. + */ +#define P0INP_MDP0_7_PULL (0 << 7) +#define P0INP_MDP0_7_TRISTATE (1 << 7) +#define P0INP_MDP0_6_PULL (0 << 6) +#define P0INP_MDP0_6_TRISTATE (1 << 6) +#define P0INP_MDP0_5_PULL (0 << 5) +#define P0INP_MDP0_5_TRISTATE (1 << 5) +#define P0INP_MDP0_4_PULL (0 << 4) +#define P0INP_MDP0_4_TRISTATE (1 << 4) +#define P0INP_MDP0_3_PULL (0 << 3) +#define P0INP_MDP0_3_TRISTATE (1 << 3) +#define P0INP_MDP0_2_PULL (0 << 2) +#define P0INP_MDP0_2_TRISTATE (1 << 2) +#define P0INP_MDP0_1_PULL (0 << 1) +#define P0INP_MDP0_1_TRISTATE (1 << 1) +#define P0INP_MDP0_0_PULL (0 << 0) +#define P0INP_MDP0_0_TRISTATE (1 << 0) + +__sfr at 0xF6 P1INP; + +/* Select between tri-state and pull up/down + * for pins P1_2 - P1_7. Pins P1_0 and P1_1 are + * always tri-stated + */ +#define P1INP_MDP1_7_PULL (0 << 7) +#define P1INP_MDP1_7_TRISTATE (1 << 7) +#define P1INP_MDP1_6_PULL (0 << 6) +#define P1INP_MDP1_6_TRISTATE (1 << 6) +#define P1INP_MDP1_5_PULL (0 << 5) +#define P1INP_MDP1_5_TRISTATE (1 << 5) +#define P1INP_MDP1_4_PULL (0 << 4) +#define P1INP_MDP1_4_TRISTATE (1 << 4) +#define P1INP_MDP1_3_PULL (0 << 3) +#define P1INP_MDP1_3_TRISTATE (1 << 3) +#define P1INP_MDP1_2_PULL (0 << 2) +#define P1INP_MDP1_2_TRISTATE (1 << 2) + +__sfr at 0xF7 P2INP; +/* P2INP has three extra bits which are used to choose + * between pull-up and pull-down when they are not tri-stated + */ +#define P2INP_PDUP2_PULL_UP (0 << 7) +#define P2INP_PDUP2_PULL_DOWN (1 << 7) +#define P2INP_PDUP1_PULL_UP (0 << 6) +#define P2INP_PDUP1_PULL_DOWN (1 << 6) +#define P2INP_PDUP0_PULL_UP (0 << 5) +#define P2INP_PDUP0_PULL_DOWN (1 << 5) + +/* For the P2 pins, choose between tri-state and pull up/down + * mode + */ +#define P2INP_MDP2_4_PULL (0 << 4) +#define P2INP_MDP2_4_TRISTATE (1 << 4) +#define P2INP_MDP2_3_PULL (0 << 3) +#define P2INP_MDP2_3_TRISTATE (1 << 3) +#define P2INP_MDP2_2_PULL (0 << 2) +#define P2INP_MDP2_2_TRISTATE (1 << 2) +#define P2INP_MDP2_1_PULL (0 << 1) +#define P2INP_MDP2_1_TRISTATE (1 << 1) +#define P2INP_MDP2_0_PULL (0 << 0) +#define P2INP_MDP2_0_TRISTATE (1 << 0) + +/* GPIO interrupt status flags */ +__sfr at 0x89 P0IFG; +__sfr at 0x8A P1IFG; +__sfr at 0x8B P2IFG; + +#define P0IFG_USB_RESUME (1 << 7) + +__sfr at 0x8C PICTL; +#define PICTL_P2IEN (1 << 5) +#define PICTL_P0IENH (1 << 4) +#define PICTL_P0IENL (1 << 3) +#define PICTL_P2ICON (1 << 2) +#define PICTL_P1ICON (1 << 1) +#define PICTL_P0ICON (1 << 0) + +/* GPIO pins */ +__sfr at 0x80 P0; + +sbit at 0x80 P0_0; +sbit at 0x81 P0_1; +sbit at 0x82 P0_2; +sbit at 0x83 P0_3; +sbit at 0x84 P0_4; +sbit at 0x85 P0_5; +sbit at 0x86 P0_6; +sbit at 0x87 P0_7; + +__sfr at 0x90 P1; + +sbit at 0x90 P1_0; +sbit at 0x91 P1_1; +sbit at 0x92 P1_2; +sbit at 0x93 P1_3; +sbit at 0x94 P1_4; +sbit at 0x95 P1_5; +sbit at 0x96 P1_6; +sbit at 0x97 P1_7; + +__sfr at 0xa0 P2; + +sbit at 0xa0 P2_0; +sbit at 0xa1 P2_1; +sbit at 0xa2 P2_2; +sbit at 0xa3 P2_3; +sbit at 0xa4 P2_4; + +/* DMA controller */ +struct cc_dma_channel { + uint8_t src_high; + uint8_t src_low; + uint8_t dst_high; + uint8_t dst_low; + uint8_t len_high; + uint8_t len_low; + uint8_t cfg0; + uint8_t cfg1; +}; + +# define DMA_LEN_HIGH_VLEN_MASK (7 << 5) +# define DMA_LEN_HIGH_VLEN_LEN (0 << 5) +# define DMA_LEN_HIGH_VLEN_PLUS_1 (1 << 5) +# define DMA_LEN_HIGH_VLEN (2 << 5) +# define DMA_LEN_HIGH_VLEN_PLUS_2 (3 << 5) +# define DMA_LEN_HIGH_VLEN_PLUS_3 (4 << 5) +# define DMA_LEN_HIGH_MASK (0x1f) + +# define DMA_CFG0_WORDSIZE_8 (0 << 7) +# define DMA_CFG0_WORDSIZE_16 (1 << 7) +# define DMA_CFG0_TMODE_MASK (3 << 5) +# define DMA_CFG0_TMODE_SINGLE (0 << 5) +# define DMA_CFG0_TMODE_BLOCK (1 << 5) +# define DMA_CFG0_TMODE_REPEATED_SINGLE (2 << 5) +# define DMA_CFG0_TMODE_REPEATED_BLOCK (3 << 5) + +/* + * DMA triggers + */ +# define DMA_CFG0_TRIGGER_NONE 0 +# define DMA_CFG0_TRIGGER_PREV 1 +# define DMA_CFG0_TRIGGER_T1_CH0 2 +# define DMA_CFG0_TRIGGER_T1_CH1 3 +# define DMA_CFG0_TRIGGER_T1_CH2 4 +# define DMA_CFG0_TRIGGER_T2_OVFL 6 +# define DMA_CFG0_TRIGGER_T3_CH0 7 +# define DMA_CFG0_TRIGGER_T3_CH1 8 +# define DMA_CFG0_TRIGGER_T4_CH0 9 +# define DMA_CFG0_TRIGGER_T4_CH1 10 +# define DMA_CFG0_TRIGGER_IOC_0 12 +# define DMA_CFG0_TRIGGER_IOC_1 13 +# define DMA_CFG0_TRIGGER_URX0 14 +# define DMA_CFG0_TRIGGER_UTX0 15 +# define DMA_CFG0_TRIGGER_URX1 16 +# define DMA_CFG0_TRIGGER_UTX1 17 +# define DMA_CFG0_TRIGGER_FLASH 18 +# define DMA_CFG0_TRIGGER_RADIO 19 +# define DMA_CFG0_TRIGGER_ADC_CHALL 20 +# define DMA_CFG0_TRIGGER_ADC_CH0 21 +# define DMA_CFG0_TRIGGER_ADC_CH1 22 +# define DMA_CFG0_TRIGGER_ADC_CH2 23 +# define DMA_CFG0_TRIGGER_ADC_CH3 24 +# define DMA_CFG0_TRIGGER_ADC_CH4 25 +# define DMA_CFG0_TRIGGER_ADC_CH5 26 +# define DMA_CFG0_TRIGGER_ADC_CH6 27 +# define DMA_CFG0_TRIGGER_I2SRX 27 +# define DMA_CFG0_TRIGGER_ADC_CH7 28 +# define DMA_CFG0_TRIGGER_I2STX 28 +# define DMA_CFG0_TRIGGER_ENC_DW 29 +# define DMA_CFG0_TRIGGER_DNC_UP 30 + +# define DMA_CFG1_SRCINC_MASK (3 << 6) +# define DMA_CFG1_SRCINC_0 (0 << 6) +# define DMA_CFG1_SRCINC_1 (1 << 6) +# define DMA_CFG1_SRCINC_2 (2 << 6) +# define DMA_CFG1_SRCINC_MINUS_1 (3 << 6) + +# define DMA_CFG1_DESTINC_MASK (3 << 4) +# define DMA_CFG1_DESTINC_0 (0 << 4) +# define DMA_CFG1_DESTINC_1 (1 << 4) +# define DMA_CFG1_DESTINC_2 (2 << 4) +# define DMA_CFG1_DESTINC_MINUS_1 (3 << 4) + +# define DMA_CFG1_IRQMASK (1 << 3) +# define DMA_CFG1_M8 (1 << 2) + +# define DMA_CFG1_PRIORITY_MASK (3 << 0) +# define DMA_CFG1_PRIORITY_LOW (0 << 0) +# define DMA_CFG1_PRIORITY_NORMAL (1 << 0) +# define DMA_CFG1_PRIORITY_HIGH (2 << 0) + +/* + * DMAARM - DMA Channel Arm + */ + +__sfr at 0xD6 DMAARM; + +# define DMAARM_ABORT (1 << 7) +# define DMAARM_DMAARM4 (1 << 4) +# define DMAARM_DMAARM3 (1 << 3) +# define DMAARM_DMAARM2 (1 << 2) +# define DMAARM_DMAARM1 (1 << 1) +# define DMAARM_DMAARM0 (1 << 0) + +/* + * DMAREQ - DMA Channel Start Request and Status + */ + +__sfr at 0xD7 DMAREQ; + +# define DMAREQ_DMAREQ4 (1 << 4) +# define DMAREQ_DMAREQ3 (1 << 3) +# define DMAREQ_DMAREQ2 (1 << 2) +# define DMAREQ_DMAREQ1 (1 << 1) +# define DMAREQ_DMAREQ0 (1 << 0) + +/* + * DMA configuration 0 address + */ + +__sfr at 0xD5 DMA0CFGH; +__sfr at 0xD4 DMA0CFGL; + +/* + * DMA configuration 1-4 address + */ + +__sfr at 0xD3 DMA1CFGH; +__sfr at 0xD2 DMA1CFGL; + +/* + * DMAIRQ - DMA Interrupt Flag + */ + +__sfr at 0xD1 DMAIRQ; + +# define DMAIRQ_DMAIF4 (1 << 4) +# define DMAIRQ_DMAIF3 (1 << 3) +# define DMAIRQ_DMAIF2 (1 << 2) +# define DMAIRQ_DMAIF1 (1 << 1) +# define DMAIRQ_DMAIF0 (1 << 0) + +/* + * UART registers + */ + +/* USART config/status registers */ +__sfr at 0x86 U0CSR; +__sfr at 0xF8 U1CSR; + +# define UxCSR_MODE_UART (1 << 7) +# define UxCSR_MODE_SPI (0 << 7) +# define UxCSR_RE (1 << 6) +# define UxCSR_SLAVE (1 << 5) +# define UxCSR_MASTER (0 << 5) +# define UxCSR_FE (1 << 4) +# define UxCSR_ERR (1 << 3) +# define UxCSR_RX_BYTE (1 << 2) +# define UxCSR_TX_BYTE (1 << 1) +# define UxCSR_ACTIVE (1 << 0) + +/* UART configuration registers */ +__sfr at 0xc4 U0UCR; +__sfr at 0xfb U1UCR; + +# define UxUCR_FLUSH (1 << 7) +# define UxUCR_FLOW_DISABLE (0 << 6) +# define UxUCR_FLOW_ENABLE (1 << 6) +# define UxUCR_D9_EVEN_PARITY (0 << 5) +# define UxUCR_D9_ODD_PARITY (1 << 5) +# define UxUCR_BIT9_8_BITS (0 << 4) +# define UxUCR_BIT9_9_BITS (1 << 4) +# define UxUCR_PARITY_DISABLE (0 << 3) +# define UxUCR_PARITY_ENABLE (1 << 3) +# define UxUCR_SPB_1_STOP_BIT (0 << 2) +# define UxUCR_SPB_2_STOP_BITS (1 << 2) +# define UxUCR_STOP_LOW (0 << 1) +# define UxUCR_STOP_HIGH (1 << 1) +# define UxUCR_START_LOW (0 << 0) +# define UxUCR_START_HIGH (1 << 0) + +/* USART General configuration registers (mostly SPI) */ +__sfr at 0xc5 U0GCR; +__sfr at 0xfc U1GCR; + +# define UxGCR_CPOL_NEGATIVE (0 << 7) +# define UxGCR_CPOL_POSITIVE (1 << 7) +# define UxGCR_CPHA_FIRST_EDGE (0 << 6) +# define UxGCR_CPHA_SECOND_EDGE (1 << 6) +# define UxGCR_ORDER_LSB (0 << 5) +# define UxGCR_ORDER_MSB (1 << 5) +# define UxGCR_BAUD_E_MASK (0x1f) +# define UxGCR_BAUD_E_SHIFT 0 + +/* USART data registers */ +__sfr at 0xc1 U0DBUF; +__xdata __at (0xDFC1) volatile uint8_t U0DBUFXADDR; +__sfr at 0xf9 U1DBUF; +__xdata __at (0xDFF9) volatile uint8_t U1DBUFXADDR; + +/* USART baud rate registers, M value */ +__sfr at 0xc2 U0BAUD; +__sfr at 0xfa U1BAUD; + +/* Flash controller */ + +__sfr at 0xAE FCTL; +#define FCTL_BUSY (1 << 7) +#define FCTL_SWBSY (1 << 6) +#define FCTL_CONTRD_ENABLE (1 << 4) +#define FCTL_WRITE (1 << 1) +#define FCTL_ERASE (1 << 0) + +/* Flash write data. Write two bytes here */ +__sfr at 0xAF FWDATA; +__xdata __at (0xDFAF) volatile uint8_t FWDATAXADDR; + +/* Flash write/erase address */ +__sfr at 0xAD FADDRH; +__sfr at 0xAC FADDRL; + +/* Flash timing */ +__sfr at 0xAB FWT; + +/* 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 0x91 RFIM; +#define RFIM_IM_TXUNF (1 << 7) +#define RFIM_IM_RXOVF (1 << 6) +#define RFIM_IM_TIMEOUT (1 << 5) +#define RFIM_IM_DONE (1 << 4) +#define RFIM_IM_CS (1 << 3) +#define RFIM_IM_PQT (1 << 2) +#define RFIM_IM_CCA (1 << 1) +#define RFIM_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 diff --git a/src/check-stack b/src/check-stack deleted file mode 100755 index 1e8044e0..00000000 --- a/src/check-stack +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -HEADER=$1 -MEM=$2 - -HEADER_STACK=`awk '/#define AO_STACK_START/ {print strtonum($3)}' $HEADER` -MEM_STACK=`awk '/Stack starts at/ {print strtonum ($4)}' $MEM` - -if [ "$HEADER_STACK" -lt "$MEM_STACK" ]; then - echo $MEM_STACK | awk '{ printf ("Set AO_STACK_START to at least 0x%x\n", $1); }' - exit 1 -else - exit 0 -fi diff --git a/src/core/altitude.h b/src/core/altitude.h new file mode 100644 index 00000000..a278bbc6 --- /dev/null +++ b/src/core/altitude.h @@ -0,0 +1,132 @@ +/*max error 3.197865153490684 at 0.782%. Average error 0.260150920474668*/ +#define NALT 129 +#define ALT_FRAC_BITS 8 + 15835, /* 10.56 kPa 0.000% */ + 15332, /* 11.42 kPa 0.781% */ + 14868, /* 12.29 kPa 1.563% */ + 14435, /* 13.16 kPa 2.344% */ + 14030, /* 14.02 kPa 3.125% */ + 13649, /* 14.90 kPa 3.906% */ + 13290, /* 15.76 kPa 4.688% */ + 12950, /* 16.63 kPa 5.469% */ + 12627, /* 17.50 kPa 6.250% */ + 12320, /* 18.37 kPa 7.031% */ + 12027, /* 19.24 kPa 7.813% */ + 11747, /* 20.10 kPa 8.594% */ + 11479, /* 20.97 kPa 9.375% */ + 11222, /* 21.84 kPa 10.156% */ + 10975, /* 22.71 kPa 10.938% */ + 10736, /* 23.58 kPa 11.719% */ + 10504, /* 24.44 kPa 12.500% */ + 10278, /* 25.31 kPa 13.281% */ + 10059, /* 26.18 kPa 14.063% */ + 9846, /* 27.05 kPa 14.844% */ + 9638, /* 27.91 kPa 15.625% */ + 9435, /* 28.78 kPa 16.406% */ + 9237, /* 29.65 kPa 17.188% */ + 9044, /* 30.52 kPa 17.969% */ + 8855, /* 31.39 kPa 18.750% */ + 8670, /* 32.26 kPa 19.531% */ + 8490, /* 33.13 kPa 20.313% */ + 8313, /* 33.99 kPa 21.094% */ + 8140, /* 34.86 kPa 21.875% */ + 7970, /* 35.73 kPa 22.656% */ + 7803, /* 36.60 kPa 23.438% */ + 7640, /* 37.47 kPa 24.219% */ + 7480, /* 38.33 kPa 25.000% */ + 7322, /* 39.20 kPa 25.781% */ + 7168, /* 40.07 kPa 26.563% */ + 7016, /* 40.94 kPa 27.344% */ + 6867, /* 41.80 kPa 28.125% */ + 6720, /* 42.67 kPa 28.906% */ + 6575, /* 43.54 kPa 29.688% */ + 6433, /* 44.41 kPa 30.469% */ + 6294, /* 45.28 kPa 31.250% */ + 6156, /* 46.15 kPa 32.031% */ + 6020, /* 47.01 kPa 32.813% */ + 5887, /* 47.88 kPa 33.594% */ + 5755, /* 48.75 kPa 34.375% */ + 5625, /* 49.62 kPa 35.156% */ + 5497, /* 50.49 kPa 35.938% */ + 5371, /* 51.35 kPa 36.719% */ + 5247, /* 52.22 kPa 37.500% */ + 5124, /* 53.09 kPa 38.281% */ + 5003, /* 53.96 kPa 39.063% */ + 4883, /* 54.83 kPa 39.844% */ + 4765, /* 55.69 kPa 40.625% */ + 4648, /* 56.56 kPa 41.406% */ + 4533, /* 57.43 kPa 42.188% */ + 4419, /* 58.30 kPa 42.969% */ + 4307, /* 59.17 kPa 43.750% */ + 4196, /* 60.03 kPa 44.531% */ + 4086, /* 60.90 kPa 45.313% */ + 3977, /* 61.77 kPa 46.094% */ + 3870, /* 62.63 kPa 46.875% */ + 3764, /* 63.51 kPa 47.656% */ + 3659, /* 64.38 kPa 48.438% */ + 3555, /* 65.24 kPa 49.219% */ + 3453, /* 66.11 kPa 50.000% */ + 3351, /* 66.98 kPa 50.781% */ + 3250, /* 67.85 kPa 51.563% */ + 3151, /* 68.72 kPa 52.344% */ + 3052, /* 69.58 kPa 53.125% */ + 2955, /* 70.45 kPa 53.906% */ + 2858, /* 71.32 kPa 54.688% */ + 2763, /* 72.19 kPa 55.469% */ + 2668, /* 73.06 kPa 56.250% */ + 2574, /* 73.92 kPa 57.031% */ + 2482, /* 74.79 kPa 57.813% */ + 2390, /* 75.66 kPa 58.594% */ + 2298, /* 76.52 kPa 59.375% */ + 2208, /* 77.40 kPa 60.156% */ + 2119, /* 78.26 kPa 60.938% */ + 2030, /* 79.13 kPa 61.719% */ + 1942, /* 80.00 kPa 62.500% */ + 1855, /* 80.87 kPa 63.281% */ + 1769, /* 81.74 kPa 64.063% */ + 1683, /* 82.60 kPa 64.844% */ + 1598, /* 83.47 kPa 65.625% */ + 1514, /* 84.34 kPa 66.406% */ + 1430, /* 85.21 kPa 67.188% */ + 1347, /* 86.08 kPa 67.969% */ + 1265, /* 86.94 kPa 68.750% */ + 1184, /* 87.81 kPa 69.531% */ + 1103, /* 88.68 kPa 70.313% */ + 1023, /* 89.55 kPa 71.094% */ + 943, /* 90.41 kPa 71.875% */ + 864, /* 91.28 kPa 72.656% */ + 786, /* 92.15 kPa 73.438% */ + 708, /* 93.02 kPa 74.219% */ + 631, /* 93.89 kPa 75.000% */ + 554, /* 94.76 kPa 75.781% */ + 478, /* 95.63 kPa 76.563% */ + 403, /* 96.49 kPa 77.344% */ + 328, /* 97.36 kPa 78.125% */ + 254, /* 98.23 kPa 78.906% */ + 180, /* 99.10 kPa 79.688% */ + 106, /* 99.97 kPa 80.469% */ + 34, /* 100.83 kPa 81.250% */ + -39, /* 101.70 kPa 82.031% */ + -111, /* 102.57 kPa 82.813% */ + -182, /* 103.44 kPa 83.594% */ + -253, /* 104.30 kPa 84.375% */ + -323, /* 105.17 kPa 85.156% */ + -393, /* 106.04 kPa 85.938% */ + -462, /* 106.91 kPa 86.719% */ + -531, /* 107.78 kPa 87.500% */ + -600, /* 108.65 kPa 88.281% */ + -668, /* 109.51 kPa 89.063% */ + -736, /* 110.38 kPa 89.844% */ + -803, /* 111.25 kPa 90.625% */ + -870, /* 112.12 kPa 91.406% */ + -936, /* 112.99 kPa 92.188% */ + -1002, /* 113.85 kPa 92.969% */ + -1068, /* 114.72 kPa 93.750% */ + -1133, /* 115.59 kPa 94.531% */ + -1198, /* 116.46 kPa 95.313% */ + -1262, /* 117.33 kPa 96.094% */ + -1326, /* 118.19 kPa 96.875% */ + -1389, /* 119.06 kPa 97.656% */ + -1453, /* 119.93 kPa 98.438% */ + -1516, /* 120.80 kPa 99.219% */ + -1578, /* 121.67 kPa 100.000% */ diff --git a/src/core/ao.h b/src/core/ao.h new file mode 100644 index 00000000..8ac9ac3d --- /dev/null +++ b/src/core/ao.h @@ -0,0 +1,1610 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_H_ +#define _AO_H_ + +#include +#include +#include +#include +#include "cc1111.h" +#include "ao_pins.h" + +#define TRUE 1 +#define FALSE 0 + +/* Convert a __data pointer into an __xdata pointer */ +#define DATA_TO_XDATA(a) ((void __xdata *) ((uint8_t) (a) | 0xff00)) + +/* 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 0x90 +#define AO_STACK_END 0xfe +#define AO_STACK_SIZE (AO_STACK_END - AO_STACK_START + 1) + +/* An AltOS task */ +struct ao_task { + __xdata void *wchan; /* current wait channel (NULL if running) */ + uint16_t alarm; /* abort ao_sleep time */ + uint8_t stack_count; /* amount of saved stack */ + uint8_t task_id; /* unique id */ + __code char *name; /* task name */ + uint8_t stack[AO_STACK_SIZE]; /* saved stack */ +}; + +extern __xdata struct ao_task *__data ao_cur_task; + +#define AO_NUM_TASKS 16 /* maximum number of tasks */ +#define AO_NO_TASK 0 /* no task id */ + +/* + ao_task.c + */ + +/* Suspend the current task until wchan is awoken. + * returns: + * 0 on normal wake + * 1 on alarm + */ +uint8_t +ao_sleep(__xdata void *wchan); + +/* Wake all tasks sleeping on wchan */ +void +ao_wakeup(__xdata void *wchan); + +/* set an alarm to go off in 'delay' ticks */ +void +ao_alarm(uint16_t delay); + +/* Yield the processor to another task */ +void +ao_yield(void) __naked; + +/* Add a task to the run queue */ +void +ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant; + +/* Terminate the current task */ +void +ao_exit(void); + +/* Dump task info to console */ +void +ao_task_info(void); + +/* Start the scheduler. This will not return */ +void +ao_start_scheduler(void); + +/* + * ao_panic.c + */ + +#define AO_PANIC_NO_TASK 1 /* AO_NUM_TASKS is not large enough */ +#define AO_PANIC_DMA 2 /* Attempt to start DMA while active */ +#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 */ +#define AO_PANIC_STDIO 7 /* Too many stdio handlers registered */ +#define AO_PANIC_REBOOT 8 /* Reboot failed */ +#define AO_PANIC_FLASH 9 /* Invalid flash part (or wrong blocksize) */ +#define AO_PANIC_USB 10 /* Trying to send USB packet while busy */ +#define AO_PANIC_BT 11 /* Communications with bluetooth device failed */ + +/* Stop the operating system, beeping and blinking the reason */ +void +ao_panic(uint8_t reason); + +/* + * ao_timer.c + */ + +/* Our timer runs at 100Hz */ +#define AO_HERTZ 100 +#define AO_MS_TO_TICKS(ms) ((ms) / (1000 / AO_HERTZ)) +#define AO_SEC_TO_TICKS(s) ((s) * AO_HERTZ) + +/* Returns the current time in ticks */ +uint16_t +ao_time(void); + +/* Suspend the current task until ticks time has passed */ +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; + +/* Initialize the timer */ +void +ao_timer_init(void); + +/* Initialize the hardware clock. Must be called first */ +void +ao_clock_init(void); + +/* + * One set of samples read from the A/D converter or telemetry + */ +struct ao_adc { + uint16_t tick; /* tick when the sample was read */ + int16_t accel; /* accelerometer */ + int16_t pres; /* pressure sensor */ + int16_t temp; /* temperature sensor */ + int16_t v_batt; /* battery voltage */ + int16_t sense_d; /* drogue continuity sense */ + int16_t sense_m; /* main continuity sense */ +}; + +#ifndef HAS_ADC +#error Please define HAS_ADC +#endif + +#if HAS_ADC + +#if HAS_ACCEL +#ifndef HAS_ACCEL_REF +#error Please define HAS_ACCEL_REF +#endif +#else +#define HAS_ACCEL_REF 0 +#endif + +/* + * ao_adc.c + */ + +#define AO_ADC_RING 32 +#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1)) +#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1)) + + +/* + * A/D data is stored in a ring, with the next sample to be written + * at ao_adc_head + */ +extern volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING]; +extern volatile __data uint8_t ao_adc_head; +#if HAS_ACCEL_REF +extern volatile __xdata uint16_t ao_accel_ref[AO_ADC_RING]; +#endif + +/* Trigger a conversion sequence (called from the timer interrupt) */ +void +ao_adc_poll(void); + +/* Suspend the current task until another A/D sample is converted */ +void +ao_adc_sleep(void); + +/* Get a copy of the last complete A/D sample set */ +void +ao_adc_get(__xdata struct ao_adc *packet); + +/* The A/D interrupt handler */ + +void +ao_adc_isr(void) __interrupt 1; + +/* Initialize the A/D converter */ +void +ao_adc_init(void); + +#endif /* HAS_ADC */ + +/* + * ao_beep.c + */ + +/* + * Various pre-defined beep frequencies + * + * frequency = 1/2 (24e6/32) / beep + */ + +#define AO_BEEP_LOW 150 /* 2500Hz */ +#define AO_BEEP_MID 94 /* 3989Hz */ +#define AO_BEEP_HIGH 75 /* 5000Hz */ +#define AO_BEEP_OFF 0 /* off */ + +#define AO_BEEP_g 240 /* 1562.5Hz */ +#define AO_BEEP_gs 227 /* 1652Hz (1655Hz) */ +#define AO_BEEP_aa 214 /* 1752Hz (1754Hz) */ +#define AO_BEEP_bbf 202 /* 1856Hz (1858Hz) */ +#define AO_BEEP_bb 190 /* 1974Hz (1969Hz) */ +#define AO_BEEP_cc 180 /* 2083Hz (2086Hz) */ +#define AO_BEEP_ccs 170 /* 2205Hz (2210Hz) */ +#define AO_BEEP_dd 160 /* 2344Hz (2341Hz) */ +#define AO_BEEP_eef 151 /* 2483Hz (2480Hz) */ +#define AO_BEEP_ee 143 /* 2622Hz (2628Hz) */ +#define AO_BEEP_ff 135 /* 2778Hz (2784Hz) */ +#define AO_BEEP_ffs 127 /* 2953Hz (2950Hz) */ +#define AO_BEEP_gg 120 /* 3125Hz */ +#define AO_BEEP_ggs 113 /* 3319Hz (3311Hz) */ +#define AO_BEEP_aaa 107 /* 3504Hz (3508Hz) */ +#define AO_BEEP_bbbf 101 /* 3713Hz (3716Hz) */ +#define AO_BEEP_bbb 95 /* 3947Hz (3937Hz) */ +#define AO_BEEP_ccc 90 /* 4167Hz (4171Hz) */ +#define AO_BEEP_cccs 85 /* 4412Hz (4419Hz) */ +#define AO_BEEP_ddd 80 /* 4688Hz (4682Hz) */ +#define AO_BEEP_eeef 76 /* 4934Hz (4961Hz) */ +#define AO_BEEP_eee 71 /* 5282Hz (5256Hz) */ +#define AO_BEEP_fff 67 /* 5597Hz (5568Hz) */ +#define AO_BEEP_fffs 64 /* 5859Hz (5899Hz) */ +#define AO_BEEP_ggg 60 /* 6250Hz */ + +/* Set the beeper to the specified tone */ +void +ao_beep(uint8_t beep); + +/* Turn on the beeper for the specified time */ +void +ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant; + +/* Initialize the beeper */ +void +ao_beep_init(void); + +/* + * ao_led.c + */ + +#define AO_LED_NONE 0 + +/* Turn on the specified LEDs */ +void +ao_led_on(uint8_t colors); + +/* Turn off the specified LEDs */ +void +ao_led_off(uint8_t colors); + +/* Set all of the LEDs to the specified state */ +void +ao_led_set(uint8_t colors); + +/* Toggle the specified LEDs */ +void +ao_led_toggle(uint8_t colors); + +/* Turn on the specified LEDs for the indicated interval */ +void +ao_led_for(uint8_t colors, uint16_t ticks) __reentrant; + +/* Initialize the LEDs */ +void +ao_led_init(uint8_t enable); + +/* + * ao_romconfig.c + */ + +#define AO_ROMCONFIG_VERSION 2 + +extern __code __at (0x00a0) uint16_t ao_romconfig_version; +extern __code __at (0x00a2) uint16_t ao_romconfig_check; +extern __code __at (0x00a4) uint16_t ao_serial_number; +extern __code __at (0x00a6) uint32_t ao_radio_cal; + +#ifndef HAS_USB +#error Please define HAS_USB +#endif + +#if HAS_USB +extern __code __at (0x00aa) uint8_t ao_usb_descriptors []; +#endif + +/* + * ao_usb.c + */ + +/* Put one character to the USB output queue */ +void +ao_usb_putchar(char c); + +/* Get one character from the USB input queue */ +char +ao_usb_getchar(void); + +/* Poll for a charcter on the USB input queue. + * returns AO_READ_AGAIN if none are available + */ +char +ao_usb_pollchar(void); + +/* Flush the USB output queue */ +void +ao_usb_flush(void); + +#if HAS_USB +/* USB interrupt handler */ +void +ao_usb_isr(void) __interrupt 6; +#endif + +/* Enable the USB controller */ +void +ao_usb_enable(void); + +/* Disable the USB controller */ +void +ao_usb_disable(void); + +/* Initialize the USB system */ +void +ao_usb_init(void); + +/* + * ao_cmd.c + */ + +enum ao_cmd_status { + ao_cmd_success = 0, + ao_cmd_lex_error = 1, + ao_cmd_syntax_error = 2, +}; + +extern __pdata uint16_t ao_cmd_lex_i; +extern __pdata uint32_t ao_cmd_lex_u32; +extern __pdata char ao_cmd_lex_c; +extern __pdata 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); + +void +ao_cmd_decimal(void); + +uint8_t +ao_match_word(__code char *word); + +struct ao_cmds { + void (*func)(void); + __code char *help; +}; + +void +ao_cmd_register(__code struct ao_cmds *cmds); + +void +ao_cmd_init(void); + +#if HAS_CMD_FILTER +/* + * Provided by an external module to filter raw command lines + */ +uint8_t +ao_cmd_filter(void); +#endif + +/* + * ao_dma.c + */ + +/* Allocate a DMA channel. the 'done' parameter will be set when the + * dma is finished and will be used to wakeup any waiters + */ + +uint8_t +ao_dma_alloc(__xdata uint8_t * done); + +/* Setup a DMA channel */ +void +ao_dma_set_transfer(uint8_t id, + void __xdata *srcaddr, + void __xdata *dstaddr, + uint16_t count, + uint8_t cfg0, + uint8_t cfg1); + +/* Start a DMA channel */ +void +ao_dma_start(uint8_t id); + +/* Manually trigger a DMA channel */ +void +ao_dma_trigger(uint8_t id); + +/* Abort a running DMA transfer */ +void +ao_dma_abort(uint8_t id); + +/* DMA interrupt routine */ +void +ao_dma_isr(void) __interrupt 8; + +/* + * ao_mutex.c + */ + +void +ao_mutex_get(__xdata uint8_t *ao_mutex) __reentrant; + +void +ao_mutex_put(__xdata uint8_t *ao_mutex) __reentrant; + +/* + * Storage interface, provided by one of the eeprom or flash + * drivers + */ + +/* Total bytes of available storage */ +extern __pdata uint32_t ao_storage_total; + +/* Block size - device is erased in these units. At least 256 bytes */ +extern __pdata uint32_t ao_storage_block; + +/* Byte offset of config block. Will be ao_storage_block bytes long */ +extern __pdata uint32_t ao_storage_config; + +/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */ +extern __pdata uint16_t ao_storage_unit; + +#define AO_STORAGE_ERASE_LOG (ao_storage_config + AO_CONFIG_MAX_SIZE) + +/* Initialize above values. Can only be called once the OS is running */ +void +ao_storage_setup(void) __reentrant; + +/* Write data. Returns 0 on failure, 1 on success */ +uint8_t +ao_storage_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; + +/* Read data. Returns 0 on failure, 1 on success */ +uint8_t +ao_storage_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; + +/* Erase a block of storage. This always clears ao_storage_block bytes */ +uint8_t +ao_storage_erase(uint32_t pos) __reentrant; + +/* Flush any pending writes to stable storage */ +void +ao_storage_flush(void) __reentrant; + +/* Initialize the storage code */ +void +ao_storage_init(void); + +/* + * Low-level functions wrapped by ao_storage.c + */ + +/* Read data within a storage unit */ +uint8_t +ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; + +/* Write data within a storage unit */ +uint8_t +ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; + +/* Initialize low-level device bits */ +void +ao_storage_device_init(void); + +/* Print out information about flash chips */ +void +ao_storage_device_info(void) __reentrant; + +/* + * ao_log.c + */ + +/* We record flight numbers in the first record of + * the log. Tasks may wait for this to be initialized + * by sleeping on this variable. + */ +extern __xdata uint16_t ao_flight_number; + +extern __pdata uint32_t ao_log_current_pos; +extern __pdata uint32_t ao_log_end_pos; +extern __pdata uint32_t ao_log_start_pos; +extern __xdata uint8_t ao_log_running; +extern __pdata enum flight_state ao_log_state; + +/* required functions from the underlying log system */ + +#define AO_LOG_FORMAT_UNKNOWN 0 /* unknown; altosui will have to guess */ +#define AO_LOG_FORMAT_FULL 1 /* 8 byte typed log records */ +#define AO_LOG_FORMAT_TINY 2 /* two byte state/baro records */ +#define AO_LOG_FORMAT_TELEMETRY 3 /* 32 byte ao_telemetry records */ +#define AO_LOG_FORMAT_TELESCIENCE 4 /* 32 byte typed telescience records */ +#define AO_LOG_FORMAT_NONE 127 /* No log at all */ + +extern __code uint8_t ao_log_format; + +/* Return the flight number from the given log slot, 0 if none */ +uint16_t +ao_log_flight(uint8_t slot); + +/* Flush the log */ +void +ao_log_flush(void); + +/* Logging thread main routine */ +void +ao_log(void); + +/* functions provided in ao_log.c */ + +/* Figure out the current flight number */ +void +ao_log_scan(void) __reentrant; + +/* Return the position of the start of the given log slot */ +uint32_t +ao_log_pos(uint8_t slot); + +/* Start logging to eeprom */ +void +ao_log_start(void); + +/* Stop logging */ +void +ao_log_stop(void); + +/* Initialize the logging system */ +void +ao_log_init(void); + +/* Write out the current flight number to the erase log */ +void +ao_log_write_erase(uint8_t pos); + +/* Returns true if there are any logs stored in eeprom */ +uint8_t +ao_log_present(void); + +/* Returns true if there is no more storage space available */ +uint8_t +ao_log_full(void); + +/* + * ao_log_big.c + */ + +/* + * The data log is recorded in the eeprom as a sequence + * of data packets. + * + * Each packet starts with a 4-byte header that has the + * packet type, the packet checksum and the tick count. Then + * they all contain 2 16 bit values which hold packet-specific + * data. + * + * For each flight, the first packet + * is FLIGHT packet, indicating the serial number of the + * device and a unique number marking the number of flights + * recorded by this device. + * + * During flight, data from the accelerometer and barometer + * are recorded in SENSOR packets, using the raw 16-bit values + * read from the A/D converter. + * + * Also during flight, but at a lower rate, the deployment + * sensors are recorded in DEPLOY packets. The goal here is to + * detect failure in the deployment circuits. + * + * STATE packets hold state transitions as the flight computer + * transitions through different stages of the flight. + */ +#define AO_LOG_FLIGHT 'F' +#define AO_LOG_SENSOR 'A' +#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_GPS_SAT 'V' +#define AO_LOG_GPS_DATE 'Y' + +#define AO_LOG_POS_NONE (~0UL) + +struct ao_log_record { + char type; + uint8_t csum; + uint16_t tick; + union { + struct { + int16_t ground_accel; + uint16_t flight; + } flight; + struct { + int16_t accel; + int16_t pres; + } sensor; + struct { + int16_t temp; + int16_t v_batt; + } temp_volt; + struct { + int16_t drogue; + int16_t main; + } deploy; + struct { + uint16_t state; + uint16_t reason; + } state; + struct { + uint8_t hour; + uint8_t minute; + uint8_t second; + uint8_t flags; + } gps_time; + int32_t gps_latitude; + int32_t gps_longitude; + struct { + int16_t altitude; + uint16_t unused; + } gps_altitude; + struct { + uint16_t svid; + uint8_t unused; + uint8_t c_n; + } gps_sat; + struct { + uint8_t year; + uint8_t month; + uint8_t day; + uint8_t extra; + } gps_date; + struct { + uint16_t d0; + uint16_t d1; + } anon; + } u; +}; + +/* Write a record to the eeprom log */ +uint8_t +ao_log_data(__xdata struct ao_log_record *log) __reentrant; + +/* + * ao_flight.c + */ + +enum ao_flight_state { + ao_flight_startup = 0, + ao_flight_idle = 1, + ao_flight_pad = 2, + ao_flight_boost = 3, + ao_flight_fast = 4, + ao_flight_coast = 5, + ao_flight_drogue = 6, + ao_flight_main = 7, + ao_flight_landed = 8, + ao_flight_invalid = 9 +}; + +extern __pdata enum ao_flight_state ao_flight_state; + +extern __pdata uint16_t ao_launch_time; +extern __pdata uint8_t ao_flight_force_idle; + +/* Flight thread */ +void +ao_flight(void); + +/* Initialize flight thread */ +void +ao_flight_init(void); + +/* + * ao_flight_nano.c + */ + +void +ao_flight_nano_init(void); + +/* + * ao_sample.c + */ + +/* + * Barometer calibration + * + * We directly sample the barometer. The specs say: + * + * Pressure range: 15-115 kPa + * Voltage at 115kPa: 2.82 + * Output scale: 27mV/kPa + * + * If we want to detect launch with the barometer, we need + * a large enough bump to not be fooled by noise. At typical + * launch elevations (0-2000m), a 200Pa pressure change cooresponds + * to about a 20m elevation change. This is 5.4mV, or about 3LSB. + * As all of our calculations are done in 16 bits, we'll actually see a change + * of 16 times this though + * + * 27 mV/kPa * 32767 / 3300 counts/mV = 268.1 counts/kPa + */ + +/* Accelerometer calibration + * + * We're sampling the accelerometer through a resistor divider which + * consists of 5k and 10k resistors. This multiplies the values by 2/3. + * That goes into the cc1111 A/D converter, which is running at 11 bits + * of precision with the bits in the MSB of the 16 bit value. Only positive + * values are used, so values should range from 0-32752 for 0-3.3V. The + * specs say we should see 40mV/g (uncalibrated), multiply by 2/3 for what + * the A/D converter sees (26.67 mV/g). We should see 32752/3300 counts/mV, + * for a final computation of: + * + * 26.67 mV/g * 32767/3300 counts/mV = 264.8 counts/g + * + * Zero g was measured at 16000 (we would expect 16384). + * Note that this value is only require to tell if the + * rocket is standing upright. Once that is determined, + * the value of the accelerometer is averaged for 100 samples + * to find the resting accelerometer value, which is used + * for all further flight computations + */ + +#define GRAVITY 9.80665 + +/* + * Above this height, the baro sensor doesn't work + */ +#define AO_MAX_BARO_HEIGHT 12000 + +/* + * Above this speed, baro measurements are unreliable + */ +#define AO_MAX_BARO_SPEED 200 + +#define ACCEL_NOSE_UP (ao_accel_2g >> 2) + +/* + * Speed and acceleration are scaled by 16 to provide a bit more + * resolution while still having reasonable range. Note that this + * limits speed to 2047m/s (around mach 6) and acceleration to + * 2047m/s² (over 200g) + */ + +#define AO_M_TO_HEIGHT(m) ((int16_t) (m)) +#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16)) +#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16)) + +extern __pdata uint16_t ao_sample_tick; /* time of last data */ +extern __pdata int16_t ao_sample_pres; /* most recent pressure sensor reading */ +extern __pdata int16_t ao_sample_alt; /* MSL of ao_sample_pres */ +extern __pdata int16_t ao_sample_height; /* AGL of ao_sample_pres */ +extern __data uint8_t ao_sample_adc; /* Ring position of last processed sample */ + +#if HAS_ACCEL +extern __pdata int16_t ao_sample_accel; /* most recent accel sensor reading */ +#endif + +extern __pdata int16_t ao_ground_pres; /* startup pressure */ +extern __pdata int16_t ao_ground_height; /* MSL of ao_ground_pres */ + +#if HAS_ACCEL +extern __pdata int16_t ao_ground_accel; /* startup acceleration */ +extern __pdata int16_t ao_accel_2g; /* factory accel calibration */ +extern __pdata int32_t ao_accel_scale; /* sensor to m/s² conversion */ +#endif + +void ao_sample_init(void); + +/* returns FALSE in preflight mode, TRUE in flight mode */ +uint8_t ao_sample(void); + +/* + * ao_kalman.c + */ + +#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5)) +#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5)) +#define from_fix(x) ((x) >> 16) + +extern __pdata int16_t ao_height; /* meters */ +extern __pdata int16_t ao_speed; /* m/s * 16 */ +extern __pdata int16_t ao_accel; /* m/s² * 16 */ +extern __pdata int16_t ao_max_height; /* max of ao_height */ +extern __pdata int16_t ao_avg_height; /* running average of height */ + +extern __pdata int16_t ao_error_h; +extern __pdata int16_t ao_error_h_sq_avg; + +#if HAS_ACCEL +extern __pdata int16_t ao_error_a; +#endif + +void ao_kalman(void); + +/* + * ao_report.c + */ + +void +ao_report_init(void); + +/* + * ao_convert.c + * + * Given raw data, convert to SI units + */ + +/* pressure from the sensor to altitude in meters */ +int16_t +ao_pres_to_altitude(int16_t pres) __reentrant; + +int16_t +ao_altitude_to_pres(int16_t alt) __reentrant; + +int16_t +ao_temp_to_dC(int16_t temp) __reentrant; + +/* + * ao_dbg.c + * + * debug another telemetrum board + */ + +/* Send a byte to the dbg target */ +void +ao_dbg_send_byte(uint8_t byte); + +/* Receive a byte from the dbg target */ +uint8_t +ao_dbg_recv_byte(void); + +/* Start a bulk transfer to/from dbg target memory */ +void +ao_dbg_start_transfer(uint16_t addr); + +/* End a bulk transfer to/from dbg target memory */ +void +ao_dbg_end_transfer(void); + +/* Write a byte to dbg target memory */ +void +ao_dbg_write_byte(uint8_t byte); + +/* Read a byte from dbg target memory */ +uint8_t +ao_dbg_read_byte(void); + +/* Enable dbg mode, switching use of the pins */ +void +ao_dbg_debug_mode(void); + +/* Reset the dbg target */ +void +ao_dbg_reset(void); + +void +ao_dbg_init(void); + +/* + * ao_serial.c + */ + +#ifndef HAS_SERIAL_1 +#error Please define HAS_SERIAL_1 +#endif + +#if HAS_SERIAL_1 +#ifndef USE_SERIAL_STDIN +#error Please define USE_SERIAL_STDIN +#endif + +void +ao_serial_rx1_isr(void) __interrupt 3; + +void +ao_serial_tx1_isr(void) __interrupt 14; + +char +ao_serial_getchar(void) __critical; + +#if USE_SERIAL_STDIN +char +ao_serial_pollchar(void) __critical; + +void +ao_serial_set_stdin(uint8_t stdin); +#endif + +void +ao_serial_putchar(char c) __critical; + +void +ao_serial_drain(void) __critical; + +#define AO_SERIAL_SPEED_4800 0 +#define AO_SERIAL_SPEED_9600 1 +#define AO_SERIAL_SPEED_19200 2 +#define AO_SERIAL_SPEED_57600 3 + +void +ao_serial_set_speed(uint8_t speed); + +void +ao_serial_init(void); +#endif + +/* + * ao_spi.c + */ + +extern __xdata uint8_t ao_spi_mutex; + +#define ao_spi_get_mask(reg,mask) do {\ + ao_mutex_get(&ao_spi_mutex); \ + (reg) &= ~(mask); \ + } while (0) + +#define ao_spi_put_mask(reg,mask) do { \ + (reg) |= (mask); \ + ao_mutex_put(&ao_spi_mutex); \ + } while (0) + +#define ao_spi_get_bit(bit) do {\ + ao_mutex_get(&ao_spi_mutex); \ + (bit) = 0; \ + } while (0) + +#define ao_spi_put_bit(bit) do { \ + (bit) = 1; \ + ao_mutex_put(&ao_spi_mutex); \ + } while (0) + +/* + * The SPI mutex must be held to call either of these + * functions -- this mutex covers the entire SPI operation, + * from chip select low to chip select high + */ + +void +ao_spi_send(void __xdata *block, uint16_t len) __reentrant; + +void +ao_spi_recv(void __xdata *block, uint16_t len) __reentrant; + +void +ao_spi_init(void); + +/* + * ao_telemetry.c + */ +#define AO_MAX_CALLSIGN 8 +#define AO_MAX_VERSION 8 +#define AO_MAX_TELEMETRY 128 + +struct ao_telemetry_generic { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + uint8_t payload[27]; /* 5 */ + /* 32 */ +}; + +#define AO_TELEMETRY_SENSOR_TELEMETRUM 0x01 +#define AO_TELEMETRY_SENSOR_TELEMINI 0x02 +#define AO_TELEMETRY_SENSOR_TELENANO 0x03 + +struct ao_telemetry_sensor { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + + uint8_t state; /* 5 flight state */ + int16_t accel; /* 6 accelerometer (TM only) */ + int16_t pres; /* 8 pressure sensor */ + int16_t temp; /* 10 temperature sensor */ + int16_t v_batt; /* 12 battery voltage */ + int16_t sense_d; /* 14 drogue continuity sense (TM/Tm) */ + int16_t sense_m; /* 16 main continuity sense (TM/Tm) */ + + int16_t acceleration; /* 18 m/s² * 16 */ + int16_t speed; /* 20 m/s * 16 */ + int16_t height; /* 22 m */ + + int16_t ground_pres; /* 24 average pres on pad */ + int16_t ground_accel; /* 26 average accel on pad */ + int16_t accel_plus_g; /* 28 accel calibration at +1g */ + int16_t accel_minus_g; /* 30 accel calibration at -1g */ + /* 32 */ +}; + +#define AO_TELEMETRY_CONFIGURATION 0x04 + +struct ao_telemetry_configuration { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + + uint8_t device; /* 5 device type */ + uint16_t flight; /* 6 flight number */ + uint8_t config_major; /* 8 Config major version */ + uint8_t config_minor; /* 9 Config minor version */ + uint16_t apogee_delay; /* 10 Apogee deploy delay in seconds */ + uint16_t main_deploy; /* 12 Main deploy alt in meters */ + uint16_t flight_log_max; /* 14 Maximum flight log size in kB */ + char callsign[AO_MAX_CALLSIGN]; /* 16 Radio operator identity */ + char version[AO_MAX_VERSION]; /* 24 Software version */ + /* 32 */ +}; + +#define AO_TELEMETRY_LOCATION 0x05 + +#define AO_GPS_MODE_NOT_VALID 'N' +#define AO_GPS_MODE_AUTONOMOUS 'A' +#define AO_GPS_MODE_DIFFERENTIAL 'D' +#define AO_GPS_MODE_ESTIMATED 'E' +#define AO_GPS_MODE_MANUAL 'M' +#define AO_GPS_MODE_SIMULATED 'S' + +struct ao_telemetry_location { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + + uint8_t flags; /* 5 Number of sats and other flags */ + int16_t altitude; /* 6 GPS reported altitude (m) */ + int32_t latitude; /* 8 latitude (degrees * 10⁷) */ + int32_t longitude; /* 12 longitude (degrees * 10⁷) */ + uint8_t year; /* 16 (- 2000) */ + uint8_t month; /* 17 (1-12) */ + uint8_t day; /* 18 (1-31) */ + uint8_t hour; /* 19 (0-23) */ + uint8_t minute; /* 20 (0-59) */ + uint8_t second; /* 21 (0-59) */ + uint8_t pdop; /* 22 (m * 5) */ + uint8_t hdop; /* 23 (m * 5) */ + uint8_t vdop; /* 24 (m * 5) */ + uint8_t mode; /* 25 */ + uint16_t ground_speed; /* 26 cm/s */ + int16_t climb_rate; /* 28 cm/s */ + uint8_t course; /* 30 degrees / 2 */ + uint8_t unused[1]; /* 31 */ + /* 32 */ +}; + +#define AO_TELEMETRY_SATELLITE 0x06 + +struct ao_telemetry_satellite_info { + uint8_t svid; + uint8_t c_n_1; +}; + +struct ao_telemetry_satellite { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + uint8_t channels; /* 5 number of reported sats */ + + struct ao_telemetry_satellite_info sats[12]; /* 6 */ + uint8_t unused[2]; /* 30 */ + /* 32 */ +}; + +#define AO_TELEMETRY_COMPANION 0x07 + +#define AO_COMPANION_MAX_CHANNELS 12 + +struct ao_telemetry_companion { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + uint8_t board_id; /* 5 */ + + uint8_t update_period; /* 6 */ + uint8_t channels; /* 7 */ + uint16_t companion_data[AO_COMPANION_MAX_CHANNELS]; /* 8 */ + /* 32 */ +}; + +union ao_telemetry_all { + struct ao_telemetry_generic generic; + struct ao_telemetry_sensor sensor; + struct ao_telemetry_configuration configuration; + struct ao_telemetry_location location; + struct ao_telemetry_satellite satellite; + struct ao_telemetry_companion companion; +}; + +/* + * ao_gps.c + */ + +#define AO_GPS_NUM_SAT_MASK (0xf << 0) +#define AO_GPS_NUM_SAT_SHIFT (0) + +#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 __pdata uint16_t ao_gps_tick; +extern __xdata uint8_t ao_gps_mutex; +extern __xdata struct ao_telemetry_location ao_gps_data; +extern __xdata struct ao_telemetry_satellite ao_gps_tracking_data; + +struct ao_gps_orig { + uint8_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + uint8_t flags; + int32_t latitude; /* degrees * 10⁷ */ + int32_t longitude; /* degrees * 10⁷ */ + int16_t altitude; /* m */ + uint16_t ground_speed; /* cm/s */ + uint8_t course; /* degrees / 2 */ + uint8_t hdop; /* * 5 */ + int16_t climb_rate; /* cm/s */ + uint16_t h_error; /* m */ + uint16_t v_error; /* m */ +}; + +struct ao_gps_sat_orig { + uint8_t svid; + uint8_t c_n_1; +}; + +#define AO_MAX_GPS_TRACKING 12 + +struct ao_gps_tracking_orig { + uint8_t channels; + struct ao_gps_sat_orig sats[AO_MAX_GPS_TRACKING]; +}; + +void +ao_gps(void); + +void +ao_gps_print(__xdata struct ao_gps_orig *gps_data); + +void +ao_gps_tracking_print(__xdata struct ao_gps_tracking_orig *gps_tracking_data); + +void +ao_gps_init(void); + +/* + * ao_gps_report.c + */ + +void +ao_gps_report(void); + +void +ao_gps_report_init(void); + +/* + * ao_telemetry_orig.c + */ + +struct ao_telemetry_orig { + uint16_t serial; + uint16_t flight; + uint8_t flight_state; + int16_t accel; + int16_t ground_accel; + union { + struct { + int16_t speed; + int16_t unused; + } k; + int32_t flight_vel; + } u; + int16_t height; + int16_t ground_pres; + int16_t accel_plus_g; + int16_t accel_minus_g; + struct ao_adc adc; + struct ao_gps_orig gps; + char callsign[AO_MAX_CALLSIGN]; + struct ao_gps_tracking_orig gps_tracking; +}; + +struct ao_telemetry_tiny { + uint16_t serial; + uint16_t flight; + uint8_t flight_state; + int16_t height; /* AGL in meters */ + int16_t speed; /* in m/s * 16 */ + int16_t accel; /* in m/s² * 16 */ + int16_t ground_pres; /* sensor units */ + struct ao_adc adc; /* raw ADC readings */ + char callsign[AO_MAX_CALLSIGN]; +}; + +/* + * ao_radio_recv tacks on rssi and status bytes + */ + +struct ao_telemetry_raw_recv { + uint8_t packet[AO_MAX_TELEMETRY + 2]; +}; + +struct ao_telemetry_orig_recv { + struct ao_telemetry_orig telemetry_orig; + int8_t rssi; + uint8_t status; +}; + +struct ao_telemetry_tiny_recv { + struct ao_telemetry_tiny telemetry_tiny; + int8_t rssi; + uint8_t status; +}; + +/* Set delay between telemetry reports (0 to disable) */ + +#define AO_TELEMETRY_INTERVAL_PAD AO_MS_TO_TICKS(1000) +#define AO_TELEMETRY_INTERVAL_FLIGHT AO_MS_TO_TICKS(100) +#define AO_TELEMETRY_INTERVAL_RECOVER AO_MS_TO_TICKS(1000) + +void +ao_telemetry_set_interval(uint16_t interval); + +void +ao_rdf_set(uint8_t rdf); + +void +ao_telemetry_init(void); + +void +ao_telemetry_orig_init(void); + +void +ao_telemetry_tiny_init(void); + +/* + * ao_radio.c + */ + +extern __xdata uint8_t ao_radio_dma; +extern __xdata uint8_t ao_radio_dma_done; +extern __xdata uint8_t ao_radio_done; +extern __xdata uint8_t ao_radio_mutex; + +void +ao_radio_general_isr(void) __interrupt 16; + +void +ao_radio_get(uint8_t len); + +#define ao_radio_put() ao_mutex_put(&ao_radio_mutex) + +void +ao_radio_set_packet(void); + +void +ao_radio_send(__xdata void *data, uint8_t size) __reentrant; + +uint8_t +ao_radio_recv(__xdata void *data, uint8_t size) __reentrant; + +void +ao_radio_recv_abort(void); + +void +ao_radio_rdf(int ms); + +void +ao_radio_rdf_abort(void); + +void +ao_radio_idle(void); + +void +ao_radio_init(void); + +/* + * ao_monitor.c + */ + +extern const char const * const ao_state_names[]; + +void +ao_monitor(void); + +#define AO_MONITORING_OFF 0 +#define AO_MONITORING_ORIG 1 +#define AO_MONITORING_TINY 2 + +void +ao_set_monitor(uint8_t monitoring); + +void +ao_monitor_init(uint8_t led, uint8_t monitoring) __reentrant; + +/* + * ao_stdio.c + */ + +#define AO_READ_AGAIN ((char) -1) + +struct ao_stdio { + char (*pollchar)(void); + void (*putchar)(char c) __reentrant; + void (*flush)(void); + uint8_t echo; +}; + +extern __xdata struct ao_stdio ao_stdios[]; +extern __pdata int8_t ao_cur_stdio; +extern __pdata int8_t ao_num_stdios; + +void +flush(void); + +extern __xdata uint8_t ao_stdin_ready; + +uint8_t +ao_echo(void); + +int8_t +ao_add_stdio(char (*pollchar)(void), + void (*putchar)(char) __reentrant, + void (*flush)(void)) __reentrant; + +/* + * ao_ignite.c + */ + +enum ao_igniter { + ao_igniter_drogue = 0, + ao_igniter_main = 1 +}; + +void +ao_ignite(enum ao_igniter igniter); + +enum ao_igniter_status { + ao_igniter_unknown, /* unknown status (ambiguous voltage) */ + ao_igniter_ready, /* continuity detected */ + ao_igniter_active, /* igniter firing */ + ao_igniter_open, /* open circuit detected */ +}; + +enum ao_igniter_status +ao_igniter_status(enum ao_igniter igniter); + +void +ao_ignite_set_pins(void); + +void +ao_igniter_init(void); + +/* + * ao_config.c + */ + +#define AO_CONFIG_MAJOR 1 +#define AO_CONFIG_MINOR 8 + +struct ao_config { + uint8_t major; + uint8_t minor; + uint16_t main_deploy; + int16_t accel_plus_g; /* changed for minor version 2 */ + uint8_t radio_channel; + char callsign[AO_MAX_CALLSIGN + 1]; + uint8_t apogee_delay; /* minor version 1 */ + int16_t accel_minus_g; /* minor version 2 */ + uint32_t radio_cal; /* minor version 3 */ + uint32_t flight_log_max; /* minor version 4 */ + uint8_t ignite_mode; /* minor version 5 */ + uint8_t pad_orientation; /* minor version 6 */ + uint32_t radio_setting; /* minor version 7 */ + uint8_t radio_enable; /* minor version 8 */ +}; + +#define AO_IGNITE_MODE_DUAL 0 +#define AO_IGNITE_MODE_APOGEE 1 +#define AO_IGNITE_MODE_MAIN 2 + +#define AO_PAD_ORIENTATION_ANTENNA_UP 0 +#define AO_PAD_ORIENTATION_ANTENNA_DOWN 1 + +extern __xdata struct ao_config ao_config; + +#define AO_CONFIG_MAX_SIZE 128 + +void +ao_config_get(void); + +void +ao_config_put(void); + +void +ao_config_init(void); + +/* + * ao_rssi.c + */ + +void +ao_rssi_set(int rssi_value); + +void +ao_rssi_init(uint8_t rssi_led); + +/* + * ao_product.c + * + * values which need to be defined for + * each instance of a product + */ + +extern const char ao_version[]; +extern const char ao_manufacturer[]; +extern const char ao_product[]; + +/* + * Fifos + */ + +#define AO_FIFO_SIZE 32 + +struct ao_fifo { + uint8_t insert; + uint8_t remove; + char fifo[AO_FIFO_SIZE]; +}; + +#define ao_fifo_insert(f,c) do { \ + (f).fifo[(f).insert] = (c); \ + (f).insert = ((f).insert + 1) & (AO_FIFO_SIZE-1); \ +} while(0) + +#define ao_fifo_remove(f,c) do {\ + c = (f).fifo[(f).remove]; \ + (f).remove = ((f).remove + 1) & (AO_FIFO_SIZE-1); \ +} while(0) + +#define ao_fifo_full(f) ((((f).insert + 1) & (AO_FIFO_SIZE-1)) == (f).remove) +#define ao_fifo_empty(f) ((f).insert == (f).remove) + +/* + * ao_packet.c + * + * Packet-based command interface + */ + +#define AO_PACKET_MAX 64 +#define AO_PACKET_SYN (uint8_t) 0xff + +struct ao_packet { + uint8_t addr; + uint8_t len; + uint8_t seq; + uint8_t ack; + uint8_t d[AO_PACKET_MAX]; + uint8_t callsign[AO_MAX_CALLSIGN]; +}; + +struct ao_packet_recv { + struct ao_packet packet; + int8_t rssi; + uint8_t status; +}; + +extern __xdata struct ao_packet_recv ao_rx_packet; +extern __xdata struct ao_packet ao_tx_packet; +extern __xdata struct ao_task ao_packet_task; +extern __xdata uint8_t ao_packet_enable; +extern __xdata uint8_t ao_packet_master_sleeping; +extern __pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used; + +void +ao_packet_send(void); + +uint8_t +ao_packet_recv(void); + +void +ao_packet_flush(void); + +void +ao_packet_putchar(char c) __reentrant; + +char +ao_packet_pollchar(void) __critical; + +/* ao_packet_master.c */ + +void +ao_packet_master_init(void); + +/* ao_packet_slave.c */ + +void +ao_packet_slave_start(void); + +void +ao_packet_slave_stop(void); + +void +ao_packet_slave_init(uint8_t enable); + +/* ao_btm.c */ + +/* If bt_link is on P2, this interrupt is shared by USB, so the USB + * code calls this function. Otherwise, it's a regular ISR. + */ + +void +ao_btm_isr(void) +#if BT_LINK_ON_P1 + __interrupt 15 +#endif + ; + +void +ao_btm_init(void); + +/* ao_companion.c */ + +#define AO_COMPANION_SETUP 1 +#define AO_COMPANION_FETCH 2 +#define AO_COMPANION_NOTIFY 3 + +struct ao_companion_command { + uint8_t command; + uint8_t flight_state; + uint16_t tick; + uint16_t serial; + uint16_t flight; +}; + +struct ao_companion_setup { + uint16_t board_id; + uint16_t board_id_inverse; + uint8_t update_period; + uint8_t channels; +}; + +extern __pdata uint8_t ao_companion_running; +extern __xdata struct ao_companion_setup ao_companion_setup; +extern __xdata uint8_t ao_companion_mutex; +extern __xdata uint16_t ao_companion_data[AO_COMPANION_MAX_CHANNELS]; + +void +ao_companion_init(void); + +#endif /* _AO_H_ */ diff --git a/src/core/ao_cmd.c b/src/core/ao_cmd.c new file mode 100644 index 00000000..1442ebea --- /dev/null +++ b/src/core/ao_cmd.c @@ -0,0 +1,320 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +__pdata uint16_t ao_cmd_lex_i; +__pdata uint32_t ao_cmd_lex_u32; +__pdata char ao_cmd_lex_c; +__pdata enum ao_cmd_status ao_cmd_status; + +#define CMD_LEN 32 + +static __xdata char cmd_line[CMD_LEN]; +static __pdata uint8_t cmd_len; +static __pdata uint8_t cmd_i; + +static void +put_string(__code char *s) +{ + char c; + while (c = *s++) + putchar(c); +} + +static void +readline(void) +{ + __pdata char c; + if (ao_echo()) + put_string("> "); + cmd_len = 0; + for (;;) { + flush(); + c = getchar(); + /* backspace/delete */ + if (c == '\010' || c == '\177') { + if (cmd_len != 0) { + if (ao_echo()) + put_string("\010 \010"); + --cmd_len; + } + continue; + } + + /* ^U */ + if (c == '\025') { + while (cmd_len != 0) { + if (ao_echo()) + put_string("\010 \010"); + --cmd_len; + } + continue; + } + + /* map CR to NL */ + if (c == '\r') + c = '\n'; + + if (c == '\n') { + if (ao_echo()) + putchar('\n'); + break; + } + + if (cmd_len >= CMD_LEN - 2) { + if (ao_echo()) + putchar('\007'); + continue; + } + cmd_line[cmd_len++] = c; + if (ao_echo()) + putchar(c); + } + cmd_line[cmd_len++] = '\n'; + cmd_line[cmd_len++] = '\0'; + cmd_i = 0; +} + +void +ao_cmd_lex(void) +{ + ao_cmd_lex_c = '\n'; + if (cmd_i < cmd_len) + ao_cmd_lex_c = cmd_line[cmd_i++]; +} + +static void +putnibble(uint8_t v) +{ + if (v < 10) + putchar(v + '0'); + else + putchar(v + ('a' - 10)); +} + +void +ao_cmd_put16(uint16_t v) +{ + ao_cmd_put8(v >> 8); + ao_cmd_put8(v); +} + +void +ao_cmd_put8(uint8_t v) +{ + putnibble((v >> 4) & 0xf); + putnibble(v & 0xf); +} + +void +ao_cmd_white(void) +{ + while (ao_cmd_lex_c == ' ' || ao_cmd_lex_c == '\t') + ao_cmd_lex(); +} + +void +ao_cmd_hex(void) +{ + __pdata uint8_t r = ao_cmd_lex_error; + uint8_t n; + + ao_cmd_lex_i = 0; + ao_cmd_white(); + for(;;) { + if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9') + n = (ao_cmd_lex_c - '0'); + else if ('a' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'f') + n = (ao_cmd_lex_c - 'a' + 10); + else if ('A' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'F') + n = (ao_cmd_lex_c - 'A' + 10); + else + break; + ao_cmd_lex_i = (ao_cmd_lex_i << 4) | n; + r = ao_cmd_success; + ao_cmd_lex(); + } + if (r != ao_cmd_success) + ao_cmd_status = r; +} + +void +ao_cmd_decimal(void) +{ + __pdata uint8_t r = ao_cmd_lex_error; + + ao_cmd_lex_u32 = 0; + ao_cmd_white(); + for(;;) { + if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9') + ao_cmd_lex_u32 = (ao_cmd_lex_u32 * 10) + (ao_cmd_lex_c - '0'); + else + break; + r = ao_cmd_success; + ao_cmd_lex(); + } + if (r != ao_cmd_success) + ao_cmd_status = r; + ao_cmd_lex_i = (uint16_t) ao_cmd_lex_u32; +} + +uint8_t +ao_match_word(__code char *word) +{ + while (*word) { + if (ao_cmd_lex_c != *word) { + ao_cmd_status = ao_cmd_syntax_error; + return 0; + } + word++; + ao_cmd_lex(); + } + return 1; +} + +static void +eol(void) +{ + while (ao_cmd_lex_c != '\n') + ao_cmd_lex(); +} + +static void +echo(void) +{ + ao_cmd_hex(); + if (ao_cmd_status == ao_cmd_success) + ao_stdios[ao_cur_stdio].echo = ao_cmd_lex_i != 0; +} + +static void +ao_reboot(void) +{ + ao_cmd_white(); + if (!ao_match_word("eboot")) + return; + WDCTL = WDCTL_EN | WDCTL_MODE_WATCHDOG | WDCTL_INT_64; + ao_delay(AO_SEC_TO_TICKS(2)); + ao_panic(AO_PANIC_REBOOT); +} + +static void +version(void) +{ + printf("manufacturer %s\n", ao_manufacturer); + printf("product %s\n", ao_product); + printf("serial-number %u\n", ao_serial_number); +#if HAS_EEPROM + printf("log-format %u\n", ao_log_format); +#endif + printf("software-version %s\n", ao_version); +} + +#define NUM_CMDS 11 + +static __code struct ao_cmds *__xdata (ao_cmds[NUM_CMDS]); +static __pdata uint8_t ao_ncmds; + +static void +help(void) +{ + register uint8_t cmds; + register uint8_t cmd; + register __code struct ao_cmds * cs; + + for (cmds = 0; cmds < ao_ncmds; cmds++) { + cs = ao_cmds[cmds]; + for (cmd = 0; cs[cmd].func; cmd++) + printf("%-45s %s\n", + cs[cmd].help, + cs[cmd].help+1+strlen(cs[cmd].help)); + } +} + +static void +report(void) +{ + 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) +{ + char c; + uint8_t cmd, cmds; + __code struct ao_cmds * __xdata cs; + void (*__xdata func)(void); + + for (;;) { + readline(); + ao_cmd_lex(); + ao_cmd_white(); + c = ao_cmd_lex_c; + ao_cmd_lex(); + if (c == '\r' || c == '\n') + continue; + func = (void (*)(void)) NULL; + for (cmds = 0; cmds < ao_ncmds; cmds++) { + cs = ao_cmds[cmds]; + for (cmd = 0; cs[cmd].func; cmd++) + if (cs[cmd].help[0] == c) { + func = cs[cmd].func; + break; + } + if (func) + break; + } + if (func) + (*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, "?\0Help" }, + { ao_task_info, "T\0Show tasks" }, + { echo, "E <0 off, 1 on>\0Set echo mode" }, + { ao_reboot, "r eboot\0Reboot" }, + { version, "v\0Version" }, + { 0, NULL }, +}; + +void +ao_cmd_init(void) +{ + ao_cmd_register(&ao_base_cmds[0]); + ao_add_task(&ao_cmd_task, ao_cmd, "cmd"); +} diff --git a/src/core/ao_config.c b/src/core/ao_config.c new file mode 100644 index 00000000..0c10e608 --- /dev/null +++ b/src/core/ao_config.c @@ -0,0 +1,542 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +__xdata struct ao_config ao_config; +__pdata uint8_t ao_config_loaded; +__pdata uint8_t ao_config_dirty; +__xdata uint8_t ao_config_mutex; + +#define AO_CONFIG_DEFAULT_MAIN_DEPLOY 250 +#define AO_CONFIG_DEFAULT_RADIO_CHANNEL 0 +#define AO_CONFIG_DEFAULT_CALLSIGN "N0CALL" +#define AO_CONFIG_DEFAULT_ACCEL_ZERO_G 16000 +#define AO_CONFIG_DEFAULT_APOGEE_DELAY 0 +#define AO_CONFIG_DEFAULT_IGNITE_MODE AO_IGNITE_MODE_DUAL +#define AO_CONFIG_DEFAULT_PAD_ORIENTATION AO_PAD_ORIENTATION_ANTENNA_UP +#if HAS_EEPROM +#ifndef USE_INTERNAL_FLASH +#error Please define USE_INTERNAL_FLASH +#endif +#endif +#if USE_INTERNAL_FLASH +#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX ao_storage_config +#else +#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX ((uint32_t) 192 * (uint32_t) 1024) +#endif + +#if HAS_EEPROM +static void +_ao_config_put(void) +{ + ao_storage_setup(); + ao_storage_erase(ao_storage_config); + ao_storage_write(ao_storage_config, &ao_config, sizeof (ao_config)); + ao_log_write_erase(0); + ao_storage_flush(); +} + +void +ao_config_put(void) +{ + ao_mutex_get(&ao_config_mutex); + _ao_config_put(); + ao_mutex_put(&ao_config_mutex); +} +#endif + +static void +_ao_config_get(void) +{ + if (ao_config_loaded) + return; +#if HAS_EEPROM + ao_storage_setup(); + ao_storage_read(ao_storage_config, &ao_config, sizeof (ao_config)); +#endif + if (ao_config.major != AO_CONFIG_MAJOR) { + ao_config.major = AO_CONFIG_MAJOR; + ao_config.minor = 0; + ao_config.main_deploy = AO_CONFIG_DEFAULT_MAIN_DEPLOY; + ao_config.radio_channel = AO_CONFIG_DEFAULT_RADIO_CHANNEL; + memset(&ao_config.callsign, '\0', sizeof (ao_config.callsign)); + memcpy(&ao_config.callsign, AO_CONFIG_DEFAULT_CALLSIGN, + sizeof(AO_CONFIG_DEFAULT_CALLSIGN) - 1); + } + if (ao_config.minor < AO_CONFIG_MINOR) { + /* Fixups for minor version 1 */ + if (ao_config.minor < 1) + ao_config.apogee_delay = AO_CONFIG_DEFAULT_APOGEE_DELAY; + /* Fixups for minor version 2 */ + if (ao_config.minor < 2) { + ao_config.accel_plus_g = 0; + ao_config.accel_minus_g = 0; + } + /* Fixups for minor version 3 */ + if (ao_config.minor < 3) + ao_config.radio_cal = ao_radio_cal; + /* Fixups for minor version 4 */ + if (ao_config.minor < 4) + ao_config.flight_log_max = AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX; + /* Fixupes for minor version 5 */ + if (ao_config.minor < 5) + ao_config.ignite_mode = AO_CONFIG_DEFAULT_IGNITE_MODE; + if (ao_config.minor < 6) + ao_config.pad_orientation = AO_CONFIG_DEFAULT_PAD_ORIENTATION; + if (ao_config.minor < 7) + ao_config.radio_setting = ao_config.radio_cal; + if (ao_config.minor < 8) + ao_config.radio_enable = TRUE; + ao_config.minor = AO_CONFIG_MINOR; + ao_config_dirty = 1; + } + ao_config_loaded = 1; +} + +static void +_ao_config_edit_start(void) +{ + ao_mutex_get(&ao_config_mutex); + _ao_config_get(); +} + +static void +_ao_config_edit_finish(void) +{ + ao_config_dirty = 1; + ao_mutex_put(&ao_config_mutex); +} + +void +ao_config_get(void) +{ + _ao_config_edit_start(); + ao_mutex_put(&ao_config_mutex); +} + +void +ao_config_callsign_show(void) +{ + printf ("Callsign: \"%s\"\n", ao_config.callsign); +} + +void +ao_config_callsign_set(void) __reentrant +{ + uint8_t c; + static __xdata char callsign[AO_MAX_CALLSIGN + 1]; + + memset(callsign, '\0', sizeof callsign); + ao_cmd_white(); + c = 0; + while (ao_cmd_lex_c != '\n') { + if (c < AO_MAX_CALLSIGN) + callsign[c++] = ao_cmd_lex_c; + else + ao_cmd_status = ao_cmd_lex_error; + ao_cmd_lex(); + } + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + memcpy(&ao_config.callsign, &callsign, + AO_MAX_CALLSIGN + 1); + _ao_config_edit_finish(); +} + +void +ao_config_radio_channel_show(void) __reentrant +{ + printf("Radio channel: %d\n", + ao_config.radio_channel); +} + +void +ao_config_radio_channel_set(void) __reentrant +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_config.radio_channel = ao_cmd_lex_i; + _ao_config_edit_finish(); + ao_radio_recv_abort(); +} + +#if HAS_ADC + +void +ao_config_main_deploy_show(void) __reentrant +{ + printf("Main deploy: %d meters\n", + ao_config.main_deploy); +} + +void +ao_config_main_deploy_set(void) __reentrant +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_config.main_deploy = ao_cmd_lex_i; + _ao_config_edit_finish(); +} + +#if HAS_ACCEL +void +ao_config_accel_calibrate_show(void) __reentrant +{ + printf("Accel cal +1g: %d -1g: %d\n", + ao_config.accel_plus_g, ao_config.accel_minus_g); +} + +#define ACCEL_CALIBRATE_SAMPLES 1024 +#define ACCEL_CALIBRATE_SHIFT 10 + +static int16_t +ao_config_accel_calibrate_auto(char *orientation) __reentrant +{ + uint16_t i; + int32_t accel_total; + uint8_t cal_adc_ring; + + printf("Orient antenna %s and press a key...", orientation); + flush(); + (void) getchar(); + puts("\r\n"); flush(); + puts("Calibrating..."); flush(); + i = ACCEL_CALIBRATE_SAMPLES; + accel_total = 0; + cal_adc_ring = ao_sample_adc; + while (i) { + ao_sleep(DATA_TO_XDATA(&ao_sample_adc)); + while (i && cal_adc_ring != ao_sample_adc) { + accel_total += (int32_t) ao_adc_ring[cal_adc_ring].accel; + cal_adc_ring = ao_adc_ring_next(cal_adc_ring); + i--; + } + } + return accel_total >> ACCEL_CALIBRATE_SHIFT; +} + +void +ao_config_accel_calibrate_set(void) __reentrant +{ + int16_t up, down; + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + if (ao_cmd_lex_i == 0) { + up = ao_config_accel_calibrate_auto("up"); + down = ao_config_accel_calibrate_auto("down"); + } else { + up = ao_cmd_lex_i; + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + down = ao_cmd_lex_i; + } + if (up >= down) { + printf("Invalid accel: up (%d) down (%d)\n", + up, down); + return; + } + _ao_config_edit_start(); + ao_config.accel_plus_g = up; + ao_config.accel_minus_g = down; + _ao_config_edit_finish(); +} +#endif /* HAS_ACCEL */ + +void +ao_config_apogee_delay_show(void) __reentrant +{ + printf("Apogee delay: %d seconds\n", + ao_config.apogee_delay); +} + +void +ao_config_apogee_delay_set(void) __reentrant +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_config.apogee_delay = ao_cmd_lex_i; + _ao_config_edit_finish(); +} + +#endif /* HAS_ADC */ + +void +ao_config_radio_cal_show(void) __reentrant +{ + printf("Radio cal: %ld\n", ao_config.radio_cal); +} + +void +ao_config_radio_cal_set(void) __reentrant +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_config.radio_setting = ao_config.radio_cal = ao_cmd_lex_u32; + _ao_config_edit_finish(); +} + +#if HAS_EEPROM +void +ao_config_log_show(void) __reentrant +{ + printf("Max flight log: %d kB\n", (int16_t) (ao_config.flight_log_max >> 10)); +} + +void +ao_config_log_set(void) __reentrant +{ + uint16_t block = (uint16_t) (ao_storage_block >> 10); + uint16_t config = (uint16_t) (ao_storage_config >> 10); + + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + if (ao_log_present()) + printf("Storage must be empty before changing log size\n"); + else if (block > 1024 && (ao_cmd_lex_i & (block - 1))) + printf("Flight log size must be multiple of %d kB\n", block); + else if (ao_cmd_lex_i > config) + printf("Flight log max %d kB\n", config); + else { + _ao_config_edit_start(); + ao_config.flight_log_max = (uint32_t) ao_cmd_lex_i << 10; + _ao_config_edit_finish(); + } +} +#endif /* HAS_EEPROM */ + +#if HAS_IGNITE +void +ao_config_ignite_mode_show(void) __reentrant +{ + printf("Ignite mode: %d\n", ao_config.ignite_mode); +} + +void +ao_config_ignite_mode_set(void) __reentrant +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_config.ignite_mode = ao_cmd_lex_i; + _ao_config_edit_finish(); +} +#endif + +#if HAS_ACCEL +void +ao_config_pad_orientation_show(void) __reentrant +{ + printf("Pad orientation: %d\n", ao_config.pad_orientation); +} + +void +ao_config_pad_orientation_set(void) __reentrant +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_cmd_lex_i &= 1; + if (ao_config.pad_orientation != ao_cmd_lex_i) { + uint16_t t; + t = ao_config.accel_plus_g; + ao_config.accel_plus_g = 0x7fff - ao_config.accel_minus_g; + ao_config.accel_minus_g = 0x7fff - t; + } + ao_config.pad_orientation = ao_cmd_lex_i; + _ao_config_edit_finish(); +} +#endif + +void +ao_config_radio_setting_show(void) __reentrant +{ + printf("Radio setting: %ld\n", ao_config.radio_setting); +} + +void +ao_config_radio_setting_set(void) __reentrant +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_config.radio_setting = ao_cmd_lex_u32; + ao_config.radio_channel = 0; + _ao_config_edit_finish(); + ao_radio_recv_abort(); +} + +void +ao_config_radio_enable_show(void) __reentrant +{ + printf("Radio enable: %d\n", ao_config.radio_enable); +} + +void +ao_config_radio_enable_set(void) __reentrant +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_config.radio_enable = ao_cmd_lex_i; + _ao_config_edit_finish(); +} + +struct ao_config_var { + __code char *str; + void (*set)(void) __reentrant; + void (*show)(void) __reentrant; +}; + +static void +ao_config_help(void) __reentrant; + +static void +ao_config_show(void) __reentrant; + +static void +ao_config_write(void) __reentrant; + +__code struct ao_config_var ao_config_vars[] = { +#if HAS_ADC + { "m \0Main deploy (in meters)", + ao_config_main_deploy_set, ao_config_main_deploy_show, }, + { "d \0Apogee delay (in seconds)", + ao_config_apogee_delay_set, ao_config_apogee_delay_show }, +#endif /* HAS_ADC */ + { "r \0Radio channel (freq = 434.550 + chan * .1)", + ao_config_radio_channel_set, ao_config_radio_channel_show }, + { "c \0Callsign (8 char max)", + ao_config_callsign_set, ao_config_callsign_show }, + { "R \0Radio freq control (freq = 434.550 * setting/cal)", + ao_config_radio_setting_set, ao_config_radio_setting_show }, + { "e <0 disable, 1 enable>\0Enable telemetry and RDF", + ao_config_radio_enable_set, ao_config_radio_enable_show }, +#if HAS_ACCEL + { "a <+g> <-g>\0Accel calib (0 for auto)", + ao_config_accel_calibrate_set,ao_config_accel_calibrate_show }, +#endif /* HAS_ACCEL */ + { "f \0Radio calib (cal = rf/(xtal/2^16))", + ao_config_radio_cal_set, ao_config_radio_cal_show }, +#if HAS_EEPROM + { "l \0Flight log size in kB", + ao_config_log_set, ao_config_log_show }, +#endif +#if HAS_IGNITE + { "i <0 dual, 1 apogee, 2 main>\0Set igniter mode", + ao_config_ignite_mode_set, ao_config_ignite_mode_show }, +#endif +#if HAS_ACCEL + { "o <0 antenna up, 1 antenna down>\0Set pad orientation", + ao_config_pad_orientation_set,ao_config_pad_orientation_show }, +#endif + { "s\0Show", + ao_config_show, 0 }, +#if HAS_EEPROM + { "w\0Write to eeprom", + ao_config_write, 0 }, +#endif + { "?\0Help", + ao_config_help, 0 }, + { 0, 0, 0 } +}; + +void +ao_config_set(void) +{ + char c; + uint8_t cmd; + void (*__xdata func)(void) __reentrant; + + ao_cmd_white(); + c = ao_cmd_lex_c; + ao_cmd_lex(); + func = 0; + for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++) + if (ao_config_vars[cmd].str[0] == c) { + (*ao_config_vars[cmd].set)(); + return; + } + ao_cmd_status = ao_cmd_syntax_error; +} + +static void +ao_config_help(void) __reentrant +{ + uint8_t cmd; + for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++) + printf("%-20s %s\n", + ao_config_vars[cmd].str, + ao_config_vars[cmd].str+1+strlen(ao_config_vars[cmd].str)); +} + +static void +ao_config_show(void) __reentrant +{ + uint8_t cmd; + printf("Config version: %d.%d\n", + ao_config.major, ao_config.minor); + for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++) + if (ao_config_vars[cmd].show) + (*ao_config_vars[cmd].show)(); +} + +#if HAS_EEPROM +static void +ao_config_write(void) __reentrant +{ + uint8_t saved = 0; + ao_mutex_get(&ao_config_mutex); + if (ao_config_dirty) { + _ao_config_put(); + ao_config_dirty = 0; + saved = 1; + } + ao_mutex_put(&ao_config_mutex); + if (saved) + puts("Saved"); + else + puts("Nothing to save"); +} +#endif + +__code struct ao_cmds ao_config_cmds[] = { + { ao_config_set, "c \0Set config variable (? for help, s to show)" }, + { 0, NULL }, +}; + +void +ao_config_init(void) +{ + ao_cmd_register(&ao_config_cmds[0]); +} diff --git a/src/core/ao_convert.c b/src/core/ao_convert.c new file mode 100644 index 00000000..0969f107 --- /dev/null +++ b/src/core/ao_convert.c @@ -0,0 +1,85 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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. + */ + +#if !defined(AO_CONVERT_TEST) && !defined(AO_FLIGHT_TEST) +#include "ao.h" +#endif + +static const int16_t altitude_table[] = { +#include "altitude.h" +}; + +#define ALT_FRAC_SCALE (1 << ALT_FRAC_BITS) +#define ALT_FRAC_MASK (ALT_FRAC_SCALE - 1) + +int16_t +ao_pres_to_altitude(int16_t pres) __reentrant +{ + uint8_t o; + int16_t part; + + if (pres < 0) + pres = 0; + o = pres >> ALT_FRAC_BITS; + part = pres & ALT_FRAC_MASK; + + return ((int32_t) altitude_table[o] * (ALT_FRAC_SCALE - part) + + (int32_t) altitude_table[o+1] * part + (ALT_FRAC_SCALE >> 1)) >> ALT_FRAC_BITS; +} + +int16_t +ao_altitude_to_pres(int16_t alt) __reentrant +{ + int16_t span, sub_span; + uint8_t l, h, m; + int32_t pres; + + l = 0; + h = NALT - 1; + while ((h - l) != 1) { + m = (l + h) >> 1; + if (altitude_table[m] < alt) + h = m; + else + l = m; + } + span = altitude_table[l] - altitude_table[h]; + sub_span = altitude_table[l] - alt; + pres = ((((int32_t) l * (span - sub_span) + (int32_t) h * sub_span) << ALT_FRAC_BITS) + (span >> 1)) / span; + if (pres > 32767) + pres = 32767; + if (pres < 0) + pres = 0; + return (int16_t) pres; +} + +int16_t +ao_temp_to_dC(int16_t temp) __reentrant +{ + int16_t ret; + + /* Output voltage at 0°C = 0.755V + * Coefficient = 0.00247V/°C + * Reference voltage = 1.25V + * + * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247 + * = (value - 19791.268) / 32768 * 1.25 / 0.00247 + * ≃ (value - 19791) * 1012 / 65536 + */ + ret = ((temp - 19791) * 1012L) >> 16; + return ret; +} diff --git a/src/core/ao_convert_test.c b/src/core/ao_convert_test.c new file mode 100644 index 00000000..e2c28b73 --- /dev/null +++ b/src/core/ao_convert_test.c @@ -0,0 +1,75 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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 +#define AO_CONVERT_TEST +#include "ao_host.h" +#include "ao_convert.c" + +#define STEP 1 + +static inline i_abs(int i) { return i < 0 ? -i : i; } + +main () +{ + int i; + int16_t p_to_a, p_to_a_to_p; + int16_t a_to_p, a_to_p_to_a; + int max_p_error = 0, max_p_error_p = -1; + int max_a_error = 0, max_a_error_a = -1; + int p_error; + int a_error; + int ret = 0; + + for (i = 0; i < 32767 + STEP; i += STEP) { + if (i > 32767) + i = 32767; + p_to_a = ao_pres_to_altitude(i); + p_to_a_to_p = ao_altitude_to_pres(p_to_a); + p_error = i_abs(p_to_a_to_p - i); + if (p_error > max_p_error) { + max_p_error = p_error; + max_p_error_p = i; + } +// printf ("pres %d alt %d pres %d\n", +// i, p_to_a, p_to_a_to_p); + } + for (i = -1578; i < 15835 + STEP; i += STEP) { + if (i > 15835) + i = 15835; + a_to_p = ao_altitude_to_pres(i); + a_to_p_to_a = ao_pres_to_altitude(a_to_p); + a_error = i_abs(a_to_p_to_a - i); + if (a_error > max_a_error) { + max_a_error = a_error; + max_a_error_a = i; + } +// printf ("alt %d pres %d alt %d\n", +// i, a_to_p, a_to_p_to_a); + } + if (max_p_error > 2) { + printf ("max p error %d at %d\n", max_p_error, + max_p_error_p); + ret++; + } + if (max_a_error > 1) { + printf ("max a error %d at %d\n", max_a_error, + max_a_error_a); + ret++; + } + return ret; +} diff --git a/src/core/ao_ee_fake.c b/src/core/ao_ee_fake.c new file mode 100644 index 00000000..b0c1d61e --- /dev/null +++ b/src/core/ao_ee_fake.c @@ -0,0 +1,37 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +/* + * For hardware without eeprom, the config code still + * wants to call these functions + */ +uint8_t +ao_ee_write_config(uint8_t *buf, uint16_t len) __reentrant +{ + (void) buf; + (void) len; + return 1; +} + +uint8_t +ao_ee_read_config(uint8_t *buf, uint16_t len) __reentrant +{ + memset(buf, '\0', len); + return 1; +} diff --git a/src/core/ao_flight.c b/src/core/ao_flight.c new file mode 100644 index 00000000..85c1825b --- /dev/null +++ b/src/core/ao_flight.c @@ -0,0 +1,315 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_FLIGHT_TEST +#include "ao.h" +#endif + +#ifndef HAS_ACCEL +#error Please define HAS_ACCEL +#endif + +#ifndef HAS_GPS +#error Please define HAS_GPS +#endif + +#ifndef HAS_USB +#error Please define HAS_USB +#endif + +/* Main flight thread. */ + +__pdata enum ao_flight_state ao_flight_state; /* current flight state */ +__pdata uint16_t ao_launch_tick; /* time of launch detect */ + +/* + * track min/max data over a long interval to detect + * resting + */ +__pdata uint16_t ao_interval_end; +__pdata int16_t ao_interval_min_height; +__pdata int16_t ao_interval_max_height; +__pdata uint8_t ao_flight_force_idle; + +/* We also have a clock, which can be used to sanity check things in + * case of other failures + */ + +#define BOOST_TICKS_MAX AO_SEC_TO_TICKS(15) + +/* Landing is detected by getting constant readings from both pressure and accelerometer + * for a fairly long time (AO_INTERVAL_TICKS) + */ +#define AO_INTERVAL_TICKS AO_SEC_TO_TICKS(10) + +#define abs(a) ((a) < 0 ? -(a) : (a)) + +void +ao_flight(void) +{ + ao_sample_init(); + ao_flight_state = ao_flight_startup; + for (;;) { + + /* + * Process ADC samples, just looping + * until the sensors are calibrated. + */ + if (!ao_sample()) + continue; + + switch (ao_flight_state) { + case ao_flight_startup: + + /* Check to see what mode we should go to. + * - Invalid mode if accel cal appears to be out + * - pad mode if we're upright, + * - idle mode otherwise + */ +#if HAS_ACCEL + if (ao_config.accel_plus_g == 0 || + ao_config.accel_minus_g == 0 || + ao_ground_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP || + ao_ground_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP) + { + /* Detected an accel value outside -1.5g to 1.5g + * (or uncalibrated values), so we go into invalid mode + */ + ao_flight_state = ao_flight_invalid; + + } else +#endif + if (!ao_flight_force_idle +#if HAS_ACCEL + && ao_ground_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP +#endif + ) + { + /* Set pad mode - we can fly! */ + ao_flight_state = ao_flight_pad; +#if HAS_USB + /* Disable the USB controller in flight mode + * to save power + */ + ao_usb_disable(); +#endif + + /* Disable packet mode in pad state */ + ao_packet_slave_stop(); + + /* Turn on telemetry system */ + ao_rdf_set(1); + ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD); + + /* signal successful initialization by turning off the LED */ + ao_led_off(AO_LED_RED); + } else { + /* Set idle mode */ + ao_flight_state = ao_flight_idle; + + /* signal successful initialization by turning off the LED */ + ao_led_off(AO_LED_RED); + } + /* wakeup threads due to state change */ + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + + break; + case ao_flight_pad: + + /* pad to boost: + * + * barometer: > 20m vertical motion + * OR + * accelerometer: > 2g AND velocity > 5m/s + * + * The accelerometer should always detect motion before + * the barometer, but we use both to make sure this + * transition is detected. If the device + * doesn't have an accelerometer, then ignore the + * speed and acceleration as they are quite noisy + * on the pad. + */ + if (ao_height > AO_M_TO_HEIGHT(20) +#if HAS_ACCEL + || (ao_accel > AO_MSS_TO_ACCEL(20) && + ao_speed > AO_MS_TO_SPEED(5)) +#endif + ) + { + ao_flight_state = ao_flight_boost; + ao_launch_tick = ao_sample_tick; + + /* start logging data */ + ao_log_start(); + + /* Increase telemetry rate */ + ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_FLIGHT); + + /* disable RDF beacon */ + ao_rdf_set(0); + +#if HAS_GPS + /* Record current GPS position by waking up GPS log tasks */ + ao_wakeup(&ao_gps_data); + ao_wakeup(&ao_gps_tracking_data); +#endif + + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + break; + case ao_flight_boost: + + /* boost to fast: + * + * accelerometer: start to fall at > 1/4 G + * OR + * time: boost for more than 15 seconds + * + * Detects motor burn out by the switch from acceleration to + * deceleration, or by waiting until the maximum burn duration + * (15 seconds) has past. + */ + if ((ao_accel < AO_MSS_TO_ACCEL(-2.5) && ao_height > AO_M_TO_HEIGHT(100)) || + (int16_t) (ao_sample_tick - ao_launch_tick) > BOOST_TICKS_MAX) + { +#if HAS_ACCEL + ao_flight_state = ao_flight_fast; +#else + ao_flight_state = ao_flight_coast; +#endif + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + break; +#if HAS_ACCEL + case ao_flight_fast: + /* + * This is essentially the same as coast, + * but the barometer is being ignored as + * it may be unreliable. + */ + if (ao_speed < AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) + { + ao_flight_state = ao_flight_coast; + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + break; +#endif + case ao_flight_coast: + + /* apogee detect: coast to drogue deploy: + * + * speed: < 0 + * + * Also make sure the model altitude is tracking + * the measured altitude reasonably closely; otherwise + * we're probably transsonic. + */ + if (ao_speed < 0 +#if !HAS_ACCEL + && (ao_sample_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 100) +#endif + ) + { + /* ignite the drogue charge */ + ao_ignite(ao_igniter_drogue); + + /* slow down the telemetry system */ + ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_RECOVER); + + /* Turn the RDF beacon back on */ + ao_rdf_set(1); + + /* and enter drogue state */ + ao_flight_state = ao_flight_drogue; + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + + break; + case ao_flight_drogue: + + /* drogue to main deploy: + * + * barometer: reach main deploy altitude + * + * Would like to use the accelerometer for this test, but + * the orientation of the flight computer is unknown after + * drogue deploy, so we ignore it. Could also detect + * high descent rate using the pressure sensor to + * recognize drogue deploy failure and eject the main + * at that point. Perhaps also use the drogue sense lines + * to notice continutity? + */ + if (ao_height <= ao_config.main_deploy) + { + ao_ignite(ao_igniter_main); + + /* + * Start recording min/max height + * to figure out when the rocket has landed + */ + + /* initialize interval values */ + ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; + + ao_interval_min_height = ao_interval_max_height = ao_avg_height; + + ao_flight_state = ao_flight_main; + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + break; + + /* fall through... */ + case ao_flight_main: + + /* main to land: + * + * barometer: altitude stable + */ + + if (ao_avg_height < ao_interval_min_height) + ao_interval_min_height = ao_avg_height; + if (ao_avg_height > ao_interval_max_height) + ao_interval_max_height = ao_avg_height; + + if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) { + if (ao_interval_max_height - ao_interval_min_height <= AO_M_TO_HEIGHT(4)) + { + ao_flight_state = ao_flight_landed; + + /* turn off the ADC capture */ + ao_timer_set_adc_interval(0); + + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + ao_interval_min_height = ao_interval_max_height = ao_avg_height; + ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; + } + break; + case ao_flight_landed: + break; + } + } +} + +static __xdata struct ao_task flight_task; + +void +ao_flight_init(void) +{ + ao_flight_state = ao_flight_startup; + ao_add_task(&flight_task, ao_flight, "flight"); +} diff --git a/src/core/ao_flight_nano.c b/src/core/ao_flight_nano.c new file mode 100644 index 00000000..2e332b12 --- /dev/null +++ b/src/core/ao_flight_nano.c @@ -0,0 +1,120 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +/* Main flight thread. */ + +__pdata enum ao_flight_state ao_flight_state; /* current flight state */ +__pdata uint16_t ao_launch_tick; /* time of launch detect */ + +/* + * track min/max data over a long interval to detect + * resting + */ +__pdata uint16_t ao_interval_end; +__pdata int16_t ao_interval_min_height; +__pdata int16_t ao_interval_max_height; + +__pdata uint8_t ao_flight_force_idle; + +/* Landing is detected by getting constant readings from both pressure and accelerometer + * for a fairly long time (AO_INTERVAL_TICKS) + */ +#define AO_INTERVAL_TICKS AO_SEC_TO_TICKS(5) + +static void +ao_flight_nano(void) +{ + ao_sample_init(); + ao_flight_state = ao_flight_startup; + + for (;;) { + /* + * Process ADC samples, just looping + * until the sensors are calibrated. + */ + if (!ao_sample()) + continue; + + switch (ao_flight_state) { + case ao_flight_startup: + if (ao_flight_force_idle) { + /* Set idle mode */ + ao_flight_state = ao_flight_idle; + } else { + ao_flight_state = ao_flight_pad; + /* Disable packet mode in pad state */ + ao_packet_slave_stop(); + + /* Turn on telemetry system */ + ao_rdf_set(1); + ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD); + } + /* signal successful initialization by turning off the LED */ + ao_led_off(AO_LED_RED); + + /* wakeup threads due to state change */ + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + break; + case ao_flight_pad: + if (ao_height> AO_M_TO_HEIGHT(20)) { + ao_flight_state = ao_flight_drogue; + ao_launch_tick = ao_sample_tick; + + /* start logging data */ + ao_log_start(); + + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + break; + case ao_flight_drogue: + /* drogue/main to land: + * + * barometer: altitude stable + */ + + if (ao_height < ao_interval_min_height) + ao_interval_min_height = ao_height; + if (ao_height > ao_interval_max_height) + ao_interval_max_height = ao_height; + + if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) { + if (ao_interval_max_height - ao_interval_min_height < AO_M_TO_HEIGHT(5)) + { + ao_flight_state = ao_flight_landed; + + /* turn off the ADC capture */ + ao_timer_set_adc_interval(0); + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + ao_interval_min_height = ao_interval_max_height = ao_height; + ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; + } + break; + } + } +} + +static __xdata struct ao_task flight_task; + +void +ao_flight_nano_init(void) +{ + ao_flight_state = ao_flight_startup; + ao_add_task(&flight_task, ao_flight_nano, "flight"); +} diff --git a/src/core/ao_gps_print.c b/src/core/ao_gps_print.c new file mode 100644 index 00000000..fcdedd30 --- /dev/null +++ b/src/core/ao_gps_print.c @@ -0,0 +1,112 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_GPS_TEST +#include "ao.h" +#endif +#include "ao_telem.h" + +void +ao_gps_print(__xdata struct ao_gps_orig *gps_data) __reentrant +{ + 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)) + 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); + + 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, + gps_data->climb_rate, + gps_data->ground_speed, + (int) gps_data->course * 2); + } +} + +void +ao_gps_tracking_print(__xdata struct ao_gps_tracking_orig *gps_tracking_data) __reentrant +{ + uint8_t c, n, v; + __xdata struct ao_gps_sat_orig *sat; + + n = gps_tracking_data->channels; + if (n == 0) + return; + + sat = gps_tracking_data->sats; + v = 0; + for (c = 0; c < n; c++) { + if (sat->svid) + v++; + sat++; + } + + printf (AO_TELEM_SAT_NUM " %d ", + v); + + sat = gps_tracking_data->sats; + v = 0; + for (c = 0; c < n; c++) { + 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++; + } +} diff --git a/src/core/ao_gps_report.c b/src/core/ao_gps_report.c new file mode 100644 index 00000000..e57f8744 --- /dev/null +++ b/src/core/ao_gps_report.c @@ -0,0 +1,99 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_report(void) +{ + static __xdata struct ao_log_record gps_log; + static __xdata struct ao_telemetry_location gps_data; + uint8_t date_reported = 0; + + for (;;) { + ao_sleep(&ao_gps_data); + ao_mutex_get(&ao_gps_mutex); + memcpy(&gps_data, &ao_gps_data, sizeof (ao_gps_data)); + ao_mutex_put(&ao_gps_mutex); + + if (!(gps_data.flags & AO_GPS_VALID)) + continue; + + gps_log.tick = ao_gps_tick; + 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 = gps_data.latitude; + ao_log_data(&gps_log); + gps_log.type = AO_LOG_GPS_LON; + gps_log.u.gps_longitude = gps_data.longitude; + 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); + if (!date_reported && (gps_data.flags & AO_GPS_DATE_VALID)) { + gps_log.type = AO_LOG_GPS_DATE; + gps_log.u.gps_date.year = gps_data.year; + gps_log.u.gps_date.month = gps_data.month; + gps_log.u.gps_date.day = gps_data.day; + gps_log.u.gps_date.extra = 0; + date_reported = ao_log_data(&gps_log); + } + } +} + +void +ao_gps_tracking_report(void) +{ + static __xdata struct ao_log_record gps_log; + static __xdata struct ao_telemetry_satellite gps_tracking_data; + uint8_t c, n; + + for (;;) { + ao_sleep(&ao_gps_tracking_data); + ao_mutex_get(&ao_gps_mutex); + gps_log.tick = ao_gps_tick; + memcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data)); + ao_mutex_put(&ao_gps_mutex); + + if (!(n = gps_tracking_data.channels)) + continue; + + 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.c_n = gps_tracking_data.sats[c].c_n_1; + 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"); +} diff --git a/src/core/ao_host.h b/src/core/ao_host.h new file mode 100644 index 00000000..65c25fe5 --- /dev/null +++ b/src/core/ao_host.h @@ -0,0 +1,127 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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 _GNU_SOURCE + +#include +#include +#include +#include +#include + +#define AO_ADC_RING 64 +#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1)) +#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1)) + +/* + * One set of samples read from the A/D converter + */ +struct ao_adc { + uint16_t tick; /* tick when the sample was read */ + int16_t accel; /* accelerometer */ + int16_t pres; /* pressure sensor */ + int16_t temp; /* temperature sensor */ + int16_t v_batt; /* battery voltage */ + int16_t sense_d; /* drogue continuity sense */ + int16_t sense_m; /* main continuity sense */ +}; + +#define __pdata +#define __data +#define __xdata +#define __code +#define __reentrant + +enum ao_flight_state { + ao_flight_startup = 0, + ao_flight_idle = 1, + ao_flight_pad = 2, + ao_flight_boost = 3, + ao_flight_fast = 4, + ao_flight_coast = 5, + ao_flight_drogue = 6, + ao_flight_main = 7, + ao_flight_landed = 8, + ao_flight_invalid = 9 +}; + +struct ao_adc ao_adc_ring[AO_ADC_RING]; +uint8_t ao_adc_head; + +#define ao_led_on(l) +#define ao_led_off(l) +#define ao_timer_set_adc_interval(i) +#define ao_wakeup(wchan) ao_dump_state(wchan) +#define ao_cmd_register(c) +#define ao_usb_disable() +#define ao_telemetry_set_interval(x) +#define ao_delay(x) + +enum ao_igniter { + ao_igniter_drogue = 0, + ao_igniter_main = 1 +}; + +void +ao_ignite(enum ao_igniter igniter) +{ + printf ("ignite %s\n", igniter == ao_igniter_drogue ? "drogue" : "main"); +} + +struct ao_task { + int dummy; +}; + +#define ao_add_task(t,f,n) + +#define ao_log_start() +#define ao_log_stop() + +#define AO_MS_TO_TICKS(ms) ((ms) / 10) +#define AO_SEC_TO_TICKS(s) ((s) * 100) + +#define AO_FLIGHT_TEST + +struct ao_adc ao_adc_static; + +FILE *emulator_in; + +void +ao_dump_state(void *wchan); + +void +ao_sleep(void *wchan); + +const char const * const ao_state_names[] = { + "startup", "idle", "pad", "boost", "fast", + "coast", "drogue", "main", "landed", "invalid" +}; + +struct ao_cmds { + void (*func)(void); + const char *help; +}; + + +struct ao_config { + uint16_t main_deploy; + int16_t accel_zero_g; +}; + +#define ao_config_get() + +struct ao_config ao_config = { 250, 16000 }; diff --git a/src/core/ao_kalman.c b/src/core/ao_kalman.c new file mode 100644 index 00000000..ee01949e --- /dev/null +++ b/src/core/ao_kalman.c @@ -0,0 +1,292 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_FLIGHT_TEST +#include "ao.h" +#endif + +#include "ao_kalman.h" + +static __pdata int32_t ao_k_height; +static __pdata int32_t ao_k_speed; +static __pdata int32_t ao_k_accel; + +#define AO_K_STEP_100 to_fix16(0.01) +#define AO_K_STEP_2_2_100 to_fix16(0.00005) + +#define AO_K_STEP_10 to_fix16(0.1) +#define AO_K_STEP_2_2_10 to_fix16(0.005) + +#define AO_K_STEP_1 to_fix16(1) +#define AO_K_STEP_2_2_1 to_fix16(0.5) + +__pdata int16_t ao_height; +__pdata int16_t ao_speed; +__pdata int16_t ao_accel; +__pdata int16_t ao_max_height; +static __pdata int32_t ao_avg_height_scaled; +__pdata int16_t ao_avg_height; + +__pdata int16_t ao_error_h; +__pdata int16_t ao_error_h_sq_avg; + +#if HAS_ACCEL +__pdata int16_t ao_error_a; +#endif + +static void +ao_kalman_predict(void) +{ +#ifdef AO_FLIGHT_TEST + if (ao_sample_tick - ao_sample_prev_tick > 50) { + ao_k_height += ((int32_t) ao_speed * AO_K_STEP_1 + + (int32_t) ao_accel * AO_K_STEP_2_2_1) >> 4; + ao_k_speed += (int32_t) ao_accel * AO_K_STEP_1; + + return; + } + if (ao_sample_tick - ao_sample_prev_tick > 5) { + ao_k_height += ((int32_t) ao_speed * AO_K_STEP_10 + + (int32_t) ao_accel * AO_K_STEP_2_2_10) >> 4; + ao_k_speed += (int32_t) ao_accel * AO_K_STEP_10; + + return; + } + if (ao_flight_debug) { + printf ("predict speed %g + (%g * %g) = %g\n", + ao_k_speed / (65536.0 * 16.0), ao_accel / 16.0, AO_K_STEP_100 / 65536.0, + (ao_k_speed + (int32_t) ao_accel * AO_K_STEP_100) / (65536.0 * 16.0)); + } +#endif + ao_k_height += ((int32_t) ao_speed * AO_K_STEP_100 + + (int32_t) ao_accel * AO_K_STEP_2_2_100) >> 4; + ao_k_speed += (int32_t) ao_accel * AO_K_STEP_100; +} + +static void +ao_kalman_err_height(void) +{ + int16_t e; + int16_t height_distrust; +#if HAS_ACCEL + int16_t speed_distrust; +#endif + + ao_error_h = ao_sample_height - (int16_t) (ao_k_height >> 16); + + e = ao_error_h; + if (e < 0) + e = -e; + if (e > 127) + e = 127; +#if HAS_ACCEL + ao_error_h_sq_avg -= ao_error_h_sq_avg >> 2; + ao_error_h_sq_avg += (e * e) >> 2; +#else + ao_error_h_sq_avg -= ao_error_h_sq_avg >> 4; + ao_error_h_sq_avg += (e * e) >> 4; +#endif + + if (ao_flight_state >= ao_flight_drogue) + return; + height_distrust = ao_sample_alt - AO_MAX_BARO_HEIGHT; +#if HAS_ACCEL + /* speed is stored * 16, but we need to ramp between 200 and 328, so + * we want to multiply by 2. The result is a shift by 3. + */ + speed_distrust = (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) >> (4 - 1); + if (speed_distrust <= 0) + speed_distrust = 0; + else if (speed_distrust > height_distrust) + height_distrust = speed_distrust; +#endif + if (height_distrust > 0) { +#ifdef AO_FLIGHT_TEST + int old_ao_error_h = ao_error_h; +#endif + if (height_distrust > 0x100) + height_distrust = 0x100; + ao_error_h = (int16_t) (((int32_t) ao_error_h * (0x100 - height_distrust)) >> 8); +#ifdef AO_FLIGHT_TEST + if (ao_flight_debug) { + printf("over height %g over speed %g distrust: %g height: error %d -> %d\n", + (double) (ao_sample_alt - AO_MAX_BARO_HEIGHT), + (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) / 16.0, + height_distrust / 256.0, + old_ao_error_h, ao_error_h); + } +#endif + } +} + +static void +ao_kalman_correct_baro(void) +{ + ao_kalman_err_height(); +#ifdef AO_FLIGHT_TEST + if (ao_sample_tick - ao_sample_prev_tick > 50) { + ao_k_height += (int32_t) AO_BARO_K0_1 * ao_error_h; + ao_k_speed += (int32_t) AO_BARO_K1_1 * ao_error_h; + ao_k_accel += (int32_t) AO_BARO_K2_1 * ao_error_h; + return; + } + if (ao_sample_tick - ao_sample_prev_tick > 5) { + ao_k_height += (int32_t) AO_BARO_K0_10 * ao_error_h; + ao_k_speed += (int32_t) AO_BARO_K1_10 * ao_error_h; + ao_k_accel += (int32_t) AO_BARO_K2_10 * ao_error_h; + return; + } +#endif + ao_k_height += (int32_t) AO_BARO_K0_100 * ao_error_h; + ao_k_speed += (int32_t) AO_BARO_K1_100 * ao_error_h; + ao_k_accel += (int32_t) AO_BARO_K2_100 * ao_error_h; +} + +#if HAS_ACCEL + +static void +ao_kalman_err_accel(void) +{ + int32_t accel; + + accel = (ao_ground_accel - ao_sample_accel) * ao_accel_scale; + + /* Can't use ao_accel here as it is the pre-prediction value still */ + ao_error_a = (accel - ao_k_accel) >> 16; +} + +static void +ao_kalman_correct_both(void) +{ + ao_kalman_err_height(); + ao_kalman_err_accel(); + +#ifdef AO_FLIGHT_TEST + if (ao_sample_tick - ao_sample_prev_tick > 50) { + if (ao_flight_debug) { + printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n", + ao_k_speed / (65536.0 * 16.0), + (double) ao_error_h, AO_BOTH_K10_1 / 65536.0, + (double) ao_error_a, AO_BOTH_K11_1 / 65536.0, + (ao_k_speed + + (int32_t) AO_BOTH_K10_1 * ao_error_h + + (int32_t) AO_BOTH_K11_1 * ao_error_a) / (65536.0 * 16.0)); + } + ao_k_height += + (int32_t) AO_BOTH_K00_1 * ao_error_h + + (int32_t) AO_BOTH_K01_1 * ao_error_a; + ao_k_speed += + (int32_t) AO_BOTH_K10_1 * ao_error_h + + (int32_t) AO_BOTH_K11_1 * ao_error_a; + ao_k_accel += + (int32_t) AO_BOTH_K20_1 * ao_error_h + + (int32_t) AO_BOTH_K21_1 * ao_error_a; + return; + } + if (ao_sample_tick - ao_sample_prev_tick > 5) { + if (ao_flight_debug) { + printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n", + ao_k_speed / (65536.0 * 16.0), + (double) ao_error_h, AO_BOTH_K10_10 / 65536.0, + (double) ao_error_a, AO_BOTH_K11_10 / 65536.0, + (ao_k_speed + + (int32_t) AO_BOTH_K10_10 * ao_error_h + + (int32_t) AO_BOTH_K11_10 * ao_error_a) / (65536.0 * 16.0)); + } + ao_k_height += + (int32_t) AO_BOTH_K00_10 * ao_error_h + + (int32_t) AO_BOTH_K01_10 * ao_error_a; + ao_k_speed += + (int32_t) AO_BOTH_K10_10 * ao_error_h + + (int32_t) AO_BOTH_K11_10 * ao_error_a; + ao_k_accel += + (int32_t) AO_BOTH_K20_10 * ao_error_h + + (int32_t) AO_BOTH_K21_10 * ao_error_a; + return; + } + if (ao_flight_debug) { + printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n", + ao_k_speed / (65536.0 * 16.0), + (double) ao_error_h, AO_BOTH_K10_100 / 65536.0, + (double) ao_error_a, AO_BOTH_K11_100 / 65536.0, + (ao_k_speed + + (int32_t) AO_BOTH_K10_100 * ao_error_h + + (int32_t) AO_BOTH_K11_100 * ao_error_a) / (65536.0 * 16.0)); + } +#endif + ao_k_height += + (int32_t) AO_BOTH_K00_100 * ao_error_h + + (int32_t) AO_BOTH_K01_100 * ao_error_a; + ao_k_speed += + (int32_t) AO_BOTH_K10_100 * ao_error_h + + (int32_t) AO_BOTH_K11_100 * ao_error_a; + ao_k_accel += + (int32_t) AO_BOTH_K20_100 * ao_error_h + + (int32_t) AO_BOTH_K21_100 * ao_error_a; +} + +#ifdef FORCE_ACCEL +static void +ao_kalman_correct_accel(void) +{ + ao_kalman_err_accel(); + + if (ao_sample_tick - ao_sample_prev_tick > 5) { + ao_k_height +=(int32_t) AO_ACCEL_K0_10 * ao_error_a; + ao_k_speed += (int32_t) AO_ACCEL_K1_10 * ao_error_a; + ao_k_accel += (int32_t) AO_ACCEL_K2_10 * ao_error_a; + return; + } + ao_k_height += (int32_t) AO_ACCEL_K0_100 * ao_error_a; + ao_k_speed += (int32_t) AO_ACCEL_K1_100 * ao_error_a; + ao_k_accel += (int32_t) AO_ACCEL_K2_100 * ao_error_a; +} +#endif +#endif /* HAS_ACCEL */ + +void +ao_kalman(void) +{ + ao_kalman_predict(); +#if HAS_ACCEL + if (ao_flight_state <= ao_flight_coast) { +#ifdef FORCE_ACCEL + ao_kalman_correct_accel(); +#else + ao_kalman_correct_both(); +#endif + } else +#endif + ao_kalman_correct_baro(); + ao_height = from_fix(ao_k_height); + ao_speed = from_fix(ao_k_speed); + ao_accel = from_fix(ao_k_accel); + if (ao_height > ao_max_height) + ao_max_height = ao_height; + ao_avg_height_scaled = ao_avg_height_scaled - ao_avg_height + ao_sample_height; +#ifdef AO_FLIGHT_TEST + if (ao_sample_tick - ao_sample_prev_tick > 50) + ao_avg_height = (ao_avg_height_scaled + 1) >> 1; + else if (ao_sample_tick - ao_sample_prev_tick > 5) + ao_avg_height = (ao_avg_height_scaled + 7) >> 4; + else +#endif + ao_avg_height = (ao_avg_height_scaled + 63) >> 7; +#ifdef AO_FLIGHT_TEST + ao_sample_prev_tick = ao_sample_tick; +#endif +} diff --git a/src/core/ao_log.c b/src/core/ao_log.c new file mode 100644 index 00000000..6d3ad535 --- /dev/null +++ b/src/core/ao_log.c @@ -0,0 +1,284 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +__pdata uint32_t ao_log_current_pos; +__pdata uint32_t ao_log_end_pos; +__pdata uint32_t ao_log_start_pos; +__xdata uint8_t ao_log_running; +__pdata enum flight_state ao_log_state; +__xdata uint16_t ao_flight_number; + +__code uint8_t ao_log_format = AO_LOG_FORMAT_FULL; + +void +ao_log_flush(void) +{ + ao_storage_flush(); +} + +/* + * When erasing a flight log, make sure the config block + * has an up-to-date version of the current flight number + */ + +struct ao_log_erase { + uint8_t unused; + uint16_t flight; +}; + +static __xdata struct ao_log_erase erase; + +#define LOG_MAX_ERASE 16 + +static uint32_t +ao_log_erase_pos(uint8_t i) +{ + return i * sizeof (struct ao_log_erase) + AO_STORAGE_ERASE_LOG; +} + +void +ao_log_write_erase(uint8_t pos) +{ + erase.unused = 0x00; + erase.flight = ao_flight_number; + ao_storage_write(ao_log_erase_pos(pos), &erase, sizeof (erase)); + ao_storage_flush(); +} + +static void +ao_log_read_erase(uint8_t pos) +{ + ao_storage_read(ao_log_erase_pos(pos), &erase, sizeof (erase)); +} + + +static void +ao_log_erase_mark(void) +{ + uint8_t i; + + for (i = 0; i < LOG_MAX_ERASE; i++) { + ao_log_read_erase(i); + if (erase.unused == 0 && erase.flight == ao_flight_number) + return; + if (erase.unused == 0xff) { + ao_log_write_erase(i); + return; + } + } + ao_config_put(); +} + +static uint8_t +ao_log_slots() +{ + return (uint8_t) (ao_storage_config / ao_config.flight_log_max); +} + +uint32_t +ao_log_pos(uint8_t slot) +{ + return ((slot) * ao_config.flight_log_max); +} + +static uint16_t +ao_log_max_flight(void) +{ + uint8_t log_slot; + uint8_t log_slots; + uint16_t log_flight; + uint16_t max_flight = 0; + + /* Scan the log space looking for the biggest flight number */ + log_slots = ao_log_slots(); + for (log_slot = 0; log_slot < log_slots; log_slot++) { + log_flight = ao_log_flight(log_slot); + if (!log_flight) + continue; + if (max_flight == 0 || (int16_t) (log_flight - max_flight) > 0) + max_flight = log_flight; + } + return max_flight; +} + +void +ao_log_scan(void) __reentrant +{ + uint8_t log_slot; + uint8_t log_slots; + uint8_t log_want; + + ao_config_get(); + + ao_flight_number = ao_log_max_flight(); + if (ao_flight_number) + if (++ao_flight_number == 0) + ao_flight_number = 1; + + /* Now look through the log of flight numbers from erase operations and + * see if the last one is bigger than what we found above + */ + for (log_slot = LOG_MAX_ERASE; log_slot-- > 0;) { + ao_log_read_erase(log_slot); + if (erase.unused == 0) { + if (ao_flight_number == 0 || + (int16_t) (erase.flight - ao_flight_number) > 0) + ao_flight_number = erase.flight; + break; + } + } + if (ao_flight_number == 0) + ao_flight_number = 1; + + /* With a flight number in hand, find a place to write a new log, + * use the target flight number to index the available log slots so + * that we write logs to each spot about the same number of times. + */ + + /* Find a log slot for the next flight, if available */ + ao_log_current_pos = ao_log_end_pos = 0; + log_slots = ao_log_slots(); + log_want = (ao_flight_number - 1) % log_slots; + log_slot = log_want; + do { + if (ao_log_flight(log_slot) == 0) { + ao_log_current_pos = ao_log_pos(log_slot); + ao_log_end_pos = ao_log_current_pos + ao_config.flight_log_max; + break; + } + if (++log_slot >= log_slots) + log_slot = 0; + } while (log_slot != log_want); + + ao_wakeup(&ao_flight_number); +} + +void +ao_log_start(void) +{ + /* start logging */ + ao_log_running = 1; + ao_wakeup(&ao_log_running); +} + +void +ao_log_stop(void) +{ + ao_log_running = 0; + ao_log_flush(); +} + +uint8_t +ao_log_present(void) +{ + return ao_log_max_flight() != 0; +} + +uint8_t +ao_log_full(void) +{ + return ao_log_current_pos == ao_log_end_pos; +} + +static __xdata struct ao_task ao_log_task; + +void +ao_log_list(void) __reentrant +{ + uint8_t slot; + uint8_t slots; + uint16_t flight; + + slots = ao_log_slots(); + for (slot = 0; slot < slots; slot++) + { + flight = ao_log_flight(slot); + if (flight) + printf ("flight %d start %x end %x\n", + flight, + (uint16_t) (ao_log_pos(slot) >> 8), + (uint16_t) (ao_log_pos(slot+1) >> 8)); + } + printf ("done\n"); +} + +void +ao_log_delete(void) __reentrant +{ + uint8_t slot; + uint8_t slots; + + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + + slots = ao_log_slots(); + /* Look for the flight log matching the requested flight */ + if (ao_cmd_lex_i) { + for (slot = 0; slot < slots; slot++) { + if (ao_log_flight(slot) == ao_cmd_lex_i) { + ao_log_erase_mark(); + ao_log_current_pos = ao_log_pos(slot); + ao_log_end_pos = ao_log_current_pos + ao_config.flight_log_max; + while (ao_log_current_pos < ao_log_end_pos) { + uint8_t i; + static __xdata uint8_t b; + + /* + * Check to see if we've reached the end of + * the used memory to avoid re-erasing the same + * memory over and over again + */ + for (i = 0; i < 16; i++) { + if (ao_storage_read(ao_log_current_pos + i, &b, 1)) + if (b != 0xff) + break; + } + if (i == 16) + break; + ao_storage_erase(ao_log_current_pos); + ao_log_current_pos += ao_storage_block; + } + puts("Erased"); + return; + } + } + } + printf("No such flight: %d\n", ao_cmd_lex_i); +} + +__code struct ao_cmds ao_log_cmds[] = { + { ao_log_list, "l\0List flight logs" }, + { ao_log_delete, "d \0Delete flight" }, + { 0, NULL }, +}; + +void +ao_log_init(void) +{ + ao_log_running = 0; + + /* For now, just log the flight starting at the begining of eeprom */ + ao_log_state = ao_flight_invalid; + + ao_cmd_register(&ao_log_cmds[0]); + + /* Create a task to log events to eeprom */ + ao_add_task(&ao_log_task, ao_log, "log"); +} diff --git a/src/core/ao_log_big.c b/src/core/ao_log_big.c new file mode 100644 index 00000000..74d94c4b --- /dev/null +++ b/src/core/ao_log_big.c @@ -0,0 +1,158 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +static __xdata uint8_t ao_log_mutex; +static __xdata struct ao_log_record log; + +static uint8_t +ao_log_csum(__xdata uint8_t *b) __reentrant +{ + uint8_t sum = 0x5a; + uint8_t i; + + for (i = 0; i < sizeof (struct ao_log_record); i++) + sum += *b++; + return -sum; +} + +uint8_t +ao_log_data(__xdata struct ao_log_record *log) __reentrant +{ + uint8_t wrote = 0; + /* set checksum */ + log->csum = 0; + log->csum = ao_log_csum((__xdata uint8_t *) log); + ao_mutex_get(&ao_log_mutex); { + if (ao_log_current_pos >= ao_log_end_pos && ao_log_running) + ao_log_stop(); + if (ao_log_running) { + wrote = 1; + ao_storage_write(ao_log_current_pos, + log, + sizeof (struct ao_log_record)); + ao_log_current_pos += sizeof (struct ao_log_record); + } + } ao_mutex_put(&ao_log_mutex); + return wrote; +} + +static uint8_t +ao_log_dump_check_data(void) +{ + if (ao_log_csum((uint8_t *) &log) != 0) + return 0; + return 1; +} + +static __data uint8_t ao_log_adc_pos; + +/* a hack to make sure that ao_log_records fill the eeprom block in even units */ +typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_record))] ; + +#define AO_SENSOR_INTERVAL_ASCENT 1 +#define AO_SENSOR_INTERVAL_DESCENT 10 +#define AO_OTHER_INTERVAL 32 + +void +ao_log(void) +{ + __pdata uint16_t next_sensor, next_other; + + ao_storage_setup(); + + ao_log_scan(); + + while (!ao_log_running) + ao_sleep(&ao_log_running); + + log.type = AO_LOG_FLIGHT; + log.tick = ao_sample_tick; +#if HAS_ACCEL + log.u.flight.ground_accel = ao_ground_accel; +#endif + log.u.flight.flight = ao_flight_number; + ao_log_data(&log); + + /* Write the whole contents of the ring to the log + * when starting up. + */ + ao_log_adc_pos = ao_adc_ring_next(ao_sample_adc); + next_other = next_sensor = ao_adc_ring[ao_log_adc_pos].tick; + ao_log_state = ao_flight_startup; + for (;;) { + /* Write samples to EEPROM */ + while (ao_log_adc_pos != ao_sample_adc) { + log.tick = ao_adc_ring[ao_log_adc_pos].tick; + if ((int16_t) (log.tick - next_sensor) >= 0) { + log.type = AO_LOG_SENSOR; + log.u.sensor.accel = ao_adc_ring[ao_log_adc_pos].accel; + log.u.sensor.pres = ao_adc_ring[ao_log_adc_pos].pres; + ao_log_data(&log); + if (ao_log_state <= ao_flight_coast) + next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT; + else + next_sensor = log.tick + AO_SENSOR_INTERVAL_DESCENT; + } + if ((int16_t) (log.tick - next_other) >= 0) { + log.type = AO_LOG_TEMP_VOLT; + log.u.temp_volt.temp = ao_adc_ring[ao_log_adc_pos].temp; + log.u.temp_volt.v_batt = ao_adc_ring[ao_log_adc_pos].v_batt; + ao_log_data(&log); + log.type = AO_LOG_DEPLOY; + log.u.deploy.drogue = ao_adc_ring[ao_log_adc_pos].sense_d; + log.u.deploy.main = ao_adc_ring[ao_log_adc_pos].sense_m; + ao_log_data(&log); + next_other = log.tick + AO_OTHER_INTERVAL; + } + ao_log_adc_pos = ao_adc_ring_next(ao_log_adc_pos); + } + /* Write state change to EEPROM */ + if (ao_flight_state != ao_log_state) { + ao_log_state = ao_flight_state; + log.type = AO_LOG_STATE; + log.tick = ao_sample_tick; + log.u.state.state = ao_log_state; + log.u.state.reason = 0; + ao_log_data(&log); + + if (ao_log_state == ao_flight_landed) + ao_log_stop(); + } + + /* Wait for a while */ + ao_delay(AO_MS_TO_TICKS(100)); + + /* Stop logging when told to */ + while (!ao_log_running) + ao_sleep(&ao_log_running); + } +} + +uint16_t +ao_log_flight(uint8_t slot) +{ + if (!ao_storage_read(ao_log_pos(slot), + &log, + sizeof (struct ao_log_record))) + return 0; + + if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT) + return log.u.flight.flight; + return 0; +} diff --git a/src/core/ao_log_telem.c b/src/core/ao_log_telem.c new file mode 100644 index 00000000..1b472efe --- /dev/null +++ b/src/core/ao_log_telem.c @@ -0,0 +1,30 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_log_write_erase(uint8_t pos) +{ + (void) pos; +} + +uint8_t +ao_log_present(void) +{ + return 0; +} diff --git a/src/core/ao_log_tiny.c b/src/core/ao_log_tiny.c new file mode 100644 index 00000000..d5a3b99f --- /dev/null +++ b/src/core/ao_log_tiny.c @@ -0,0 +1,161 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +static __data uint16_t ao_log_tiny_interval; + +#define AO_LOG_TINY_INTERVAL_DEFAULT AO_MS_TO_TICKS(1000) +#if USE_FAST_ASCENT_LOG +#define AO_LOG_TINY_INTERVAL_ASCENT AO_MS_TO_TICKS(100) +#define AO_PAD_RING 8 +#else +#define AO_LOG_TINY_INTERVAL_ASCENT AO_LOG_TINY_INTERVAL_DEFAULT +#define AO_PAD_RING 2 +#endif + +__code uint8_t ao_log_format = AO_LOG_FORMAT_TINY; + +void +ao_log_tiny_set_interval(uint16_t ticks) +{ + ao_log_tiny_interval = ticks; +} + + +static void ao_log_tiny_data(uint16_t d) +{ + if (ao_log_current_pos >= ao_log_end_pos && ao_log_running) + ao_log_stop(); + if (ao_log_running) { + ao_storage_write(ao_log_current_pos, DATA_TO_XDATA(&d), 2); + ao_log_current_pos += 2; + } +} + +static __xdata uint16_t ao_log_pad_ring[AO_PAD_RING]; +static __pdata uint8_t ao_log_pad_ring_pos; + +#define ao_pad_ring_next(n) (((n) + 1) & (AO_PAD_RING - 1)) + +static void ao_log_tiny_queue(uint16_t d) +{ + ao_log_pad_ring[ao_log_pad_ring_pos] = d; + ao_log_pad_ring_pos = ao_pad_ring_next(ao_log_pad_ring_pos); +} + +static void ao_log_tiny_start(void) +{ + uint8_t p; + uint16_t d; + + ao_log_tiny_data(ao_flight_number); + ao_log_tiny_data(ao_ground_pres); + p = ao_log_pad_ring_pos; + do { + d = ao_log_pad_ring[p]; + /* + * ignore unwritten slots + */ + if (d) + ao_log_tiny_data(d); + p = ao_pad_ring_next(p); + } while (p != ao_log_pad_ring_pos); +} + +void +ao_log(void) +{ + uint16_t last_time; + uint16_t now; + enum ao_flight_state ao_log_tiny_state; + int32_t sum; + int16_t count; + uint8_t ao_log_adc; + uint8_t ao_log_started = 0; + + ao_storage_setup(); + + ao_log_scan(); + + ao_log_tiny_state = ao_flight_invalid; + ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_ASCENT; + sum = 0; + count = 0; + ao_log_adc = ao_sample_adc; + last_time = ao_time(); + for (;;) { + + /* + * Add in pending sample data + */ + ao_sleep(DATA_TO_XDATA(&ao_sample_adc)); + while (ao_log_adc != ao_sample_adc) { + sum += ao_adc_ring[ao_log_adc].pres; + count++; + ao_log_adc = ao_adc_ring_next(ao_log_adc); + } + if (ao_log_running) { + if (!ao_log_started) { + ao_log_tiny_start(); + ao_log_started = 1; + } + if (ao_flight_state != ao_log_tiny_state) { + ao_log_tiny_data(ao_flight_state | 0x8000); + ao_log_tiny_state = ao_flight_state; + ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_DEFAULT; +#if AO_LOG_TINY_INTERVAL_ASCENT != AO_LOG_TINY_INTERVAL_DEFAULT + if (ao_log_tiny_state <= ao_flight_coast) + ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_ASCENT; +#endif + if (ao_log_tiny_state == ao_flight_landed) + ao_log_stop(); + } + } + + /* Stop logging when told to */ + if (!ao_log_running && ao_log_started) + ao_exit(); + + /* + * Write out the sample when finished + */ + now = ao_time(); + if ((int16_t) (now - (last_time + ao_log_tiny_interval)) >= 0 && count) { + count = sum / count; + if (ao_log_started) + ao_log_tiny_data(count); + else + ao_log_tiny_queue(count); + sum = 0; + count = 0; + last_time = now; + } + } +} + +uint16_t +ao_log_flight(uint8_t slot) +{ + static __xdata uint16_t flight; + + (void) slot; + ao_storage_read(0, &flight, 2); + if (flight == 0xffff) + flight = 0; + return flight; +} diff --git a/src/core/ao_monitor.c b/src/core/ao_monitor.c new file mode 100644 index 00000000..69eb58e8 --- /dev/null +++ b/src/core/ao_monitor.c @@ -0,0 +1,277 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" +#include "ao_telem.h" + +#if !HAS_MONITOR +#error Must define HAS_MONITOR to 1 +#endif + +__xdata uint8_t ao_monitoring; +__pdata uint8_t ao_monitor_led; + +#define AO_MONITOR_RING 8 + +__xdata union ao_monitor { + struct ao_telemetry_raw_recv raw; + struct ao_telemetry_orig_recv orig; + struct ao_telemetry_tiny_recv tiny; +} ao_monitor_ring[AO_MONITOR_RING]; + +#define ao_monitor_ring_next(n) (((n) + 1) & (AO_MONITOR_RING - 1)) + +__data uint8_t ao_monitor_head; + +void +ao_monitor_get(void) +{ + uint8_t size; + + for (;;) { + switch (ao_monitoring) { + case 0: + ao_sleep(&ao_monitoring); + continue; + case AO_MONITORING_ORIG: + size = sizeof (struct ao_telemetry_orig_recv); + break; + case AO_MONITORING_TINY: + size = sizeof (struct ao_telemetry_tiny_recv); + break; + default: + if (ao_monitoring > AO_MAX_TELEMETRY) + ao_monitoring = AO_MAX_TELEMETRY; + size = ao_monitoring; + break; + } + if (!ao_radio_recv(&ao_monitor_ring[ao_monitor_head], size + 2)) + continue; + ao_monitor_head = ao_monitor_ring_next(ao_monitor_head); + ao_wakeup(DATA_TO_XDATA(&ao_monitor_head)); + ao_led_toggle(ao_monitor_led); + } +} + +void +ao_monitor_put(void) +{ + __xdata char callsign[AO_MAX_CALLSIGN+1]; + + uint8_t ao_monitor_tail; + uint8_t state; + uint8_t sum, byte; + int16_t rssi; + __xdata union ao_monitor *m; + +#define recv_raw ((m->raw)) +#define recv_orig ((m->orig)) +#define recv_tiny ((m->tiny)) + + ao_monitor_tail = ao_monitor_head; + for (;;) { + while (ao_monitor_tail == ao_monitor_head) + ao_sleep(DATA_TO_XDATA(&ao_monitor_head)); + m = &ao_monitor_ring[ao_monitor_tail]; + ao_monitor_tail = ao_monitor_ring_next(ao_monitor_tail); + switch (ao_monitoring) { + case AO_MONITORING_ORIG: + state = recv_orig.telemetry_orig.flight_state; + + /* Typical RSSI offset for 38.4kBaud at 433 MHz is 74 */ + rssi = (int16_t) (recv_orig.rssi >> 1) - 74; + memcpy(callsign, recv_orig.telemetry_orig.callsign, AO_MAX_CALLSIGN); + if (state > ao_flight_invalid) + state = ao_flight_invalid; + if (recv_orig.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_orig.telemetry_orig.serial, + recv_orig.telemetry_orig.flight, + rssi, + ao_state_names[state], + recv_orig.telemetry_orig.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_orig.telemetry_orig.adc.accel, + recv_orig.telemetry_orig.adc.pres, + recv_orig.telemetry_orig.adc.temp, + recv_orig.telemetry_orig.adc.v_batt, + recv_orig.telemetry_orig.adc.sense_d, + recv_orig.telemetry_orig.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_orig.telemetry_orig.ground_accel, + recv_orig.telemetry_orig.ground_pres, + recv_orig.telemetry_orig.accel_plus_g, + recv_orig.telemetry_orig.accel_minus_g); + + if (recv_orig.telemetry_orig.u.k.unused == 0x8000) { + /* Kalman state values */ + printf(AO_TELEM_KALMAN_HEIGHT " %d " + AO_TELEM_KALMAN_SPEED " %d " + AO_TELEM_KALMAN_ACCEL " %d ", + recv_orig.telemetry_orig.height, + recv_orig.telemetry_orig.u.k.speed, + recv_orig.telemetry_orig.accel); + } else { + /* Ad-hoc flight values */ + printf(AO_TELEM_ADHOC_ACCEL " %d " + AO_TELEM_ADHOC_SPEED " %ld " + AO_TELEM_ADHOC_BARO " %d ", + recv_orig.telemetry_orig.accel, + recv_orig.telemetry_orig.u.flight_vel, + recv_orig.telemetry_orig.height); + } + ao_gps_print(&recv_orig.telemetry_orig.gps); + ao_gps_tracking_print(&recv_orig.telemetry_orig.gps_tracking); + putchar('\n'); + ao_rssi_set(rssi); + } else { + printf("CRC INVALID RSSI %3d\n", rssi); + } + break; + case AO_MONITORING_TINY: + 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); + } + break; + default: + printf ("TELEM %02x", ao_monitoring + 2); + sum = 0x5a; + for (state = 0; state < ao_monitoring + 2; state++) { + byte = recv_raw.packet[state]; + sum += byte; + printf("%02x", byte); + } + printf("%02x\n", sum); + break; + } + ao_usb_flush(); + } +} + +__xdata struct ao_task ao_monitor_get_task; +__xdata struct ao_task ao_monitor_put_task; + +void +ao_set_monitor(uint8_t monitoring) +{ + if (ao_monitoring) + ao_radio_recv_abort(); + ao_monitoring = monitoring; + ao_wakeup(&ao_monitoring); +} + +static void +set_monitor(void) +{ + ao_cmd_hex(); + ao_set_monitor(ao_cmd_lex_i); +} + +__code struct ao_cmds ao_monitor_cmds[] = { + { set_monitor, "m <0 off, 1 full, 2 tiny>\0Enable/disable radio monitoring" }, + { 0, NULL }, +}; + +void +ao_monitor_init(uint8_t monitor_led, uint8_t monitoring) __reentrant +{ + ao_monitor_led = monitor_led; + ao_monitoring = monitoring; + ao_cmd_register(&ao_monitor_cmds[0]); + ao_add_task(&ao_monitor_get_task, ao_monitor_get, "monitor_get"); + ao_add_task(&ao_monitor_put_task, ao_monitor_put, "monitor_put"); +} diff --git a/src/core/ao_mutex.c b/src/core/ao_mutex.c new file mode 100644 index 00000000..c82a7d57 --- /dev/null +++ b/src/core/ao_mutex.c @@ -0,0 +1,41 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_mutex_get(__xdata uint8_t *mutex) __reentrant +{ + if (*mutex == ao_cur_task->task_id) + ao_panic(AO_PANIC_MUTEX); + __critical { + while (*mutex) + ao_sleep(mutex); + *mutex = ao_cur_task->task_id; + } +} + +void +ao_mutex_put(__xdata uint8_t *mutex) __reentrant +{ + if (*mutex != ao_cur_task->task_id) + ao_panic(AO_PANIC_MUTEX); + __critical { + *mutex = 0; + ao_wakeup(mutex); + } +} diff --git a/src/core/ao_panic.c b/src/core/ao_panic.c new file mode 100644 index 00000000..fdada201 --- /dev/null +++ b/src/core/ao_panic.c @@ -0,0 +1,66 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +#ifndef HAS_BEEP +#error Please define HAS_BEEP +#endif + +#if !HAS_BEEP +#define ao_beep(x) +#endif + +static void +ao_panic_delay(uint8_t n) +{ + uint8_t i = 0, j = 0; + + while (n--) + while (--j) + while (--i) + _asm nop _endasm; +} + +void +ao_panic(uint8_t reason) +{ + 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_panic_delay(1); + ao_led_off(AO_LED_RED); + ao_beep(AO_BEEP_LOW); + ao_panic_delay(1); + } + 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_panic_delay(10); + ao_led_off(AO_LED_RED); + ao_beep(AO_BEEP_OFF); + ao_panic_delay(10); + } + } +} diff --git a/src/core/ao_pins.h b/src/core/ao_pins.h new file mode 100644 index 00000000..e1f5459f --- /dev/null +++ b/src/core/ao_pins.h @@ -0,0 +1,408 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_PINS_H_ +#define _AO_PINS_H_ + +#if defined(TELEMETRUM_V_1_0) + #define HAS_FLIGHT 1 + #define HAS_USB 1 + #define HAS_BEEP 1 + #define HAS_GPS 1 + #define HAS_SERIAL_1 1 + #define HAS_ADC 1 + #define USE_SERIAL_STDIN 0 + #define HAS_EEPROM 1 + #define USE_INTERNAL_FLASH 0 + #define HAS_DBG 1 + #define DBG_ON_P1 1 + #define DBG_ON_P0 0 + #define IGNITE_ON_P2 1 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 0 + #define PACKET_HAS_SLAVE 1 + + #define HAS_COMPANION 1 + #define COMPANION_CS_ON_P1 1 + #define COMPANION_CS_MASK 0x4 /* CS1 is P1_2 */ + #define COMPANION_CS P1_2 + + #define AO_LED_RED 1 + #define LEDS_AVAILABLE (AO_LED_RED) + #define HAS_EXTERNAL_TEMP 0 + #define HAS_ACCEL_REF 0 + #define HAS_ACCEL 1 + #define HAS_IGNITE 1 + #define HAS_MONITOR 0 +#endif + +#if defined(TELEMETRUM_V_1_1) + #define HAS_FLIGHT 1 + #define HAS_USB 1 + #define HAS_BEEP 1 + #define HAS_GPS 1 + #define HAS_SERIAL_1 1 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 1 + #define HAS_EEPROM 1 + #define USE_INTERNAL_FLASH 0 + #define HAS_DBG 1 + #define DBG_ON_P1 1 + #define DBG_ON_P0 0 + #define IGNITE_ON_P2 1 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 0 + #define PACKET_HAS_SLAVE 1 + + #define HAS_COMPANION 1 + #define COMPANION_CS_ON_P1 1 + #define COMPANION_CS_MASK 0x4 /* CS1 is P1_2 */ + #define COMPANION_CS P1_2 + + #define AO_LED_RED 1 + #define LEDS_AVAILABLE (AO_LED_RED) + #define HAS_EXTERNAL_TEMP 0 + #define HAS_ACCEL_REF 1 + #define SPI_CS_ON_P1 1 + #define SPI_CS_ON_P0 0 + #define M25_CS_MASK 0x02 /* CS0 is P1_1 */ + #define M25_MAX_CHIPS 1 + #define HAS_ACCEL 1 + #define HAS_IGNITE 1 + #define HAS_MONITOR 0 +#endif + +#if defined(TELEDONGLE_V_0_2) + #define HAS_FLIGHT 0 + #define HAS_USB 1 + #define HAS_BEEP 0 + #define HAS_SERIAL_1 0 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 0 + #define HAS_DBG 1 + #define HAS_EEPROM 0 + #define DBG_ON_P1 1 + #define DBG_ON_P0 0 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 1 + #define PACKET_HAS_SLAVE 0 + #define AO_LED_RED 1 + #define AO_LED_GREEN 2 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define SPI_CS_ON_P1 1 + #define SPI_CS_ON_P0 0 + #define HAS_IGNITE 0 + #define HAS_MONITOR 1 +#endif + +#if defined(TELEMINI_V_1_0) + #define HAS_FLIGHT 1 + #define HAS_USB 0 + #define HAS_BEEP 0 + #define HAS_GPS 0 + #define HAS_SERIAL_1 0 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 1 + #define HAS_EEPROM 1 + #define USE_INTERNAL_FLASH 1 + #define HAS_DBG 0 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 1 + #define PACKET_HAS_MASTER 0 + #define PACKET_HAS_SLAVE 1 + #define USE_FAST_ASCENT_LOG 1 + + #define AO_LED_GREEN 1 + #define AO_LED_RED 2 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define HAS_EXTERNAL_TEMP 0 + #define HAS_ACCEL 0 + #define HAS_IGNITE 1 + #define HAS_MONITOR 0 +#endif + +#if defined(TELENANO_V_0_1) + #define HAS_FLIGHT 1 + #define HAS_USB 0 + #define HAS_BEEP 0 + #define HAS_GPS 0 + #define HAS_SERIAL_1 0 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 1 + #define HAS_EEPROM 1 + #define USE_INTERNAL_FLASH 1 + #define HAS_DBG 0 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 1 + #define PACKET_HAS_MASTER 0 + #define PACKET_HAS_SLAVE 1 + + #define AO_LED_GREEN 1 + #define AO_LED_RED 2 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define HAS_EXTERNAL_TEMP 0 + #define HAS_ACCEL 0 + #define HAS_IGNITE 0 + #define HAS_MONITOR 0 +#endif + +#if defined(TELEMETRUM_V_0_1) + #define HAS_FLIGHT 1 + #define HAS_USB 1 + #define HAS_BEEP 1 + #define HAS_GPS 1 + #define HAS_SERIAL_1 1 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 1 + #define HAS_DBG 0 + #define HAS_EEPROM 1 + #define USE_INTERNAL_FLASH 0 + #define DBG_ON_P1 0 + #define DBG_ON_P0 1 + #define IGNITE_ON_P2 1 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 0 + #define PACKET_HAS_SLAVE 1 + #define AO_LED_RED 2 + #define AO_LED_GREEN 1 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define HAS_EXTERNAL_TEMP 1 + #define HAS_ACCEL_REF 0 + #define SPI_CS_ON_P1 1 + #define SPI_CS_ON_P0 0 + #define HAS_ACCEL 1 + #define HAS_IGNITE 1 + #define HAS_MONITOR 0 +#endif + +#if defined(TELEDONGLE_V_0_1) + #define HAS_FLIGHT 0 + #define HAS_USB 1 + #define HAS_BEEP 0 + #define HAS_SERIAL_1 0 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 0 + #define HAS_DBG 0 + #define HAS_EEPROM 0 + #define DBG_ON_P1 0 + #define DBG_ON_P0 1 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 1 + #define PACKET_HAS_SLAVE 0 + #define AO_LED_RED 2 + #define AO_LED_GREEN 1 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define SPI_CS_ON_P1 0 + #define SPI_CS_ON_P0 1 + #define HAS_IGNITE 0 + #define HAS_MONITOR 1 +#endif + +#if defined(TIDONGLE) + #define HAS_FLIGHT 0 + #define HAS_USB 1 + #define HAS_BEEP 0 + #define HAS_SERIAL_1 0 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 0 + #define HAS_DBG 1 + #define HAS_EEPROM 0 + #define DBG_ON_P1 0 + #define DBG_ON_P0 1 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 1 + #define PACKET_HAS_SLAVE 0 + #define AO_LED_RED 2 + #define LEDS_AVAILABLE (AO_LED_RED) + #define SPI_CS_ON_P1 0 + #define SPI_CS_ON_P0 1 + #define HAS_IGNITE 0 + #define HAS_MONITOR 1 +#endif + +#if defined(TELEBT_V_0_0) + #define HAS_FLIGHT 0 + #define HAS_USB 1 + #define HAS_BEEP 0 + #define HAS_SERIAL_1 1 + #define USE_SERIAL_STDIN 1 + #define HAS_ADC 0 + #define HAS_DBG 1 + #define HAS_EEPROM 0 + #define HAS_BTM 1 + #define DBG_ON_P1 0 + #define DBG_ON_P0 1 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 1 + #define PACKET_HAS_SLAVE 0 + #define AO_LED_RED 2 + #define AO_LED_GREEN 1 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define SPI_CS_ON_P1 1 + #define SPI_CS_ON_P0 0 + #define HAS_IGNITE 0 + #define BT_LINK_ON_P2 1 + #define BT_LINK_ON_P1 0 + #define BT_LINK_PIN_INDEX 7 + #define BT_LINK_PIN P2_1 + #define HAS_MONITOR 1 +#endif + +#if defined(TELEBT_V_0_1) + #define HAS_FLIGHT 0 + #define HAS_USB 1 + #define HAS_BEEP 1 + #define HAS_SERIAL_1 1 + #define HAS_SERIAL_1_ALT_1 1 + #define HAS_SERIAL_1_ALT_2 0 + #define HAS_SERIAL_1_HW_FLOW 1 + #define USE_SERIAL_STDIN 1 + #define HAS_ADC 0 + #define HAS_DBG 1 + #define HAS_EEPROM 1 + #define USE_INTERNAL_FLASH 0 + #define HAS_BTM 1 + #define DBG_ON_P1 1 + #define DBG_ON_P0 0 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 1 + #define PACKET_HAS_SLAVE 0 + #define AO_LED_RED 1 + #define AO_LED_GREEN 2 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define SPI_CS_ON_P1 1 + #define SPI_CS_ON_P0 0 + #define M25_CS_MASK 0x04 /* CS0 is P1_2 */ + #define M25_MAX_CHIPS 1 + #define HAS_ACCEL 0 + #define HAS_IGNITE 0 + #define BT_LINK_ON_P2 0 + #define BT_LINK_ON_P1 1 + #define BT_LINK_PIN_INDEX 7 + #define BT_LINK_PIN P1_7 + #define HAS_MONITOR 1 +#endif + +#if DBG_ON_P1 + + #define DBG_CLOCK (1 << 4) /* mi0 */ + #define DBG_DATA (1 << 5) /* mo0 */ + #define DBG_RESET_N (1 << 3) /* c0 */ + + #define DBG_CLOCK_PIN (P1_4) + #define DBG_DATA_PIN (P1_5) + #define DBG_RESET_N_PIN (P1_3) + + #define DBG_PORT_NUM 1 + #define DBG_PORT P1 + #define DBG_PORT_SEL P1SEL + #define DBG_PORT_INP P1INP + #define DBG_PORT_DIR P1DIR + +#endif /* DBG_ON_P1 */ + +#if DBG_ON_P0 + + #define DBG_CLOCK (1 << 3) + #define DBG_DATA (1 << 4) + #define DBG_RESET_N (1 << 5) + + #define DBG_CLOCK_PIN (P0_3) + #define DBG_DATA_PIN (P0_4) + #define DBG_RESET_N_PIN (P0_5) + + #define DBG_PORT_NUM 0 + #define DBG_PORT P0 + #define DBG_PORT_SEL P0SEL + #define DBG_PORT_INP P0INP + #define DBG_PORT_DIR P0DIR + +#endif /* DBG_ON_P0 */ + +#if COMPANION_CS_ON_P1 + #define COMPANION_CS_PORT P1 + #define COMPANION_CS_SEL P1SEL + #define COMPANION_CS_DIR P1DIR +#endif + +#if SPI_CS_ON_P1 + #define SPI_CS_PORT P1 + #define SPI_CS_SEL P1SEL + #define SPI_CS_DIR P1DIR +#endif + +#if SPI_CS_ON_P0 + #define SPI_CS_PORT P0 + #define SPI_CS_SEL P0SEL + #define SPI_CS_DIR P0DIR +#endif + +#ifndef IGNITE_ON_P2 +#error Please define IGNITE_ON_P2 +#endif + +#ifndef IGNITE_ON_P0 +#error Please define IGNITE_ON_P0 +#endif + +#ifndef HAS_SERIAL_1 +#error Please define HAS_SERIAL_1 +#endif + +#ifndef USE_SERIAL_STDIN +#error Please define USE_SERIAL_STDIN +#endif + +#ifndef HAS_ADC +#error Please define HAS_ADC +#endif + +#ifndef HAS_EEPROM +#error Please define HAS_EEPROM +#endif + +#if HAS_EEPROM +#ifndef USE_INTERNAL_FLASH +#error Please define USE_INTERNAL_FLASH +#endif +#endif + +#ifndef HAS_DBG +#error Please define HAS_DBG +#endif + +#ifndef HAS_IGNITE +#error Please define HAS_IGNITE +#endif + +#ifndef PACKET_HAS_MASTER +#error Please define PACKET_HAS_MASTER +#endif + +#ifndef PACKET_HAS_SLAVE +#error Please define PACKET_HAS_SLAVE +#endif + +#ifndef HAS_MONITOR +#error Please define HAS_MONITOR +#endif +#endif /* _AO_PINS_H_ */ diff --git a/src/core/ao_product.c b/src/core/ao_product.c new file mode 100644 index 00000000..fb59580b --- /dev/null +++ b/src/core/ao_product.c @@ -0,0 +1,155 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" +#include "ao_product.h" + +/* Defines which mark this particular AltOS product */ + +const char ao_version[AO_MAX_VERSION] = AO_iVersion_STRING; +const char ao_manufacturer[] = AO_iManufacturer_STRING; +const char ao_product[] = AO_iProduct_STRING; + +#define LE_WORD(x) ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8)) + +#if HAS_USB +#include "ao_usb.h" +/* USB descriptors in one giant block of bytes */ +__code __at(0x00aa) uint8_t ao_usb_descriptors [] = +{ + /* Device descriptor */ + 0x12, + AO_USB_DESC_DEVICE, + LE_WORD(0x0110), /* bcdUSB */ + 0x02, /* bDeviceClass */ + 0x00, /* bDeviceSubClass */ + 0x00, /* bDeviceProtocol */ + AO_USB_CONTROL_SIZE, /* bMaxPacketSize */ + LE_WORD(0xFFFE), /* idVendor */ + LE_WORD(AO_idProduct_NUMBER), /* idProduct */ + LE_WORD(0x0100), /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x03, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration descriptor */ + 0x09, + AO_USB_DESC_CONFIGURATION, + LE_WORD(67), /* wTotalLength */ + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xC0, /* bmAttributes */ + 0x32, /* bMaxPower */ + + /* Control class interface */ + 0x09, + AO_USB_DESC_INTERFACE, + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndPoints */ + 0x02, /* bInterfaceClass */ + 0x02, /* bInterfaceSubClass */ + 0x01, /* bInterfaceProtocol, linux requires value of 1 for the cdc_acm module */ + 0x00, /* iInterface */ + + /* Header functional descriptor */ + 0x05, + CS_INTERFACE, + 0x00, /* bDescriptor SubType Header */ + LE_WORD(0x0110), /* CDC version 1.1 */ + + /* Call management functional descriptor */ + 0x05, + CS_INTERFACE, + 0x01, /* bDescriptor SubType Call Management */ + 0x01, /* bmCapabilities = device handles call management */ + 0x01, /* bDataInterface call management interface number */ + + /* ACM functional descriptor */ + 0x04, + CS_INTERFACE, + 0x02, /* bDescriptor SubType Abstract Control Management */ + 0x02, /* bmCapabilities = D1 (Set_line_Coding, Set_Control_Line_State, Get_Line_Coding and Serial_State) */ + + /* Union functional descriptor */ + 0x05, + CS_INTERFACE, + 0x06, /* bDescriptor SubType Union Functional descriptor */ + 0x00, /* bMasterInterface */ + 0x01, /* bSlaveInterface0 */ + + /* Notification EP */ + 0x07, + AO_USB_DESC_ENDPOINT, + AO_USB_INT_EP|0x80, /* bEndpointAddress */ + 0x03, /* bmAttributes = intr */ + LE_WORD(8), /* wMaxPacketSize */ + 0x0A, /* bInterval */ + + /* Data class interface descriptor */ + 0x09, + AO_USB_DESC_INTERFACE, + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x02, /* bNumEndPoints */ + 0x0A, /* bInterfaceClass = data */ + 0x00, /* bInterfaceSubClass */ + 0x00, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + + /* Data EP OUT */ + 0x07, + AO_USB_DESC_ENDPOINT, + AO_USB_OUT_EP, /* bEndpointAddress */ + 0x02, /* bmAttributes = bulk */ + LE_WORD(AO_USB_OUT_SIZE),/* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Data EP in */ + 0x07, + AO_USB_DESC_ENDPOINT, + AO_USB_IN_EP|0x80, /* bEndpointAddress */ + 0x02, /* bmAttributes = bulk */ + LE_WORD(AO_USB_IN_SIZE),/* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* String descriptors */ + 0x04, + AO_USB_DESC_STRING, + LE_WORD(0x0409), + + /* iManufacturer */ + AO_iManufacturer_LEN, + AO_USB_DESC_STRING, + AO_iManufacturer_UCS2, + + /* iProduct */ + AO_iProduct_LEN, + AO_USB_DESC_STRING, + AO_iProduct_UCS2, + + /* iSerial */ + AO_iSerial_LEN, + AO_USB_DESC_STRING, + AO_iSerial_UCS2, + + /* Terminating zero */ + 0 +}; +#endif diff --git a/src/core/ao_report.c b/src/core/ao_report.c new file mode 100644 index 00000000..3cf558e1 --- /dev/null +++ b/src/core/ao_report.c @@ -0,0 +1,180 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +#define BIT(i,x) ((x) ? (1 << (i)) : 0) +#define MORSE1(a) (1 | BIT(3,a)) +#define MORSE2(a,b) (2 | BIT(3,a) | BIT(4,b)) +#define MORSE3(a,b,c) (3 | BIT(3,a) | BIT(4,b) | BIT(5,c)) +#define MORSE4(a,b,c,d) (4 | BIT(3,a) | BIT(4,b) | BIT(5,c) | BIT(6,d)) +#define MORSE5(a,b,c,d,e) (5 | BIT(3,a) | BIT(4,b) | BIT(5,c) | BIT(6,d) | BIT(7,e)) + +static const uint8_t flight_reports[] = { + MORSE3(0,0,0), /* startup, 'S' */ + MORSE2(0,0), /* idle 'I' */ + MORSE4(0,1,1,0), /* pad 'P' */ + MORSE4(1,0,0,0), /* boost 'B' */ + MORSE4(0,0,1,0), /* fast 'F' */ + MORSE4(1,0,1,0), /* coast 'C' */ + MORSE3(1,0,0), /* drogue 'D' */ + MORSE2(1,1), /* main 'M' */ + MORSE4(0,1,0,0), /* landed 'L' */ + MORSE4(1,0,0,1), /* invalid 'X' */ +}; + +#if HAS_BEEP +#define low(time) ao_beep_for(AO_BEEP_LOW, time) +#define mid(time) ao_beep_for(AO_BEEP_MID, time) +#define high(time) ao_beep_for(AO_BEEP_HIGH, time) +#else +#define low(time) ao_led_for(AO_LED_GREEN, time) +#define mid(time) ao_led_for(AO_LED_RED, time) +#define high(time) ao_led_for(AO_LED_GREEN|AO_LED_RED, time) +#endif +#define pause(time) ao_delay(time) + +static __pdata enum ao_flight_state ao_report_state; + +static void +ao_report_beep(void) __reentrant +{ + uint8_t r = flight_reports[ao_flight_state]; + uint8_t l = r & 7; + + if (!r) + return; + while (l--) { + if (r & 8) + mid(AO_MS_TO_TICKS(600)); + else + mid(AO_MS_TO_TICKS(200)); + pause(AO_MS_TO_TICKS(200)); + r >>= 1; + } + pause(AO_MS_TO_TICKS(400)); +} + +static void +ao_report_digit(uint8_t digit) __reentrant +{ + if (!digit) { + mid(AO_MS_TO_TICKS(500)); + pause(AO_MS_TO_TICKS(200)); + } else { + while (digit--) { + mid(AO_MS_TO_TICKS(200)); + pause(AO_MS_TO_TICKS(200)); + } + } + pause(AO_MS_TO_TICKS(300)); +} + +static void +ao_report_altitude(void) +{ + __pdata int16_t agl = ao_max_height; + __xdata uint8_t digits[10]; + __pdata uint8_t ndigits, i; + + if (agl < 0) + agl = 0; + ndigits = 0; + do { + digits[ndigits++] = agl % 10; + agl /= 10; + } while (agl); + + for (;;) { + ao_report_beep(); + i = ndigits; + do + ao_report_digit(digits[--i]); + while (i != 0); + pause(AO_SEC_TO_TICKS(5)); + } +} + +#if HAS_IGNITE +static uint8_t +ao_report_igniter_ready(enum ao_igniter igniter) +{ + return ao_igniter_status(igniter) == ao_igniter_ready ? 1 : 0; +} + +static void +ao_report_continuity(void) __reentrant +{ + uint8_t c = (ao_report_igniter_ready(ao_igniter_drogue) | + (ao_report_igniter_ready(ao_igniter_main) << 1)); + if (c) { + while (c--) { + high(AO_MS_TO_TICKS(25)); + pause(AO_MS_TO_TICKS(100)); + } + } else { + c = 10; + while (c--) { + high(AO_MS_TO_TICKS(20)); + low(AO_MS_TO_TICKS(20)); + } + } + if (ao_log_full()) { + pause(AO_MS_TO_TICKS(100)); + c = 2; + while (c--) { + low(AO_MS_TO_TICKS(100)); + mid(AO_MS_TO_TICKS(100)); + high(AO_MS_TO_TICKS(100)); + mid(AO_MS_TO_TICKS(100)); + } + } + c = 50; + while (c-- && ao_flight_state == ao_flight_pad) + pause(AO_MS_TO_TICKS(100)); +} +#endif + +void +ao_report(void) +{ + ao_report_state = ao_flight_state; + for(;;) { + if (ao_flight_state == ao_flight_landed) + ao_report_altitude(); + ao_report_beep(); +#if HAS_IGNITE + if (ao_flight_state == ao_flight_idle) + ao_report_continuity(); + while (ao_flight_state == ao_flight_pad) + ao_report_continuity(); +#endif + __critical { + while (ao_report_state == ao_flight_state) + ao_sleep(DATA_TO_XDATA(&ao_flight_state)); + ao_report_state = ao_flight_state; + } + } +} + +static __xdata struct ao_task ao_report_task; + +void +ao_report_init(void) +{ + ao_add_task(&ao_report_task, ao_report, "report"); +} diff --git a/src/core/ao_rssi.c b/src/core/ao_rssi.c new file mode 100644 index 00000000..e3964d2d --- /dev/null +++ b/src/core/ao_rssi.c @@ -0,0 +1,53 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +static __xdata volatile uint16_t ao_rssi_time; +static __pdata volatile uint16_t ao_rssi_delay; +static __pdata uint8_t ao_rssi_led; + +void +ao_rssi(void) +{ + for (;;) { + while ((int16_t) (ao_time() - ao_rssi_time) > AO_SEC_TO_TICKS(3)) + ao_sleep(&ao_rssi_time); + ao_led_for(ao_rssi_led, AO_MS_TO_TICKS(100)); + ao_delay(ao_rssi_delay); + } +} + +void +ao_rssi_set(int rssi_value) +{ + if (rssi_value > 0) + rssi_value = 0; + ao_rssi_delay = AO_MS_TO_TICKS((-rssi_value) * 5); + ao_rssi_time = ao_time(); + ao_wakeup(&ao_rssi_time); +} + +__xdata struct ao_task ao_rssi_task; + +void +ao_rssi_init(uint8_t rssi_led) +{ + ao_rssi_led = rssi_led; + ao_rssi_delay = 0; + ao_add_task(&ao_rssi_task, ao_rssi, "rssi"); +} diff --git a/src/core/ao_sample.c b/src/core/ao_sample.c new file mode 100644 index 00000000..b2b8e9f6 --- /dev/null +++ b/src/core/ao_sample.c @@ -0,0 +1,209 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_FLIGHT_TEST +#include "ao.h" +#endif + +/* + * Current sensor values + */ + +__pdata uint16_t ao_sample_tick; /* time of last data */ +__pdata int16_t ao_sample_pres; +__pdata int16_t ao_sample_alt; +__pdata int16_t ao_sample_height; +#if HAS_ACCEL +__pdata int16_t ao_sample_accel; +#endif + +__data uint8_t ao_sample_adc; + +/* + * Sensor calibration values + */ + +__pdata int16_t ao_ground_pres; /* startup pressure */ +__pdata int16_t ao_ground_height; /* MSL of ao_ground_pres */ + +#if HAS_ACCEL +__pdata int16_t ao_ground_accel; /* startup acceleration */ +__pdata int16_t ao_accel_2g; /* factory accel calibration */ +__pdata int32_t ao_accel_scale; /* sensor to m/s² conversion */ +#endif + +static __pdata uint8_t ao_preflight; /* in preflight mode */ + +static __pdata uint16_t nsamples; +__pdata int32_t ao_sample_pres_sum; +#if HAS_ACCEL +__pdata int32_t ao_sample_accel_sum; +#endif + +static void +ao_sample_preflight(void) +{ + /* startup state: + * + * Collect 512 samples of acceleration and pressure + * data and average them to find the resting values + */ + if (nsamples < 512) { +#if HAS_ACCEL + ao_sample_accel_sum += ao_sample_accel; +#endif + ao_sample_pres_sum += ao_sample_pres; + ++nsamples; + } else { + ao_config_get(); +#if HAS_ACCEL + ao_ground_accel = ao_sample_accel_sum >> 9; + ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g; + ao_accel_scale = to_fix32(GRAVITY * 2 * 16) / ao_accel_2g; +#endif + ao_ground_pres = ao_sample_pres_sum >> 9; + ao_ground_height = ao_pres_to_altitude(ao_ground_pres); + ao_preflight = FALSE; + } +} + +uint8_t +ao_sample(void) +{ + ao_wakeup(DATA_TO_XDATA(&ao_sample_adc)); + ao_sleep(DATA_TO_XDATA(&ao_adc_head)); + while (ao_sample_adc != ao_adc_head) { + __xdata struct ao_adc *ao_adc; + + /* Capture a sample */ + ao_adc = &ao_adc_ring[ao_sample_adc]; + ao_sample_tick = ao_adc->tick; + ao_sample_pres = ao_adc->pres; + ao_sample_alt = ao_pres_to_altitude(ao_sample_pres); + ao_sample_height = ao_sample_alt - ao_ground_height; +#if HAS_ACCEL + ao_sample_accel = ao_adc->accel; +#if HAS_ACCEL_REF + /* + * Ok, the math here is a bit tricky. + * + * ao_sample_accel: ADC output for acceleration + * ao_accel_ref: ADC output for the 5V reference. + * ao_cook_accel: Corrected acceleration value + * Vcc: 3.3V supply to the CC1111 + * Vac: 5V supply to the accelerometer + * accel: input voltage to accelerometer ADC pin + * ref: input voltage to 5V reference ADC pin + * + * + * Measured acceleration is ratiometric to Vcc: + * + * ao_sample_accel accel + * ------------ = ----- + * 32767 Vcc + * + * Measured 5v reference is also ratiometric to Vcc: + * + * ao_accel_ref ref + * ------------ = ----- + * 32767 Vcc + * + * + * ao_accel_ref = 32767 * (ref / Vcc) + * + * Acceleration is measured ratiometric to the 5V supply, + * so what we want is: + * + * ao_cook_accel accel + * ------------- = ----- + * 32767 ref + * + * + * accel Vcc + * = ----- * --- + * Vcc ref + * + * ao_sample_accel 32767 + * = ------------ * ------------ + * 32767 ao_accel_ref + * + * Multiply through by 32767: + * + * ao_sample_accel * 32767 + * ao_cook_accel = -------------------- + * ao_accel_ref + * + * Now, the tricky part. Getting this to compile efficiently + * and keeping all of the values in-range. + * + * First off, we need to use a shift of 16 instead of * 32767 as SDCC + * does the obvious optimizations for byte-granularity shifts: + * + * ao_cook_accel = (ao_sample_accel << 16) / ao_accel_ref + * + * Next, lets check our input ranges: + * + * 0 <= ao_sample_accel <= 0x7fff (singled ended ADC conversion) + * 0x7000 <= ao_accel_ref <= 0x7fff (the 5V ref value is close to 0x7fff) + * + * Plugging in our input ranges, we get an output range of 0 - 0x12490, + * which is 17 bits. That won't work. If we take the accel ref and shift + * by a bit, we'll change its range: + * + * 0xe000 <= ao_accel_ref<<1 <= 0xfffe + * + * ao_cook_accel = (ao_sample_accel << 16) / (ao_accel_ref << 1) + * + * Now the output range is 0 - 0x9248, which nicely fits in 16 bits. It + * is, however, one bit too large for our signed computations. So, we + * take the result and shift that by a bit: + * + * ao_cook_accel = ((ao_sample_accel << 16) / (ao_accel_ref << 1)) >> 1 + * + * This finally creates an output range of 0 - 0x4924. As the ADC only + * provides 11 bits of data, we haven't actually lost any precision, + * just dropped a bit of noise off the low end. + */ + ao_sample_accel = (uint16_t) ((((uint32_t) ao_sample_accel << 16) / (ao_accel_ref[ao_sample_adc] << 1))) >> 1; + if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP) + ao_sample_accel = 0x7fff - ao_sample_accel; + ao_adc->accel = ao_sample_accel; +#endif +#endif + + if (ao_preflight) + ao_sample_preflight(); + else + ao_kalman(); + ao_sample_adc = ao_adc_ring_next(ao_sample_adc); + } + return !ao_preflight; +} + +void +ao_sample_init(void) +{ + nsamples = 0; + ao_sample_pres_sum = 0; + ao_sample_pres = 0; +#if HAS_ACCEL + ao_sample_accel_sum = 0; + ao_sample_accel = 0; +#endif + ao_sample_adc = ao_adc_head; + ao_preflight = TRUE; +} diff --git a/src/core/ao_state.c b/src/core/ao_state.c new file mode 100644 index 00000000..ed197aa5 --- /dev/null +++ b/src/core/ao_state.c @@ -0,0 +1,23 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +const char const * const ao_state_names[] = { + "startup", "idle", "pad", "boost", "fast", + "coast", "drogue", "main", "landed", "invalid" +}; diff --git a/src/core/ao_stdio.c b/src/core/ao_stdio.c new file mode 100644 index 00000000..c0138a30 --- /dev/null +++ b/src/core/ao_stdio.c @@ -0,0 +1,84 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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 + */ + +#define AO_NUM_STDIOS (HAS_USB + PACKET_HAS_SLAVE + USE_SERIAL_STDIN) + +__xdata struct ao_stdio ao_stdios[AO_NUM_STDIOS]; +__pdata int8_t ao_cur_stdio; +__pdata int8_t ao_num_stdios; + +void +putchar(char c) +{ + if (c == '\n') + (*ao_stdios[ao_cur_stdio].putchar)('\r'); + (*ao_stdios[ao_cur_stdio].putchar)(c); +} + +void +flush(void) +{ + if (ao_stdios[ao_cur_stdio].flush) + ao_stdios[ao_cur_stdio].flush(); +} + +__xdata uint8_t ao_stdin_ready; + +char +getchar(void) __reentrant __critical +{ + char c; + int8_t stdio = ao_cur_stdio; + + for (;;) { + c = ao_stdios[stdio].pollchar(); + if (c != AO_READ_AGAIN) + break; + if (++stdio == ao_num_stdios) + stdio = 0; + if (stdio == ao_cur_stdio) + ao_sleep(&ao_stdin_ready); + } + ao_cur_stdio = stdio; + return c; +} + +uint8_t +ao_echo(void) +{ + return ao_stdios[ao_cur_stdio].echo; +} + +int8_t +ao_add_stdio(char (*pollchar)(void), + void (*putchar)(char), + void (*flush)(void)) __reentrant +{ + if (ao_num_stdios == AO_NUM_STDIOS) + ao_panic(AO_PANIC_STDIO); + ao_stdios[ao_num_stdios].pollchar = pollchar; + ao_stdios[ao_num_stdios].putchar = putchar; + ao_stdios[ao_num_stdios].flush = flush; + ao_stdios[ao_num_stdios].echo = 1; + return ao_num_stdios++; +} diff --git a/src/core/ao_storage.c b/src/core/ao_storage.c new file mode 100644 index 00000000..6ffca0e5 --- /dev/null +++ b/src/core/ao_storage.c @@ -0,0 +1,184 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +uint8_t +ao_storage_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant +{ + uint16_t this_len; + uint16_t this_off; + + ao_storage_setup(); + if (pos >= ao_storage_total || pos + len > ao_storage_total) + return 0; + while (len) { + + /* Compute portion of transfer within + * a single block + */ + this_off = (uint16_t) pos & (ao_storage_unit - 1); + this_len = ao_storage_unit - this_off; + if (this_len > len) + this_len = len; + + if (!ao_storage_device_read(pos, buf, this_len)) + return 0; + + /* See how much is left */ + buf += this_len; + len -= this_len; + pos += this_len; + } + return 1; +} + +uint8_t +ao_storage_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant +{ + uint16_t this_len; + uint16_t this_off; + + ao_storage_setup(); + if (pos >= ao_storage_total || pos + len > ao_storage_total) + return 0; + while (len) { + + /* Compute portion of transfer within + * a single block + */ + this_off = (uint16_t) pos & (ao_storage_unit - 1); + this_len = ao_storage_unit - this_off; + if (this_len > len) + this_len = len; + + if (!ao_storage_device_write(pos, buf, this_len)) + return 0; + + /* See how much is left */ + buf += this_len; + len -= this_len; + pos += this_len; + } + return 1; +} + +static __xdata uint8_t storage_data[8]; + +static void +ao_storage_dump(void) __reentrant +{ + uint8_t i, j; + + ao_cmd_hex(); + if (ao_cmd_status != ao_cmd_success) + return; + for (i = 0; ; i += 8) { + if (ao_storage_read(((uint32_t) (ao_cmd_lex_i) << 8) + i, + storage_data, + 8)) { + ao_cmd_put16((uint16_t) i); + for (j = 0; j < 8; j++) { + putchar(' '); + ao_cmd_put8(storage_data[j]); + } + putchar ('\n'); + } + if (i == 248) + break; + } +} + +#if 0 + +/* not enough space for this today + */ +static void +ao_storage_store(void) __reentrant +{ + uint16_t block; + uint8_t i; + uint16_t len; + static __xdata uint8_t b; + 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_storage_write(addr, &b, 1); + addr++; + } +} +#endif + +void +ao_storage_zap(void) __reentrant +{ + ao_cmd_hex(); + if (ao_cmd_status != ao_cmd_success) + return; + ao_storage_erase((uint32_t) ao_cmd_lex_i << 8); +} + +void +ao_storage_zapall(void) __reentrant +{ + uint32_t pos; + + ao_cmd_white(); + if (!ao_match_word("DoIt")) + return; + for (pos = 0; pos < ao_storage_config; pos += ao_storage_block) + ao_storage_erase(pos); +} + +void +ao_storage_info(void) __reentrant +{ + printf("Storage size: %ld\n", ao_storage_total); + printf("Storage erase unit: %ld\n", ao_storage_block); + ao_storage_device_info(); +} + +__code struct ao_cmds ao_storage_cmds[] = { + { ao_storage_info, "f\0Show storage" }, + { ao_storage_dump, "e \0Dump flash" }, +#ifdef HAS_STORAGE_DBG + { ao_storage_store, "w ...\0Write data to flash" }, +#endif + { ao_storage_zap, "z \0Erase " }, + { ao_storage_zapall,"Z \0Erase all. is doit with D&I" }, + { 0, NULL }, +}; + +void +ao_storage_init(void) +{ + ao_storage_device_init(); + ao_cmd_register(&ao_storage_cmds[0]); +} diff --git a/src/core/ao_task.c b/src/core/ao_task.c new file mode 100644 index 00000000..f5850fa4 --- /dev/null +++ b/src/core/ao_task.c @@ -0,0 +1,275 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +#define AO_NO_TASK_INDEX 0xff + +__xdata struct ao_task * __xdata ao_tasks[AO_NUM_TASKS]; +__data uint8_t ao_num_tasks; +__data uint8_t ao_cur_task_index; +__xdata struct ao_task *__data ao_cur_task; + +void +ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant +{ + uint8_t __xdata *stack; + uint8_t task_id; + uint8_t t; + if (ao_num_tasks == AO_NUM_TASKS) + ao_panic(AO_PANIC_NO_TASK); + for (task_id = 1; task_id != 0; task_id++) { + for (t = 0; t < ao_num_tasks; t++) + if (ao_tasks[t]->task_id == task_id) + break; + if (t == ao_num_tasks) + break; + } + ao_tasks[ao_num_tasks++] = task; + task->task_id = task_id; + task->name = name; + /* + * Construct a stack frame so that it will 'return' + * to the start of the task + */ + stack = task->stack; + + *stack++ = ((uint16_t) start); /* 0 */ + *stack++ = ((uint16_t) start) >> 8; /* 1 */ + + /* and the stuff saved by ao_switch */ + *stack++ = 0; /* 2 acc */ + *stack++ = 0x80; /* 3 IE */ + + /* 4 DPL + * 5 DPH + * 6 B + * 7 R2 + * 8 R3 + * 9 R4 + * 10 R5 + * 11 R6 + * 12 R7 + * 13 R0 + * 14 R1 + * 15 PSW + * 16 BP + */ + for (t = 0; t < 13; t++) + *stack++ = 0; + + task->stack_count = 17; + task->wchan = NULL; +} + +/* Task switching function. This must not use any stack variables */ +void +ao_yield(void) __naked +{ + + /* Save current context */ + _asm + /* Push ACC first, as when restoring the context it must be restored + * last (it is used to set the IE register). */ + push ACC + /* Store the IE register then enable interrupts. */ + push _IEN0 + setb _EA + push DPL + push DPH + push b + push ar2 + push ar3 + push ar4 + push ar5 + push ar6 + push ar7 + push ar0 + push ar1 + push PSW + _endasm; + PSW = 0; + _asm + push _bp + _endasm; + + if (ao_cur_task_index == AO_NO_TASK_INDEX) + ao_cur_task_index = ao_num_tasks-1; + else + { + uint8_t stack_len; + __data uint8_t *stack_ptr; + __xdata uint8_t *save_ptr; + /* Save the current stack */ + stack_len = SP - (AO_STACK_START - 1); + ao_cur_task->stack_count = stack_len; + stack_ptr = (uint8_t __data *) AO_STACK_START; + save_ptr = (uint8_t __xdata *) ao_cur_task->stack; + do + *save_ptr++ = *stack_ptr++; + while (--stack_len); + } + + /* Empty the stack; might as well let interrupts have the whole thing */ + SP = AO_STACK_START - 1; + + /* Find a task to run. If there isn't any runnable task, + * this loop will run forever, which is just fine + */ + { + __pdata uint8_t ao_next_task_index = ao_cur_task_index; + for (;;) { + ++ao_next_task_index; + if (ao_next_task_index == ao_num_tasks) + ao_next_task_index = 0; + + ao_cur_task = ao_tasks[ao_next_task_index]; + if (ao_cur_task->wchan == NULL) { + ao_cur_task_index = ao_next_task_index; + break; + } + + /* Check if the alarm is set for a time which has passed */ + if (ao_cur_task->alarm && + (int16_t) (ao_time() - ao_cur_task->alarm) >= 0) { + ao_cur_task_index = ao_next_task_index; + break; + } + + /* Enter lower power mode when there isn't anything to do */ + if (ao_next_task_index == ao_cur_task_index) + PCON = PCON_IDLE; + } + } + + { + uint8_t stack_len; + __data uint8_t *stack_ptr; + __xdata uint8_t *save_ptr; + + /* Restore the old stack */ + stack_len = ao_cur_task->stack_count; + SP = AO_STACK_START - 1 + stack_len; + + stack_ptr = (uint8_t __data *) AO_STACK_START; + save_ptr = (uint8_t __xdata *) ao_cur_task->stack; + do + *stack_ptr++ = *save_ptr++; + while (--stack_len); + } + + _asm + pop _bp + pop PSW + pop ar1 + pop ar0 + pop ar7 + pop ar6 + pop ar5 + pop ar4 + pop ar3 + pop ar2 + pop b + pop DPH + pop DPL + /* The next byte of the stack is the IE register. Only the global + enable bit forms part of the task context. Pop off the IE then set + the global enable bit to match that of the stored IE register. */ + pop ACC + JB ACC.7,0098$ + CLR _EA + LJMP 0099$ + 0098$: + SETB _EA + 0099$: + /* Finally pop off the ACC, which was the first register saved. */ + pop ACC + ret + _endasm; +} + +uint8_t +ao_sleep(__xdata void *wchan) +{ + __critical { + ao_cur_task->wchan = wchan; + } + ao_yield(); + ao_cur_task->alarm = 0; + if (ao_cur_task->wchan) { + ao_cur_task->wchan = NULL; + return 1; + } + return 0; +} + +void +ao_wakeup(__xdata void *wchan) +{ + uint8_t i; + + for (i = 0; i < ao_num_tasks; i++) + if (ao_tasks[i]->wchan == wchan) + ao_tasks[i]->wchan = NULL; +} + +void +ao_alarm(uint16_t delay) +{ + /* Make sure we sleep *at least* delay ticks, which means adding + * one to account for the fact that we may be close to the next tick + */ + if (!(ao_cur_task->alarm = ao_time() + delay + 1)) + ao_cur_task->alarm = 1; +} + +void +ao_exit(void) __critical +{ + uint8_t i; + ao_num_tasks--; + for (i = ao_cur_task_index; i < ao_num_tasks; i++) + ao_tasks[i] = ao_tasks[i+1]; + ao_cur_task_index = AO_NO_TASK_INDEX; + ao_yield(); + /* we'll never get back here */ +} + +void +ao_task_info(void) +{ + uint8_t i; + uint8_t pc_loc; + __xdata struct ao_task *task; + + for (i = 0; i < ao_num_tasks; i++) { + task = ao_tasks[i]; + pc_loc = task->stack_count - 17; + printf("%12s: wchan %04x pc %04x\n", + task->name, + (int16_t) task->wchan, + (task->stack[pc_loc]) | (task->stack[pc_loc+1] << 8)); + } +} + +void +ao_start_scheduler(void) +{ + ao_cur_task_index = AO_NO_TASK_INDEX; + ao_cur_task = NULL; + ao_yield(); +} diff --git a/src/core/ao_telem.h b/src/core/ao_telem.h new file mode 100644 index 00000000..1a8da291 --- /dev/null +++ b/src/core/ao_telem.h @@ -0,0 +1,172 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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 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_g 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" +#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_g" +#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_ */ diff --git a/src/core/ao_telemetry.c b/src/core/ao_telemetry.c new file mode 100644 index 00000000..c7338a58 --- /dev/null +++ b/src/core/ao_telemetry.c @@ -0,0 +1,270 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" +#include "ao_product.h" + +static __pdata uint16_t ao_telemetry_interval; +static __pdata int8_t ao_telemetry_config_max; +static __pdata int8_t ao_telemetry_config_cur; +#if HAS_GPS +static __pdata int8_t ao_telemetry_loc_cur; +static __pdata int8_t ao_telemetry_sat_cur; +#endif +#if HAS_COMPANION +static __pdata int8_t ao_telemetry_companion_max; +static __pdata int8_t ao_telemetry_companion_cur; +#endif +static __pdata uint8_t ao_rdf = 0; +static __pdata uint16_t ao_rdf_time; + +#define AO_RDF_INTERVAL_TICKS AO_SEC_TO_TICKS(5) +#define AO_RDF_LENGTH_MS 500 + +#if defined(TELEMETRUM_V_0_1) || defined(TELEMETRUM_V_0_2) || defined(TELEMETRUM_V_1_0) || defined(TELEMETRUM_V_1_1) +#define AO_TELEMETRY_SENSOR AO_TELEMETRY_SENSOR_TELEMETRUM +#endif + +#if defined(TELEMINI_V_1_0) +#define AO_TELEMETRY_SENSOR AO_TELEMETRY_SENSOR_TELEMINI +#endif + +#if defined(TELENANO_V_0_1) +#define AO_TELEMETRY_SENSOR AO_TELEMETRY_SENSOR_TELENANO +#endif + +static __xdata union ao_telemetry_all telemetry; + +/* Send sensor packet */ +static void +ao_send_sensor(void) +{ + uint8_t sample; + sample = ao_sample_adc; + + telemetry.generic.tick = ao_adc_ring[sample].tick; + telemetry.generic.type = AO_TELEMETRY_SENSOR; + + telemetry.sensor.state = ao_flight_state; +#if HAS_ACCEL + telemetry.sensor.accel = ao_adc_ring[sample].accel; +#else + telemetry.sensor.accel = 0; +#endif + telemetry.sensor.pres = ao_adc_ring[sample].pres; + telemetry.sensor.temp = ao_adc_ring[sample].temp; + telemetry.sensor.v_batt = ao_adc_ring[sample].v_batt; +#if HAS_IGNITE + telemetry.sensor.sense_d = ao_adc_ring[sample].sense_d; + telemetry.sensor.sense_m = ao_adc_ring[sample].sense_m; +#else + telemetry.sensor.sense_d = 0; + telemetry.sensor.sense_m = 0; +#endif + + telemetry.sensor.acceleration = ao_accel; + telemetry.sensor.speed = ao_speed; + telemetry.sensor.height = ao_height; + + telemetry.sensor.ground_pres = ao_ground_pres; +#if HAS_ACCEL + telemetry.sensor.ground_accel = ao_ground_accel; + telemetry.sensor.accel_plus_g = ao_config.accel_plus_g; + telemetry.sensor.accel_minus_g = ao_config.accel_minus_g; +#else + telemetry.sensor.ground_accel = 0; + telemetry.sensor.accel_plus_g = 0; + telemetry.sensor.accel_minus_g = 0; +#endif + + ao_radio_send(&telemetry, sizeof (telemetry)); +} + +static void +ao_send_configuration(void) +{ + if (--ao_telemetry_config_cur <= 0) + { + telemetry.generic.type = AO_TELEMETRY_CONFIGURATION; + telemetry.configuration.device = AO_idProduct_NUMBER; + telemetry.configuration.flight = ao_log_full() ? 0 : ao_flight_number; + telemetry.configuration.config_major = AO_CONFIG_MAJOR; + telemetry.configuration.config_minor = AO_CONFIG_MINOR; + telemetry.configuration.apogee_delay = ao_config.apogee_delay; + telemetry.configuration.main_deploy = ao_config.main_deploy; + telemetry.configuration.flight_log_max = ao_config.flight_log_max >> 10; + memcpy (telemetry.configuration.callsign, + ao_config.callsign, + AO_MAX_CALLSIGN); + memcpy (telemetry.configuration.version, + ao_version, + AO_MAX_VERSION); + ao_radio_send(&telemetry, sizeof (telemetry)); + ao_telemetry_config_cur = ao_telemetry_config_max; + } +} + +#if HAS_GPS +static void +ao_send_location(void) +{ + if (--ao_telemetry_loc_cur <= 0) + { + telemetry.generic.type = AO_TELEMETRY_LOCATION; + ao_mutex_get(&ao_gps_mutex); + memcpy(&telemetry.location.flags, + &ao_gps_data.flags, + 26); + ao_mutex_put(&ao_gps_mutex); + ao_radio_send(&telemetry, sizeof (telemetry)); + ao_telemetry_loc_cur = ao_telemetry_config_max; + } +} + +static void +ao_send_satellite(void) +{ + if (--ao_telemetry_sat_cur <= 0) + { + telemetry.generic.type = AO_TELEMETRY_SATELLITE; + ao_mutex_get(&ao_gps_mutex); + telemetry.satellite.channels = ao_gps_tracking_data.channels; + memcpy(&telemetry.satellite.sats, + &ao_gps_tracking_data.sats, + AO_MAX_GPS_TRACKING * sizeof (struct ao_telemetry_satellite_info)); + ao_mutex_put(&ao_gps_mutex); + ao_radio_send(&telemetry, sizeof (telemetry)); + ao_telemetry_sat_cur = ao_telemetry_config_max; + } +} +#endif + +#if HAS_COMPANION +static void +ao_send_companion(void) +{ + if (--ao_telemetry_companion_cur <= 0) { + telemetry.generic.type = AO_TELEMETRY_COMPANION; + telemetry.companion.board_id = ao_companion_setup.board_id; + telemetry.companion.update_period = ao_companion_setup.update_period; + telemetry.companion.channels = ao_companion_setup.channels; + ao_mutex_get(&ao_companion_mutex); + memcpy(&telemetry.companion.companion_data, + ao_companion_data, + ao_companion_setup.channels * 2); + ao_mutex_put(&ao_companion_mutex); + ao_radio_send(&telemetry, sizeof (telemetry)); + ao_telemetry_companion_cur = ao_telemetry_companion_max; + } +} +#endif + +void +ao_telemetry(void) +{ + uint16_t time; + int16_t delay; + + ao_config_get(); + if (!ao_config.radio_enable) + ao_exit(); + while (!ao_flight_number) + ao_sleep(&ao_flight_number); + + telemetry.generic.serial = ao_serial_number; + for (;;) { + while (ao_telemetry_interval == 0) + ao_sleep(&telemetry); + time = ao_rdf_time = ao_time(); + while (ao_telemetry_interval) { + + + ao_send_sensor(); +#if HAS_COMPANION + if (ao_companion_running) + ao_send_companion(); +#endif + ao_send_configuration(); +#if HAS_GPS + ao_send_location(); + ao_send_satellite(); +#endif + if (ao_rdf && + (int16_t) (ao_time() - ao_rdf_time) >= 0) + { + ao_rdf_time = ao_time() + AO_RDF_INTERVAL_TICKS; + ao_radio_rdf(AO_RDF_LENGTH_MS); + } + time += ao_telemetry_interval; + delay = time - ao_time(); + if (delay > 0) + ao_delay(delay); + else + time = ao_time(); + } + } +} + +void +ao_telemetry_set_interval(uint16_t interval) +{ + ao_telemetry_interval = interval; + +#if HAS_COMPANION + if (!ao_companion_setup.update_period) + ao_companion_setup.update_period = AO_SEC_TO_TICKS(1); + ao_telemetry_companion_max = ao_companion_setup.update_period / interval; + ao_telemetry_companion_cur = 1; +#endif + + ao_telemetry_config_max = AO_SEC_TO_TICKS(1) / interval; +#if HAS_COMPANION + ao_telemetry_config_cur = ao_telemetry_companion_cur; + if (ao_telemetry_config_max > ao_telemetry_config_cur) + ao_telemetry_config_cur++; +#else + ao_telemetry_config_cur = 1; +#endif + +#if HAS_GPS + ao_telemetry_loc_cur = ao_telemetry_config_cur; + if (ao_telemetry_config_max > ao_telemetry_loc_cur) + ao_telemetry_loc_cur++; + ao_telemetry_sat_cur = ao_telemetry_loc_cur; + if (ao_telemetry_config_max > ao_telemetry_sat_cur) + ao_telemetry_sat_cur++; +#endif + ao_wakeup(&telemetry); +} + +void +ao_rdf_set(uint8_t rdf) +{ + ao_rdf = rdf; + if (rdf == 0) + ao_radio_rdf_abort(); + else + ao_rdf_time = ao_time(); +} + +__xdata struct ao_task ao_telemetry_task; + +void +ao_telemetry_init() +{ + ao_add_task(&ao_telemetry_task, ao_telemetry, "telemetry"); +} diff --git a/src/drivers/ao_25lc1024.c b/src/drivers/ao_25lc1024.c new file mode 100644 index 00000000..738f8ce6 --- /dev/null +++ b/src/drivers/ao_25lc1024.c @@ -0,0 +1,241 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" +#include "ao_25lc1024.h" + +#define EE_BLOCK_SIZE ((uint16_t) (256)) +#define EE_BLOCK_SHIFT 8 +#define EE_DEVICE_SIZE ((uint32_t) 128 * (uint32_t) 1024) + +/* Total bytes of available storage */ +__pdata uint32_t ao_storage_total; + +/* Block size - device is erased in these units. At least 256 bytes */ +__pdata uint32_t ao_storage_block; + +/* Byte offset of config block. Will be ao_storage_block bytes long */ +__pdata uint32_t ao_storage_config; + +/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */ +__pdata uint16_t ao_storage_unit; + +/* + * Using SPI on USART 0, with P1_2 as the chip select + */ + +#define EE_CS P1_2 +#define EE_CS_INDEX 2 + +static __xdata uint8_t ao_ee_mutex; + +#define ao_ee_delay() do { \ + _asm nop _endasm; \ + _asm nop _endasm; \ + _asm nop _endasm; \ +} while(0) + +#define ao_ee_cs_low() ao_spi_get_bit(EE_CS) + +#define ao_ee_cs_high() ao_spi_put_bit(EE_CS) + +struct ao_ee_instruction { + uint8_t instruction; + uint8_t address[3]; +} __xdata ao_ee_instruction; + +static void +ao_ee_write_enable(void) +{ + ao_ee_cs_low(); + ao_ee_instruction.instruction = EE_WREN; + ao_spi_send(&ao_ee_instruction, 1); + ao_ee_cs_high(); +} + +static uint8_t +ao_ee_rdsr(void) +{ + ao_ee_cs_low(); + ao_ee_instruction.instruction = EE_RDSR; + ao_spi_send(&ao_ee_instruction, 1); + ao_spi_recv(&ao_ee_instruction, 1); + ao_ee_cs_high(); + return ao_ee_instruction.instruction; +} + +static void +ao_ee_wrsr(uint8_t status) +{ + ao_ee_cs_low(); + ao_ee_instruction.instruction = EE_WRSR; + ao_ee_instruction.address[0] = status; + ao_spi_send(&ao_ee_instruction, 2); + ao_ee_cs_high(); +} + +#define EE_BLOCK_NONE 0xffff + +static __xdata uint8_t ao_ee_data[EE_BLOCK_SIZE]; +static __pdata uint16_t ao_ee_block = EE_BLOCK_NONE; +static __pdata uint8_t ao_ee_block_dirty; + +/* Write the current block to the EEPROM */ +static void +ao_ee_write_block(void) +{ + uint8_t status; + + status = ao_ee_rdsr(); + if (status & (EE_STATUS_BP0|EE_STATUS_BP1|EE_STATUS_WPEN)) { + status &= ~(EE_STATUS_BP0|EE_STATUS_BP1|EE_STATUS_WPEN); + ao_ee_wrsr(status); + } + ao_ee_write_enable(); + ao_ee_cs_low(); + ao_ee_instruction.instruction = EE_WRITE; + ao_ee_instruction.address[0] = ao_ee_block >> 8; + ao_ee_instruction.address[1] = ao_ee_block; + ao_ee_instruction.address[2] = 0; + ao_spi_send(&ao_ee_instruction, 4); + ao_spi_send(ao_ee_data, EE_BLOCK_SIZE); + ao_ee_cs_high(); + for (;;) { + uint8_t status = ao_ee_rdsr(); + if ((status & EE_STATUS_WIP) == 0) + break; + } +} + +/* Read the current block from the EEPROM */ +static void +ao_ee_read_block(void) +{ + ao_ee_cs_low(); + ao_ee_instruction.instruction = EE_READ; + ao_ee_instruction.address[0] = ao_ee_block >> 8; + ao_ee_instruction.address[1] = ao_ee_block; + ao_ee_instruction.address[2] = 0; + ao_spi_send(&ao_ee_instruction, 4); + ao_spi_recv(ao_ee_data, EE_BLOCK_SIZE); + ao_ee_cs_high(); +} + +static void +ao_ee_flush_internal(void) +{ + if (ao_ee_block_dirty) { + ao_ee_write_block(); + ao_ee_block_dirty = 0; + } +} + +static void +ao_ee_fill(uint16_t block) +{ + if (block != ao_ee_block) { + ao_ee_flush_internal(); + ao_ee_block = block; + ao_ee_read_block(); + } +} + +uint8_t +ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant +{ + uint16_t block = (uint16_t) (pos >> EE_BLOCK_SHIFT); + + /* Transfer the data */ + ao_mutex_get(&ao_ee_mutex); { + if (len != EE_BLOCK_SIZE) + ao_ee_fill(block); + else { + ao_ee_flush_internal(); + ao_ee_block = block; + } + memcpy(ao_ee_data + (uint16_t) (pos & 0xff), buf, len); + ao_ee_block_dirty = 1; + } ao_mutex_put(&ao_ee_mutex); + return 1; +} + +uint8_t +ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant +{ + uint16_t block = (uint16_t) (pos >> EE_BLOCK_SHIFT); + + /* Transfer the data */ + ao_mutex_get(&ao_ee_mutex); { + ao_ee_fill(block); + memcpy(buf, ao_ee_data + (uint16_t) (pos & 0xff), len); + } ao_mutex_put(&ao_ee_mutex); + return 1; +} + +void +ao_storage_flush(void) __reentrant +{ + ao_mutex_get(&ao_ee_mutex); { + ao_ee_flush_internal(); + } ao_mutex_put(&ao_ee_mutex); +} + +uint8_t +ao_storage_erase(uint32_t pos) __reentrant +{ + ao_mutex_get(&ao_ee_mutex); { + ao_ee_flush_internal(); + ao_ee_block = (uint16_t) (pos >> EE_BLOCK_SHIFT); + memset(ao_ee_data, 0xff, EE_BLOCK_SIZE); + ao_ee_block_dirty = 1; + } ao_mutex_put(&ao_ee_mutex); + return 1; +} + +static void +ee_store(void) __reentrant +{ +} + +void +ao_storage_setup(void) +{ + if (ao_storage_total == 0) { + ao_storage_total = EE_DEVICE_SIZE; + ao_storage_block = EE_BLOCK_SIZE; + ao_storage_config = EE_DEVICE_SIZE - EE_BLOCK_SIZE; + ao_storage_unit = EE_BLOCK_SIZE; + } +} + +void +ao_storage_device_info(void) __reentrant +{ +} + +/* + * To initialize the chip, set up the CS line and + * the SPI interface + */ +void +ao_storage_device_init(void) +{ + /* set up CS */ + EE_CS = 1; + P1DIR |= (1 << EE_CS_INDEX); + P1SEL &= ~(1 << EE_CS_INDEX); +} diff --git a/src/drivers/ao_25lc1024.h b/src/drivers/ao_25lc1024.h new file mode 100644 index 00000000..44e52387 --- /dev/null +++ b/src/drivers/ao_25lc1024.h @@ -0,0 +1,41 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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. + */ + +/* Defines for the 25LC1024 1Mbit SPI Bus Serial EEPROM */ + +#ifndef _25LC1024_H_ +#define _25LC1024_H_ + +#define EE_READ 0x03 +#define EE_WRITE 0x02 +#define EE_WREN 0x06 +#define EE_WRDI 0x04 +#define EE_RDSR 0x05 +#define EE_WRSR 0x01 +#define EE_PE 0x42 +#define EE_SE 0xd8 +#define EE_CE 0xc7 +#define EE_RDID 0xab +#define EE_DPD 0xb9 + +#define EE_STATUS_WIP (1 << 0) +#define EE_STATUS_WEL (1 << 1) +#define EE_STATUS_BP0 (1 << 2) +#define EE_STATUS_BP1 (1 << 3) +#define EE_STATUS_WPEN (1 << 7) + +#endif /* _25LC1024_H_ */ diff --git a/src/drivers/ao_at45db161d.c b/src/drivers/ao_at45db161d.c new file mode 100644 index 00000000..aee9877a --- /dev/null +++ b/src/drivers/ao_at45db161d.c @@ -0,0 +1,318 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" +#include "ao_at45db161d.h" + +/* Total bytes of available storage */ +__pdata uint32_t ao_storage_total; + +/* Block size - device is erased in these units. At least 256 bytes */ +__pdata uint32_t ao_storage_block; + +/* Byte offset of config block. Will be ao_storage_block bytes long */ +__pdata uint32_t ao_storage_config; + +/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */ +__pdata uint16_t ao_storage_unit; + +#define FLASH_CS P1_1 +#define FLASH_CS_INDEX 1 + +#define FLASH_BLOCK_SIZE_MAX 512 + +__xdata uint8_t ao_flash_mutex; + +#define ao_flash_delay() do { \ + _asm nop _endasm; \ + _asm nop _endasm; \ + _asm nop _endasm; \ +} while(0) + +#define ao_flash_cs_low() ao_spi_get_bit(FLASH_CS) + +#define ao_flash_cs_high() ao_spi_put_bit(FLASH_CS) + +struct ao_flash_instruction { + uint8_t instruction; + uint8_t address[3]; +} __xdata ao_flash_instruction; + +static void +ao_flash_set_pagesize_512(void) +{ + ao_flash_cs_low(); + ao_flash_instruction.instruction = FLASH_SET_CONFIG; + ao_flash_instruction.address[0] = FLASH_SET_512_BYTE_0; + ao_flash_instruction.address[1] = FLASH_SET_512_BYTE_1; + ao_flash_instruction.address[2] = FLASH_SET_512_BYTE_2; + ao_spi_send(&ao_flash_instruction, 4); + ao_flash_cs_high(); +} + + +static uint8_t +ao_flash_read_status(void) +{ + ao_flash_cs_low(); + ao_flash_instruction.instruction = FLASH_READ_STATUS; + ao_spi_send(&ao_flash_instruction, 1); + ao_spi_recv(&ao_flash_instruction, 1); + ao_flash_cs_high(); + return ao_flash_instruction.instruction; +} + +#define FLASH_BLOCK_NONE 0xffff + +static __xdata uint8_t ao_flash_data[FLASH_BLOCK_SIZE_MAX]; +static __pdata uint16_t ao_flash_block = FLASH_BLOCK_NONE; +static __pdata uint8_t ao_flash_block_dirty; +static __pdata uint8_t ao_flash_write_pending; +static __pdata uint8_t ao_flash_setup_done; +static __pdata uint8_t ao_flash_block_shift; +static __pdata uint16_t ao_flash_block_size; +static __pdata uint16_t ao_flash_block_mask; + +void +ao_storage_setup(void) __reentrant +{ + uint8_t status; + + if (ao_flash_setup_done) + return; + + ao_mutex_get(&ao_flash_mutex); + if (ao_flash_setup_done) { + ao_mutex_put(&ao_flash_mutex); + return; + } + + /* On first use, check to see if the flash chip has + * been programmed to use 512 byte pages. If not, do so. + * And then, because the flash part must be power cycled + * for that change to take effect, panic. + */ + status = ao_flash_read_status(); + + if (!(status & FLASH_STATUS_PAGESIZE_512)) { + ao_flash_set_pagesize_512(); + ao_panic(AO_PANIC_FLASH); + } + + switch (status & 0x3c) { + + /* AT45DB321D */ + case 0x34: + ao_flash_block_shift = 9; + ao_storage_total = ((uint32_t) 4 * (uint32_t) 1024 * (uint32_t) 1024); + break; + + /* AT45DB161D */ + case 0x2c: + ao_flash_block_shift = 9; + ao_storage_total = ((uint32_t) 2 * (uint32_t) 1024 * (uint32_t) 1024); + break; + + /* AT45DB081D */ + case 0x24: + ao_flash_block_shift = 8; + ao_storage_total = ((uint32_t) 1024 * (uint32_t) 1024); + break; + + /* AT45DB041D */ + case 0x1c: + ao_flash_block_shift = 8; + ao_storage_total = ((uint32_t) 512 * (uint32_t) 1024); + break; + + /* AT45DB021D */ + case 0x14: + ao_flash_block_shift = 8; + ao_storage_total = ((uint32_t) 256 * (uint32_t) 1024); + break; + + /* AT45DB011D */ + case 0x0c: + ao_flash_block_shift = 8; + ao_storage_total = ((uint32_t) 128 * (uint32_t) 1024); + break; + + default: + ao_panic(AO_PANIC_FLASH); + } + ao_flash_block_size = 1 << ao_flash_block_shift; + ao_flash_block_mask = ao_flash_block_size - 1; + + ao_storage_block = ao_flash_block_size; + ao_storage_config = ao_storage_total - ao_storage_block; + ao_storage_unit = ao_flash_block_size; + + ao_flash_setup_done = 1; + ao_mutex_put(&ao_flash_mutex); +} + +static void +ao_flash_wait_write(void) +{ + if (ao_flash_write_pending) { + for (;;) { + uint8_t status = ao_flash_read_status(); + if ((status & FLASH_STATUS_RDY)) + break; + } + ao_flash_write_pending = 0; + } +} + +/* Write the current block to the FLASHPROM */ +static void +ao_flash_write_block(void) +{ + ao_flash_wait_write(); + ao_flash_cs_low(); + ao_flash_instruction.instruction = FLASH_WRITE; + + /* 13/14 block bits + 9/8 byte bits (always 0) */ + ao_flash_instruction.address[0] = ao_flash_block >> (16 - ao_flash_block_shift); + ao_flash_instruction.address[1] = ao_flash_block << (ao_flash_block_shift - 8); + ao_flash_instruction.address[2] = 0; + ao_spi_send(&ao_flash_instruction, 4); + ao_spi_send(ao_flash_data, ao_storage_block); + ao_flash_cs_high(); + ao_flash_write_pending = 1; +} + +/* Read the current block from the FLASHPROM */ +static void +ao_flash_read_block(void) +{ + ao_flash_wait_write(); + ao_flash_cs_low(); + ao_flash_instruction.instruction = FLASH_READ; + + /* 13/14 block bits + 9/8 byte bits (always 0) */ + ao_flash_instruction.address[0] = ao_flash_block >> (16 - ao_flash_block_shift); + ao_flash_instruction.address[1] = ao_flash_block << (ao_flash_block_shift - 8); + ao_flash_instruction.address[2] = 0; + ao_spi_send(&ao_flash_instruction, 4); + ao_spi_recv(ao_flash_data, ao_flash_block_size); + ao_flash_cs_high(); +} + +static void +ao_flash_flush_internal(void) +{ + if (ao_flash_block_dirty) { + ao_flash_write_block(); + ao_flash_block_dirty = 0; + } +} + +static void +ao_flash_fill(uint16_t block) +{ + if (block != ao_flash_block) { + ao_flash_flush_internal(); + ao_flash_block = block; + ao_flash_read_block(); + } +} + +uint8_t +ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant +{ + uint16_t block = (uint16_t) (pos >> ao_flash_block_shift); + + /* Transfer the data */ + ao_mutex_get(&ao_flash_mutex); { + if (len != ao_flash_block_size) + ao_flash_fill(block); + else { + ao_flash_flush_internal(); + ao_flash_block = block; + } + memcpy(ao_flash_data + (uint16_t) (pos & ao_flash_block_mask), + buf, + len); + ao_flash_block_dirty = 1; + } ao_mutex_put(&ao_flash_mutex); + return 1; +} + +uint8_t +ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant +{ + uint16_t block = (uint16_t) (pos >> ao_flash_block_shift); + + /* Transfer the data */ + ao_mutex_get(&ao_flash_mutex); { + ao_flash_fill(block); + memcpy(buf, + ao_flash_data + (uint16_t) (pos & ao_flash_block_mask), + len); + } ao_mutex_put(&ao_flash_mutex); + return 1; +} + +void +ao_storage_flush(void) __reentrant +{ + ao_mutex_get(&ao_flash_mutex); { + ao_flash_flush_internal(); + } ao_mutex_put(&ao_flash_mutex); +} + +uint8_t +ao_storage_erase(uint32_t pos) __reentrant +{ + ao_mutex_get(&ao_flash_mutex); { + ao_flash_flush_internal(); + ao_flash_block = (uint16_t) (pos >> ao_flash_block_shift); + memset(ao_flash_data, 0xff, ao_flash_block_size); + ao_flash_block_dirty = 1; + } ao_mutex_put(&ao_flash_mutex); + return 1; +} + +void +ao_storage_device_info(void) __reentrant +{ + uint8_t status; + + ao_storage_setup(); + ao_mutex_get(&ao_flash_mutex); { + status = ao_flash_read_status(); + printf ("Flash status: 0x%02x\n", status); + printf ("Flash block shift: %d\n", ao_flash_block_shift); + printf ("Flash block size: %d\n", ao_flash_block_size); + printf ("Flash block mask: %d\n", ao_flash_block_mask); + printf ("Flash device size: %ld\n", ao_storage_total); + } ao_mutex_put(&ao_flash_mutex); +} + +/* + * To initialize the chip, set up the CS line and + * the SPI interface + */ +void +ao_storage_device_init(void) +{ + /* set up CS */ + FLASH_CS = 1; + P1DIR |= (1 << FLASH_CS_INDEX); + P1SEL &= ~(1 << FLASH_CS_INDEX); +} diff --git a/src/drivers/ao_at45db161d.h b/src/drivers/ao_at45db161d.h new file mode 100644 index 00000000..9ee6f1b6 --- /dev/null +++ b/src/drivers/ao_at45db161d.h @@ -0,0 +1,45 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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. + */ + +/* Defines for the Atmel AT45DB161D 16Mbit SPI Bus DataFlash® */ + +#ifndef _AT45DB161D_H_ +#define _AT45DB161D_H_ + +/* + * We reserve the last block on the device for + * configuration space. Writes and reads in this + * area return errors. + */ + + +#define FLASH_READ 0x03 +#define FLASH_WRITE 0x82 +#define FLASH_PAGE_ERASE 0x81 +#define FLASH_READ_STATUS 0xd7 +#define FLASH_SET_CONFIG 0x3d + +#define FLASH_SET_512_BYTE_0 0x2a +#define FLASH_SET_512_BYTE_1 0x80 +#define FLASH_SET_512_BYTE_2 0xa6 + +#define FLASH_STATUS_RDY (1 << 7) +#define FLASH_STATUS_COMP (1 << 6) +#define FLASH_STATUS_PROTECT (1 << 1) +#define FLASH_STATUS_PAGESIZE_512 (1 << 0) + +#endif /* _AT45DB161D_H_ */ diff --git a/src/drivers/ao_btm.c b/src/drivers/ao_btm.c new file mode 100644 index 00000000..44155ec1 --- /dev/null +++ b/src/drivers/ao_btm.c @@ -0,0 +1,302 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +int8_t ao_btm_stdio; +__xdata uint8_t ao_btm_connected; + +#define AO_BTM_MAX_REPLY 16 +__xdata char ao_btm_reply[AO_BTM_MAX_REPLY]; + +extern volatile __xdata struct ao_fifo ao_usart1_rx_fifo; + +/* + * Read a line of data from the serial port, truncating + * it after a few characters. + */ + +uint8_t +ao_btm_get_line(void) +{ + uint8_t ao_btm_reply_len = 0; + char c; + + for (;;) { + + while ((c = ao_serial_pollchar()) != AO_READ_AGAIN) { + if (ao_btm_reply_len < sizeof (ao_btm_reply)) + ao_btm_reply[ao_btm_reply_len++] = c; + if (c == '\r' || c == '\n') + goto done; + } + for (c = 0; c < 10; c++) { + ao_delay(AO_MS_TO_TICKS(10)); + if (!ao_fifo_empty(ao_usart1_rx_fifo)) + break; + } + if (c == 10) + goto done; + } +done: + for (c = ao_btm_reply_len; c < sizeof (ao_btm_reply);) + ao_btm_reply[c++] = '\0'; + return ao_btm_reply_len; +} + +/* + * Drain the serial port completely + */ +void +ao_btm_drain() +{ + while (ao_btm_get_line()) + ; +} + +/* + * Set the stdio echo for the bluetooth link + */ +void +ao_btm_echo(uint8_t echo) +{ + ao_stdios[ao_btm_stdio].echo = echo; +} + +/* + * Delay between command charaters; the BT module + * can't keep up with 57600 baud + */ + +void +ao_btm_putchar(char c) +{ + ao_serial_putchar(c); + ao_delay(1); +} + +/* + * Wait for the bluetooth device to return + * status from the previously executed command + */ +uint8_t +ao_btm_wait_reply(void) +{ + for (;;) { + ao_btm_get_line(); + if (!strncmp(ao_btm_reply, "OK", 2)) + return 1; + if (!strncmp(ao_btm_reply, "ERROR", 5)) + return -1; + if (ao_btm_reply[0] == '\0') + return 0; + } +} + +void +ao_btm_string(__code char *cmd) +{ + char c; + + while (c = *cmd++) + ao_btm_putchar(c); +} + +uint8_t +ao_btm_cmd(__code char *cmd) +{ + ao_btm_drain(); + ao_btm_string(cmd); + return ao_btm_wait_reply(); +} + +uint8_t +ao_btm_set_name(void) +{ + char sn[8]; + char *s = sn + 8; + char c; + int n; + ao_btm_string("ATN=TeleBT-"); + *--s = '\0'; + *--s = '\r'; + n = ao_serial_number; + do { + *--s = '0' + n % 10; + } while (n /= 10); + while ((c = *s++)) + ao_btm_putchar(c); + return ao_btm_wait_reply(); +} + +uint8_t +ao_btm_try_speed(uint8_t speed) +{ + ao_serial_set_speed(speed); + ao_btm_drain(); + (void) ao_btm_cmd("\rATE0\rATQ0\r"); + if (ao_btm_cmd("AT\r") == 1) + return 1; + return 0; +} + +/* + * A thread to initialize the bluetooth device and + * hang around to blink the LED when connected + */ +void +ao_btm(void) +{ + /* + * Wait for the bluetooth device to boot + */ + ao_delay(AO_SEC_TO_TICKS(3)); + +#if HAS_BEEP + ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200)); +#endif + + /* + * The first time we connect, the BTM-180 comes up at 19200 baud. + * After that, it will remember and come up at 57600 baud. So, see + * if it is already running at 57600 baud, and if that doesn't work + * then tell it to switch to 57600 from 19200 baud. + */ + while (!ao_btm_try_speed(AO_SERIAL_SPEED_57600)) { + ao_delay(AO_SEC_TO_TICKS(1)); + if (ao_btm_try_speed(AO_SERIAL_SPEED_19200)) + ao_btm_cmd("ATL4\r"); + ao_delay(AO_SEC_TO_TICKS(1)); + } + + /* Disable echo */ + ao_btm_cmd("ATE0\r"); + + /* Enable flow control */ + ao_btm_cmd("ATC1\r"); + + /* Set the reported name to something we can find on the host */ + ao_btm_set_name(); + + /* Turn off status reporting */ + ao_btm_cmd("ATQ1\r"); + + ao_btm_stdio = ao_add_stdio(ao_serial_pollchar, + ao_serial_putchar, + NULL); + ao_btm_echo(0); + + for (;;) { + while (!ao_btm_connected) + ao_sleep(&ao_btm_connected); + while (ao_btm_connected) { + ao_led_for(AO_LED_GREEN, AO_MS_TO_TICKS(20)); + ao_delay(AO_SEC_TO_TICKS(3)); + } + } +} + +__xdata struct ao_task ao_btm_task; + +#if BT_LINK_ON_P2 +#define BT_PICTL_ICON PICTL_P2ICON +#define BT_PIFG P2IFG +#define BT_PDIR P2DIR +#define BT_PINP P2INP +#define BT_IEN2_PIE IEN2_P2IE +#endif +#if BT_LINK_ON_P1 +#define BT_PICTL_ICON PICTL_P1ICON +#define BT_PIFG P1IFG +#define BT_PDIR P1DIR +#define BT_PINP P1INP +#define BT_IEN2_PIE IEN2_P1IE +#endif + +void +ao_btm_check_link() __critical +{ + /* Check the pin and configure the interrupt detector to wait for the + * pin to flip the other way + */ + if (BT_LINK_PIN) { + ao_btm_connected = 0; + PICTL |= BT_PICTL_ICON; + } else { + ao_btm_connected = 1; + PICTL &= ~BT_PICTL_ICON; + } +} + +void +ao_btm_isr(void) +#if BT_LINK_ON_P1 + __interrupt 15 +#endif +{ +#if BT_LINK_ON_P1 + P1IF = 0; +#endif + if (BT_PIFG & (1 << BT_LINK_PIN_INDEX)) { + ao_btm_check_link(); + ao_wakeup(&ao_btm_connected); + } + BT_PIFG = 0; +} + +void +ao_btm_init (void) +{ + ao_serial_init(); + ao_serial_set_speed(AO_SERIAL_SPEED_19200); + +#if BT_LINK_ON_P1 + /* + * Configure ser reset line + */ + + P1_6 = 0; + P1DIR |= (1 << 6); +#endif + + /* + * Configure link status line + */ + + /* Set pin to input */ + BT_PDIR &= ~(1 << BT_LINK_PIN_INDEX); + + /* Set pin to tri-state */ + BT_PINP |= (1 << BT_LINK_PIN_INDEX); + + /* Enable interrupts */ + IEN2 |= BT_IEN2_PIE; + + /* Check current pin state */ + ao_btm_check_link(); + +#if BT_LINK_ON_P2 + /* Eable the pin interrupt */ + PICTL |= PICTL_P2IEN; +#endif +#if BT_LINK_ON_P1 + /* Enable pin interrupt */ + P1IEN |= (1 << BT_LINK_PIN_INDEX); +#endif + + ao_add_task(&ao_btm_task, ao_btm, "bt"); +} diff --git a/src/drivers/ao_companion.c b/src/drivers/ao_companion.c new file mode 100644 index 00000000..4c8f4269 --- /dev/null +++ b/src/drivers/ao_companion.c @@ -0,0 +1,132 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +#define ao_spi_slow() (U0GCR = (UxGCR_CPOL_NEGATIVE | \ + UxGCR_CPHA_FIRST_EDGE | \ + UxGCR_ORDER_MSB | \ + (13 << UxGCR_BAUD_E_SHIFT))) + +#define ao_spi_fast() (U0GCR = (UxGCR_CPOL_NEGATIVE | \ + UxGCR_CPHA_FIRST_EDGE | \ + UxGCR_ORDER_MSB | \ + (17 << UxGCR_BAUD_E_SHIFT))) + +#define COMPANION_SELECT() do { ao_spi_get_bit(COMPANION_CS); ao_spi_slow(); } while (0) +#define COMPANION_DESELECT() do { ao_spi_fast(); ao_spi_put_bit(COMPANION_CS); } while (0) + +static __xdata struct ao_companion_command ao_companion_command; +__xdata struct ao_companion_setup ao_companion_setup; + +__xdata uint16_t ao_companion_data[AO_COMPANION_MAX_CHANNELS]; +__pdata uint8_t ao_companion_running; +__xdata uint8_t ao_companion_mutex; + +static void +ao_companion_send_command(uint8_t command) +{ + ao_companion_command.command = command; + ao_companion_command.flight_state = ao_flight_state; + ao_companion_command.tick = ao_time(); + ao_companion_command.serial = ao_serial_number; + ao_companion_command.flight = ao_flight_number; + ao_spi_send(&ao_companion_command, sizeof (ao_companion_command)); +} + +static uint8_t +ao_companion_get_setup(void) +{ + COMPANION_SELECT(); + ao_companion_send_command(AO_COMPANION_SETUP); + ao_spi_recv(&ao_companion_setup, sizeof (ao_companion_setup)); + COMPANION_DESELECT(); + return (ao_companion_setup.board_id == + ~ao_companion_setup.board_id_inverse); +} + +static void +ao_companion_get_data(void) +{ + COMPANION_SELECT(); + ao_companion_send_command(AO_COMPANION_FETCH); + ao_mutex_get(&ao_companion_mutex); + ao_spi_recv(&ao_companion_data, ao_companion_setup.channels * 2); + ao_mutex_put(&ao_companion_mutex); + COMPANION_DESELECT(); +} + +static void +ao_companion_notify(void) +{ + COMPANION_SELECT(); + ao_companion_send_command(AO_COMPANION_NOTIFY); + COMPANION_DESELECT(); +} + +void +ao_companion(void) +{ + uint8_t i; + while (!ao_flight_number) + ao_sleep(&ao_flight_number); + for (i = 0; i < 10; i++) { + ao_delay(AO_SEC_TO_TICKS(1)); + if ((ao_companion_running = ao_companion_get_setup())) + break; + } + while (ao_companion_running) { + ao_alarm(ao_companion_setup.update_period); + if (ao_sleep(DATA_TO_XDATA(&ao_flight_state))) + ao_companion_get_data(); + else + ao_companion_notify(); + } + ao_exit(); +} + +void +ao_companion_status(void) __reentrant +{ + uint8_t i; + printf("Companion running: %d\n", ao_companion_running); + printf("device: %d\n", ao_companion_setup.board_id); + printf("update period: %d\n", ao_companion_setup.update_period); + printf("channels: %d\n", ao_companion_setup.channels); + printf("data:"); + for(i = 0; i < ao_companion_setup.channels; i++) + printf(" %5u", ao_companion_data[i]); + printf("\n"); +} + +__code struct ao_cmds ao_companion_cmds[] = { + { ao_companion_status, "L\0Companion link status" }, + { 0, NULL }, +}; + +static __xdata struct ao_task ao_companion_task; + +void +ao_companion_init(void) +{ + COMPANION_CS_PORT |= COMPANION_CS_MASK; /* raise all CS pins */ + COMPANION_CS_DIR |= COMPANION_CS_MASK; /* set CS pins as outputs */ + COMPANION_CS_SEL &= ~COMPANION_CS_MASK; /* set CS pins as GPIO */ + + ao_cmd_register(&ao_companion_cmds[0]); + ao_add_task(&ao_companion_task, ao_companion, "companion"); +} diff --git a/src/drivers/ao_gps_sirf.c b/src/drivers/ao_gps_sirf.c new file mode 100644 index 00000000..f2abbf84 --- /dev/null +++ b/src/drivers/ao_gps_sirf.c @@ -0,0 +1,442 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_GPS_TEST +#include "ao.h" +#endif + +__xdata uint8_t ao_gps_mutex; +__pdata uint16_t ao_gps_tick; +__xdata struct ao_telemetry_location ao_gps_data; +__xdata struct ao_telemetry_satellite ao_gps_tracking_data; + +static const char ao_gps_set_nmea[] = "\r\n$PSRF100,0,57600,8,1,0*37\r\n"; + +const char ao_gps_config[] = { + + 0xa0, 0xa2, 0x00, 0x0e, /* length: 14 bytes */ + 136, /* mode control */ + 0, 0, /* reserved */ + 0, /* degraded mode (allow 1-SV navigation) */ + 0, 0, /* reserved */ + 0, 0, /* user specified altitude */ + 2, /* alt hold mode (disabled, require 3d fixes) */ + 0, /* alt hold source (use last computed altitude) */ + 0, /* reserved */ + 10, /* Degraded time out (10 sec) */ + 10, /* Dead Reckoning time out (10 sec) */ + 0, /* Track smoothing (disabled) */ + 0x00, 0x8e, 0xb0, 0xb3, + + 0xa0, 0xa2, 0x00, 0x08, /* length: 8 bytes */ + 166, /* Set message rate */ + 2, /* enable/disable all messages */ + 0, /* message id (ignored) */ + 0, /* update rate (0 = disable) */ + 0, 0, 0, 0, /* reserved */ + 0x00, 0xa8, 0xb0, 0xb3, + + 0xa0, 0xa2, 0x00, 0x02, /* length: 2 bytes */ + 143, /* static navigation */ + 0, /* disable */ + 0x00, 0x8f, 0xb0, 0xb3, +}; + +#define NAV_TYPE_GPS_FIX_TYPE_MASK (7 << 0) +#define NAV_TYPE_NO_FIX (0 << 0) +#define NAV_TYPE_SV_KF (1 << 0) +#define NAV_TYPE_2_SV_KF (2 << 0) +#define NAV_TYPE_3_SV_KF (3 << 0) +#define NAV_TYPE_4_SV_KF (4 << 0) +#define NAV_TYPE_2D_LEAST_SQUARES (5 << 0) +#define NAV_TYPE_3D_LEAST_SQUARES (6 << 0) +#define NAV_TYPE_DR (7 << 0) +#define NAV_TYPE_TRICKLE_POWER (1 << 3) +#define NAV_TYPE_ALTITUDE_HOLD_MASK (3 << 4) +#define NAV_TYPE_ALTITUDE_HOLD_NONE (0 << 4) +#define NAV_TYPE_ALTITUDE_HOLD_KF (1 << 4) +#define NAV_TYPE_ALTITUDE_HOLD_USER (2 << 4) +#define NAV_TYPE_ALTITUDE_HOLD_ALWAYS (3 << 4) +#define NAV_TYPE_DOP_LIMIT_EXCEEDED (1 << 6) +#define NAV_TYPE_DGPS_APPLIED (1 << 7) +#define NAV_TYPE_SENSOR_DR (1 << 8) +#define NAV_TYPE_OVERDETERMINED (1 << 9) +#define NAV_TYPE_DR_TIMEOUT_EXCEEDED (1 << 10) +#define NAV_TYPE_FIX_MI_EDIT (1 << 11) +#define NAV_TYPE_INVALID_VELOCITY (1 << 12) +#define NAV_TYPE_ALTITUDE_HOLD_DISABLED (1 << 13) +#define NAV_TYPE_DR_ERROR_STATUS_MASK (3 << 14) +#define NAV_TYPE_DR_ERROR_STATUS_GPS_ONLY (0 << 14) +#define NAV_TYPE_DR_ERROR_STATUS_DR_FROM_GPS (1 << 14) +#define NAV_TYPE_DR_ERROR_STATUS_DR_SENSOR_ERROR (2 << 14) +#define NAV_TYPE_DR_ERROR_STATUS_DR_IN_TEST (3 << 14) + +struct sirf_geodetic_nav_data { + uint16_t nav_type; + uint16_t utc_year; + uint8_t utc_month; + uint8_t utc_day; + uint8_t utc_hour; + uint8_t utc_minute; + uint16_t utc_second; + int32_t lat; + int32_t lon; + int32_t alt_msl; + uint16_t ground_speed; + uint16_t course; + int16_t climb_rate; + uint32_t h_error; + uint32_t v_error; + uint8_t num_sv; + uint8_t hdop; +}; + +static __xdata struct sirf_geodetic_nav_data ao_sirf_data; + +struct sirf_measured_sat_data { + uint8_t svid; + 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; + +#define ao_sirf_byte() ((uint8_t) ao_serial_getchar()) + +static uint8_t data_byte(void) +{ + uint8_t c = ao_sirf_byte(); + --ao_sirf_len; + ao_sirf_cksum += c; + return c; +} + +static char __xdata *sirf_target; + +static void sirf_u16(uint8_t offset) +{ + uint16_t __xdata *ptr = (uint16_t __xdata *) (sirf_target + offset); + uint16_t val; + + val = data_byte() << 8; + val |= data_byte (); + *ptr = val; +} + +static void sirf_u8(uint8_t 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) __reentrant +{ + uint32_t __xdata *ptr = (uint32_t __xdata *) (sirf_target + offset); + uint32_t val; + + val = ((uint32_t) data_byte ()) << 24; + val |= ((uint32_t) data_byte ()) << 16; + val |= ((uint32_t) data_byte ()) << 8; + val |= ((uint32_t) data_byte ()); + *ptr = val; +} + +static void sirf_discard(uint8_t len) +{ + while (len--) + data_byte(); +} + +#define SIRF_END 0 +#define SIRF_DISCARD 1 +#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 */ + { SIRF_DISCARD, 6 }, /* 5 week number, time of week */ + { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, utc_year) }, /* 11 */ + { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_month) }, /* 13 */ + { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_day) }, /* 14 */ + { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_hour) }, /* 15 */ + { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_minute) }, /* 16 */ + { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, utc_second) }, /* 17 */ + { SIRF_DISCARD, 4 }, /* satellite id list */ /* 19 */ + { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, lat) }, /* 23 */ + { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, lon) }, /* 27 */ + { SIRF_DISCARD, 4 }, /* altitude from ellipsoid */ /* 31 */ + { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, alt_msl) }, /* 35 */ + { SIRF_DISCARD, 1 }, /* map datum */ /* 39 */ + { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, ground_speed) }, /* 40 */ + { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, course) }, /* 42 */ + { SIRF_DISCARD, 2 }, /* magnetic variation */ /* 44 */ + { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, climb_rate) }, /* 46 */ + { SIRF_DISCARD, 2 }, /* turn rate */ /* 48 */ + { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, h_error) }, /* 50 */ + { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, v_error) }, /* 54 */ + { SIRF_DISCARD, 30 }, /* time error, h_vel error, clock_bias, + clock bias error, clock drift, + clock drift error, distance, + distance error, heading error */ /* 58 */ + { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, num_sv) }, /* 88 */ + { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, hdop) }, /* 89 */ + { SIRF_DISCARD, 1 }, /* additional mode info */ /* 90 */ + { SIRF_END, 0 }, /* 91 */ +}; + +static void +ao_sirf_parse_41(void) __reentrant +{ + ao_sirf_parse(&ao_sirf_data, geodetic_nav_data_packet); +} + +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, 4 }, /* 1 azimuth, 2 elevation, 3 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 +ao_gps_setup(void) __reentrant +{ + uint8_t i, k; + ao_serial_set_speed(AO_SERIAL_SPEED_4800); + for (i = 0; i < 64; i++) + ao_serial_putchar(0x00); + for (k = 0; k < 3; k++) + for (i = 0; i < sizeof (ao_gps_set_nmea); i++) + ao_serial_putchar(ao_gps_set_nmea[i]); + ao_serial_set_speed(AO_SERIAL_SPEED_57600); + for (i = 0; i < 64; i++) + ao_serial_putchar(0x00); +} + +static const char ao_gps_set_message_rate[] = { + 0xa0, 0xa2, 0x00, 0x08, + 166, + 0, +}; + +void +ao_sirf_set_message_rate(uint8_t msg, uint8_t rate) __reentrant +{ + uint16_t cksum = 0x00a6; + uint8_t i; + + for (i = 0; i < sizeof (ao_gps_set_message_rate); i++) + ao_serial_putchar(ao_gps_set_message_rate[i]); + ao_serial_putchar(msg); + ao_serial_putchar(rate); + cksum = 0xa6 + msg + rate; + for (i = 0; i < 4; i++) + ao_serial_putchar(0); + ao_serial_putchar((cksum >> 8) & 0x7f); + ao_serial_putchar(cksum & 0xff); + ao_serial_putchar(0xb0); + ao_serial_putchar(0xb3); +} + +static const uint8_t sirf_disable[] = { + 2, + 9, + 10, + 27, + 50, + 52, +}; + +void +ao_gps(void) __reentrant +{ + uint8_t i, k; + uint16_t cksum; + + ao_gps_setup(); + for (k = 0; k < 5; k++) + { + for (i = 0; i < sizeof (ao_gps_config); i++) + ao_serial_putchar(ao_gps_config[i]); + 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 */ + while (ao_sirf_byte() != (uint8_t) 0xa0) + ; + if (ao_sirf_byte() != (uint8_t) 0xa2) + continue; + + /* Length */ + ao_sirf_len = ao_sirf_byte() << 8; + ao_sirf_len |= ao_sirf_byte(); + if (ao_sirf_len > 1023) + continue; + + ao_sirf_cksum = 0; + + /* message ID */ + i = data_byte (); /* 0 */ + + switch (i) { + case 41: + if (ao_sirf_len < 90) + 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; + + /* verify checksum and end sequence */ + ao_sirf_cksum &= 0x7fff; + cksum = ao_sirf_byte() << 8; + cksum |= ao_sirf_byte(); + if (ao_sirf_cksum != cksum) + continue; + if (ao_sirf_byte() != (uint8_t) 0xb0) + continue; + if (ao_sirf_byte() != (uint8_t) 0xb3) + continue; + + switch (i) { + case 41: + ao_mutex_get(&ao_gps_mutex); + ao_gps_tick = ao_time(); + ao_gps_data.hour = ao_sirf_data.utc_hour; + ao_gps_data.minute = ao_sirf_data.utc_minute; + ao_gps_data.second = ao_sirf_data.utc_second / 1000; + ao_gps_data.flags = ((ao_sirf_data.num_sv << AO_GPS_NUM_SAT_SHIFT) & AO_GPS_NUM_SAT_MASK) | AO_GPS_RUNNING; + if ((ao_sirf_data.nav_type & NAV_TYPE_GPS_FIX_TYPE_MASK) >= NAV_TYPE_4_SV_KF) + ao_gps_data.flags |= AO_GPS_VALID; + ao_gps_data.latitude = ao_sirf_data.lat; + ao_gps_data.longitude = ao_sirf_data.lon; + ao_gps_data.altitude = ao_sirf_data.alt_msl / 100; + ao_gps_data.ground_speed = ao_sirf_data.ground_speed; + 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 0 + if (ao_sirf_data.h_error > 6553500) + ao_gps_data.h_error = 65535; + else + ao_gps_data.h_error = ao_sirf_data.h_error / 100; + if (ao_sirf_data.v_error > 6553500) + ao_gps_data.v_error = 65535; + else + ao_gps_data.v_error = ao_sirf_data.v_error / 100; +#endif + 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].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; + } + } +} + +__xdata struct ao_task ao_gps_task; + +void +ao_gps_init(void) +{ + ao_add_task(&ao_gps_task, ao_gps, "gps"); +} diff --git a/src/drivers/ao_gps_skytraq.c b/src/drivers/ao_gps_skytraq.c new file mode 100644 index 00000000..7ac26946 --- /dev/null +++ b/src/drivers/ao_gps_skytraq.c @@ -0,0 +1,490 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_GPS_TEST +#include "ao.h" +#endif + +#define AO_GPS_LEADER 2 + +static __code char ao_gps_header[] = "GP"; + +__xdata uint8_t ao_gps_mutex; +static __data char ao_gps_char; +static __pdata uint8_t ao_gps_cksum; +static __pdata uint8_t ao_gps_error; + +__pdata uint16_t ao_gps_tick; +__xdata struct ao_telemetry_location ao_gps_data; +__xdata struct ao_telemetry_satellite ao_gps_tracking_data; + +static __pdata uint16_t ao_gps_next_tick; +static __xdata struct ao_telemetry_location ao_gps_next; +static __pdata uint8_t ao_gps_date_flags; +static __xdata struct ao_telemetry_satellite ao_gps_tracking_next; + +#define STQ_S 0xa0, 0xa1 +#define STQ_E 0x0d, 0x0a +#define SKYTRAQ_MSG_2(id,a,b) \ + STQ_S, 0, 3, id, a,b, (id^a^b), STQ_E +#define SKYTRAQ_MSG_3(id,a,b,c) \ + STQ_S, 0, 4, id, a,b,c, (id^a^b^c), STQ_E +#define SKYTRAQ_MSG_8(id,a,b,c,d,e,f,g,h) \ + STQ_S, 0, 9, id, a,b,c,d,e,f,g,h, (id^a^b^c^d^e^f^g^h), STQ_E +#define SKYTRAQ_MSG_14(id,a,b,c,d,e,f,g,h,i,j,k,l,m,n) \ + STQ_S, 0,15, id, a,b,c,d,e,f,g,h,i,j,k,l,m,n, \ + (id^a^b^c^d^e^f^g^h^i^j^k^l^m^n), STQ_E + +static __code uint8_t ao_gps_config[] = { + SKYTRAQ_MSG_8(0x08, 1, 1, 1, 1, 1, 1, 1, 0), /* configure nmea */ + /* gga interval */ + /* gsa interval */ + /* gsv interval */ + /* gll interval */ + /* rmc interval */ + /* vtg interval */ + /* zda interval */ + /* attributes (0 = update to sram, 1 = update flash too) */ + + SKYTRAQ_MSG_2(0x3c, 0x00, 0x00), /* configure navigation mode */ + /* 0 = car, 1 = pedestrian */ + /* 0 = update to sram, 1 = update sram + flash */ +}; + +static void +ao_gps_lexchar(void) +{ + if (ao_gps_error) + ao_gps_char = '\n'; + else + ao_gps_char = ao_serial_getchar(); + ao_gps_cksum ^= ao_gps_char; +} + +void +ao_gps_skip_field(void) +{ + while (ao_gps_char != ',' && ao_gps_char != '*' && ao_gps_char != '\n') + ao_gps_lexchar(); +} + +void +ao_gps_skip_sep(void) +{ + if (ao_gps_char == ',' || ao_gps_char == '.' || ao_gps_char == '*') + ao_gps_lexchar(); +} + +__pdata static uint8_t ao_gps_num_width; + +static int16_t +ao_gps_decimal(uint8_t max_width) +{ + int16_t v; + __pdata uint8_t neg = 0; + + ao_gps_skip_sep(); + if (ao_gps_char == '-') { + neg = 1; + ao_gps_lexchar(); + } + v = 0; + ao_gps_num_width = 0; + while (ao_gps_num_width < max_width) { + if (ao_gps_char < '0' || '9' < ao_gps_char) + break; + v = v * (int16_t) 10 + ao_gps_char - '0'; + ao_gps_num_width++; + ao_gps_lexchar(); + } + if (neg) + v = -v; + return v; +} + +static uint8_t +ao_gps_hex(uint8_t max_width) +{ + uint8_t v, d; + + ao_gps_skip_sep(); + v = 0; + ao_gps_num_width = 0; + while (ao_gps_num_width < max_width) { + if ('0' <= ao_gps_char && ao_gps_char <= '9') + d = ao_gps_char - '0'; + else if ('A' <= ao_gps_char && ao_gps_char <= 'F') + d = ao_gps_char - 'A' + 10; + else if ('a' <= ao_gps_char && ao_gps_char <= 'f') + d = ao_gps_char - 'a' + 10; + else + break; + v = (v << 4) | d; + ao_gps_num_width++; + ao_gps_lexchar(); + } + return v; +} + +static int32_t +ao_gps_parse_pos(uint8_t deg_width) __reentrant +{ + int32_t d; + int32_t m; + int32_t f; + + d = ao_gps_decimal(deg_width); + m = ao_gps_decimal(2); + if (ao_gps_char == '.') { + f = ao_gps_decimal(4); + while (ao_gps_num_width < 4) { + f *= 10; + ao_gps_num_width++; + } + } else { + f = 0; + if (ao_gps_char != ',') + ao_gps_error = 1; + } + d = d * 10000000l; + m = m * 10000l + f; + d = d + m * 50 / 3; + return d; +} + +static uint8_t +ao_gps_parse_flag(char no_c, char yes_c) __reentrant +{ + uint8_t ret = 0; + ao_gps_skip_sep(); + if (ao_gps_char == yes_c) + ret = 1; + else if (ao_gps_char == no_c) + ret = 0; + else + ao_gps_error = 1; + ao_gps_lexchar(); + return ret; +} + +static void +ao_nmea_gga() +{ + uint8_t i; + + /* Now read the data into the gps data record + * + * $GPGGA,025149.000,4528.1723,N,12244.2480,W,1,05,2.0,103.5,M,-19.5,M,,0000*66 + * + * Essential fix data + * + * 025149.000 time (02:51:49.000 GMT) + * 4528.1723,N Latitude 45°28.1723' N + * 12244.2480,W Longitude 122°44.2480' W + * 1 Fix quality: + * 0 = invalid + * 1 = GPS fix (SPS) + * 2 = DGPS fix + * 3 = PPS fix + * 4 = Real Time Kinematic + * 5 = Float RTK + * 6 = estimated (dead reckoning) + * 7 = Manual input mode + * 8 = Simulation mode + * 05 Number of satellites (5) + * 2.0 Horizontal dilution + * 103.5,M Altitude, 103.5M above msl + * -19.5,M Height of geoid above WGS84 ellipsoid + * ? time in seconds since last DGPS update + * 0000 DGPS station ID + * *66 checksum + */ + + ao_gps_next_tick = ao_time(); + ao_gps_next.flags = AO_GPS_RUNNING | ao_gps_date_flags; + ao_gps_next.hour = ao_gps_decimal(2); + ao_gps_next.minute = ao_gps_decimal(2); + ao_gps_next.second = ao_gps_decimal(2); + ao_gps_skip_field(); /* skip seconds fraction */ + + ao_gps_next.latitude = ao_gps_parse_pos(2); + if (ao_gps_parse_flag('N', 'S')) + ao_gps_next.latitude = -ao_gps_next.latitude; + ao_gps_next.longitude = ao_gps_parse_pos(3); + if (ao_gps_parse_flag('E', 'W')) + ao_gps_next.longitude = -ao_gps_next.longitude; + + i = ao_gps_decimal(0xff); + if (i == 1) + ao_gps_next.flags |= AO_GPS_VALID; + + i = ao_gps_decimal(0xff) << AO_GPS_NUM_SAT_SHIFT; + if (i > AO_GPS_NUM_SAT_MASK) + i = AO_GPS_NUM_SAT_MASK; + ao_gps_next.flags |= i; + + ao_gps_lexchar(); + i = ao_gps_decimal(0xff); + if (i <= 50) { + i = (uint8_t) 5 * i; + if (ao_gps_char == '.') + i = (i + ((uint8_t) ao_gps_decimal(1) >> 1)); + } else + i = 255; + ao_gps_next.hdop = i; + ao_gps_skip_field(); + + ao_gps_next.altitude = ao_gps_decimal(0xff); + ao_gps_skip_field(); /* skip any fractional portion */ + + /* Skip remaining fields */ + while (ao_gps_char != '*' && ao_gps_char != '\n' && ao_gps_char != '\r') { + ao_gps_lexchar(); + ao_gps_skip_field(); + } + if (ao_gps_char == '*') { + uint8_t cksum = ao_gps_cksum ^ '*'; + if (cksum != ao_gps_hex(2)) + ao_gps_error = 1; + } else + ao_gps_error = 1; + if (!ao_gps_error) { + ao_mutex_get(&ao_gps_mutex); + ao_gps_tick = ao_gps_next_tick; + memcpy(&ao_gps_data, &ao_gps_next, sizeof (ao_gps_data)); + ao_mutex_put(&ao_gps_mutex); + ao_wakeup(&ao_gps_data); + } +} + +static void +ao_nmea_gsv(void) +{ + char c; + uint8_t i; + uint8_t done; + /* Now read the data into the GPS tracking data record + * + * $GPGSV,3,1,12,05,54,069,45,12,44,061,44,21,07,184,46,22,78,289,47*72 + * + * Satellites in view data + * + * 3 Total number of GSV messages + * 1 Sequence number of current GSV message + * 12 Total sats in view (0-12) + * 05 SVID + * 54 Elevation + * 069 Azimuth + * 45 C/N0 in dB + * ... other SVIDs + * 72 checksum + */ + c = ao_gps_decimal(1); /* total messages */ + i = ao_gps_decimal(1); /* message sequence */ + if (i == 1) { + ao_gps_tracking_next.channels = 0; + } + done = (uint8_t) c == i; + ao_gps_lexchar(); + ao_gps_skip_field(); /* sats in view */ + while (ao_gps_char != '*' && ao_gps_char != '\n' && ao_gps_char != '\r') { + i = ao_gps_tracking_next.channels; + c = ao_gps_decimal(2); /* SVID */ + if (i < AO_MAX_GPS_TRACKING) + ao_gps_tracking_next.sats[i].svid = c; + ao_gps_lexchar(); + ao_gps_skip_field(); /* elevation */ + ao_gps_lexchar(); + ao_gps_skip_field(); /* azimuth */ + c = ao_gps_decimal(2); /* C/N0 */ + if (i < AO_MAX_GPS_TRACKING) { + if ((ao_gps_tracking_next.sats[i].c_n_1 = c) != 0) + ao_gps_tracking_next.channels = i + 1; + } + } + if (ao_gps_char == '*') { + uint8_t cksum = ao_gps_cksum ^ '*'; + if (cksum != ao_gps_hex(2)) + ao_gps_error = 1; + } + else + ao_gps_error = 1; + if (ao_gps_error) + ao_gps_tracking_next.channels = 0; + else if (done) { + ao_mutex_get(&ao_gps_mutex); + memcpy(&ao_gps_tracking_data, &ao_gps_tracking_next, + sizeof(ao_gps_tracking_data)); + ao_mutex_put(&ao_gps_mutex); + ao_wakeup(&ao_gps_tracking_data); + } +} + +static void +ao_nmea_rmc(void) +{ + char a, c; + uint8_t i; + /* Parse the RMC record to read out the current date */ + + /* $GPRMC,111636.932,A,2447.0949,N,12100.5223,E,000.0,000.0,030407,,,A*61 + * + * Recommended Minimum Specific GNSS Data + * + * 111636.932 UTC time 11:16:36.932 + * A Data Valid (V = receiver warning) + * 2447.0949 Latitude + * N North/south indicator + * 12100.5223 Longitude + * E East/west indicator + * 000.0 Speed over ground + * 000.0 Course over ground + * 030407 UTC date (ddmmyy format) + * A Mode indicator: + * N = data not valid + * A = autonomous mode + * D = differential mode + * E = estimated (dead reckoning) mode + * M = manual input mode + * S = simulator mode + * 61 checksum + */ + ao_gps_skip_field(); + for (i = 0; i < 8; i++) { + ao_gps_lexchar(); + ao_gps_skip_field(); + } + a = ao_gps_decimal(2); + c = ao_gps_decimal(2); + i = ao_gps_decimal(2); + /* Skip remaining fields */ + while (ao_gps_char != '*' && ao_gps_char != '\n' && ao_gps_char != '\r') { + ao_gps_lexchar(); + ao_gps_skip_field(); + } + if (ao_gps_char == '*') { + uint8_t cksum = ao_gps_cksum ^ '*'; + if (cksum != ao_gps_hex(2)) + ao_gps_error = 1; + } else + ao_gps_error = 1; + if (!ao_gps_error) { + ao_gps_next.year = i; + ao_gps_next.month = c; + ao_gps_next.day = a; + ao_gps_date_flags = AO_GPS_DATE_VALID; + } +} + +#define ao_skytraq_sendstruct(s) ao_skytraq_sendbytes((s), sizeof(s)) + +static void +ao_skytraq_sendbytes(__code uint8_t *b, uint8_t l) +{ + while (l--) { + uint8_t c = *b++; + if (c == 0xa0) + ao_delay(AO_MS_TO_TICKS(500)); + ao_serial_putchar(c); + } +} + +static void +ao_gps_nmea_parse(void) +{ + uint8_t a, b, c; + + ao_gps_cksum = 0; + ao_gps_error = 0; + + for (a = 0; a < AO_GPS_LEADER; a++) { + ao_gps_lexchar(); + if (ao_gps_char != ao_gps_header[a]) + return; + } + + ao_gps_lexchar(); + a = ao_gps_char; + ao_gps_lexchar(); + b = ao_gps_char; + ao_gps_lexchar(); + c = ao_gps_char; + ao_gps_lexchar(); + + if (ao_gps_char != ',') + return; + + if (a == (uint8_t) 'G' && b == (uint8_t) 'G' && c == (uint8_t) 'A') { + ao_nmea_gga(); + } else if (a == (uint8_t) 'G' && b == (uint8_t) 'S' && c == (uint8_t) 'V') { + ao_nmea_gsv(); + } else if (a == (uint8_t) 'R' && b == (uint8_t) 'M' && c == (uint8_t) 'C') { + ao_nmea_rmc(); + } +} + +void +ao_gps(void) __reentrant +{ + ao_serial_set_speed(AO_SERIAL_SPEED_9600); + + /* give skytraq time to boot in case of cold start */ + ao_delay(AO_MS_TO_TICKS(2000)); + + ao_skytraq_sendstruct(ao_gps_config); + + for (;;) { + /* Locate the begining of the next record */ + if (ao_serial_getchar() == '$') { + ao_gps_nmea_parse(); + } + + } +} + +__xdata struct ao_task ao_gps_task; + +static void +gps_dump(void) __reentrant +{ + uint8_t i; + ao_mutex_get(&ao_gps_mutex); + printf ("Date: %02d/%02d/%02d\n", ao_gps_data.year, ao_gps_data.month, ao_gps_data.day); + printf ("Time: %02d:%02d:%02d\n", ao_gps_data.hour, ao_gps_data.minute, ao_gps_data.second); + printf ("Lat/Lon: %ld %ld\n", ao_gps_data.latitude, ao_gps_data.longitude); + printf ("Alt: %d\n", ao_gps_data.altitude); + printf ("Flags: 0x%x\n", ao_gps_data.flags); + printf ("Sats: %d", ao_gps_tracking_data.channels); + for (i = 0; i < ao_gps_tracking_data.channels; i++) + printf (" %d %d", + ao_gps_tracking_data.sats[i].svid, + ao_gps_tracking_data.sats[i].c_n_1); + printf ("\ndone\n"); + ao_mutex_put(&ao_gps_mutex); +} + +__code struct ao_cmds ao_gps_cmds[] = { + { gps_dump, "g\0Display GPS" }, + { 0, NULL }, +}; + +void +ao_gps_init(void) +{ + ao_add_task(&ao_gps_task, ao_gps, "gps"); + ao_cmd_register(&ao_gps_cmds[0]); +} diff --git a/src/drivers/ao_m25.c b/src/drivers/ao_m25.c new file mode 100644 index 00000000..d7208273 --- /dev/null +++ b/src/drivers/ao_m25.c @@ -0,0 +1,380 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +/* Total bytes of available storage */ +__pdata uint32_t ao_storage_total; + +/* Block size - device is erased in these units. At least 256 bytes */ +__pdata uint32_t ao_storage_block; + +/* Byte offset of config block. Will be ao_storage_block bytes long */ +__pdata uint32_t ao_storage_config; + +/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */ +__pdata uint16_t ao_storage_unit; + +/* + * Each flash chip is arranged in 64kB sectors; the + * chip cannot erase in units smaller than that. + * + * Writing happens in units of 256 byte pages and + * can only change bits from 1 to 0. So, you can rewrite + * the same contents, or append to an existing page easily enough + */ + +#define M25_WREN 0x06 /* Write Enable */ +#define M25_WRDI 0x04 /* Write Disable */ +#define M25_RDID 0x9f /* Read Identification */ +#define M25_RDSR 0x05 /* Read Status Register */ +#define M25_WRSR 0x01 /* Write Status Register */ +#define M25_READ 0x03 /* Read Data Bytes */ +#define M25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define M25_PP 0x02 /* Page Program */ +#define M25_SE 0xd8 /* Sector Erase */ +#define M25_BE 0xc7 /* Bulk Erase */ +#define M25_DP 0xb9 /* Deep Power-down */ + +/* RDID response */ +#define M25_MANUF_OFFSET 0 +#define M25_MEMORY_TYPE_OFFSET 1 +#define M25_CAPACITY_OFFSET 2 +#define M25_UID_OFFSET 3 +#define M25_CFI_OFFSET 4 +#define M25_RDID_LEN 4 /* that's all we need */ + +#define M25_CAPACITY_128KB 0x11 +#define M25_CAPACITY_256KB 0x12 +#define M25_CAPACITY_512KB 0x13 +#define M25_CAPACITY_1MB 0x14 +#define M25_CAPACITY_2MB 0x15 + +/* + * Status register bits + */ + +#define M25_STATUS_SRWD (1 << 7) /* Status register write disable */ +#define M25_STATUS_BP_MASK (7 << 2) /* Block protect bits */ +#define M25_STATUS_BP_SHIFT (2) +#define M25_STATUS_WEL (1 << 1) /* Write enable latch */ +#define M25_STATUS_WIP (1 << 0) /* Write in progress */ + +/* + * On teleterra, the m25 chip select pins are + * wired on P0_0 through P0_3. + */ + +#if M25_MAX_CHIPS > 1 +static uint8_t ao_m25_size[M25_MAX_CHIPS]; /* number of sectors in each chip */ +static uint8_t ao_m25_pin[M25_MAX_CHIPS]; /* chip select pin for each chip */ +static uint8_t ao_m25_numchips; /* number of chips detected */ +#endif +static uint8_t ao_m25_total; /* total sectors available */ +static uint8_t ao_m25_wip; /* write in progress */ + +static __xdata uint8_t ao_m25_mutex; + +/* + * This little array is abused to send and receive data. A particular + * caution -- the read and write addresses are written into the last + * three bytes of the array by ao_m25_set_page_address and then the + * first byte is used by ao_m25_wait_wip and ao_m25_write_enable, neither + * of which touch those last three bytes. + */ + +static __xdata uint8_t ao_m25_instruction[4]; + +#define M25_SELECT(cs) ao_spi_get_mask(SPI_CS_PORT,cs) +#define M25_DESELECT(cs) ao_spi_put_mask(SPI_CS_PORT,cs) + +#define M25_BLOCK_SHIFT 16 +#define M25_BLOCK 65536L +#define M25_POS_TO_SECTOR(pos) ((uint8_t) ((pos) >> M25_BLOCK_SHIFT)) +#define M25_SECTOR_TO_POS(sector) (((uint32_t) (sector)) << M25_BLOCK_SHIFT) + +/* + * Block until the specified chip is done writing + */ +static void +ao_m25_wait_wip(uint8_t cs) +{ + if (ao_m25_wip & cs) { + M25_SELECT(cs); + ao_m25_instruction[0] = M25_RDSR; + ao_spi_send(ao_m25_instruction, 1); + do { + ao_spi_recv(ao_m25_instruction, 1); + } while (ao_m25_instruction[0] & M25_STATUS_WIP); + M25_DESELECT(cs); + ao_m25_wip &= ~cs; + } +} + +/* + * Set the write enable latch so that page program and sector + * erase commands will work. Also mark the chip as busy writing + * so that future operations will block until the WIP bit goes off + */ +static void +ao_m25_write_enable(uint8_t cs) +{ + M25_SELECT(cs); + ao_m25_instruction[0] = M25_WREN; + ao_spi_send(&ao_m25_instruction, 1); + M25_DESELECT(cs); + ao_m25_wip |= cs; +} + + +/* + * Returns the number of 64kB sectors + */ +static uint8_t +ao_m25_read_capacity(uint8_t cs) +{ + uint8_t capacity; + M25_SELECT(cs); + ao_m25_instruction[0] = M25_RDID; + ao_spi_send(ao_m25_instruction, 1); + ao_spi_recv(ao_m25_instruction, M25_RDID_LEN); + M25_DESELECT(cs); + + /* Check to see if the chip is present */ + if (ao_m25_instruction[0] == 0xff) + return 0; + capacity = ao_m25_instruction[M25_CAPACITY_OFFSET]; + + /* Sanity check capacity number */ + if (capacity < 0x11 || 0x1f < capacity) + return 0; + return 1 << (capacity - 0x10); +} + +static uint8_t +ao_m25_set_address(uint32_t pos) +{ + uint8_t chip; +#if M25_MAX_CHIPS > 1 + uint8_t size; + + for (chip = 0; chip < ao_m25_numchips; chip++) { + size = ao_m25_size[chip]; + if (M25_POS_TO_SECTOR(pos) < size) + break; + pos -= M25_SECTOR_TO_POS(size); + } + if (chip == ao_m25_numchips) + return 0xff; + + chip = ao_m25_pin[chip]; +#else + chip = M25_CS_MASK; +#endif + ao_m25_wait_wip(chip); + + ao_m25_instruction[1] = pos >> 16; + ao_m25_instruction[2] = pos >> 8; + ao_m25_instruction[3] = pos; + return chip; +} + +/* + * Scan the possible chip select lines + * to see which flash chips are connected + */ +static uint8_t +ao_m25_scan(void) +{ +#if M25_MAX_CHIPS > 1 + uint8_t pin, size; +#endif + + if (ao_m25_total) + return 1; + +#if M25_MAX_CHIPS > 1 + ao_m25_numchips = 0; + for (pin = 1; pin != 0; pin <<= 1) { + if (M25_CS_MASK & pin) { + size = ao_m25_read_capacity(pin); + if (size != 0) { + ao_m25_size[ao_m25_numchips] = size; + ao_m25_pin[ao_m25_numchips] = pin; + ao_m25_total += size; + ao_m25_numchips++; + } + } + } +#else + ao_m25_total = ao_m25_read_capacity(M25_CS_MASK); +#endif + if (!ao_m25_total) + return 0; + ao_storage_total = M25_SECTOR_TO_POS(ao_m25_total); + ao_storage_block = M25_BLOCK; + ao_storage_config = ao_storage_total - M25_BLOCK; + ao_storage_unit = 256; + return 1; +} + +/* + * Erase the specified sector + */ +uint8_t +ao_storage_erase(uint32_t pos) __reentrant +{ + uint8_t cs; + + if (pos >= ao_storage_total || pos + ao_storage_block > ao_storage_total) + return 0; + + ao_mutex_get(&ao_m25_mutex); + ao_m25_scan(); + + cs = ao_m25_set_address(pos); + + ao_m25_wait_wip(cs); + ao_m25_write_enable(cs); + + ao_m25_instruction[0] = M25_SE; + M25_SELECT(cs); + ao_spi_send(ao_m25_instruction, 4); + M25_DESELECT(cs); + ao_m25_wip |= cs; + + ao_mutex_put(&ao_m25_mutex); + return 1; +} + +/* + * Write to flash + */ +uint8_t +ao_storage_device_write(uint32_t pos, __xdata void *d, uint16_t len) __reentrant +{ + uint8_t cs; + + if (pos >= ao_storage_total || pos + len > ao_storage_total) + return 0; + + ao_mutex_get(&ao_m25_mutex); + ao_m25_scan(); + + cs = ao_m25_set_address(pos); + ao_m25_write_enable(cs); + + ao_m25_instruction[0] = M25_PP; + M25_SELECT(cs); + ao_spi_send(ao_m25_instruction, 4); + ao_spi_send(d, len); + M25_DESELECT(cs); + + ao_mutex_put(&ao_m25_mutex); + return 1; +} + +/* + * Read from flash + */ +uint8_t +ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant +{ + uint8_t cs; + + if (pos >= ao_storage_total || pos + len > ao_storage_total) + return 0; + ao_mutex_get(&ao_m25_mutex); + ao_m25_scan(); + + cs = ao_m25_set_address(pos); + + /* No need to use the FAST_READ as we're running at only 8MHz */ + ao_m25_instruction[0] = M25_READ; + M25_SELECT(cs); + ao_spi_send(ao_m25_instruction, 4); + ao_spi_recv(d, len); + M25_DESELECT(cs); + + ao_mutex_put(&ao_m25_mutex); + return 1; +} + +void +ao_storage_flush(void) __reentrant +{ +} + +void +ao_storage_setup(void) +{ + ao_mutex_get(&ao_m25_mutex); + ao_m25_scan(); + ao_mutex_put(&ao_m25_mutex); +} + +void +ao_storage_device_info(void) __reentrant +{ + uint8_t cs; +#if M25_MAX_CHIPS > 1 + uint8_t chip; +#endif + + ao_mutex_get(&ao_m25_mutex); + ao_m25_scan(); + ao_mutex_put(&ao_m25_mutex); + +#if M25_MAX_CHIPS > 1 + printf ("Detected chips %d size %d\n", ao_m25_numchips, ao_m25_total); + for (chip = 0; chip < ao_m25_numchips; chip++) + printf ("Flash chip %d select %02x size %d\n", + chip, ao_m25_pin[chip], ao_m25_size[chip]); +#else + printf ("Detected chips 1 size %d\n", ao_m25_total); +#endif + + printf ("Available chips:\n"); + for (cs = 1; cs != 0; cs <<= 1) { + if ((M25_CS_MASK & cs) == 0) + continue; + + ao_mutex_get(&ao_m25_mutex); + M25_SELECT(cs); + ao_m25_instruction[0] = M25_RDID; + ao_spi_send(ao_m25_instruction, 1); + ao_spi_recv(ao_m25_instruction, M25_RDID_LEN); + M25_DESELECT(cs); + + printf ("Select %02x manf %02x type %02x cap %02x uid %02x\n", + cs, + ao_m25_instruction[M25_MANUF_OFFSET], + ao_m25_instruction[M25_MEMORY_TYPE_OFFSET], + ao_m25_instruction[M25_CAPACITY_OFFSET], + ao_m25_instruction[M25_UID_OFFSET]); + ao_mutex_put(&ao_m25_mutex); + } +} + +void +ao_storage_device_init(void) +{ + /* Set up chip select wires */ + SPI_CS_PORT |= M25_CS_MASK; /* raise all CS pins */ + SPI_CS_DIR |= M25_CS_MASK; /* set CS pins as outputs */ + SPI_CS_SEL &= ~M25_CS_MASK; /* set CS pins as GPIO */ +} diff --git a/src/gps-cksum b/src/gps-cksum deleted file mode 100755 index a08153bf..00000000 --- a/src/gps-cksum +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env nickle - -int checksum(string a) -{ - int c = 0; - for (int i = 0; i < String::length(a); i++) - c ^= a[i]; - return c; -} - -void main() -{ - for (int i = 1; i < dim(argv); i++) - printf ("$%s*%02x\n", argv[i], checksum(argv[i])); -} - -main(); diff --git a/src/make-altitude b/src/make-altitude deleted file mode 100644 index 716aa8a8..00000000 --- a/src/make-altitude +++ /dev/null @@ -1,283 +0,0 @@ -#!/usr/bin/nickle -f -/* - * Pressure Sensor Model, version 1.1 - * - * written by Holly Grimes - * - * Uses the International Standard Atmosphere as described in - * "A Quick Derivation relating altitude to air pressure" (version 1.03) - * from the Portland State Aerospace Society, except that the atmosphere - * is divided into layers with each layer having a different lapse rate. - * - * Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007 - * at site MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */ - return 0; - - /* calculate the base temperature and pressure for the atmospheric layer - associated with the inputted altitude */ - for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) { - delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; - if (lapse_rate[layer_number] == 0.0) { - exponent = GRAVITATIONAL_ACCELERATION * delta_z - / AIR_GAS_CONSTANT / base_temperature; - base_pressure *= exp(exponent); - } - else { - base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; - exponent = GRAVITATIONAL_ACCELERATION / - (AIR_GAS_CONSTANT * lapse_rate[layer_number]); - base_pressure *= pow(base, exponent); - } - base_temperature += delta_z * lapse_rate[layer_number]; - } - - /* calculate the pressure at the inputted altitude */ - delta_z = altitude - base_altitude[layer_number]; - if (lapse_rate[layer_number] == 0.0) { - exponent = GRAVITATIONAL_ACCELERATION * delta_z - / AIR_GAS_CONSTANT / base_temperature; - pressure = base_pressure * exp(exponent); - } - else { - base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; - exponent = GRAVITATIONAL_ACCELERATION / - (AIR_GAS_CONSTANT * lapse_rate[layer_number]); - pressure = base_pressure * pow(base, exponent); - } - - return pressure; -} - - -/* outputs the altitude associated with the given pressure. the altitude - returned is measured with respect to the mean sea level */ -real pressure_to_altitude(real pressure) { - - real next_base_temperature = LAYER0_BASE_TEMPERATURE; - real next_base_pressure = LAYER0_BASE_PRESSURE; - - real altitude; - real base_pressure; - real base_temperature; - real base; /* base for function to determine base pressure of next layer */ - real exponent; /* exponent for function to determine base pressure - of next layer */ - real coefficient; - int layer_number; /* identifies layer in the atmosphere */ - int delta_z; /* difference between two altitudes */ - - if (pressure < 0) /* illegal pressure */ - return -1; - if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */ - return MAXIMUM_ALTITUDE; - - /* calculate the base temperature and pressure for the atmospheric layer - associated with the inputted pressure. */ - layer_number = -1; - do { - layer_number++; - base_pressure = next_base_pressure; - base_temperature = next_base_temperature; - delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; - if (lapse_rate[layer_number] == 0.0) { - exponent = GRAVITATIONAL_ACCELERATION * delta_z - / AIR_GAS_CONSTANT / base_temperature; - next_base_pressure *= exp(exponent); - } - else { - base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; - exponent = GRAVITATIONAL_ACCELERATION / - (AIR_GAS_CONSTANT * lapse_rate[layer_number]); - next_base_pressure *= pow(base, exponent); - } - next_base_temperature += delta_z * lapse_rate[layer_number]; - } - while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure); - - /* calculate the altitude associated with the inputted pressure */ - if (lapse_rate[layer_number] == 0.0) { - coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION) - * base_temperature; - altitude = base_altitude[layer_number] - + coefficient * log(pressure / base_pressure); - } - else { - base = pressure / base_pressure; - exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number] - / GRAVITATIONAL_ACCELERATION; - coefficient = base_temperature / lapse_rate[layer_number]; - altitude = base_altitude[layer_number] - + coefficient * (pow(base, exponent) - 1); - } - - return altitude; -} - -real feet_to_meters(real feet) -{ - return feet * (12 * 2.54 / 100); -} - -real meters_to_feet(real meters) -{ - return meters / (12 * 2.54 / 100); -} - -/* - * Values for our MP3H6115A pressure sensor - * - * From the data sheet: - * - * Pressure range: 15-115 kPa - * Voltage at 115kPa: 2.82 - * Output scale: 27mV/kPa - * - * - * 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa - * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa - */ - -real counts_per_kPa = 27 * 2047 / 3300; -real counts_at_101_3kPa = 1674; - -real fraction_to_kPa(real fraction) -{ - return (fraction + 0.095) / 0.009; -} - - -real count_to_kPa(real count) = fraction_to_kPa(count / 2047); - -typedef struct { - real m, b; - int m_i, b_i; -} line_t; - -line_t best_fit(real[] values, int first, int last) { - real sum_x = 0, sum_x2 = 0, sum_y = 0, sum_xy = 0; - int n = last - first + 1; - real m, b; - int m_i, b_i; - - for (int i = first; i <= last; i++) { - sum_x += i; - sum_x2 += i**2; - sum_y += values[i]; - sum_xy += values[i] * i; - } - m = (n*sum_xy - sum_y*sum_x) / (n*sum_x2 - sum_x**2); - b = sum_y/n - m*(sum_x/n); - return (line_t) { m = m, b = b }; -} - -real count_to_altitude(real count) { - return pressure_to_altitude(count_to_kPa(count) * 1000); -} - -real fraction_to_altitude(real frac) = pressure_to_altitude(fraction_to_kPa(frac) * 1000); - -int num_samples = 1024; - -real[num_samples] alt = { [n] = fraction_to_altitude(n/(num_samples - 1)) }; - -int num_part = 128; -int seg_len = num_samples / num_part; - -line_t [dim(alt) / seg_len] fit = { - [n] = best_fit(alt, n * seg_len, n * seg_len + seg_len - 1) -}; - -int[num_samples/seg_len + 1] alt_part; - -alt_part[0] = floor (fit[0].b + 0.5); -alt_part[dim(fit)] = floor(fit[dim(fit)-1].m * dim(fit) * seg_len + fit[dim(fit)-1].b + 0.5); - -for (int i = 0; i < dim(fit) - 1; i++) { - real here, there; - here = fit[i].m * (i+1) * seg_len + fit[i].b; - there = fit[i+1].m * (i+1) * seg_len + fit[i+1].b; - alt_part[i+1] = floor ((here + there) / 2 + 0.5); -} - -real count_to_fit_altitude(int count) { - int sub = count // seg_len; - int off = count % seg_len; - line_t l = fit[sub]; - real r_v; - real i_v; - - r_v = count * l.m + l.b; - i_v = (alt_part[sub] * (seg_len - off) + alt_part[sub+1] * off) / seg_len; - return i_v; -} - -real max_error = 0; -int max_error_count = 0; -real total_error = 0; - -for (int count = 0; count < num_samples; count++) { - real kPa = fraction_to_kPa(count / (num_samples - 1)); - real meters = pressure_to_altitude(kPa * 1000); - - real meters_approx = count_to_fit_altitude(count); - real error = abs(meters - meters_approx); - - total_error += error; - if (error > max_error) { - max_error = error; - max_error_count = count; - } -# printf (" %7d, /* %6.2g kPa %5d count approx %d */\n", -# floor (meters + 0.5), kPa, count, floor(count_to_fit_altitude(count) + 0.5)); -} - -printf ("/*max error %f at %7.3f%%. Average error %f*/\n", max_error, max_error_count / (num_samples - 1) * 100, total_error / num_samples); - -printf ("#define NALT %d\n", dim(alt_part)); -printf ("#define ALT_FRAC_BITS %d\n", floor (log2(32768/(dim(alt_part)-1)) + 0.1)); - -for (int i = 0; i < dim(alt_part); i++) { - real fraction = i / (dim(alt_part) - 1); - real kPa = fraction_to_kPa(fraction); - printf ("%9d, /* %6.2f kPa %7.3f%% */\n", - alt_part[i], kPa, fraction * 100); -} diff --git a/src/make-kalman b/src/make-kalman deleted file mode 100644 index 9ac35134..00000000 --- a/src/make-kalman +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -cd ../kalman - -SIGMA_BOTH="-M 2 -H 6 -A 2" -SIGMA_BARO="-M 2 -H 6 -A 2" -SIGMA_ACCEL="-M 2 -H 4 -A 4" - -nickle kalman.5c -p AO_BOTH -c both -t 0.01 $SIGMA_BOTH -nickle kalman.5c -p AO_BOTH -c both -t 0.1 $SIGMA_BOTH -nickle kalman.5c -p AO_BOTH -c both -t 1 $SIGMA_BOTH - -nickle kalman.5c -p AO_ACCEL -c accel -t 0.01 $SIGMA_ACCEL -nickle kalman.5c -p AO_ACCEL -c accel -t 0.1 $SIGMA_ACCEL -nickle kalman.5c -p AO_ACCEL -c accel -t 1 $SIGMA_ACCEL - -nickle kalman.5c -p AO_BARO -c baro -t 0.01 $SIGMA_BARO -nickle kalman.5c -p AO_BARO -c baro -t 0.1 $SIGMA_BARO -nickle kalman.5c -p AO_BARO -c baro -t 1 $SIGMA_BARO diff --git a/src/product/Makefile.telebt b/src/product/Makefile.telebt new file mode 100644 index 00000000..99730b9f --- /dev/null +++ b/src/product/Makefile.telebt @@ -0,0 +1,97 @@ +# +# TeleBT build file +# +# Define TELEBT_VER, TELEBT_DEF, TELEBT_INC and TELEBT_SRC +# and include this file + +vpath %.c ..:../core:../cc1111:../drivers:../product +vpath %.h ..:../core:../cc1111:../drivers:../product +vpath ao-make-product.5c ../util + +ifndef VERSION +include ../Version +endif + +INC = \ + ao.h \ + ao_pins.h \ + cc1111.h \ + ao_product.h \ + $(TELEBT_INC) + +CORE_SRC = \ + ao_cmd.c \ + ao_config.c \ + ao_gps_print.c \ + ao_monitor.c \ + ao_mutex.c \ + ao_panic.c \ + ao_rssi.c \ + ao_state.c \ + ao_stdio.c \ + ao_task.c + +CC1111_SRC = \ + ao_dbg.c \ + ao_dma.c \ + ao_led.c \ + ao_packet.c \ + ao_packet_master.c \ + ao_radio.c \ + ao_romconfig.c \ + ao_serial.c \ + ao_timer.c \ + ao_usb.c \ + _bp.c + +DRIVER_SRC = \ + ao_btm.c + +PRODUCT_SRC = \ + ao_telebt.c + +SRC = \ + $(CORE_SRC) \ + $(CC1111_SRC) \ + $(DRIVER_SRC) \ + $(PRODUCT_SRC) \ + $(TELEBT_SRC) + +PROG = telebt-v$(TELEBT_VER)-$(VERSION).ihx +PRODUCT=TeleBT-v$(TELEBT_VER) +PRODUCT_DEF=-DTELEBT_V_$(TELEBT_DEF) +IDPRODUCT=0x000e + +include ../cc1111/Makefile.cc1111 + +NICKLE=nickle +CHECK_STACK=sh ../util/check-stack + +V=0 +# The user has explicitly enabled quiet compilation. +ifeq ($(V),0) +quiet = @printf " $1 $2 $@\n"; $($1) +endif +# Otherwise, print the full command line. +quiet ?= $($1) + +all: ../$(PROG) + +../$(PROG): $(REL) Makefile + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. + $(call quiet,CHECK_STACK) ../core/ao.h $(PMEM) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean: clean + +clean: + rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) + rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) + rm -f ao_product.h + rm -f ../$(PROG) ../$(PMAP) + +install: + +uninstall: diff --git a/src/product/Makefile.teledongle b/src/product/Makefile.teledongle new file mode 100644 index 00000000..f32c037f --- /dev/null +++ b/src/product/Makefile.teledongle @@ -0,0 +1,96 @@ +# +# TeleDongle build file +# +# The various teledongle versions differ only +# in minor pin variations +# so the per-board makefiles simply define +# TD_VER, TD_DEF and include +# this file + +vpath %.c ..:../core:../cc1111:../drivers:../product +vpath %.h ..:../core:../cc1111:../drivers:../product +vpath ao-make-product.5c ../util + +ifndef VERSION +include ../Version +endif + +INC = \ + ao.h \ + ao_pins.h \ + cc1111.h \ + ao_product.h + +CORE_SRC = \ + ao_cmd.c \ + ao_config.c \ + ao_gps_print.c \ + ao_monitor.c \ + ao_mutex.c \ + ao_panic.c \ + ao_rssi.c \ + ao_state.c \ + ao_stdio.c \ + ao_task.c + +CC1111_SRC = \ + ao_dbg.c \ + ao_dma.c \ + ao_led.c \ + ao_packet.c \ + ao_packet_master.c \ + ao_radio.c \ + ao_romconfig.c \ + ao_timer.c \ + ao_usb.c \ + _bp.c + +DRIVER_SRC = + +PRODUCT_SRC = \ + ao_teledongle.c + +SRC = \ + $(CORE_SRC) \ + $(CC1111_SRC) \ + $(DRIVER_SRC) \ + $(PRODUCT_SRC) + +PROG = teledongle-v$(TD_VER)-$(VERSION).ihx +PRODUCT=TeleDongle-v$(TD_VER) +PRODUCT_DEF=-DTELEDONGLE_V_$(TD_DEF) +IDPRODUCT=0x000c + +include ../cc1111/Makefile.cc1111 + +NICKLE=nickle +CHECK_STACK=sh ../util/check-stack + +V=0 +# The user has explicitly enabled quiet compilation. +ifeq ($(V),0) +quiet = @printf " $1 $2 $@\n"; $($1) +endif +# Otherwise, print the full command line. +quiet ?= $($1) + +all: ../$(PROG) + +../$(PROG): $(REL) Makefile + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. + $(call quiet,CHECK_STACK) ../core/ao.h $(PMEM) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean: clean + +clean: + rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) + rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) + rm -f ao_product.h + rm -f ../$(PROG) ../$(PMAP) + +install: + +uninstall: diff --git a/src/product/Makefile.telemetrum b/src/product/Makefile.telemetrum new file mode 100644 index 00000000..fd958aea --- /dev/null +++ b/src/product/Makefile.telemetrum @@ -0,0 +1,111 @@ +# +# TeleMetrum build file +# +# The various telemetrum versions differ only +# in which flash and GPS drivers are included, +# so the per-board makefiles simply define +# TM_VER, TM_DEF, TM_INC and TM_SRC and include +# this file + +vpath %.c ..:../core:../cc1111:../drivers:../product +vpath %.h ..:../core:../cc1111:../drivers:../product +vpath ao-make-product.5c ../util + +ifndef VERSION +include ../Version +endif + +INC = \ + ao.h \ + ao_pins.h \ + cc1111.h \ + altitude.h \ + ao_kalman.h \ + ao_product.h \ + $(TM_INC) + +CORE_SRC = \ + ao_cmd.c \ + ao_config.c \ + ao_convert.c \ + ao_gps_report.c \ + ao_mutex.c \ + ao_panic.c \ + ao_stdio.c \ + ao_storage.c \ + ao_task.c \ + ao_flight.c \ + ao_sample.c \ + ao_kalman.c \ + ao_log.c \ + ao_log_big.c \ + ao_report.c \ + ao_telemetry.c + +CC1111_SRC = \ + ao_adc.c \ + ao_beep.c \ + ao_dbg.c \ + ao_dma.c \ + ao_ignite.c \ + ao_led.c \ + ao_packet.c \ + ao_packet_slave.c \ + ao_radio.c \ + ao_romconfig.c \ + ao_serial.c \ + ao_spi.c \ + ao_timer.c \ + ao_usb.c \ + _bp.c + +DRIVER_SRC = \ + $(TM_SRC) + +PRODUCT_SRC = \ + ao_telemetrum.c + +SRC = \ + $(CORE_SRC) \ + $(CC1111_SRC) \ + $(DRIVER_SRC) \ + $(PRODUCT_SRC) + +PROG = telemetrum-v$(TM_VER)-$(VERSION).ihx +PRODUCT=TeleMetrum-v$(TM_VER) +PRODUCT_DEF=-DTELEMETRUM_V_$(TM_DEF) +IDPRODUCT=0x000b + +include ../cc1111/Makefile.cc1111 + +NICKLE=nickle +CHECK_STACK=sh ../util/check-stack + +V=0 +# The user has explicitly enabled quiet compilation. +ifeq ($(V),0) +quiet = @printf " $1 $2 $@\n"; $($1) +endif +# Otherwise, print the full command line. +quiet ?= $($1) + +all: ../$(PROG) + +../$(PROG): $(REL) Makefile + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. + $(call quiet,CHECK_STACK) ../core/ao.h $(PMEM) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean: clean + +clean: + rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) + rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) + rm -f ao_product.h + rm -f ../$(PROG) ../$(PMAP) + +install: + +uninstall: diff --git a/src/product/Makefile.telemini b/src/product/Makefile.telemini new file mode 100644 index 00000000..3bd14226 --- /dev/null +++ b/src/product/Makefile.telemini @@ -0,0 +1,100 @@ +# +# TeleMini build file +# +# Define TELEMINI_VER and TELEMINI_DEF and then +# include this file + +vpath %.c ..:../core:../cc1111:../drivers:../product +vpath %.h ..:../core:../cc1111:../drivers:../product +vpath ao-make-product.5c ../util + +ifndef VERSION +include ../Version +endif + +INC = \ + ao.h \ + ao_pins.h \ + cc1111.h \ + ao_product.h + +CORE_SRC = \ + ao_cmd.c \ + ao_config.c \ + ao_convert.c \ + ao_flight.c \ + ao_kalman.c \ + ao_log.c \ + ao_log_tiny.c \ + ao_mutex.c \ + ao_panic.c \ + ao_report.c \ + ao_sample.c \ + ao_stdio.c \ + ao_storage.c \ + ao_task.c \ + ao_telemetry.c + +CC1111_SRC = \ + ao_adc.c \ + ao_dma.c \ + ao_ignite.c \ + ao_intflash.c \ + ao_led.c \ + ao_packet.c \ + ao_packet_slave.c \ + ao_radio.c \ + ao_romconfig.c \ + ao_timer.c \ + _bp.c + +DRIVER_SRC = + +PRODUCT_SRC = \ + ao_telemini.c + +SRC = \ + $(CORE_SRC) \ + $(CC1111_SRC) \ + $(DRIVER_SRC) \ + $(PRODUCT_SRC) + +PROG = telemini-v$(TELEMINI_VER)-$(VERSION).ihx +PRODUCT=TeleMini-v$(TELEMINI_VER) +PRODUCT_DEF=-DTELEMINI_V_$(TELEMINI_DEF) +IDPRODUCT=0x000a +CODESIZE=0x6700 + +include ../cc1111/Makefile.cc1111 + +NICKLE=nickle +CHECK_STACK=sh ../util/check-stack + +V=0 +# The user has explicitly enabled quiet compilation. +ifeq ($(V),0) +quiet = @printf " $1 $2 $@\n"; $($1) +endif +# Otherwise, print the full command line. +quiet ?= $($1) + +all: ../$(PROG) + +../$(PROG): $(REL) Makefile + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. + $(call quiet,CHECK_STACK) ../core/ao.h $(PMEM) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean: clean + +clean: + rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) + rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) + rm -f ao_product.h + rm -f ../$(PROG) ../$(PMAP) + +install: + +uninstall: diff --git a/src/product/Makefile.telenano b/src/product/Makefile.telenano new file mode 100644 index 00000000..72043044 --- /dev/null +++ b/src/product/Makefile.telenano @@ -0,0 +1,99 @@ +# +# TeleNano build file +# +# Define TELENANO_VER and TELENANO_DEF and then +# include this file + +vpath %.c ..:../core:../cc1111:../drivers:../product +vpath %.h ..:../core:../cc1111:../drivers:../product +vpath ao-make-product.5c ../util + +ifndef VERSION +include ../Version +endif + +INC = \ + ao.h \ + ao_pins.h \ + cc1111.h \ + ao_product.h + +CORE_SRC = \ + ao_cmd.c \ + ao_config.c \ + ao_convert.c \ + ao_flight_nano.c \ + ao_kalman.c \ + ao_log.c \ + ao_log_tiny.c \ + ao_mutex.c \ + ao_panic.c \ + ao_report.c \ + ao_sample.c \ + ao_stdio.c \ + ao_storage.c \ + ao_task.c \ + ao_telemetry.c + +CC1111_SRC = \ + ao_adc.c \ + ao_dma.c \ + ao_intflash.c \ + ao_led.c \ + ao_packet.c \ + ao_packet_slave.c \ + ao_radio.c \ + ao_romconfig.c \ + ao_timer.c \ + _bp.c + +DRIVER_SRC = + +PRODUCT_SRC = \ + ao_telenano.c + +SRC = \ + $(CORE_SRC) \ + $(CC1111_SRC) \ + $(DRIVER_SRC) \ + $(PRODUCT_SRC) + +PROG = telenano-v$(TELENANO_VER)-$(VERSION).ihx +PRODUCT=TeleNano-v$(TELENANO_VER) +PRODUCT_DEF=-DTELENANO_V_$(TELENANO_DEF) +IDPRODUCT=0x000a +CODESIZE=0x6700 + +include ../cc1111/Makefile.cc1111 + +NICKLE=nickle +CHECK_STACK=sh ../util/check-stack + +V=0 +# The user has explicitly enabled quiet compilation. +ifeq ($(V),0) +quiet = @printf " $1 $2 $@\n"; $($1) +endif +# Otherwise, print the full command line. +quiet ?= $($1) + +all: ../$(PROG) + +../$(PROG): $(REL) Makefile + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. + $(call quiet,CHECK_STACK) ../core/ao.h $(PMEM) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean: clean + +clean: + rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) + rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) + rm -f ao_product.h + rm -f ../$(PROG) ../$(PMAP) + +install: + +uninstall: diff --git a/src/product/ao_telebt.c b/src/product/ao_telebt.c new file mode 100644 index 00000000..85565172 --- /dev/null +++ b/src/product/ao_telebt.c @@ -0,0 +1,50 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +__code uint8_t ao_log_format = AO_LOG_FORMAT_NONE; /* until we actually log stuff */ + +void +main(void) +{ + ao_clock_init(); + + /* Turn on the LED until the system is stable */ + ao_led_init(LEDS_AVAILABLE); + ao_led_on(AO_LED_RED); + ao_timer_init(); +#if HAS_BEEP + ao_beep_init(); +#endif + ao_cmd_init(); +#if HAS_EEPROM + ao_spi_init(); + ao_storage_init(); +#endif + ao_usb_init(); + ao_monitor_init(AO_LED_GREEN, TRUE); + ao_rssi_init(AO_LED_RED); + ao_radio_init(); + ao_packet_master_init(); + ao_btm_init(); +#if HAS_DBG + ao_dbg_init(); +#endif + ao_config_init(); + ao_start_scheduler(); +} diff --git a/src/product/ao_teledongle.c b/src/product/ao_teledongle.c new file mode 100644 index 00000000..008b200a --- /dev/null +++ b/src/product/ao_teledongle.c @@ -0,0 +1,40 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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) +{ + ao_clock_init(); + + /* Turn on the LED until the system is stable */ + ao_led_init(LEDS_AVAILABLE); + ao_led_on(AO_LED_RED); + ao_timer_init(); + ao_cmd_init(); + ao_usb_init(); + ao_monitor_init(AO_LED_GREEN, TRUE); + ao_rssi_init(AO_LED_RED); + ao_radio_init(); + ao_packet_master_init(); +#if HAS_DBG + ao_dbg_init(); +#endif + ao_config_init(); + ao_start_scheduler(); +} diff --git a/src/product/ao_telemetrum.c b/src/product/ao_telemetrum.c new file mode 100644 index 00000000..f560740a --- /dev/null +++ b/src/product/ao_telemetrum.c @@ -0,0 +1,70 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" +#include "ao_pins.h" + +void +main(void) +{ + /* + * Reduce the transient on the ignite pins at startup by + * pulling the pins low as soon as possible at power up + */ + ao_ignite_set_pins(); + + ao_clock_init(); + + /* Turn on the red LED until the system is stable */ + ao_led_init(LEDS_AVAILABLE); + ao_led_on(AO_LED_RED); + + /* A hack -- look at the SPI clock pin, if it's sitting at + * ground, then we force the computer to idle mode instead of + * flight mode + */ + if (P1_3 == 0) { + ao_flight_force_idle = 1; + while (P1_3 == 0) + ; + } + ao_timer_init(); + ao_adc_init(); + ao_beep_init(); + ao_cmd_init(); + ao_spi_init(); + ao_storage_init(); + ao_flight_init(); + ao_log_init(); + ao_report_init(); + ao_usb_init(); + ao_serial_init(); + ao_gps_init(); + ao_gps_report_init(); + ao_telemetry_init(); + ao_radio_init(); + ao_packet_slave_init(TRUE); + ao_igniter_init(); +#if HAS_DBG + ao_dbg_init(); +#endif +#if HAS_COMPANION + ao_companion_init(); +#endif + ao_config_init(); + ao_start_scheduler(); +} diff --git a/src/product/ao_telemini.c b/src/product/ao_telemini.c new file mode 100644 index 00000000..fa23de01 --- /dev/null +++ b/src/product/ao_telemini.c @@ -0,0 +1,49 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" +#include "ao_pins.h" + +void +main(void) +{ + /* + * Reduce the transient on the ignite pins at startup by + * pulling the pins low as soon as possible at power up + */ + ao_ignite_set_pins(); + + ao_clock_init(); + + /* Turn on the red LED until the system is stable */ + ao_led_init(LEDS_AVAILABLE); + ao_led_on(AO_LED_RED); + + ao_timer_init(); + ao_adc_init(); + ao_cmd_init(); + ao_storage_init(); + ao_flight_init(); + ao_log_init(); + ao_report_init(); + ao_telemetry_init(); + ao_radio_init(); + ao_packet_slave_init(TRUE); + ao_igniter_init(); + ao_config_init(); + ao_start_scheduler(); +} diff --git a/src/product/ao_telenano.c b/src/product/ao_telenano.c new file mode 100644 index 00000000..d91983d0 --- /dev/null +++ b/src/product/ao_telenano.c @@ -0,0 +1,43 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" +#include "ao_pins.h" + +void +main(void) +{ + ao_clock_init(); + + + /* Turn on the red LED until the system is stable */ + ao_led_init(LEDS_AVAILABLE); + ao_led_on(AO_LED_RED); + + ao_timer_init(); + ao_adc_init(); + ao_cmd_init(); + ao_storage_init(); + ao_flight_nano_init(); + ao_log_init(); + ao_report_init(); + ao_telemetry_init(); + ao_radio_init(); + ao_packet_slave_init(TRUE); + ao_config_init(); + ao_start_scheduler(); +} diff --git a/src/product/ao_teleterra.c b/src/product/ao_teleterra.c new file mode 100644 index 00000000..d696b914 --- /dev/null +++ b/src/product/ao_teleterra.c @@ -0,0 +1,38 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_ADC_ISR 1 +#include "ao.h" + +void +main(void) +{ + ao_clock_init(); + + /* Turn on the red LED until the system is stable */ + ao_led_init(AO_LED_RED|AO_LED_GREEN); + ao_led_on(AO_LED_RED); + ao_timer_init(); + ao_beep_init(); + ao_cmd_init(); + ao_usb_init(); + ao_serial_init(); + ao_monitor_init(AO_LED_GREEN, TRUE); + ao_radio_init(); + ao_config_init(); + ao_start_scheduler(); +} diff --git a/src/product/ao_test.c b/src/product/ao_test.c new file mode 100644 index 00000000..14c2eb75 --- /dev/null +++ b/src/product/ao_test.c @@ -0,0 +1,117 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +struct ao_task __xdata blink_0_task; +struct ao_task __xdata blink_1_task; +struct ao_task __xdata wakeup_task; +struct ao_task __xdata beep_task; +struct ao_task __xdata echo_task; + +void delay(int n) __reentrant +{ + uint8_t j = 0; + while (--n) + while (--j) + ao_yield(); +} + +static __xdata uint8_t blink_chan; + +void +blink_0(void) +{ + uint8_t b = 0; + for (;;) { + b = 1 - b; + if (b) + ao_led_on(AO_LED_GREEN); + else + ao_led_off(AO_LED_GREEN); + ao_sleep(&blink_chan); + } +} + +void +blink_1(void) +{ + static __xdata struct ao_adc adc; + + for (;;) { + ao_sleep(&ao_adc_head); + ao_adc_get(&adc); + if (adc.accel < 15900) + ao_led_on(AO_LED_RED); + else + ao_led_off(AO_LED_RED); + } +} + +void +wakeup(void) +{ + for (;;) { + ao_delay(AO_MS_TO_TICKS(100)); + ao_wakeup(&blink_chan); + } +} + +void +beep(void) +{ + static __xdata struct ao_adc adc; + + for (;;) { + ao_delay(AO_SEC_TO_TICKS(1)); + ao_adc_get(&adc); + if (adc.temp > 7400) + ao_beep_for(AO_BEEP_LOW, AO_MS_TO_TICKS(50)); + } +} + +void +echo(void) +{ + char c; + for (;;) { + ao_usb_flush(); + c = ao_usb_getchar(); + ao_usb_putchar(c); + if (c == '\r') + ao_usb_putchar('\n'); + } +} + +void +main(void) +{ + ao_clock_init(); + +// ao_add_task(&blink_0_task, blink_0); +// ao_add_task(&blink_1_task, blink_1); +// ao_add_task(&wakeup_task, wakeup); +// ao_add_task(&beep_task, beep); + ao_add_task(&echo_task, echo); + ao_timer_init(); + ao_adc_init(); + ao_beep_init(); + ao_led_init(); + ao_usb_init(); + + ao_start_scheduler(); +} diff --git a/src/product/ao_tidongle.c b/src/product/ao_tidongle.c new file mode 100644 index 00000000..3b7c2733 --- /dev/null +++ b/src/product/ao_tidongle.c @@ -0,0 +1,42 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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) +{ + ao_clock_init(); + + /* Turn on the LED until the system is stable */ + ao_led_init(AO_LED_RED); + ao_led_on(AO_LED_RED); + ao_timer_init(); + ao_cmd_init(); + ao_usb_init(); + ao_monitor_init(AO_LED_RED, TRUE); + ao_rssi_init(AO_LED_RED); + ao_radio_init(); + ao_dbg_init(); + ao_config_init(); + /* Bring up the USB link */ + P1DIR |= 1; + P1 |= 1; + ao_start_scheduler(); +} diff --git a/src/sirf-cksum b/src/sirf-cksum deleted file mode 100755 index b905f318..00000000 --- a/src/sirf-cksum +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env nickle - -int checksum(int[] msg) -{ - int sum = 0; - for (int i = 0; i < dim(msg); i++) { - sum += msg[i]; - sum &= 0x7fff; - } - return sum; -} - -void main() -{ - string[...] input; - int[...] msg; - - setdim(input, 0); - while (!File::end(stdin)) { - input[dim(input)] = gets(); - } - - setdim(msg, 0); - for (int i = 0; i < dim(input); i++) { - string[*] words = String::wordsplit(input[i], " ,\t"); - for (int j = 0; j < dim(words); j++) { - if (words[j] == "/" + "*") - break; - if (String::length(words[j]) > 0 && - Ctype::isdigit(words[j][0])) { - msg[dim(msg)] = string_to_integer(words[j]); - } - } - } - printf("\t0xa0, 0xa2, 0x%02x, 0x%02x,\t/* length: %d bytes */\n", - dim(msg) >> 8, dim(msg) & 0xff, dim(msg)); - for (int i = 0; i < dim(input); i++) - printf("%s\n", input[i]); - int csum = checksum(msg); - printf ("\t0x%02x, 0x%02x, 0xb0, 0xb3,\n", - csum >> 8, csum & 0xff); -} - -main(); diff --git a/src/skytraq-cksum b/src/skytraq-cksum deleted file mode 100644 index ab0464a7..00000000 --- a/src/skytraq-cksum +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env nickle - -int checksum(int[] msg) -{ - int sum = 0; - for (int i = 0; i < dim(msg); i++) { - sum ^= msg[i]; - sum &= 0xff; - } - return sum; -} - -void main() -{ - string[...] input; - int[...] msg; - - setdim(input, 0); - while (!File::end(stdin)) { - input[dim(input)] = gets(); - } - - setdim(msg, 0); - for (int i = 0; i < dim(input); i++) { - string[*] words = String::wordsplit(input[i], " ,\t"); - for (int j = 0; j < dim(words); j++) { - if (words[j] == "/" + "*") - break; - if (String::length(words[j]) > 0 && - Ctype::isdigit(words[j][0])) { - msg[dim(msg)] = string_to_integer(words[j]); - } - } - } - printf("\t0xa0, 0xa1, 0x%02x, 0x%02x,\t\t/* length: %d bytes */\n", - dim(msg) >> 8, dim(msg) & 0xff, dim(msg)); - for (int i = 0; i < dim(input); i++) - printf("%s\n", input[i]); - int csum = checksum(msg); - printf ("\t0x%02x, 0x0d, 0x0a,\n", - csum); -} - -main(); diff --git a/src/telebt-v0.0/Makefile b/src/telebt-v0.0/Makefile index d8867b19..e89639ab 100644 --- a/src/telebt-v0.0/Makefile +++ b/src/telebt-v0.0/Makefile @@ -1 +1,9 @@ -include ../Makefile.proto +# +# TeleBT v0.0 build +# + +TELEBT_VER=0.0 +TELEBT_DEF=0_0 + +include ../product/Makefile.telebt + diff --git a/src/telebt-v0.0/Makefile.defs b/src/telebt-v0.0/Makefile.defs deleted file mode 100644 index f0bb5e0c..00000000 --- a/src/telebt-v0.0/Makefile.defs +++ /dev/null @@ -1,8 +0,0 @@ -PROG = telebt-v0.0-$(VERSION).ihx - -SRC = \ - $(TBT_BASE_SRC) - -PRODUCT=TeleBT-v0.0 -PRODUCT_DEF=-DTELEBT_V_0_0 -IDPRODUCT=0x000e diff --git a/src/telebt-v0.1/Makefile b/src/telebt-v0.1/Makefile index d8867b19..a34e8912 100644 --- a/src/telebt-v0.1/Makefile +++ b/src/telebt-v0.1/Makefile @@ -1 +1,19 @@ -include ../Makefile.proto +# +# TeleBT v0.1 build +# + +TELEBT_VER=0.1 +TELEBT_DEF=0_1 + +TELEBT_INC = \ + ao_25lc1024.h + +TELEBT_SRC = \ + ao_beep.c \ + ao_log_telem.c \ + ao_spi.c \ + ao_storage.c \ + ao_m25.c + +include ../product/Makefile.telebt + diff --git a/src/telebt-v0.1/Makefile.defs b/src/telebt-v0.1/Makefile.defs deleted file mode 100644 index 50657c83..00000000 --- a/src/telebt-v0.1/Makefile.defs +++ /dev/null @@ -1,8 +0,0 @@ -PROG = telebt-v0.1-$(VERSION).ihx - -SRC = \ - $(TBT_V_0_1_SRC) - -PRODUCT=TeleBT-v0.1 -PRODUCT_DEF=-DTELEBT_V_0_1 -IDPRODUCT=0x000e diff --git a/src/teledongle-v0.1/Makefile b/src/teledongle-v0.1/Makefile index d8867b19..48425107 100644 --- a/src/teledongle-v0.1/Makefile +++ b/src/teledongle-v0.1/Makefile @@ -1 +1,8 @@ -include ../Makefile.proto +# +# TeleDongle v0.2 build +# + +TD_VER=0.1 +TD_DEF=0_1 + +include ../product/Makefile.teledongle diff --git a/src/teledongle-v0.1/Makefile.defs b/src/teledongle-v0.1/Makefile.defs deleted file mode 100644 index ceb80b7a..00000000 --- a/src/teledongle-v0.1/Makefile.defs +++ /dev/null @@ -1,9 +0,0 @@ -PROG = teledongle-v0.1-$(VERSION).ihx - -SRC = \ - $(TD_SRC) \ - $(DBG_SRC) - -PRODUCT=TeleDongle-v0.1 -PRODUCT_DEF=-DTELEDONGLE_V_0_1 -IDPRODUCT=0x000c diff --git a/src/teledongle-v0.2/Makefile b/src/teledongle-v0.2/Makefile index d8867b19..ce4ab437 100644 --- a/src/teledongle-v0.2/Makefile +++ b/src/teledongle-v0.2/Makefile @@ -1 +1,8 @@ -include ../Makefile.proto +# +# TeleDongle v0.2 build +# + +TD_VER=0.2 +TD_DEF=0_2 + +include ../product/Makefile.teledongle \ No newline at end of file diff --git a/src/teledongle-v0.2/Makefile.defs b/src/teledongle-v0.2/Makefile.defs deleted file mode 100644 index ea9713b6..00000000 --- a/src/teledongle-v0.2/Makefile.defs +++ /dev/null @@ -1,9 +0,0 @@ -PROG = teledongle-v0.2-$(VERSION).ihx - -SRC = \ - $(TD_SRC) \ - $(DBG_SRC) - -PRODUCT=TeleDongle-v0.2 -PRODUCT_DEF=-DTELEDONGLE_V_0_2 -IDPRODUCT=0x000c diff --git a/src/telemetrum-v0.1-sirf/Makefile b/src/telemetrum-v0.1-sirf/Makefile index d8867b19..00cdc9c5 100644 --- a/src/telemetrum-v0.1-sirf/Makefile +++ b/src/telemetrum-v0.1-sirf/Makefile @@ -1 +1,16 @@ -include ../Makefile.proto +# +# TeleMetrum v0.1 with SkyTraq GPS build +# + +TM_VER=0.1 +TM_DEF=0_1 + +TM_INC = \ + ao_25lc1024.h + +TM_SRC = \ + ao_gps_sirf.c \ + ao_25lc1024.c + +include ../product/Makefile.telemetrum + diff --git a/src/telemetrum-v0.1-sirf/Makefile.defs b/src/telemetrum-v0.1-sirf/Makefile.defs deleted file mode 100644 index ac8dcdb9..00000000 --- a/src/telemetrum-v0.1-sirf/Makefile.defs +++ /dev/null @@ -1,12 +0,0 @@ -PROG = telemetrum-v0.1-sirf-$(VERSION).ihx - -SRC = \ - $(TM_BASE_SRC) \ - $(SPI_DRIVER_SRC) \ - $(EE_DRIVER_SRC) \ - $(SIRF_DRIVER_SRC) \ - $(DBG_SRC) - -PRODUCT=TeleMetrum-v0.1-SiRF -PRODUCT_DEF=-DTELEMETRUM_V_0_1 -IDPRODUCT=0x000b diff --git a/src/telemetrum-v0.1-sky/Makefile b/src/telemetrum-v0.1-sky/Makefile index d8867b19..e3c61db6 100644 --- a/src/telemetrum-v0.1-sky/Makefile +++ b/src/telemetrum-v0.1-sky/Makefile @@ -1 +1,16 @@ -include ../Makefile.proto +# +# TeleMetrum v0.1 with SkyTraq GPS build +# + +TM_VER=0.1 +TM_DEF=0_1 + +TM_INC = \ + ao_25lc1024.h + +TM_SRC = \ + ao_gps_skytraq.c \ + ao_25lc1024.c + +include ../product/Makefile.telemetrum + diff --git a/src/telemetrum-v0.1-sky/Makefile.defs b/src/telemetrum-v0.1-sky/Makefile.defs deleted file mode 100644 index e032d1eb..00000000 --- a/src/telemetrum-v0.1-sky/Makefile.defs +++ /dev/null @@ -1,12 +0,0 @@ -PROG = telemetrum-v0.1-sky-$(VERSION).ihx - -SRC = \ - $(TM_BASE_SRC) \ - $(SPI_DRIVER_SRC) \ - $(EE_DRIVER_SRC) \ - $(SKY_DRIVER_SRC) \ - $(DBG_SRC) - -PRODUCT=TeleMetrum-v0.1 -PRODUCT_DEF=-DTELEMETRUM_V_0_1 -IDPRODUCT=0x000b diff --git a/src/telemetrum-v1.0/Makefile b/src/telemetrum-v1.0/Makefile index d8867b19..4aae84c8 100644 --- a/src/telemetrum-v1.0/Makefile +++ b/src/telemetrum-v1.0/Makefile @@ -1 +1,16 @@ -include ../Makefile.proto +# +# TeleMetrum v1.0 build +# + +TM_VER=1.0 +TM_DEF=1_0 + +TM_INC = \ + ao_at45db161d.h + +TM_SRC = \ + ao_companion.c \ + ao_gps_skytraq.c \ + ao_at45db161d.c + +include ../product/Makefile.telemetrum diff --git a/src/telemetrum-v1.0/Makefile.defs b/src/telemetrum-v1.0/Makefile.defs deleted file mode 100644 index 5eefc392..00000000 --- a/src/telemetrum-v1.0/Makefile.defs +++ /dev/null @@ -1,13 +0,0 @@ -PROG = telemetrum-v1.0-$(VERSION).ihx - -SRC = \ - $(TM_BASE_SRC) \ - $(SPI_DRIVER_SRC) \ - $(FLASH_DRIVER_SRC) \ - $(SKY_DRIVER_SRC) \ - $(COMPANION_SRC) \ - $(DBG_SRC) - -PRODUCT=TeleMetrum-v1.0 -PRODUCT_DEF=-DTELEMETRUM_V_1_0 -IDPRODUCT=0x000b diff --git a/src/telemetrum-v1.1/Makefile b/src/telemetrum-v1.1/Makefile index d8867b19..4bea03db 100644 --- a/src/telemetrum-v1.1/Makefile +++ b/src/telemetrum-v1.1/Makefile @@ -1 +1,16 @@ -include ../Makefile.proto +# +# AltOS build +# +# + +TM_VER=1.1 +TM_DEF=1_1 + +TM_INC = + +TM_SRC = \ + ao_companion.c \ + ao_gps_skytraq.c \ + ao_m25.c + +include ../product/Makefile.telemetrum diff --git a/src/telemetrum-v1.1/Makefile.defs b/src/telemetrum-v1.1/Makefile.defs deleted file mode 100644 index 3c8b8793..00000000 --- a/src/telemetrum-v1.1/Makefile.defs +++ /dev/null @@ -1,13 +0,0 @@ -PROG = telemetrum-v1.1-$(VERSION).ihx - -SRC = \ - $(TM_BASE_SRC) \ - $(SPI_DRIVER_SRC) \ - $(M25_DRIVER_SRC) \ - $(SKY_DRIVER_SRC) \ - $(COMPANION_SRC) \ - $(DBG_SRC) - -PRODUCT=TeleMetrum-v1.1 -PRODUCT_DEF=-DTELEMETRUM_V_1_1 -IDPRODUCT=0x000b diff --git a/src/telemini-v1.0/Makefile b/src/telemini-v1.0/Makefile index d8867b19..4f1c8b51 100644 --- a/src/telemini-v1.0/Makefile +++ b/src/telemini-v1.0/Makefile @@ -1 +1,8 @@ -include ../Makefile.proto +# +# TeleMini build file +# + +TELEMINI_VER=1.0 +TELEMINI_DEF=1_0 + +include ../product/Makefile.telemini diff --git a/src/telemini-v1.0/Makefile.defs b/src/telemini-v1.0/Makefile.defs deleted file mode 100644 index 0e91f2fc..00000000 --- a/src/telemini-v1.0/Makefile.defs +++ /dev/null @@ -1,9 +0,0 @@ -PROG = telemini-v1.0-$(VERSION).ihx - -SRC = \ - $(TMINI_BASE_SRC) - -PRODUCT=TeleMini-v1.0 -PRODUCT_DEF=-DTELEMINI_V_1_0 -IDPRODUCT=0x000a -CODESIZE=0x6700 diff --git a/src/telenano-v0.1/Makefile b/src/telenano-v0.1/Makefile index d8867b19..2714c1e9 100644 --- a/src/telenano-v0.1/Makefile +++ b/src/telenano-v0.1/Makefile @@ -1 +1,9 @@ -include ../Makefile.proto +# +# TeleNano build file +# + +TELENANO_VER=0.1 +TELENANO_DEF=0_1 + +include ../product/Makefile.telenano + diff --git a/src/telenano-v0.1/Makefile.defs b/src/telenano-v0.1/Makefile.defs deleted file mode 100644 index 34cf69d1..00000000 --- a/src/telenano-v0.1/Makefile.defs +++ /dev/null @@ -1,9 +0,0 @@ -PROG = telenano-v0.1-$(VERSION).ihx - -SRC = \ - $(TNANO_BASE_SRC) - -PRODUCT=TeleNano-v0.1 -PRODUCT_DEF=-DTELENANO_V_0_1 -IDPRODUCT=0x000a -CODESIZE=0x6700 diff --git a/src/test/Makefile b/src/test/Makefile index 33203ffd..333850e4 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -1,9 +1,8 @@ -vpath % .. -vpath % ../kalman +vpath % ..:../core:../drivers PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_gps_test ao_gps_test_skytraq ao_convert_test -CFLAGS=-I.. -I. +CFLAGS=-I.. -I. -I../core -I../drivers -O0 -g all: $(PROGS) @@ -13,22 +12,19 @@ clean: install: ao_flight_test: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c altitude.h ao_kalman.h - cc -g -o $@ $< + cc $(CFLAGS) -o $@ $< ao_flight_test_baro: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c altitude.h ao_kalman.h - cc -g -o $@ -DHAS_ACCEL=0 ../ao_flight_test.c + cc $(CFLAGS) -o $@ -DHAS_ACCEL=0 ao_flight_test.c ao_flight_test_accel: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c altitude.h ao_kalman.h - cc -g -o $@ -DFORCE_ACCEL=1 ../ao_flight_test.c + cc $(CFLAGS) -o $@ -DFORCE_ACCEL=1 ao_flight_test.c ao_gps_test: ao_gps_test.c ao_gps_sirf.c ao_gps_print.c ao_host.h - cc -g -o $@ $< + cc $(CFLAGS) -o $@ $< ao_gps_test_skytraq: ao_gps_test_skytraq.c ao_gps_skytraq.c ao_gps_print.c ao_host.h - cc -g -o $@ $< + cc $(CFLAGS) -o $@ $< ao_convert_test: ao_convert_test.c ao_convert.c altitude.h - cc -g -o $@ $< - -../ao_kalman.h: make-kalman kalman.5c kalman_filter.5c load_csv.5c matrix.5c - sh $< > $@ + cc $(CFLAGS) -o $@ $< diff --git a/src/test/ao_flight_test.c b/src/test/ao_flight_test.c new file mode 100644 index 00000000..56733c89 --- /dev/null +++ b/src/test/ao_flight_test.c @@ -0,0 +1,716 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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 _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +#define AO_HERTZ 100 + +#define AO_ADC_RING 64 +#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1)) +#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1)) + +#define AO_M_TO_HEIGHT(m) ((int16_t) (m)) +#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16)) +#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16)) + +/* + * One set of samples read from the A/D converter + */ +struct ao_adc { + uint16_t tick; /* tick when the sample was read */ + int16_t accel; /* accelerometer */ + int16_t pres; /* pressure sensor */ + int16_t pres_real; /* unclipped */ + int16_t temp; /* temperature sensor */ + int16_t v_batt; /* battery voltage */ + int16_t sense_d; /* drogue continuity sense */ + int16_t sense_m; /* main continuity sense */ +}; + +#define __pdata +#define __data +#define __xdata +#define __code +#define __reentrant + +#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5)) +#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5)) +#define from_fix(x) ((x) >> 16) + +/* + * Above this height, the baro sensor doesn't work + */ +#define AO_MAX_BARO_HEIGHT 12000 +#define AO_BARO_SATURATE 13000 +#define AO_MIN_BARO_VALUE ao_altitude_to_pres(AO_BARO_SATURATE) + +/* + * Above this speed, baro measurements are unreliable + */ +#define AO_MAX_BARO_SPEED 200 + +#define ACCEL_NOSE_UP (ao_accel_2g >> 2) + +enum ao_flight_state { + ao_flight_startup = 0, + ao_flight_idle = 1, + ao_flight_pad = 2, + ao_flight_boost = 3, + ao_flight_fast = 4, + ao_flight_coast = 5, + ao_flight_drogue = 6, + ao_flight_main = 7, + ao_flight_landed = 8, + ao_flight_invalid = 9 +}; + +extern enum ao_flight_state ao_flight_state; + +#define FALSE 0 +#define TRUE 1 + +struct ao_adc ao_adc_ring[AO_ADC_RING]; +uint8_t ao_adc_head; +int ao_summary = 0; + +#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_cmd_register(c) +#define ao_usb_disable() +#define ao_telemetry_set_interval(x) +#define ao_rdf_set(rdf) +#define ao_packet_slave_start() +#define ao_packet_slave_stop() + +enum ao_igniter { + ao_igniter_drogue = 0, + ao_igniter_main = 1 +}; + +struct ao_adc ao_adc_static; + +int drogue_height; +double drogue_time; +int main_height; +double main_time; + +int tick_offset; + +static int32_t ao_k_height; + +void +ao_ignite(enum ao_igniter igniter) +{ + double time = (double) (ao_adc_static.tick + tick_offset) / 100; + + if (igniter == ao_igniter_drogue) { + drogue_time = time; + drogue_height = ao_k_height >> 16; + } else { + main_time = time; + main_height = ao_k_height >> 16; + } +} + +struct ao_task { + int dummy; +}; + +#define ao_add_task(t,f,n) + +#define ao_log_start() +#define ao_log_stop() + +#define AO_MS_TO_TICKS(ms) ((ms) / 10) +#define AO_SEC_TO_TICKS(s) ((s) * 100) + +#define AO_FLIGHT_TEST + +int ao_flight_debug; + +FILE *emulator_in; +char *emulator_app; +char *emulator_name; +double emulator_error_max = 4; +double emulator_height_error_max = 20; /* noise in the baro sensor */ + +void +ao_dump_state(void); + +void +ao_sleep(void *wchan); + +const char const * const ao_state_names[] = { + "startup", "idle", "pad", "boost", "fast", + "coast", "drogue", "main", "landed", "invalid" +}; + +struct ao_cmds { + void (*func)(void); + const char *help; +}; + +#include "ao_convert.c" + +struct ao_config { + uint16_t main_deploy; + int16_t accel_plus_g; + int16_t accel_minus_g; + uint8_t pad_orientation; +}; + +#define AO_PAD_ORIENTATION_ANTENNA_UP 0 +#define AO_PAD_ORIENTATION_ANTENNA_DOWN 1 + +#define ao_config_get() + +struct ao_config ao_config; + +#define DATA_TO_XDATA(x) (x) + +#define HAS_FLIGHT 1 +#define HAS_ADC 1 +#define HAS_USB 1 +#define HAS_GPS 1 +#ifndef HAS_ACCEL +#define HAS_ACCEL 1 +#define HAS_ACCEL_REF 0 +#endif + +#define GRAVITY 9.80665 +extern int16_t ao_ground_accel, ao_flight_accel; +extern int16_t ao_accel_2g; + +extern uint16_t ao_sample_tick; + +extern int16_t ao_sample_height; +extern int16_t ao_sample_accel; +extern int32_t ao_accel_scale; +extern int16_t ao_ground_height; +extern int16_t ao_sample_alt; + +int ao_sample_prev_tick; +uint16_t prev_tick; + +#include "ao_kalman.c" +#include "ao_sample.c" +#include "ao_flight.c" + +#define to_double(f) ((f) / 65536.0) + +static int ao_records_read = 0; +static int ao_eof_read = 0; +static int ao_flight_ground_accel; +static int ao_flight_started = 0; +static int ao_test_max_height; +static double ao_test_max_height_time; +static int ao_test_main_height; +static double ao_test_main_height_time; +static double ao_test_landed_time; +static double ao_test_landed_height; +static double ao_test_landed_time; +static int landed_set; +static double landed_time; +static double landed_height; + +void +ao_test_exit(void) +{ + double drogue_error; + double main_error; + double landed_error; + double landed_time_error; + + if (!ao_test_main_height_time) { + ao_test_main_height_time = ao_test_max_height_time; + ao_test_main_height = ao_test_max_height; + } + drogue_error = fabs(ao_test_max_height_time - drogue_time); + main_error = fabs(ao_test_main_height_time - main_time); + landed_error = fabs(ao_test_landed_height - landed_height); + landed_time_error = ao_test_landed_time - landed_time; + if (drogue_error > emulator_error_max || main_error > emulator_error_max || + landed_time_error > emulator_error_max || landed_error > emulator_height_error_max) { + printf ("%s %s\n", + emulator_app, emulator_name); + printf ("\tApogee error %g\n", drogue_error); + printf ("\tMain error %g\n", main_error); + printf ("\tLanded height error %g\n", landed_error); + printf ("\tLanded time error %g\n", landed_time_error); + printf ("\tActual: apogee: %d at %7.2f main: %d at %7.2f landed %7.2f at %7.2f\n", + ao_test_max_height, ao_test_max_height_time, + ao_test_main_height, ao_test_main_height_time, + ao_test_landed_height, ao_test_landed_time); + printf ("\tComputed: apogee: %d at %7.2f main: %d at %7.2f landed %7.2f at %7.2f\n", + drogue_height, drogue_time, main_height, main_time, + landed_height, landed_time); + exit (1); + } + exit(0); +} + +void +ao_insert(void) +{ + double time; + + ao_adc_ring[ao_adc_head] = ao_adc_static; + ao_adc_head = ao_adc_ring_next(ao_adc_head); + if (ao_flight_state != ao_flight_startup) { + double height = ao_pres_to_altitude(ao_adc_static.pres_real) - ao_ground_height; + double accel = ((ao_flight_ground_accel - ao_adc_static.accel) * GRAVITY * 2.0) / + (ao_config.accel_minus_g - ao_config.accel_plus_g); + + if (!tick_offset) + tick_offset = -ao_adc_static.tick; + if ((prev_tick - ao_adc_static.tick) > 0x400) + tick_offset += 65536; + prev_tick = ao_adc_static.tick; + time = (double) (ao_adc_static.tick + tick_offset) / 100; + + if (ao_test_max_height < height) { + ao_test_max_height = height; + ao_test_max_height_time = time; + ao_test_landed_height = height; + ao_test_landed_time = time; + } + if (height > ao_config.main_deploy) { + ao_test_main_height_time = time; + ao_test_main_height = height; + } + + if (ao_test_landed_height > height) { + ao_test_landed_height = height; + ao_test_landed_time = time; + } + + if (ao_flight_state == ao_flight_landed && !landed_set) { + landed_set = 1; + landed_time = time; + landed_height = height; + } + + if (!ao_summary) { + printf("%7.2f height %8.2f accel %8.3f state %-8.8s k_height %8.2f k_speed %8.3f k_accel %8.3f avg_height %5d drogue %4d main %4d error %5d\n", + time, + height, + accel, + ao_state_names[ao_flight_state], + ao_k_height / 65536.0, + ao_k_speed / 65536.0 / 16.0, + ao_k_accel / 65536.0 / 16.0, + ao_avg_height, + drogue_height, + main_height, + ao_error_h_sq_avg); + +// if (ao_flight_state == ao_flight_landed) +// ao_test_exit(); + } + } +} + +#define AO_MAX_CALLSIGN 8 +#define AO_MAX_VERSION 8 +#define AO_MAX_TELEMETRY 128 + +struct ao_telemetry_generic { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + uint8_t payload[27]; /* 5 */ + /* 32 */ +}; + +#define AO_TELEMETRY_SENSOR_TELEMETRUM 0x01 +#define AO_TELEMETRY_SENSOR_TELEMINI 0x02 +#define AO_TELEMETRY_SENSOR_TELENANO 0x03 + +struct ao_telemetry_sensor { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + + uint8_t state; /* 5 flight state */ + int16_t accel; /* 6 accelerometer (TM only) */ + int16_t pres; /* 8 pressure sensor */ + int16_t temp; /* 10 temperature sensor */ + int16_t v_batt; /* 12 battery voltage */ + int16_t sense_d; /* 14 drogue continuity sense (TM/Tm) */ + int16_t sense_m; /* 16 main continuity sense (TM/Tm) */ + + int16_t acceleration; /* 18 m/s² * 16 */ + int16_t speed; /* 20 m/s * 16 */ + int16_t height; /* 22 m */ + + int16_t ground_pres; /* 24 average pres on pad */ + int16_t ground_accel; /* 26 average accel on pad */ + int16_t accel_plus_g; /* 28 accel calibration at +1g */ + int16_t accel_minus_g; /* 30 accel calibration at -1g */ + /* 32 */ +}; + +#define AO_TELEMETRY_CONFIGURATION 0x04 + +struct ao_telemetry_configuration { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + + uint8_t device; /* 5 device type */ + uint16_t flight; /* 6 flight number */ + uint8_t config_major; /* 8 Config major version */ + uint8_t config_minor; /* 9 Config minor version */ + uint16_t apogee_delay; /* 10 Apogee deploy delay in seconds */ + uint16_t main_deploy; /* 12 Main deploy alt in meters */ + uint16_t flight_log_max; /* 14 Maximum flight log size in kB */ + char callsign[AO_MAX_CALLSIGN]; /* 16 Radio operator identity */ + char version[AO_MAX_VERSION]; /* 24 Software version */ + /* 32 */ +}; + +#define AO_TELEMETRY_LOCATION 0x05 + +#define AO_GPS_MODE_NOT_VALID 'N' +#define AO_GPS_MODE_AUTONOMOUS 'A' +#define AO_GPS_MODE_DIFFERENTIAL 'D' +#define AO_GPS_MODE_ESTIMATED 'E' +#define AO_GPS_MODE_MANUAL 'M' +#define AO_GPS_MODE_SIMULATED 'S' + +struct ao_telemetry_location { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + + uint8_t flags; /* 5 Number of sats and other flags */ + int16_t altitude; /* 6 GPS reported altitude (m) */ + int32_t latitude; /* 8 latitude (degrees * 10⁷) */ + int32_t longitude; /* 12 longitude (degrees * 10⁷) */ + uint8_t year; /* 16 (- 2000) */ + uint8_t month; /* 17 (1-12) */ + uint8_t day; /* 18 (1-31) */ + uint8_t hour; /* 19 (0-23) */ + uint8_t minute; /* 20 (0-59) */ + uint8_t second; /* 21 (0-59) */ + uint8_t pdop; /* 22 (m * 5) */ + uint8_t hdop; /* 23 (m * 5) */ + uint8_t vdop; /* 24 (m * 5) */ + uint8_t mode; /* 25 */ + uint16_t ground_speed; /* 26 cm/s */ + int16_t climb_rate; /* 28 cm/s */ + uint8_t course; /* 30 degrees / 2 */ + uint8_t unused[1]; /* 31 */ + /* 32 */ +}; + +#define AO_TELEMETRY_SATELLITE 0x06 + +struct ao_telemetry_satellite_info { + uint8_t svid; + uint8_t c_n_1; +}; + +struct ao_telemetry_satellite { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + uint8_t channels; /* 5 number of reported sats */ + + struct ao_telemetry_satellite_info sats[12]; /* 6 */ + uint8_t unused[2]; /* 30 */ + /* 32 */ +}; + +union ao_telemetry_all { + struct ao_telemetry_generic generic; + struct ao_telemetry_sensor sensor; + struct ao_telemetry_configuration configuration; + struct ao_telemetry_location location; + struct ao_telemetry_satellite satellite; +}; + +uint16_t +uint16(uint8_t *bytes, int off) +{ + off++; + return (uint16_t) bytes[off] | (((uint16_t) bytes[off+1]) << 8); +} + +int16_t +int16(uint8_t *bytes, int off) +{ + return (int16_t) uint16(bytes, off); +} + +void +ao_sleep(void *wchan) +{ + if (wchan == &ao_adc_head) { + char type; + uint16_t tick; + uint16_t a, b; + int ret; + uint8_t bytes[1024]; + union ao_telemetry_all telem; + char line[1024]; + char *saveptr; + char *l; + char *words[64]; + int nword; + + for (;;) { + if (ao_records_read > 2 && ao_flight_state == ao_flight_startup) + { + ao_adc_static.accel = ao_flight_ground_accel; + ao_insert(); + return; + } + + if (!fgets(line, sizeof (line), emulator_in)) { + if (++ao_eof_read >= 1000) { + if (!ao_summary) + printf ("no more data, exiting simulation\n"); + ao_test_exit(); + } + ao_adc_static.tick += 10; + ao_insert(); + return; + } + l = line; + for (nword = 0; nword < 64; nword++) { + words[nword] = strtok_r(l, " \t\n", &saveptr); + l = NULL; + if (words[nword] == NULL) + break; + } + if (nword == 4) { + type = words[0][0]; + tick = strtoul(words[1], NULL, 16); + a = strtoul(words[2], NULL, 16); + b = strtoul(words[3], NULL, 16); + if (type == 'P') + type = 'A'; + } else if (nword >= 6 && strcmp(words[0], "Accel") == 0) { + ao_config.accel_plus_g = atoi(words[3]); + ao_config.accel_minus_g = atoi(words[5]); + } else if (nword >= 4 && strcmp(words[0], "Main") == 0) { + ao_config.main_deploy = atoi(words[2]); + } else if (nword >= 36 && strcmp(words[0], "CALL") == 0) { + tick = atoi(words[10]); + if (!ao_flight_started) { + type = 'F'; + a = atoi(words[26]); + ao_flight_started = 1; + } else { + type = 'A'; + a = atoi(words[12]); + b = atoi(words[14]); + } + } else if (nword == 3 && strcmp(words[0], "BARO") == 0) { + tick = strtol(words[1], NULL, 16); + a = 16384 - 328; + b = strtol(words[2], NULL, 10); + type = 'A'; + if (!ao_flight_started) { + ao_flight_ground_accel = 16384 - 328; + ao_config.accel_plus_g = 16384 - 328; + ao_config.accel_minus_g = 16384 + 328; + ao_flight_started = 1; + } + } else if (nword == 2 && strcmp(words[0], "TELEM") == 0) { + char *hex = words[1]; + char elt[3]; + int i, len; + uint8_t sum; + + len = strlen(hex); + if (len > sizeof (bytes) * 2) { + len = sizeof (bytes)*2; + hex[len] = '\0'; + } + for (i = 0; i < len; i += 2) { + elt[0] = hex[i]; + elt[1] = hex[i+1]; + elt[2] = '\0'; + bytes[i/2] = (uint8_t) strtol(elt, NULL, 16); + } + len = i/2; + if (bytes[0] != len - 2) { + printf ("bad length %d != %d\n", bytes[0], len - 2); + continue; + } + sum = 0x5a; + for (i = 1; i < len-1; i++) + sum += bytes[i]; + if (sum != bytes[len-1]) { + printf ("bad checksum\n"); + continue; + } + if ((bytes[len-2] & 0x80) == 0) { + continue; + } + if (len == 36) { + memcpy(&telem, bytes + 1, 32); + tick = telem.generic.tick; + switch (telem.generic.type) { + case AO_TELEMETRY_SENSOR_TELEMETRUM: + case AO_TELEMETRY_SENSOR_TELEMINI: + case AO_TELEMETRY_SENSOR_TELENANO: + if (!ao_flight_started) { + ao_flight_ground_accel = telem.sensor.ground_accel; + ao_config.accel_plus_g = telem.sensor.accel_plus_g; + ao_config.accel_minus_g = telem.sensor.accel_minus_g; + ao_flight_started = 1; + } + type = 'A'; + a = telem.sensor.accel; + b = telem.sensor.pres; + break; + } + } else if (len == 99) { + ao_flight_started = 1; + tick = uint16(bytes, 21); + ao_flight_ground_accel = int16(bytes, 7); + ao_config.accel_plus_g = int16(bytes, 17); + ao_config.accel_minus_g = int16(bytes, 19); + type = 'A'; + a = int16(bytes, 23); + b = int16(bytes, 25); + } else if (len == 98) { + ao_flight_started = 1; + tick = uint16(bytes, 20); + ao_flight_ground_accel = int16(bytes, 6); + ao_config.accel_plus_g = int16(bytes, 16); + ao_config.accel_minus_g = int16(bytes, 18); + type = 'A'; + a = int16(bytes, 22); + b = int16(bytes, 24); + } else { + printf("unknown len %d\n", len); + continue; + } + } + if (type != 'F' && !ao_flight_started) + continue; + + switch (type) { + case 'F': + ao_flight_ground_accel = a; + if (ao_config.accel_plus_g == 0) { + ao_config.accel_plus_g = a; + ao_config.accel_minus_g = a + 530; + } + if (ao_config.main_deploy == 0) + ao_config.main_deploy = 250; + ao_flight_started = 1; + break; + case 'S': + break; + case 'A': + ao_adc_static.tick = tick; + ao_adc_static.accel = a; + ao_adc_static.pres_real = b; + if (b < AO_MIN_BARO_VALUE) + b = AO_MIN_BARO_VALUE; + ao_adc_static.pres = b; + ao_records_read++; + ao_insert(); + return; + case 'T': + ao_adc_static.tick = tick; + ao_adc_static.temp = a; + ao_adc_static.v_batt = b; + break; + case 'D': + case 'G': + case 'N': + case 'W': + case 'H': + break; + } + } + + } +} +#define COUNTS_PER_G 264.8 + +void +ao_dump_state(void) +{ +} + +static const struct option options[] = { + { .name = "summary", .has_arg = 0, .val = 's' }, + { .name = "debug", .has_arg = 0, .val = 'd' }, + { 0, 0, 0, 0}, +}; + +void run_flight_fixed(char *name, FILE *f, int summary) +{ + emulator_name = name; + emulator_in = f; + ao_summary = summary; + ao_flight_init(); + ao_flight(); +} + +int +main (int argc, char **argv) +{ + int summary = 0; + int c; + int i; + +#if HAS_ACCEL + emulator_app="full"; +#else + emulator_app="baro"; +#endif + while ((c = getopt_long(argc, argv, "sd", options, NULL)) != -1) { + switch (c) { + case 's': + summary = 1; + break; + case 'd': + ao_flight_debug = 1; + break; + } + } + + if (optind == argc) + run_flight_fixed("", stdin, summary); + else + for (i = optind; i < argc; i++) { + FILE *f = fopen(argv[i], "r"); + if (!f) { + perror(argv[i]); + continue; + } + run_flight_fixed(argv[i], f, summary); + fclose(f); + } +} diff --git a/src/test/ao_gps_test.c b/src/test/ao_gps_test.c new file mode 100644 index 00000000..93d7a9ab --- /dev/null +++ b/src/test/ao_gps_test.c @@ -0,0 +1,508 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_GPS_TEST +#include "ao_host.h" +#include +#include +#include +#include +#include +#define AO_GPS_NUM_SAT_MASK (0xf << 0) +#define AO_GPS_NUM_SAT_SHIFT (0) + +#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_orig { + uint8_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + uint8_t flags; + int32_t latitude; /* degrees * 10⁷ */ + int32_t longitude; /* degrees * 10⁷ */ + int16_t altitude; /* m */ + uint16_t ground_speed; /* cm/s */ + uint8_t course; /* degrees / 2 */ + uint8_t hdop; /* * 5 */ + int16_t climb_rate; /* cm/s */ + uint16_t h_error; /* m */ + 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_orig { + uint8_t svid; + uint8_t c_n_1; +}; + +#define AO_MAX_GPS_TRACKING 12 + +struct ao_gps_tracking_orig { + uint8_t channels; + struct ao_gps_sat_orig sats[AO_MAX_GPS_TRACKING]; +}; + +#define ao_telemetry_location ao_gps_orig +#define ao_telemetry_satellite ao_gps_tracking_orig +#define ao_telemetry_satellite_info ao_gps_sat_orig + +void +ao_mutex_get(uint8_t *mutex) +{ +} + +void +ao_mutex_put(uint8_t *mutex) +{ +} + +static int +ao_gps_fd; + +static void +ao_dbg_char(char c) +{ + char line[128]; + line[0] = '\0'; + if (c < ' ') { + if (c == '\n') + sprintf (line, "\n"); + else + sprintf (line, "\\%02x", ((int) c) & 0xff); + } else { + sprintf (line, "%c", c); + } + write(1, line, strlen(line)); +} + +#define QUEUE_LEN 4096 + +static char input_queue[QUEUE_LEN]; +int input_head, input_tail; + +#include + +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) +{ + uint16_t encoded_len, encoded_cksum; + uint16_t cksum; + uint8_t id; + int i; + + if (msg[0] != 0xa0 || msg[1] != 0xa2) { + printf ("bad header\n"); + return; + } + if (len < 7) { + printf("short\n"); + return; + } + if (msg[len-1] != 0xb3 || msg[len-2] != 0xb0) { + printf ("bad trailer\n"); + return; + } + encoded_len = (msg[2] << 8) | msg[3]; + id = msg[4]; +/* printf ("%9d: %3d\n", get_millis(), id); */ + if (encoded_len != len - 8) { + 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]; + cksum = 0; + for (i = 4; i < len - 4; i++) + cksum = (cksum + msg[i]) & 0x7fff; + if (encoded_cksum != cksum) { + printf ("cksum mismatch (got %04x wanted %04x)\n", + cksum, encoded_cksum); + return; + } + id = msg[4]; + switch (id) { + case 41:{ + int off = 4; + + uint8_t id; + uint16_t nav_valid; + uint16_t nav_type; + uint16_t week; + uint32_t tow; + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint16_t second; + uint32_t sat_list; + int32_t lat; + int32_t lon; + int32_t alt_ell; + int32_t alt_msl; + int8_t datum; + uint16_t sog; + uint16_t cog; + int16_t mag_var; + int16_t climb_rate; + int16_t heading_rate; + uint32_t h_error; + uint32_t v_error; + uint32_t t_error; + uint16_t h_v_error; + +#define get_u8(u) u = (msg[off]); off+= 1 +#define get_u16(u) u = (msg[off] << 8) | (msg[off + 1]); off+= 2 +#define get_u32(u) u = (msg[off] << 24) | (msg[off + 1] << 16) | (msg[off+2] << 8) | (msg[off+3]); off+= 4 + + get_u8(id); + get_u16(nav_valid); + get_u16(nav_type); + get_u16(week); + get_u32(tow); + get_u16(year); + get_u8(month); + get_u8(day); + get_u8(hour); + get_u8(minute); + get_u16(second); + get_u32(sat_list); + get_u32(lat); + get_u32(lon); + get_u32(alt_ell); + get_u32(alt_msl); + get_u8(datum); + get_u16(sog); + get_u16(cog); + get_u16(mag_var); + get_u16(climb_rate); + get_u16(heading_rate); + get_u32(h_error); + get_u32(v_error); + get_u32(t_error); + get_u16(h_v_error); + + + printf ("Geodetic Navigation Data (41):\n"); + printf ("\tNav valid %04x\n", nav_valid); + printf ("\tNav type %04x\n", nav_type); + 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", 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++) { + if (((i - 4) & 0xf) == 0) + printf("\n "); + printf (" %3d", msg[i]); + } + printf ("\n"); + } +} + +static uint8_t sirf_message[4096]; +static int sirf_message_len; +static uint8_t sirf_in_message[4096]; +static int sirf_in_len; + +char +ao_serial_getchar(void) +{ + char c; + uint8_t uc; + + while (input_head == input_tail) { + for (;;) { + input_tail = read(ao_gps_fd, input_queue, QUEUE_LEN); + if (input_tail < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + perror ("getchar"); + exit (1); + } + input_head = 0; + break; + } + } + c = input_queue[input_head]; + input_head = (input_head + 1) % QUEUE_LEN; + uc = c; + if (sirf_in_len || uc == 0xa0) { + if (sirf_in_len < 4096) + sirf_in_message[sirf_in_len++] = uc; + if (uc == 0xb3) { + check_sirf_message("recv", sirf_in_message, sirf_in_len); + sirf_in_len = 0; + } + } + return c; +} + + +void +ao_serial_putchar(char c) +{ + int i; + uint8_t uc = (uint8_t) c; + + if (sirf_message_len || uc == 0xa0) { + if (sirf_message_len < 4096) + sirf_message[sirf_message_len++] = uc; + if (uc == 0xb3) { + check_sirf_message("send", sirf_message, sirf_message_len); + sirf_message_len = 0; + } + } + for (;;) { + i = write(ao_gps_fd, &c, 1); + if (i == 1) { + if ((uint8_t) c == 0xb3 || c == '\r') { + static const struct timespec delay = { + .tv_sec = 0, + .tv_nsec = 100 * 1000 * 1000 + }; + tcdrain(ao_gps_fd); +// nanosleep(&delay, NULL); + } + break; + } + if (i < 0 && (errno == EINTR || errno == EAGAIN)) + continue; + perror("putchar"); + exit(1); + } +} + +#define AO_SERIAL_SPEED_4800 0 +#define AO_SERIAL_SPEED_57600 1 + +static void +ao_serial_set_speed(uint8_t speed) +{ + int fd = ao_gps_fd; + struct termios termios; + + tcdrain(fd); + tcgetattr(fd, &termios); + switch (speed) { + case AO_SERIAL_SPEED_4800: + cfsetspeed(&termios, B4800); + break; + case AO_SERIAL_SPEED_57600: + cfsetspeed(&termios, B57600); + break; + } + tcsetattr(fd, TCSAFLUSH, &termios); + tcflush(fd, TCIFLUSH); +} + +#define ao_time() 0 + +#include "ao_gps_print.c" +#include "ao_gps_sirf.c" + +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); + printf (" nsat %d %svalid", + ao_gps_data.flags & AO_GPS_NUM_SAT_MASK, + ao_gps_data.flags & AO_GPS_VALID ? "" : "not "); + printf (" lat %g lon %g alt %d", + ao_gps_data.latitude / 1.0e7, + ao_gps_data.longitude / 1.0e7, + ao_gps_data.altitude); + printf (" speed %g climb %g course %d", + ao_gps_data.ground_speed / 100.0, + ao_gps_data.climb_rate / 100.0, + ao_gps_data.course * 2); + printf (" hdop %g h_error %d v_error %d", + 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(%02d)", + ao_gps_tracking_data.sats[i].svid, + ao_gps_tracking_data.sats[i].c_n_1); + printf ("\n"); +} + +int +ao_gps_open(const char *tty) +{ + struct termios termios; + int fd; + + fd = open (tty, O_RDWR); + if (fd < 0) + return -1; + + tcgetattr(fd, &termios); + cfmakeraw(&termios); + cfsetspeed(&termios, B4800); + tcsetattr(fd, TCSAFLUSH, &termios); + + tcdrain(fd); + tcflush(fd, TCIFLUSH); + return fd; +} + +#include + +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 ]\n", program); + exit(1); +} + +int +main (int argc, char **argv) +{ + char *tty = "/dev/ttyUSB0"; + int c; + + 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 (tty); + exit (1); + } + ao_gps_setup(); + ao_gps(); +} diff --git a/src/test/ao_gps_test_skytraq.c b/src/test/ao_gps_test_skytraq.c new file mode 100644 index 00000000..a78fae0f --- /dev/null +++ b/src/test/ao_gps_test_skytraq.c @@ -0,0 +1,490 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_GPS_TEST +#include "ao_host.h" +#include +#include +#include +#include +#include +#define AO_GPS_NUM_SAT_MASK (0xf << 0) +#define AO_GPS_NUM_SAT_SHIFT (0) + +#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_orig { + uint8_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + uint8_t flags; + int32_t latitude; /* degrees * 10⁷ */ + int32_t longitude; /* degrees * 10⁷ */ + int16_t altitude; /* m */ + uint16_t ground_speed; /* cm/s */ + uint8_t course; /* degrees / 2 */ + uint8_t hdop; /* * 5 */ + int16_t climb_rate; /* cm/s */ + uint16_t h_error; /* m */ + 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_orig { + uint8_t svid; + uint8_t c_n_1; +}; + +#define AO_MAX_GPS_TRACKING 12 + +struct ao_gps_tracking_orig { + uint8_t channels; + struct ao_gps_sat_orig sats[AO_MAX_GPS_TRACKING]; +}; + +#define ao_telemetry_location ao_gps_orig +#define ao_telemetry_satellite ao_gps_tracking_orig +#define ao_telemetry_satellite_info ao_gps_sat_orig + +void +ao_mutex_get(uint8_t *mutex) +{ +} + +void +ao_mutex_put(uint8_t *mutex) +{ +} + +static int +ao_gps_fd; + +static void +ao_dbg_char(char c) +{ + char line[128]; + line[0] = '\0'; + if (c < ' ') { + if (c == '\n') + sprintf (line, "\n"); + else + sprintf (line, "\\%02x", ((int) c) & 0xff); + } else { + sprintf (line, "%c", c); + } + write(1, line, strlen(line)); +} + +#define QUEUE_LEN 4096 + +static char input_queue[QUEUE_LEN]; +int input_head, input_tail; + +#include + +int +get_millis(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +static void +check_skytraq_message(char *from, uint8_t *msg, int len) +{ + uint16_t encoded_len, encoded_cksum; + uint16_t cksum; + uint8_t id; + int i; + +// fwrite(msg, 1, len, stdout); + return; + if (msg[0] != 0xa0 || msg[1] != 0xa2) { + printf ("bad header\n"); + return; + } + if (len < 7) { + printf("short\n"); + return; + } + if (msg[len-1] != 0xb3 || msg[len-2] != 0xb0) { + printf ("bad trailer\n"); + return; + } + encoded_len = (msg[2] << 8) | msg[3]; + id = msg[4]; +/* printf ("%9d: %3d\n", get_millis(), id); */ + if (encoded_len != len - 8) { + 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]; + cksum = 0; + for (i = 4; i < len - 4; i++) + cksum = (cksum + msg[i]) & 0x7fff; + if (encoded_cksum != cksum) { + printf ("cksum mismatch (got %04x wanted %04x)\n", + cksum, encoded_cksum); + return; + } + id = msg[4]; + switch (id) { + case 41:{ + int off = 4; + + uint8_t id; + uint16_t nav_valid; + uint16_t nav_type; + uint16_t week; + uint32_t tow; + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint16_t second; + uint32_t sat_list; + int32_t lat; + int32_t lon; + int32_t alt_ell; + int32_t alt_msl; + int8_t datum; + uint16_t sog; + uint16_t cog; + int16_t mag_var; + int16_t climb_rate; + int16_t heading_rate; + uint32_t h_error; + uint32_t v_error; + uint32_t t_error; + uint16_t h_v_error; + +#define get_u8(u) u = (msg[off]); off+= 1 +#define get_u16(u) u = (msg[off] << 8) | (msg[off + 1]); off+= 2 +#define get_u32(u) u = (msg[off] << 24) | (msg[off + 1] << 16) | (msg[off+2] << 8) | (msg[off+3]); off+= 4 + + get_u8(id); + get_u16(nav_valid); + get_u16(nav_type); + get_u16(week); + get_u32(tow); + get_u16(year); + get_u8(month); + get_u8(day); + get_u8(hour); + get_u8(minute); + get_u16(second); + get_u32(sat_list); + get_u32(lat); + get_u32(lon); + get_u32(alt_ell); + get_u32(alt_msl); + get_u8(datum); + get_u16(sog); + get_u16(cog); + get_u16(mag_var); + get_u16(climb_rate); + get_u16(heading_rate); + get_u32(h_error); + get_u32(v_error); + get_u32(t_error); + get_u16(h_v_error); + + + printf ("Geodetic Navigation Data (41):\n"); + printf ("\tNav valid %04x\n", nav_valid); + printf ("\tNav type %04x\n", nav_type); + 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", 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++) { + if (((i - 4) & 0xf) == 0) + printf("\n "); + printf (" %3d", msg[i]); + } + printf ("\n"); + } +} + +static uint8_t skytraq_message[4096]; +static int skytraq_message_len; +static uint8_t skytraq_in_message[4096]; +static int skytraq_in_len; + +char +ao_serial_getchar(void) +{ + char c; + uint8_t uc; + + while (input_head == input_tail) { + for (;;) { + input_tail = read(ao_gps_fd, input_queue, QUEUE_LEN); + if (input_tail < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + perror ("getchar"); + exit (1); + } + input_head = 0; + break; + } + } + c = input_queue[input_head]; + input_head = (input_head + 1) % QUEUE_LEN; + uc = c; +// printf ("c: %02x %c\n", uc, uc); + if (skytraq_in_len || uc == '$') { + if (skytraq_in_len < 4096) + skytraq_in_message[skytraq_in_len++] = uc; + if (uc == 0x0a) { + check_skytraq_message("recv", skytraq_in_message, skytraq_in_len); + skytraq_in_len = 0; + } + } + return c; +} + + +void +ao_serial_putchar(char c) +{ + int i; + uint8_t uc = (uint8_t) c; + + if (skytraq_message_len || uc == 0xa0) { + if (skytraq_message_len < 4096) + skytraq_message[skytraq_message_len++] = uc; + if (uc == 0x0a) { + check_skytraq_message("send", skytraq_message, skytraq_message_len); + skytraq_message_len = 0; + } + } + for (;;) { + i = write(ao_gps_fd, &c, 1); + if (i == 1) { + if ((uint8_t) c == 0xb3 || c == '\r') { + static const struct timespec delay = { + .tv_sec = 0, + .tv_nsec = 100 * 1000 * 1000 + }; + tcdrain(ao_gps_fd); +// nanosleep(&delay, NULL); + } + break; + } + if (i < 0 && (errno == EINTR || errno == EAGAIN)) + continue; + perror("putchar"); + exit(1); + } +} + +#define AO_SERIAL_SPEED_4800 0 +#define AO_SERIAL_SPEED_9600 1 +#define AO_SERIAL_SPEED_57600 2 + +static void +ao_serial_set_speed(uint8_t speed) +{ + int fd = ao_gps_fd; + struct termios termios; + + tcdrain(fd); + tcgetattr(fd, &termios); + switch (speed) { + case AO_SERIAL_SPEED_4800: + cfsetspeed(&termios, B4800); + break; + case AO_SERIAL_SPEED_9600: + cfsetspeed(&termios, B38400); + break; + case AO_SERIAL_SPEED_57600: + cfsetspeed(&termios, B57600); + break; + } + tcsetattr(fd, TCSAFLUSH, &termios); + tcflush(fd, TCIFLUSH); +} + +#define ao_time() 0 + +#include "ao_gps_print.c" +#include "ao_gps_skytraq.c" + +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; +} + +int +ao_gps_open(const char *tty) +{ + struct termios termios; + int fd; + + fd = open (tty, O_RDWR); + if (fd < 0) + return -1; + + tcgetattr(fd, &termios); + cfmakeraw(&termios); + cfsetspeed(&termios, B4800); + tcsetattr(fd, TCSAFLUSH, &termios); + + tcdrain(fd); + tcflush(fd, TCIFLUSH); + return fd; +} + +#include + +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 ]\n", program); + exit(1); +} + +int +main (int argc, char **argv) +{ + char *tty = "/dev/ttyUSB0"; + int c; + + 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 (tty); + exit (1); + } + ao_gps(); +} diff --git a/src/tidongle/Makefile b/src/tidongle/Makefile index d8867b19..fc8df1f4 100644 --- a/src/tidongle/Makefile +++ b/src/tidongle/Makefile @@ -1 +1,92 @@ -include ../Makefile.proto +# +# TIDongle build file +# + +vpath %.c ..:../core:../cc1111:../drivers:../product +vpath %.h ..:../core:../cc1111:../drivers:../product +vpath ao-make-product.5c ../util + +ifndef VERSION +include ../Version +endif + +INC = \ + ao.h \ + ao_pins.h \ + cc1111.h \ + ao_product.h + +CORE_SRC = \ + ao_cmd.c \ + ao_config.c \ + ao_gps_print.c \ + ao_monitor.c \ + ao_mutex.c \ + ao_panic.c \ + ao_rssi.c \ + ao_state.c \ + ao_stdio.c \ + ao_task.c + +CC1111_SRC = \ + ao_dbg.c \ + ao_dma.c \ + ao_led.c \ + ao_packet.c \ + ao_packet_master.c \ + ao_radio.c \ + ao_romconfig.c \ + ao_timer.c \ + ao_usb.c \ + _bp.c + +DRIVER_SRC = + +PRODUCT_SRC = \ + ao_tidongle.c + +SRC = \ + $(CORE_SRC) \ + $(CC1111_SRC) \ + $(DRIVER_SRC) \ + $(PRODUCT_SRC) + +PROG = tidongle-$(VERSION).ihx +PRODUCT=TIDongle +PRODUCT_DEF=-DTIDONGLE +IDPRODUCT=0x000a + +include ../cc1111/Makefile.cc1111 + +NICKLE=nickle +CHECK_STACK=sh ../util/check-stack + +V=0 +# The user has explicitly enabled quiet compilation. +ifeq ($(V),0) +quiet = @printf " $1 $2 $@\n"; $($1) +endif +# Otherwise, print the full command line. +quiet ?= $($1) + +all: ../$(PROG) + +../$(PROG): $(REL) Makefile + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. + $(call quiet,CHECK_STACK) ../core/ao.h $(PMEM) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean: clean + +clean: + rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) + rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) + rm -f ao_product.h + rm -f ../$(PROG) ../$(PMAP) + +install: + +uninstall: + diff --git a/src/tidongle/Makefile.defs b/src/tidongle/Makefile.defs deleted file mode 100644 index 0e13cb20..00000000 --- a/src/tidongle/Makefile.defs +++ /dev/null @@ -1,9 +0,0 @@ -PROG = tidongle-$(VERSION).ihx - -SRC = \ - $(TI_SRC) - -PRODUCT=TIDongle - -PRODUCT_DEF=-DTIDONGLE -IDPRODUCT=0x000a diff --git a/src/util/ao-make-product.5c b/src/util/ao-make-product.5c new file mode 100644 index 00000000..5f2eb8e8 --- /dev/null +++ b/src/util/ao-make-product.5c @@ -0,0 +1,103 @@ +#!/bin/sh + +autoimport ParseArgs; + +void +write_ucs2(string a, string description) +{ + int len = String::length(a); + + printf("/* %s */\n", description); + printf("#define AO_%s_LEN 0x%02x\n", description, len * 2 + 2); + printf("#define AO_%s_STRING \"%s\"\n", description, a); + printf("#define AO_%s_UCS2", description); + for (int i = 0; i < len; i++) { + int c = a[i]; + if (i > 0) + printf(","); + if (0x20 <= c && c < 128) + printf(" '%c', 0", c); + else + printf(" LE_WORD(0x%04x),", c); + } + printf("\n\n"); +} + +void +write_string(string a, string description) +{ + printf ("/* %s */\n", description); + printf ("#define AO_%s_STRING \"%s\"\n", description, a); +} + +void +write_int(int a, string description) +{ + printf ("/* %s */\n", description); + printf ("#define AO_%s_NUMBER %d\n\n", description, a); +} + +void +write_hex(int a, string description) +{ + printf ("/* %s */\n", description); + printf ("#define AO_%s_NUMBER 0x%04x\n\n", description, a); +} + +string manufacturer = "altusmetrum.org"; +string product = "TeleMetrum"; +string version = "0.0"; +int serial = 1; +int user_argind = 0; +int id_product = 0x000a; + +argdesc argd = { + .args = { + { + .var = { .arg_string = &manufacturer }, + .abbr = 'm', + .name = "manufacturer", + .expr_name = "manf", + .desc = "Manufacturer name." }, + { + .var = { .arg_string = &product }, + .abbr = 'p', + .name = "product", + .expr_name = "prod", + .desc = "Product name." }, + { + .var = { .arg_int = &id_product }, + .abbr = 'i', + .name = "id_product", + .expr_name = "id_p", + .desc = "Product ID." }, + { + .var = { .arg_int = &serial }, + .abbr = 's', + .name = "serial", + .expr_name = "number", + .desc = "Serial number." }, + { + .var = { .arg_string = &version }, + .abbr = 'v', + .name = "version", + .expr_name = "string", + .desc = "Program version." }, + }, + .prog_name = "usb descriptors", +}; + +void +main() +{ + string[dim(argv)-1] nargv = {[n] = argv[n+1]}; + parseargs(&argd, &nargv); + write_ucs2(manufacturer, "iManufacturer"); + write_ucs2(product, "iProduct"); + write_ucs2(sprintf("%06d", serial), "iSerial"); + write_int(serial, "iSerial"); + write_hex(id_product, "idProduct"); + write_string(version, "iVersion"); +} + +main(); diff --git a/src/util/check-stack b/src/util/check-stack new file mode 100755 index 00000000..1e8044e0 --- /dev/null +++ b/src/util/check-stack @@ -0,0 +1,13 @@ +#!/bin/sh +HEADER=$1 +MEM=$2 + +HEADER_STACK=`awk '/#define AO_STACK_START/ {print strtonum($3)}' $HEADER` +MEM_STACK=`awk '/Stack starts at/ {print strtonum ($4)}' $MEM` + +if [ "$HEADER_STACK" -lt "$MEM_STACK" ]; then + echo $MEM_STACK | awk '{ printf ("Set AO_STACK_START to at least 0x%x\n", $1); }' + exit 1 +else + exit 0 +fi diff --git a/src/util/gps-cksum b/src/util/gps-cksum new file mode 100755 index 00000000..a08153bf --- /dev/null +++ b/src/util/gps-cksum @@ -0,0 +1,17 @@ +#!/usr/bin/env nickle + +int checksum(string a) +{ + int c = 0; + for (int i = 0; i < String::length(a); i++) + c ^= a[i]; + return c; +} + +void main() +{ + for (int i = 1; i < dim(argv); i++) + printf ("$%s*%02x\n", argv[i], checksum(argv[i])); +} + +main(); diff --git a/src/util/make-altitude b/src/util/make-altitude new file mode 100644 index 00000000..716aa8a8 --- /dev/null +++ b/src/util/make-altitude @@ -0,0 +1,283 @@ +#!/usr/bin/nickle -f +/* + * Pressure Sensor Model, version 1.1 + * + * written by Holly Grimes + * + * Uses the International Standard Atmosphere as described in + * "A Quick Derivation relating altitude to air pressure" (version 1.03) + * from the Portland State Aerospace Society, except that the atmosphere + * is divided into layers with each layer having a different lapse rate. + * + * Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007 + * at site MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */ + return 0; + + /* calculate the base temperature and pressure for the atmospheric layer + associated with the inputted altitude */ + for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) { + delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + base_pressure *= exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + base_pressure *= pow(base, exponent); + } + base_temperature += delta_z * lapse_rate[layer_number]; + } + + /* calculate the pressure at the inputted altitude */ + delta_z = altitude - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + pressure = base_pressure * exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + pressure = base_pressure * pow(base, exponent); + } + + return pressure; +} + + +/* outputs the altitude associated with the given pressure. the altitude + returned is measured with respect to the mean sea level */ +real pressure_to_altitude(real pressure) { + + real next_base_temperature = LAYER0_BASE_TEMPERATURE; + real next_base_pressure = LAYER0_BASE_PRESSURE; + + real altitude; + real base_pressure; + real base_temperature; + real base; /* base for function to determine base pressure of next layer */ + real exponent; /* exponent for function to determine base pressure + of next layer */ + real coefficient; + int layer_number; /* identifies layer in the atmosphere */ + int delta_z; /* difference between two altitudes */ + + if (pressure < 0) /* illegal pressure */ + return -1; + if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */ + return MAXIMUM_ALTITUDE; + + /* calculate the base temperature and pressure for the atmospheric layer + associated with the inputted pressure. */ + layer_number = -1; + do { + layer_number++; + base_pressure = next_base_pressure; + base_temperature = next_base_temperature; + delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + next_base_pressure *= exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + next_base_pressure *= pow(base, exponent); + } + next_base_temperature += delta_z * lapse_rate[layer_number]; + } + while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure); + + /* calculate the altitude associated with the inputted pressure */ + if (lapse_rate[layer_number] == 0.0) { + coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION) + * base_temperature; + altitude = base_altitude[layer_number] + + coefficient * log(pressure / base_pressure); + } + else { + base = pressure / base_pressure; + exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number] + / GRAVITATIONAL_ACCELERATION; + coefficient = base_temperature / lapse_rate[layer_number]; + altitude = base_altitude[layer_number] + + coefficient * (pow(base, exponent) - 1); + } + + return altitude; +} + +real feet_to_meters(real feet) +{ + return feet * (12 * 2.54 / 100); +} + +real meters_to_feet(real meters) +{ + return meters / (12 * 2.54 / 100); +} + +/* + * Values for our MP3H6115A pressure sensor + * + * From the data sheet: + * + * Pressure range: 15-115 kPa + * Voltage at 115kPa: 2.82 + * Output scale: 27mV/kPa + * + * + * 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa + * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa + */ + +real counts_per_kPa = 27 * 2047 / 3300; +real counts_at_101_3kPa = 1674; + +real fraction_to_kPa(real fraction) +{ + return (fraction + 0.095) / 0.009; +} + + +real count_to_kPa(real count) = fraction_to_kPa(count / 2047); + +typedef struct { + real m, b; + int m_i, b_i; +} line_t; + +line_t best_fit(real[] values, int first, int last) { + real sum_x = 0, sum_x2 = 0, sum_y = 0, sum_xy = 0; + int n = last - first + 1; + real m, b; + int m_i, b_i; + + for (int i = first; i <= last; i++) { + sum_x += i; + sum_x2 += i**2; + sum_y += values[i]; + sum_xy += values[i] * i; + } + m = (n*sum_xy - sum_y*sum_x) / (n*sum_x2 - sum_x**2); + b = sum_y/n - m*(sum_x/n); + return (line_t) { m = m, b = b }; +} + +real count_to_altitude(real count) { + return pressure_to_altitude(count_to_kPa(count) * 1000); +} + +real fraction_to_altitude(real frac) = pressure_to_altitude(fraction_to_kPa(frac) * 1000); + +int num_samples = 1024; + +real[num_samples] alt = { [n] = fraction_to_altitude(n/(num_samples - 1)) }; + +int num_part = 128; +int seg_len = num_samples / num_part; + +line_t [dim(alt) / seg_len] fit = { + [n] = best_fit(alt, n * seg_len, n * seg_len + seg_len - 1) +}; + +int[num_samples/seg_len + 1] alt_part; + +alt_part[0] = floor (fit[0].b + 0.5); +alt_part[dim(fit)] = floor(fit[dim(fit)-1].m * dim(fit) * seg_len + fit[dim(fit)-1].b + 0.5); + +for (int i = 0; i < dim(fit) - 1; i++) { + real here, there; + here = fit[i].m * (i+1) * seg_len + fit[i].b; + there = fit[i+1].m * (i+1) * seg_len + fit[i+1].b; + alt_part[i+1] = floor ((here + there) / 2 + 0.5); +} + +real count_to_fit_altitude(int count) { + int sub = count // seg_len; + int off = count % seg_len; + line_t l = fit[sub]; + real r_v; + real i_v; + + r_v = count * l.m + l.b; + i_v = (alt_part[sub] * (seg_len - off) + alt_part[sub+1] * off) / seg_len; + return i_v; +} + +real max_error = 0; +int max_error_count = 0; +real total_error = 0; + +for (int count = 0; count < num_samples; count++) { + real kPa = fraction_to_kPa(count / (num_samples - 1)); + real meters = pressure_to_altitude(kPa * 1000); + + real meters_approx = count_to_fit_altitude(count); + real error = abs(meters - meters_approx); + + total_error += error; + if (error > max_error) { + max_error = error; + max_error_count = count; + } +# printf (" %7d, /* %6.2g kPa %5d count approx %d */\n", +# floor (meters + 0.5), kPa, count, floor(count_to_fit_altitude(count) + 0.5)); +} + +printf ("/*max error %f at %7.3f%%. Average error %f*/\n", max_error, max_error_count / (num_samples - 1) * 100, total_error / num_samples); + +printf ("#define NALT %d\n", dim(alt_part)); +printf ("#define ALT_FRAC_BITS %d\n", floor (log2(32768/(dim(alt_part)-1)) + 0.1)); + +for (int i = 0; i < dim(alt_part); i++) { + real fraction = i / (dim(alt_part) - 1); + real kPa = fraction_to_kPa(fraction); + printf ("%9d, /* %6.2f kPa %7.3f%% */\n", + alt_part[i], kPa, fraction * 100); +} diff --git a/src/util/make-kalman b/src/util/make-kalman new file mode 100644 index 00000000..f78f30a9 --- /dev/null +++ b/src/util/make-kalman @@ -0,0 +1,19 @@ +#!/bin/sh + +cd $1 >&/dev/null + +SIGMA_BOTH="-M 2 -H 6 -A 2" +SIGMA_BARO="-M 2 -H 6 -A 2" +SIGMA_ACCEL="-M 2 -H 4 -A 4" + +nickle kalman.5c -p AO_BOTH -c both -t 0.01 $SIGMA_BOTH +nickle kalman.5c -p AO_BOTH -c both -t 0.1 $SIGMA_BOTH +nickle kalman.5c -p AO_BOTH -c both -t 1 $SIGMA_BOTH + +nickle kalman.5c -p AO_ACCEL -c accel -t 0.01 $SIGMA_ACCEL +nickle kalman.5c -p AO_ACCEL -c accel -t 0.1 $SIGMA_ACCEL +nickle kalman.5c -p AO_ACCEL -c accel -t 1 $SIGMA_ACCEL + +nickle kalman.5c -p AO_BARO -c baro -t 0.01 $SIGMA_BARO +nickle kalman.5c -p AO_BARO -c baro -t 0.1 $SIGMA_BARO +nickle kalman.5c -p AO_BARO -c baro -t 1 $SIGMA_BARO diff --git a/src/util/sirf-cksum b/src/util/sirf-cksum new file mode 100755 index 00000000..b905f318 --- /dev/null +++ b/src/util/sirf-cksum @@ -0,0 +1,44 @@ +#!/usr/bin/env nickle + +int checksum(int[] msg) +{ + int sum = 0; + for (int i = 0; i < dim(msg); i++) { + sum += msg[i]; + sum &= 0x7fff; + } + return sum; +} + +void main() +{ + string[...] input; + int[...] msg; + + setdim(input, 0); + while (!File::end(stdin)) { + input[dim(input)] = gets(); + } + + setdim(msg, 0); + for (int i = 0; i < dim(input); i++) { + string[*] words = String::wordsplit(input[i], " ,\t"); + for (int j = 0; j < dim(words); j++) { + if (words[j] == "/" + "*") + break; + if (String::length(words[j]) > 0 && + Ctype::isdigit(words[j][0])) { + msg[dim(msg)] = string_to_integer(words[j]); + } + } + } + printf("\t0xa0, 0xa2, 0x%02x, 0x%02x,\t/* length: %d bytes */\n", + dim(msg) >> 8, dim(msg) & 0xff, dim(msg)); + for (int i = 0; i < dim(input); i++) + printf("%s\n", input[i]); + int csum = checksum(msg); + printf ("\t0x%02x, 0x%02x, 0xb0, 0xb3,\n", + csum >> 8, csum & 0xff); +} + +main(); diff --git a/src/util/skytraq-cksum b/src/util/skytraq-cksum new file mode 100644 index 00000000..ab0464a7 --- /dev/null +++ b/src/util/skytraq-cksum @@ -0,0 +1,44 @@ +#!/usr/bin/env nickle + +int checksum(int[] msg) +{ + int sum = 0; + for (int i = 0; i < dim(msg); i++) { + sum ^= msg[i]; + sum &= 0xff; + } + return sum; +} + +void main() +{ + string[...] input; + int[...] msg; + + setdim(input, 0); + while (!File::end(stdin)) { + input[dim(input)] = gets(); + } + + setdim(msg, 0); + for (int i = 0; i < dim(input); i++) { + string[*] words = String::wordsplit(input[i], " ,\t"); + for (int j = 0; j < dim(words); j++) { + if (words[j] == "/" + "*") + break; + if (String::length(words[j]) > 0 && + Ctype::isdigit(words[j][0])) { + msg[dim(msg)] = string_to_integer(words[j]); + } + } + } + printf("\t0xa0, 0xa1, 0x%02x, 0x%02x,\t\t/* length: %d bytes */\n", + dim(msg) >> 8, dim(msg) & 0xff, dim(msg)); + for (int i = 0; i < dim(input); i++) + printf("%s\n", input[i]); + int csum = checksum(msg); + printf ("\t0x%02x, 0x0d, 0x0a,\n", + csum); +} + +main(); -- cgit v1.2.3