radio_setting = 0;
radio_frequency = 0;
stored_flight = 0;
+ serial = -1;
for (;;) {
String line = link.get_reply();
if (line == null)
class Distance extends DescentValue {
void show(AltosState state, int crc_errors) {
- show(AltosConvert.distance, state.from_pad.distance);
+ if (state.from_pad != null)
+ show(AltosConvert.distance, state.from_pad.distance);
+ else
+ show("???");
}
public Distance (GridBagLayout layout, int x, int y) {
done = false;
start = true;
- if (flights.config_data.serial == 0)
+ if (flights.config_data.serial < 0)
throw new IOException("no serial number found");
/* Reset per-capture variables */
}
}
} catch (Exception e) {
- System.out.print("Show exception" + e);
+ System.out.print("Show exception " + e + "\n");
+ e.printStackTrace();
}
}
//AltosReplayReader reader;
if (file.getName().endsWith("eeprom")) {
recs = new AltosEepromIterable(in);
+ } else if (file.getName().endsWith("mega")) {
+ recs = new AltosEepromMegaIterable(in);
} else {
recs = new AltosTelemetryIterable(in);
}
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_ARCH_H_
+#define _AO_ARCH_H_
+
+#include <stdio.h>
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/sleep.h>
+
+#define F_CPU 8000000UL // 8 MHz
+
+/*
+ * AVR definitions and code fragments for AltOS
+ */
+
+#define AO_STACK_SIZE 116
+
+/* Various definitions to make GCC look more like SDCC */
+
+#define ao_arch_naked_declare __attribute__((naked))
+#define ao_arch_naked_define
+#define __pdata
+#define __data
+#define __xdata
+#define __code const
+#define __reentrant
+#define __critical
+#define __interrupt(n)
+#define __at(n)
+
+#define ao_arch_reboot() /* XXX */
+
+#define ao_arch_nop() asm("nop")
+
+#define ao_arch_interrupt(n) /* nothing */
+
+#undef putchar
+#undef getchar
+#define putchar(c) ao_putchar(c)
+#define getchar ao_getchar
+
+#define ao_arch_cpu_idle() do { \
+ sleep_enable(); \
+ sei(); \
+ sleep_cpu(); \
+ sleep_disable(); \
+ } while (0)
+
+#define ao_arch_critical(b) do { cli(); do { b } while (0); sei(); } while (0)
+
+#define ao_mutex_get(m)
+#define ao_mutex_put(m)
+
+void
+ao_delay_until(uint16_t target);
+
+/* We can't hit 100 Hz, but we can hit 125 */
+#define AO_HERTZ 125
+
+void
+ao_eeprom_read(uint16_t addr, void *buf, uint16_t len);
+
+void
+ao_eeprom_write(uint16_t addr, void *buf, uint16_t len);
+
+#endif /* _AO_ARCH_H_ */
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+/*
+ * ao_spi.c
+ */
+
+#define ao_spi_get_mask(reg,mask,bus,speed) do { \
+ (reg) &= ~(mask); \
+ } while (0)
+
+#define ao_spi_put_mask(reg,mask,bus) do { \
+ (reg) |= (mask); \
+ } while (0)
+
+#define ao_spi_get_bit(reg,bit,pin,bus,speed) do { \
+ (pin) = 0; \
+ } while (0)
+
+#define ao_spi_put_bit(reg,bit,pin,bus) do { \
+ (pin) = 1; \
+ } while (0)
+
+
+#define ao_gpio_token_paster(x,y) x ## y
+#define ao_gpio_token_evaluator(x,y) ao_gpio_token_paster(x,y)
+
+#define ao_gpio_set(port, bit, pin, v) do { \
+ if (v) \
+ PORTB |= (1 << bit); \
+ else \
+ PORTB &= ~(1 << bit); \
+ } 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
+ */
+
+#define ao_enable_output(port, bit, pin, v) do { \
+ ao_gpio_set(port, bit, pin, v); \
+ ao_gpio_token_evaluator(DDR,port) |= (1 << bit); \
+ } while (0)
+
+
+void
+ao_spi_send_bus(void __xdata *block, uint16_t len) __reentrant;
+
+void
+ao_spi_recv_bus(void __xdata *block, uint16_t len) __reentrant;
+
+#define ao_spi_send(block, len, bus) ao_spi_send_bus(block, len)
+#define ao_spi_recv(block, len, bus) ao_spi_recv_bus(block, len)
+
+void
+ao_spi_init(void);
+
+#define ao_spi_get(bus, speed)
+#define ao_spi_put(bus)
+
+#define ao_spi_init_cs(port, mask) do { \
+ PORTB |= (mask); \
+ DDRB |= (mask); \
+ } while (0)
+
+/* I2C */
+
+void
+ao_i2c_get(uint8_t i2c_index);
+
+uint8_t
+ao_i2c_start_bus(uint8_t address);
+
+#define ao_i2c_start(i,a) ao_i2c_start_bus(a)
+
+void
+ao_i2c_put(uint8_t i2c_index);
+
+uint8_t
+ao_i2c_send_bus(void *block, uint16_t len, uint8_t stop);
+
+#define ao_i2c_send(b,l,i,s) ao_i2c_send_bus(b,l.s)
+
+uint8_t
+ao_i2c_send_fixed_bus(uint8_t value, uint16_t len, uint8_t stop);
+
+#define ao_i2c_send_fixed(v,l,i,s) ao_i2c_send_fixed_bus(v,l.s)
+
+uint8_t
+ao_i2c_recv_bus(void *block, uint16_t len, uint8_t stop);
+
+#define ao_i2c_recv(b,l,i,s) ao_i2c_recv_bus(b,l.s)
+
+void
+ao_i2c_init(void);
+
+/* notask.c */
+
+uint8_t
+ao_sleep(__xdata void *wchan);
+
+void
+ao_wakeup(__xdata void *wchan);
+
+extern alt_t ao_max_height;
+
+extern void ao_report_altitude(void);
+
+void ao_delay_us(uint16_t us);
+
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+volatile AO_TICK_TYPE ao_tick_count;
+static volatile AO_TICK_TYPE ao_wakeup_count;
+
+ISR(TIMER1_COMPA_vect)
+{
+ PORTB ^= 2;
+ ++ao_tick_count;
+ if ((int16_t) (ao_tick_count - ao_wakeup_count) >= 0)
+ ao_wakeup((void *) &ao_tick_count);
+}
+
+uint16_t
+ao_time(void)
+{
+ uint16_t r;
+
+ cli();
+ r = ao_tick_count;
+ sei();
+ return r;
+}
+
+void
+ao_timer_init(void)
+{
+ cli();
+ CLKPR = (1 << CLKPCE);
+ CLKPR = 0;
+ sei();
+
+ /* Overall division ratio is 512 * 125,
+ * so our 8MHz base clock ends up as a 125Hz
+ * clock
+ */
+ TCCR1 = ((1 << CTC1) | /* Clear timer on match */
+ (0 << PWM1A) | /* Not PWM mode */
+ (0 << COM1A0) | /* Don't change output pins */
+ (0 << COM1A1) | /* ... */
+ (1 << CS13) | /* Prescale by 512 */
+ (0 << CS12) | /* ... */
+ (1 << CS11) | /* ... */
+ (0 << CS10)); /* ... */
+ GTCCR = ((0 << PWM1B) | /* Not PWM mode */
+ (0 << COM1B1) | /* Don't change output pins */
+ (0 << COM1B0) | /* ... */
+ (0 << FOC1B) | /* Don't force output compare */
+ (0 << FOC1A) | /* ... */
+ (0 << PSR1)); /* Don't bother to reset scaler */
+
+ OCR1A = 0;
+ OCR1B = 0;
+ OCR1C = 124; /* Divide by as many 5s as we can (5^3 = 125) */
+
+ TIMSK = ((1 << OCIE1A) | /* Enable TIMER1_COMPA interrupt */
+ (0 << OCIE1B) | /* Disable TIMER1_COMPB interrupt */
+ (0 << TOIE1)); /* Disable TIMER1_OVF interrupt */
+ DDRB |= 2;
+}
+
+#define PER_LOOP 8
+#define US_LOOPS ((AVR_CLOCK / 1000000) / PER_LOOP)
+
+void ao_delay_us(uint16_t us)
+{
+#if US_LOOPS > 1
+ us *= US_LOOPS;
+#endif
+ for (;;) {
+ ao_arch_nop();
+ ao_arch_nop();
+ ao_arch_nop();
+ --us;
+ /* A bit funky to keep the optimizer
+ * from short-circuiting the test */
+ if (!((uint8_t) (us | (us >> 8))))
+ break;
+ }
+}
+
+void
+ao_delay_until(uint16_t target)
+{
+ cli();
+ ao_wakeup_count = target;
+ while ((int16_t) (target - ao_tick_count) > 0)
+ ao_sleep((void *) &ao_tick_count);
+ sei();
+}
+
+void
+ao_delay(uint16_t ticks)
+{
+ ao_delay_until(ao_time() + ticks);
+}
+
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+static void
+ao_eeprom_wait(void)
+{
+ /* Wait for previous write to complete */
+ while (EECR & (1 << EEPE))
+ ;
+}
+
+static uint8_t
+ao_eeprom_read_byte(uint16_t addr)
+{
+ uint8_t v;
+
+ ao_eeprom_wait();
+ EEAR = addr;
+ cli();
+ EECR |= (1 << EERE);
+ v = EEDR;
+ sei();
+ return v;
+}
+
+static void
+ao_eeprom_write_byte(uint16_t addr, uint8_t v)
+{
+ ao_eeprom_wait();
+ EECR = (0 << EEPM1) | (0 << EEPM0);
+ EEAR = addr;
+ EEDR = v;
+ cli();
+ EECR |= (1 << EEMPE);
+ EECR |= (1 << EEPE);
+ sei();
+}
+
+void
+ao_eeprom_read(uint16_t addr, void *buf, uint16_t len)
+{
+ uint8_t *b = buf;
+
+ while (len--)
+ *b++ = ao_eeprom_read_byte(addr++);
+}
+
+void
+ao_eeprom_write(uint16_t addr, void *buf, uint16_t len)
+{
+ uint8_t *b = buf;
+
+ while (len--)
+ ao_eeprom_write_byte(addr++, *b++);
+}
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_exti.h>
+
+static void (*pcint_callback)(void);
+static uint8_t pcint_mask;
+
+ISR(PCINT0_vect)
+{
+ if (PINB & pcint_mask)
+ (*pcint_callback)();
+}
+
+void
+ao_exti_setup_port(uint8_t pin, uint8_t mode, void (*callback)(void))
+{
+ pcint_callback = callback;
+ pcint_mask = (1 << pin);
+ ao_exti_disable(PORTB, pin);
+ GIMSK |= (1 << PCIE);
+}
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_EXTI_H_
+#define _AO_EXTI_H_
+
+void
+ao_exti_setup_port(uint8_t pin, uint8_t mode, void (*callback)(void));
+
+#define ao_exti_setup(port, pin, mode, callback) ao_exti_setup_port(pin, mode, callback)
+
+#define ao_exti_enable(gpio, pin) (PCMSK |= (1 << (pin)))
+
+#define ao_exti_disable(gpio, pin) (PCMSK &= ~(1 << (pin)))
+
+#define ao_exti_init()
+
+#define AO_EXTI_MODE_RISING 1
+
+#endif /* _AO_EXTI_H_ */
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+/*
+ * ATtiny USI as an I2C interface
+ */
+
+#define I2C_USICR ((0 << USISIE) | /* No start condition interrupt */ \
+ (0 << USIOIE) | /* No counter overflow interrupt */ \
+ (1 << USIWM1) | /* Two-wire mode */ \
+ (0 << USIWM0) | /* ... */ \
+ (1 << USICS1) | /* Software clock strobe */ \
+ (0 << USICS0) | /* ... */ \
+ (1 << USICLK)) /* ... */ \
+
+#define I2C_USICR_TICK (I2C_USICR | (1 << USITC)) /* Toggle the clock on every write */
+
+#define I2C_USISR_1BIT ((1<<USISIF)| /* Clear start condition flag */ \
+ (1<<USIOIF)| /* Clear overflow flag */ \
+ (1<<USIPF)| /* Clear stop condition flag */ \
+ (1<<USIDC)| /* Clear data collision flag */ \
+ (0xE<<USICNT0)) /* Set counter value to 0xe */
+
+#define I2C_USISR_8BIT ((1<<USISIF)| /* Clear start condition flag */ \
+ (1<<USIOIF)| /* Clear overflow flag */ \
+ (1<<USIPF)| /* Clear stop condition flag */ \
+ (1<<USIDC)| /* Clear data collision flag */ \
+ (0x0<<USICNT0)) /* Set counter value to 0 */
+
+#define T2_TWI 5 /* >4.7μs */
+#define T4_TWI 4 /* >4.0μs */
+
+static inline void ao_i2c_transfer(uint8_t sr)
+{
+ USISR = sr;
+ for (;;) {
+ ao_delay_us(T2_TWI);
+
+ /* Clock high */
+ USICR = I2C_USICR_TICK;
+
+ /* Wait for clock high (clock stretching) */
+ ao_delay_us(T4_TWI);
+ while(!(I2C_PIN & (1<<I2C_PIN_SCL)))
+ ;
+
+ /* Clock low */
+ USICR = I2C_USICR_TICK;
+
+ /* Check for transfer complete */
+ if (USISR & (1 << USIOIF))
+ break;
+ }
+ ao_delay_us(T2_TWI);
+}
+
+static inline uint8_t ao_i2c_get_byte(uint8_t sr)
+{
+ uint8_t ret;
+
+ /* Set SDA to input */
+ I2C_DIR &= ~(1<<I2C_PIN_SDA);
+
+ ao_i2c_transfer(sr);
+
+ ret = USIDR;
+ USIDR = 0xff;
+
+ /* Set SDA to output */
+ I2C_DIR |= (1<<I2C_PIN_SDA);
+
+ return ret;
+}
+
+static uint8_t
+ao_i2c_write_byte(uint8_t byte)
+{
+ /* Pull SCL low */
+ I2C_PORT &= ~(1<<I2C_PIN_SCL);
+
+ /* Write the byte */
+ USIDR = byte;
+
+ /* Clock and verify (N)ACK from slave */
+
+ ao_i2c_transfer(I2C_USISR_8BIT);
+
+ if (ao_i2c_get_byte(I2C_USISR_1BIT) & 0x80)
+ return 0;
+
+ return 1;
+}
+
+static uint8_t
+ao_i2c_read_byte(uint8_t ack)
+{
+ uint8_t ret;
+
+ /* Read the data */
+ ret = ao_i2c_get_byte(I2C_USISR_8BIT);
+
+ /* Ack it */
+ USIDR = ack;
+ ao_i2c_transfer(I2C_USISR_8BIT);
+
+ return ret;
+}
+
+uint8_t
+ao_i2c_start_bus(uint8_t address)
+{
+ /* Release SCL to ensure that (repeated) Start can be performed */
+
+ I2C_PORT |= (1<<I2C_PIN_SCL);
+
+ while( !(I2C_PORT & (1<<I2C_PIN_SCL)) )
+ ;
+ ao_delay_us(T2_TWI);
+
+ /* Generate Start Condition */
+
+ /* Pull SDA low */
+ I2C_PORT &= ~(1<<I2C_PIN_SDA);
+ ao_delay_us(T4_TWI);
+
+ /* Pull SCL low */
+ I2C_PORT &= ~(1<<I2C_PIN_SCL);
+
+ /* Raise SDA */
+ I2C_PORT |= (1<<I2C_PIN_SDA);
+
+ return ao_i2c_write_byte(address);
+}
+
+static void
+ao_i2c_stop_bus(void)
+{
+ /* Pull SDA low. */
+ I2C_PORT &= ~(1<<I2C_PIN_SDA);
+
+ /* Release SCL. */
+ I2C_PORT |= (1<<I2C_PIN_SCL);
+
+ /* Wait for SCL to go high */
+ while( !(I2C_PIN & (1<<I2C_PIN_SCL)) );
+ ao_delay_us(T4_TWI);
+
+ /* Raise SDA */
+ I2C_PORT |= (1<<I2C_PIN_SDA);
+ ao_delay_us(T2_TWI);
+}
+
+/* Send bytes over SPI.
+ *
+ * This just polls; the SPI is set to go as fast as possible,
+ * so using interrupts would take way too long
+ */
+uint8_t
+ao_i2c_send_bus(void __xdata *block, uint16_t len, uint8_t stop)
+{
+ uint8_t *d = block;
+
+ while (len--)
+ if (!ao_i2c_write_byte (*d++))
+ return 0;
+ if (stop)
+ ao_i2c_stop_bus();
+ return 1;
+}
+
+/* Send bytes over SPI.
+ *
+ * This just polls; the SPI is set to go as fast as possible,
+ * so using interrupts would take way too long
+ */
+uint8_t
+ao_i2c_send_fixed_bus(uint8_t d, uint16_t len, uint8_t stop)
+{
+ while (len--)
+ if (!ao_i2c_write_byte (d))
+ return 0;
+ if (stop)
+ ao_i2c_stop_bus();
+ return 1;
+}
+
+/* Receive bytes over SPI.
+ *
+ * Poll, sending zeros and reading data back
+ */
+uint8_t
+ao_i2c_recv_bus(void __xdata *block, uint16_t len, uint8_t stop)
+{
+ uint8_t *d = block;
+
+ while (len--)
+ *d++ = ao_i2c_read_byte (len ? 0x00 : 0xff);
+ if (stop)
+ ao_i2c_stop_bus();
+ return 1;
+}
+
+/*
+ * Initialize USI
+ *
+ * Chip select is the responsibility of the caller
+ */
+
+void
+ao_i2c_init(void)
+{
+ /* Pull-ups on SDA and SCL */
+ I2C_PORT |= (1<<I2C_PIN_SDA);
+ I2C_PORT |= (1<<I2C_PIN_SCL);
+
+ /* SCL and SDA are outputs */
+ I2C_DIR |= (1<<I2C_PIN_SCL);
+ I2C_DIR |= (1<<I2C_PIN_SDA);
+
+ USIDR = 0xFF;
+ USICR = I2C_USICR;
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+__pdata uint8_t ao_led_enable;
+
+#define LED_PORT PORTB
+#define LED_DDR DDRB
+
+void
+ao_led_on(uint8_t colors)
+{
+ LED_PORT |= (colors & ao_led_enable);
+}
+
+void
+ao_led_off(uint8_t colors)
+{
+ LED_PORT &= ~(colors & ao_led_enable);
+}
+
+void
+ao_led_set(uint8_t colors)
+{
+ LED_PORT = (LED_PORT & ~(ao_led_enable)) | (colors & ao_led_enable);
+}
+
+void
+ao_led_toggle(uint8_t colors)
+{
+ LED_PORT ^= (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;
+ LED_PORT &= ~enable;
+ LED_DDR |= enable;
+}
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+/*
+ * ATtiny USI as a SPI interface
+ */
+
+/*
+ * Transfer one byte in/out of the USI interface
+ */
+
+/* Three wire mode */
+#define SPI_USICR_WM ((0 << USIWM1) | (1 << USIWM0))
+#define SPI_USICR_CS ((1 << USICS1) | (0 << USICS0) | (1 << USICLK))
+
+#define SPI_USICR_FAST_2 ((1 << USIWM0) | (1 << USITC))
+#define SPI_USICR_FAST_1 ((1 << USIWM0) | (1 << USITC) | (1 << USICLK))
+
+
+static uint8_t
+ao_spi_transfer(uint8_t i)
+{
+ /* Load data register */
+ USIDR = i;
+
+#if 1
+ USISR = (1 << USIOIF);
+ do {
+ USICR = SPI_USICR_WM | SPI_USICR_CS | (1 << USITC);
+ } while ((USISR & (1 << USIOIF)) == 0);
+#else
+ /* 8 clocks */
+ USICR = SPI_USICR_FAST_1;
+ USICR = SPI_USICR_FAST_2;
+
+ USICR = SPI_USICR_FAST_1;
+ USICR = SPI_USICR_FAST_2;
+
+ USICR = SPI_USICR_FAST_1;
+ USICR = SPI_USICR_FAST_2;
+
+ USICR = SPI_USICR_FAST_1;
+ USICR = SPI_USICR_FAST_2;
+
+ USICR = SPI_USICR_FAST_1;
+ USICR = SPI_USICR_FAST_2;
+
+ USICR = SPI_USICR_FAST_1;
+ USICR = SPI_USICR_FAST_2;
+
+ USICR = SPI_USICR_FAST_1;
+ USICR = SPI_USICR_FAST_2;
+
+ USICR = SPI_USICR_FAST_1;
+ USICR = SPI_USICR_FAST_2;
+#endif
+
+ /* Pull data from the port */
+ return USIDR;
+}
+
+/* Send bytes over SPI.
+ *
+ * This just polls; the SPI is set to go as fast as possible,
+ * so using interrupts would take way too long
+ */
+void
+ao_spi_send_bus(void __xdata *block, uint16_t len) __reentrant
+{
+ uint8_t *d = block;
+
+ while (len--)
+ ao_spi_transfer (*d++);
+}
+
+/* Receive bytes over SPI.
+ *
+ * Poll, sending zeros and reading data back
+ */
+void
+ao_spi_recv_bus(void __xdata *block, uint16_t len) __reentrant
+{
+ uint8_t *d = block;
+
+ while (len--)
+ *d++ = ao_spi_transfer (0xff);
+}
+
+/*
+ * Initialize USI
+ *
+ * Chip select is the responsibility of the caller
+ */
+
+void
+ao_spi_init(void)
+{
+#if 1
+ USICR = (1 << USIWM0) | (1 << USICS1) | (1 << USICLK);
+#else
+ USICR = SPI_USICR_FAST_2;
+#endif
+ SPI_DIR &= ~(1 << DDB0); /* DI */
+ SPI_DIR |= (1 << DDB1); /* DO */
+ SPI_DIR |= (1 << DDB2); /* SCLK */
+ SPI_DIR |= (1 << DDB3); /* CS */
+}
static uint8_t ao_spi_slave_running;
-ISR(PCINT0_vect)
+ISR(PCINT0_vect, ISR_BLOCK)
{
- cli();
#if SPI_SLAVE_PIN_0_3
if ((PINB & (1 << PORTB0)) == 0)
#endif
} else {
ao_spi_slave_running = 0;
}
- sei();
}
void
volatile __xdata struct ao_data ao_data_ring[AO_DATA_RING];
volatile __data uint8_t ao_data_head;
+#ifndef AO_ADC_FIRST_PIN
+#define AO_ADC_FIRST_PIN 0
+#endif
+
void
ao_adc_poll(void)
{
# ifdef TELENANO_V_0_1
ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 1;
# else
- ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 0;
+ ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | AO_ADC_FIRST_PIN;
# endif
#endif
}
#endif /* telemini || telenano */
#ifdef TELEFIRE_V_0_1
- a = (uint8_t __xdata *) (&ao_data_ring[ao_data_head].adc.sense[0] + sequence);
+ a = (uint8_t __xdata *) (&ao_data_ring[ao_data_head].adc.sense[0] + sequence - AO_ADC_FIRST_PIN);
a[0] = ADCL;
a[1] = ADCH;
if (sequence < 5)
#define CODE_TO_XDATA(a) (a)
#endif
-/* An AltOS task */
-struct ao_task {
- __xdata void *wchan; /* current wait channel (NULL if running) */
- uint16_t alarm; /* abort ao_sleep time */
- ao_arch_task_members /* any architecture-specific fields */
- 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);
-
-/* Clear any pending alarm */
-void
-ao_clear_alarm(void);
-
-/* Yield the processor to another task */
-void
-ao_yield(void) ao_arch_naked_declare;
-
-/* 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);
+#ifndef HAS_TASK
+#define HAS_TASK 1
+#endif
-/* Start the scheduler. This will not return */
-void
-ao_start_scheduler(void);
+#if HAS_TASK
+#include <ao_task.h>
+#endif
/*
* ao_panic.c
extern volatile __data AO_TICK_TYPE ao_tick_count;
/* Our timer runs at 100Hz */
+#ifndef AO_HERTZ
#define AO_HERTZ 100
+#endif
#define AO_MS_TO_TICKS(ms) ((ms) / (1000 / AO_HERTZ))
#define AO_SEC_TO_TICKS(s) ((s) * AO_HERTZ)
* ao_mutex.c
*/
+#ifndef ao_mutex_get
void
ao_mutex_get(__xdata uint8_t *ao_mutex) __reentrant;
void
ao_mutex_put(__xdata uint8_t *ao_mutex) __reentrant;
+#endif
/*
* ao_cmd.c
* Convert between pressure in Pa and altitude in meters
*/
-int32_t
+#include <ao_data.h>
+
+alt_t
ao_pa_to_altitude(int32_t pa);
int32_t
-ao_altitude_to_pa(int32_t alt);
+ao_altitude_to_pa(alt_t alt);
#if HAS_DBG
#include <ao_dbg.h>
ao_xmemset(&ao_config.callsign, '\0', sizeof (ao_config.callsign));
ao_xmemcpy(&ao_config.callsign, CODE_TO_XDATA(AO_CONFIG_DEFAULT_CALLSIGN),
sizeof(AO_CONFIG_DEFAULT_CALLSIGN) - 1);
+ ao_config._legacy_radio_channel = 0;
}
minor = ao_config.minor;
if (minor != AO_CONFIG_MINOR) {
if (minor < 9)
ao_xmemset(&ao_config.aes_key, '\0', AO_AES_LEN);
if (minor < 10)
- ao_config.frequency = 434550;
+ ao_config.frequency = 434550 + ao_config._legacy_radio_channel * 100;
if (minor < 11)
ao_config.apogee_lockout = 0;
#if AO_PYRO_NUM
#include "ao.h"
#endif
-static const int32_t altitude_table[] = {
+#ifndef AO_CONST_ATTRIB
+#define AO_CONST_ATTRIB
+#endif
+
+static const alt_t altitude_table[] AO_CONST_ATTRIB = {
#include "altitude-pa.h"
};
+#ifndef FETCH_ALT
+#define FETCH_ALT(o) altitude_table[o]
+#endif
+
#define ALT_SCALE (1 << ALT_SHIFT)
#define ALT_MASK (ALT_SCALE - 1)
-int32_t
+alt_t
ao_pa_to_altitude(int32_t pa)
{
int16_t o;
o = pa >> ALT_SHIFT;
part = pa & ALT_MASK;
- low = (int32_t) altitude_table[o] * (ALT_SCALE - part);
- high = (int32_t) altitude_table[o+1] * part + (ALT_SCALE >> 1);
+ low = (alt_t) FETCH_ALT(o) * (ALT_SCALE - part);
+ high = (alt_t) FETCH_ALT(o+1) * part + (ALT_SCALE >> 1);
return (low + high) >> ALT_SHIFT;
}
+#ifdef AO_CONVERT_TEST
int32_t
ao_altitude_to_pa(int32_t alt)
{
pa = 0;
return pa;
}
+#endif
#include <stdint.h>
#define AO_CONVERT_TEST
+typedef int32_t alt_t;
#include "ao_host.h"
#include "ao_convert_pa.c"
#define STEP_P 1
#define STEP_A 1
-static inline i_abs(int i) { return i < 0 ? -i : i; }
+static inline int i_abs(int i) { return i < 0 ? -i : i; }
-main ()
+int
+main (int argc, char **argv)
{
int i;
int32_t p_to_a, p_to_a_to_p;
// printf ("pa %d alt %d pa %d\n",
// i, p_to_a, p_to_a_to_p);
}
- for (i = -1450; i < 74250 + STEP_A; i += STEP_A) {
- if (i > 74250)
- i = 74250;
+ for (i = -1450; i < 40000 + STEP_A; i += STEP_A) {
a_to_p = ao_altitude_to_pa(i);
a_to_p_to_a = ao_pa_to_altitude(a_to_p);
a_error = i_abs(a_to_p_to_a - i);
#define AO_DATA_MMA655X 0
#endif
+#ifdef AO_DATA_RING
+
#define AO_DATA_ALL (AO_DATA_ADC|AO_DATA_MS5607|AO_DATA_MPU6000|AO_DATA_HMC5883|AO_DATA_MMA655X)
struct ao_data {
#endif
#if HAS_MPU6000
struct ao_mpu6000_sample mpu6000;
+#if !HAS_MMA655X
+ int16_t z_accel;
+#endif
#endif
#if HAS_HMC5883
struct ao_hmc5883_sample hmc5883;
ao_sleep((void *) &ao_data_count); \
} while (0)
+#endif /* AO_DATA_RING */
+
#if !HAS_BARO && HAS_MS5607
/* Either an MS5607 or an MS5611 hooked to a SPI port
#define HAS_BARO 1
typedef int32_t pres_t;
-typedef int32_t alt_t;
+
+#ifndef AO_ALT_TYPE
+#define AO_ALT_TYPE int32_t
+#endif
+
+typedef AO_ALT_TYPE alt_t;
#define ao_data_pres_cook(packet) ao_ms5607_convert(&packet->ms5607_raw, &packet->ms5607_cooked)
#endif
+#if !HAS_BARO
+typedef int16_t alt_t;
+#endif
+
/*
* Need a few macros to pull data from the sensors:
*
typedef int16_t accel_t;
/* MPU6000 is hooked up so that positive y is positive acceleration */
-#define ao_data_accel(packet) ((packet)->mpu6000.accel_y)
+#define ao_data_accel(packet) ((packet)->z_accel)
#define ao_data_accel_cook(packet) (-(packet)->mpu6000.accel_y)
-#define ao_data_set_accel(packet, accel) ((packet)->mpu6000.accel_y = (accel))
+#define ao_data_set_accel(packet, accel) ((packet)->z_accel = (accel))
#define ao_data_accel_invert(a) (-(a))
#endif
#define AO_LOG_POS_NONE (~0UL)
struct ao_log_record {
- char type;
- uint8_t csum;
- uint16_t tick;
+ char type; /* 0 */
+ uint8_t csum; /* 1 */
+ uint16_t tick; /* 2 */
union {
struct {
- int16_t ground_accel;
- uint16_t flight;
+ int16_t ground_accel; /* 4 */
+ uint16_t flight; /* 6 */
} flight;
struct {
- int16_t accel;
- int16_t pres;
+ int16_t accel; /* 4 */
+ int16_t pres; /* 6 */
} sensor;
struct {
int16_t temp;
uint16_t flight; /* 4 */
int16_t ground_accel; /* 6 */
uint32_t ground_pres; /* 8 */
- uint32_t ground_temp; /* 12 */
- } flight; /* 16 */
+ } flight; /* 12 */
struct {
uint16_t state;
uint16_t reason;
#define ao_led_off(x)
#endif
+#ifndef AO_LED_PANIC
+#define AO_LED_PANIC AO_LED_RED
+#endif
+
static void
ao_panic_delay(uint8_t n)
{
__critical for (;;) {
ao_panic_delay(20);
for (n = 0; n < 5; n++) {
- ao_led_on(AO_LED_RED);
+ ao_led_on(AO_LED_PANIC);
ao_beep(AO_BEEP_HIGH);
ao_panic_delay(1);
- ao_led_off(AO_LED_RED);
+ ao_led_off(AO_LED_PANIC);
ao_beep(AO_BEEP_LOW);
ao_panic_delay(1);
}
#pragma disable_warning 126
#endif
if (reason & 0x40) {
- ao_led_on(AO_LED_RED);
+ ao_led_on(AO_LED_PANIC);
ao_beep(AO_BEEP_HIGH);
ao_panic_delay(40);
- ao_led_off(AO_LED_RED);
+ ao_led_off(AO_LED_PANIC);
ao_beep(AO_BEEP_OFF);
ao_panic_delay(10);
}
for (n = 0; n < (reason & 0x3f); n++) {
- ao_led_on(AO_LED_RED);
+ ao_led_on(AO_LED_PANIC);
ao_beep(AO_BEEP_MID);
ao_panic_delay(10);
- ao_led_off(AO_LED_RED);
+ ao_led_off(AO_LED_PANIC);
ao_beep(AO_BEEP_OFF);
ao_panic_delay(10);
}
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_TASK_H_
+#define _AO_TASK_H_
+
+/* An AltOS task */
+struct ao_task {
+ __xdata void *wchan; /* current wait channel (NULL if running) */
+ uint16_t alarm; /* abort ao_sleep time */
+ ao_arch_task_members /* any architecture-specific fields */
+ 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);
+
+/* Clear any pending alarm */
+void
+ao_clear_alarm(void);
+
+/* Yield the processor to another task */
+void
+ao_yield(void) ao_arch_naked_declare;
+
+/* 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);
+
+#endif
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+#if HAS_EEPROM
+#define AO_AT24C_ADDR 0xa0
+#define AO_AT24C_ADDR_WRITE (AO_AT24C_ADDR|0)
+#define AO_AT24C_ADDR_READ (AO_AT24C_ADDR|1)
+#define AO_AT24C_PAGE_LEN 128
+
+/* Total bytes of available storage */
+__pdata ao_pos_t ao_storage_total = 64l * 1024l;
+
+/* Storage unit size - device reads and writes must be within blocks of this size. */
+__pdata uint16_t ao_storage_unit = 128;
+
+static void
+ao_at24c_set_address(uint8_t addr, ao_pos_t pos)
+{
+ uint8_t a[2];
+
+ a[0] = pos >> 8;
+ a[1] = pos;
+ ao_i2c_start_bus(addr);
+ ao_i2c_send_bus(a, 2, 0);
+}
+
+/*
+ * Erase the specified sector
+ */
+uint8_t
+ao_storage_erase(ao_pos_t pos) __reentrant
+{
+ if (pos >= ao_storage_total || pos + AO_AT24C_PAGE_LEN > ao_storage_total)
+ return 0;
+
+ ao_mutex_get(&ao_at24c_mutex);
+ ao_at24c_set_address(AO_AT24C_ADDR_WRITE, pos);
+ ao_i2c_send_fixed_bus(0xff, AO_AT24C_PAGE_LEN, 1);
+ ao_mutex_put(&ao_at24c_mutex);
+ return 1;
+}
+
+/*
+ * Write to flash
+ */
+uint8_t
+ao_storage_device_write(ao_pos_t pos, __xdata void *d, uint16_t len) __reentrant
+{
+ if (pos >= ao_storage_total || pos + len > ao_storage_total)
+ return 0;
+
+ ao_mutex_get(&ao_m25_mutex);
+ ao_at24c_set_address(AO_AT24C_ADDR_WRITE, pos);
+ ao_i2c_send_bus(d, len, 1);
+ ao_mutex_put(&ao_m25_mutex);
+ return 1;
+}
+
+/*
+ * Read from flash
+ */
+uint8_t
+ao_storage_device_read(ao_pos_t pos, __xdata void *d, uint16_t len) __reentrant
+{
+ if (pos >= ao_storage_total || pos + len > ao_storage_total)
+ return 0;
+ ao_mutex_get(&ao_m25_mutex);
+ ao_at24c_set_address(AO_AT24C_ADDR_READ, pos);
+ ao_i2c_recv_bus(d, len, 1);
+ ao_mutex_put(&ao_m25_mutex);
+ return 1;
+}
+
+void
+ao_storage_flush(void) __reentrant
+{
+}
+
+void
+ao_storage_setup(void)
+{
+}
+
+void
+ao_storage_device_init(void)
+{
+}
+#endif
/* Self test gyro is approximately 50°/s */
#define MPU6000_ST_GYRO(full_scale) ((int16_t) (((int32_t) 32767 * (int32_t) 50) / (full_scale)))
+#define MPU6000_GYRO_FULLSCALE 2000
+#define MPU6000_ACCEL_FULLSCALE 16
+
struct ao_mpu6000_sample {
int16_t accel_x;
int16_t accel_y;
#include <ao.h>
#include <ao_exti.h>
-#include "ao_ms5607.h"
+#include <ao_ms5607.h>
#if HAS_MS5607 || HAS_MS5611
static void
ao_ms5607_start(void) {
ao_spi_get(AO_MS5607_SPI_INDEX,AO_SPI_SPEED_FAST);
- stm_gpio_set(AO_MS5607_CS_PORT, AO_MS5607_CS_PIN, 0);
+ ao_gpio_set(AO_MS5607_CS_PORT, AO_MS5607_CS_PIN, AO_MS5607_CS, 0);
}
static void
ao_ms5607_stop(void) {
- stm_gpio_set(AO_MS5607_CS_PORT, AO_MS5607_CS_PIN, 1);
+ ao_gpio_set(AO_MS5607_CS_PORT, AO_MS5607_CS_PIN, AO_MS5607_CS, 1);
ao_spi_put(AO_MS5607_SPI_INDEX);
}
uint8_t crc_byte = prom[15];
uint8_t cnt;
uint16_t n_rem = 0;
- uint16_t crc_read;
uint8_t n_bit;
prom[15] = 0;
}
crc = ao_ms5607_crc((uint8_t *) prom);
if (crc != (((uint8_t *) prom)[15] & 0xf)) {
+#if HAS_TASK
printf ("MS5607 PROM CRC error (computed %x actual %x)\n",
crc, (((uint8_t *) prom)[15] & 0xf));
flush();
+#endif
ao_panic(AO_PANIC_SELF_TEST_MS5607);
}
#endif
}
-static void
+void
ao_ms5607_setup(void)
{
if (ms5607_configured)
ao_ms5607_prom_read(&ms5607_prom);
}
-static uint8_t ao_ms5607_done;
+static volatile uint8_t ao_ms5607_done;
static void
ao_ms5607_isr(void)
{
ao_exti_disable(AO_MS5607_MISO_PORT, AO_MS5607_MISO_PIN);
ao_ms5607_done = 1;
- ao_wakeup(&ao_ms5607_done);
+ ao_wakeup((void *) &ao_ms5607_done);
}
static uint32_t
ao_ms5607_get_sample(uint8_t cmd) {
uint8_t reply[3];
uint8_t read;
- uint16_t now;
ao_ms5607_done = 0;
ao_ms5607_start();
ao_spi_send(&cmd, 1, AO_MS5607_SPI_INDEX);
+
ao_exti_enable(AO_MS5607_MISO_PORT, AO_MS5607_MISO_PIN);
+
#if AO_MS5607_PRIVATE_PINS
ao_spi_put(AO_MS5607_SPI_INDEX);
#endif
cli();
while (!ao_ms5607_done)
- ao_sleep(&ao_ms5607_done);
+ ao_sleep((void *) &ao_ms5607_done);
sei();
#if AO_MS5607_PRIVATE_PINS
stm_gpio_set(AO_MS5607_CS_PORT, AO_MS5607_CS_PIN, 1);
sample->temp = ao_ms5607_get_sample(AO_MS5607_CONVERT_D2_2048);
}
-void
-ao_ms5607_convert(struct ao_ms5607_sample *sample, struct ao_ms5607_value *value)
-{
- uint8_t addr;
- int32_t dT;
- int32_t TEMP;
- int64_t OFF;
- int64_t SENS;
- int32_t P;
-
- dT = sample->temp - ((int32_t) ms5607_prom.tref << 8);
-
- TEMP = 2000 + (((int64_t) dT * ms5607_prom.tempsens) >> 23);
-
-#if HAS_MS5611
- OFF = ((int64_t) ms5607_prom.off << 16) + (((int64_t) ms5607_prom.tco * dT) >> 7);
- SENS = ((int64_t) ms5607_prom.sens << 15) + (((int64_t) ms5607_prom.tcs * dT) >> 8);
-#else
- OFF = ((int64_t) ms5607_prom.off << 17) + (((int64_t) ms5607_prom.tco * dT) >> 6);
- SENS = ((int64_t) ms5607_prom.sens << 16) + (((int64_t) ms5607_prom.tcs * dT) >> 7);
-#endif
-
- if (TEMP < 2000) {
- int32_t T2 = ((int64_t) dT * (int64_t) dT) >> 31;
- int32_t TEMPM = TEMP - 2000;
- int64_t OFF2 = (61 * (int64_t) TEMPM * (int64_t) TEMPM) >> 4;
- int64_t SENS2 = 2 * (int64_t) TEMPM * (int64_t) TEMPM;
- if (TEMP < 1500) {
- int32_t TEMPP = TEMP + 1500;
- int64_t TEMPP2 = TEMPP * TEMPP;
- OFF2 = OFF2 + 15 * TEMPP2;
- SENS2 = SENS2 + 8 * TEMPP2;
- }
- TEMP -= T2;
- OFF -= OFF2;
- SENS -= SENS2;
- }
-
- value->pres = ((((int64_t) sample->pres * SENS) >> 21) - OFF) >> 15;
- value->temp = TEMP;
-}
+#include "ao_ms5607_convert.c"
+#if HAS_TASK
struct ao_ms5607_sample ao_ms5607_current;
static void
{ ao_ms5607_dump, "B\0Display MS5607 data" },
{ 0, NULL },
};
+#endif /* HAS_TASK */
void
ao_ms5607_init(void)
{
ms5607_configured = 0;
- ao_cmd_register(&ao_ms5607_cmds[0]);
ao_spi_init_cs(AO_MS5607_CS_PORT, (1 << AO_MS5607_CS_PIN));
+#if HAS_TASK
+ ao_cmd_register(&ao_ms5607_cmds[0]);
ao_add_task(&ao_ms5607_task, ao_ms5607, "ms5607");
+#endif
/* Configure the MISO pin as an interrupt; when the
* conversion is complete, the MS5607 will raise this
AO_EXTI_MODE_RISING,
ao_ms5607_isr);
+#ifdef STM_MODER_ALTERNATE
/* Reset the pin from INPUT to ALTERNATE so that SPI works
* This needs an abstraction at some point...
*/
stm_moder_set(AO_MS5607_MISO_PORT,
AO_MS5607_MISO_PIN,
STM_MODER_ALTERNATE);
+#endif
}
#endif
extern struct ao_ms5607_sample ao_ms5607_current;
+void
+ao_ms5607_setup(void);
+
void
ao_ms5607_init(void);
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao_ms5607.h>
+
+void
+ao_ms5607_convert(struct ao_ms5607_sample *sample, struct ao_ms5607_value *value)
+{
+ int32_t dT;
+ int32_t TEMP;
+ int64_t OFF;
+ int64_t SENS;
+
+ dT = sample->temp - ((int32_t) ms5607_prom.tref << 8);
+
+ TEMP = 2000 + (((int64_t) dT * ms5607_prom.tempsens) >> 23);
+
+#if HAS_MS5611
+ OFF = ((int64_t) ms5607_prom.off << 16) + (((int64_t) ms5607_prom.tco * dT) >> 7);
+ SENS = ((int64_t) ms5607_prom.sens << 15) + (((int64_t) ms5607_prom.tcs * dT) >> 8);
+#else
+ OFF = ((int64_t) ms5607_prom.off << 17) + (((int64_t) ms5607_prom.tco * dT) >> 6);
+ SENS = ((int64_t) ms5607_prom.sens << 16) + (((int64_t) ms5607_prom.tcs * dT) >> 7);
+#endif
+
+ if (TEMP < 2000) {
+ int32_t T2 = ((int64_t) dT * (int64_t) dT) >> 31;
+ int32_t TEMPM = TEMP - 2000;
+ int64_t OFF2 = (61 * (int64_t) TEMPM * (int64_t) TEMPM) >> 4;
+ int64_t SENS2 = 2 * (int64_t) TEMPM * (int64_t) TEMPM;
+ if (TEMP < 1500) {
+ int32_t TEMPP = TEMP + 1500;
+ int64_t TEMPP2 = TEMPP * TEMPP;
+ OFF2 = OFF2 + 15 * TEMPP2;
+ SENS2 = SENS2 + 8 * TEMPP2;
+ }
+ TEMP -= T2;
+ OFF -= OFF2;
+ SENS -= SENS2;
+ }
+
+ value->pres = ((((int64_t) sample->pres * SENS) >> 21) - OFF) >> 15;
+ value->temp = TEMP;
+}
#define FLUSHD()
#endif
+static void
+ao_siren(uint8_t v)
+{
+#ifdef AO_SIREN
+ ao_gpio_set(AO_SIREN_PORT, AO_SIREN_PIN, AO_SIREN, v);
+#else
+ ao_beep(v ? AO_BEEP_MID : 0);
+#endif
+}
+
+static void
+ao_strobe(uint8_t v)
+{
+#ifdef AO_STROBE
+ ao_gpio_set(AO_STROBE_PORT, AO_STROBE_PIN, AO_STROBE, v);
+#endif
+}
+
static void
ao_pad_run(void)
{
+ uint8_t pins;
+
for (;;) {
while (!ao_pad_ignite)
ao_sleep(&ao_pad_ignite);
/*
* Actually set the pad bits
*/
- AO_PAD_PORT = (AO_PAD_PORT & (~AO_PAD_ALL_PINS)) | ao_pad_ignite;
+ pins = 0;
+#if AO_PAD_NUM > 0
+ if (ao_pad_ignite & (1 << 0))
+ pins |= (1 << AO_PAD_PIN_0);
+#endif
+#if AO_PAD_NUM > 1
+ if (ao_pad_ignite & (1 << 1))
+ pins |= (1 << AO_PAD_PIN_1);
+#endif
+#if AO_PAD_NUM > 2
+ if (ao_pad_ignite & (1 << 2))
+ pins |= (1 << AO_PAD_PIN_2);
+#endif
+#if AO_PAD_NUM > 3
+ if (ao_pad_ignite & (1 << 3))
+ pins |= (1 << AO_PAD_PIN_3);
+#endif
+ AO_PAD_PORT = (AO_PAD_PORT & (~AO_PAD_ALL_PINS)) | pins;
while (ao_pad_ignite) {
ao_pad_ignite = 0;
+
ao_delay(AO_PAD_FIRE_TIME);
}
AO_PAD_PORT &= ~(AO_PAD_ALL_PINS);
}
}
-#define AO_PAD_ARM_BEEP_INTERVAL 200
+#define AO_PAD_ARM_SIREN_INTERVAL 200
static void
ao_pad_monitor(void)
prev = cur;
}
+ if (ao_pad_armed && (int16_t) (ao_time() - ao_pad_arm_time) > AO_PAD_ARM_TIME)
+ ao_pad_armed = 0;
+
if (ao_pad_armed) {
+ ao_strobe(1);
if (sample & 2)
- ao_beep(AO_BEEP_HIGH);
+ ao_siren(1);
else
- ao_beep(AO_BEEP_LOW);
+ ao_siren(0);
beeping = 1;
} else if (query.arm_status == AO_PAD_ARM_STATUS_ARMED && !beeping) {
if (arm_beep_time == 0) {
- arm_beep_time = AO_PAD_ARM_BEEP_INTERVAL;
+ arm_beep_time = AO_PAD_ARM_SIREN_INTERVAL;
beeping = 1;
- ao_beep(AO_BEEP_HIGH);
+ ao_siren(1);
}
--arm_beep_time;
} else if (beeping) {
beeping = 0;
- ao_beep(0);
+ ao_siren(0);
+ ao_strobe(0);
}
}
}
int16_t time_difference;
int8_t ret;
- ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));
ao_pad_box = 0;
ao_led_set(0);
ao_led_on(AO_LED_POWER);
PRINTD ("tick %d box %d cmd %d channels %02x\n",
command.tick, command.box, command.cmd, command.channels);
- if (ao_pad_armed && (int16_t) (ao_time() - ao_pad_arm_time) > AO_PAD_ARM_TIME)
- ao_pad_armed = 0;
-
switch (command.cmd) {
case AO_LAUNCH_ARM:
if (command.box != ao_pad_box) {
break;
}
- if (command.channels & ~(AO_PAD_ALL_PINS))
+ if (command.channels & ~(AO_PAD_ALL_CHANNELS))
break;
time_difference = command.tick - ao_time();
query.tick = ao_time();
query.box = ao_pad_box;
- query.channels = AO_PAD_ALL_PINS;
+ query.channels = AO_PAD_ALL_CHANNELS;
query.armed = ao_pad_armed;
PRINTD ("query tick %d box %d channels %02x arm %d arm_status %d igniter %d,%d,%d,%d\n",
query.tick, query.box, query.channels, query.armed,
#endif
#if AO_PAD_NUM > 3
ao_enable_output(AO_PAD_PORT, AO_PAD_PIN_3, AO_PAD_3, 0);
+#endif
+#ifdef AO_STROBE
+ ao_enable_output(AO_STROBE_PORT, AO_STROBE_PIN, AO_STROBE, 0);
+#endif
+#ifdef AO_SIREN
+ ao_enable_output(AO_SIREN_PORT, AO_SIREN_PIN, AO_SIREN, 0);
#endif
ao_cmd_register(&ao_pad_cmds[0]);
ao_add_task(&ao_pad_task, ao_pad, "pad listener");
{
ao_spi_get_bit(AO_RADIO_CS_PORT, AO_RADIO_CS_PIN, AO_RADIO_CS,
AO_RADIO_SPI_BUS,
- AO_SPI_SPEED_200kHz);
+ AO_SPI_SPEED_2MHz);
}
static void
ao_data.h \
ao_sample.h \
ao_pins.h \
- altitude.h \
+ altitude-pa.h \
ao_kalman.h \
ao_product.h \
ao_ms5607.h \
$(PROG): Makefile $(OBJ) altos.ld
$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc
-../altitude.h: make-altitude
+../altitude-pa.h: make-altitude-pa
nickle $< > $@
$(OBJ): $(INC)
--- /dev/null
+ao_product.h
+micropeak-*
--- /dev/null
+#
+# Tiny AltOS build
+#
+#
+vpath % ../attiny:../drivers:../core:..
+vpath ao-make-product.5c ../util
+vpath make-altitude-pa ../util
+
+MCU=attiny85
+DUDECPUTYPE=t85
+#PROGRAMMER=stk500v2 -P usb
+PROGRAMMER=usbtiny
+LOADCMD=avrdude
+LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w:
+CC=avr-gcc
+OBJCOPY=avr-objcopy
+
+ifndef VERSION
+include ../Version
+endif
+
+ALTOS_SRC = \
+ ao_micropeak.c \
+ ao_spi_attiny.c \
+ ao_led.c \
+ ao_clock.c \
+ ao_ms5607.c \
+ ao_exti.c \
+ ao_convert_pa.c \
+ ao_i2c_attiny.c \
+ ao_at24c.c \
+ ao_report_tiny.c \
+ ao_async.c \
+ ao_notask.c \
+ ao_eeprom_tiny.c \
+ ao_panic.c
+
+INC=\
+ ao.h \
+ ao_pins.h \
+ ao_arch.h \
+ ao_arch_funcs.h \
+ ao_exti.h \
+ ao_ms5607.h \
+ altitude-pa.h
+
+IDPRODUCT=0
+PRODUCT=MicroPeak-v0.1
+PRODUCT_DEF=-DMICROPEAK
+CFLAGS = $(PRODUCT_DEF) -I. -I../attiny -I../core -I.. -I../drivers
+CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O3 -mcall-prologues -DATTINY
+
+NICKLE=nickle
+
+PROG=micropeak-v0.1
+
+SRC=$(ALTOS_SRC)
+OBJ=$(SRC:.c=.o)
+
+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).hex
+
+CHECK=sh ../util/check-avr-mem
+
+$(PROG): Makefile $(OBJ)
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ)
+ $(call quiet,CHECK) $(PROG) || ($(RM) -f $(PROG); exit 1)
+
+$(PROG).hex: $(PROG)
+ avr-size $(PROG)
+ $(OBJCOPY) -R .eeprom -O ihex $(PROG) $@
+
+
+load: $(PROG).hex
+ $(LOADCMD) $(LOADARG)$(PROG).hex
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+ao_product.o: ao_product.c ao_product.h
+
+%.o : %.c $(INC)
+ $(call quiet,CC) -c $(CFLAGS) $<
+
+distclean: clean
+
+clean:
+ rm -f *.o $(PROG) $(PROG).hex
+ rm -f ao_product.h
+
+../altitude-pa.h: make-altitude-pa
+ nickle $< > $@
+
+install:
+
+uninstall:
+
+$(OBJ): ao_product.h $(INC)
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_async.h>
+
+#define AO_ASYNC_BAUD 38400l
+#define AO_ASYNC_DELAY (uint8_t) (1000000l / AO_ASYNC_BAUD)
+
+void
+ao_async_byte(uint8_t byte)
+{
+ uint8_t b;
+ uint16_t w;
+
+ /* start bit */
+
+ /* start data stop */
+ w = 0x001 | (byte << 1) | 0x000;
+
+ for (b = 0; b < 10; b++) {
+ ao_led_set((w & 1) << AO_LED_SERIAL);
+ w >>= 1;
+ ao_delay_us(26);
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_ASYNC_H_
+#define _AO_ASYNC_H_
+
+void
+ao_async_byte(uint8_t byte);
+
+#endif /* _AO_ASYNC_H_ */
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_log_micro.h>
+#include <ao_async.h>
+
+#if HAS_EEPROM
+
+ao_pos_t ao_log_micro_pos;
+
+void
+ao_log_micro_data(uint32_t data)
+{
+ ao_storage_write(ao_log_micro_pos, &data, sizeof (data));
+ ao_log_micro_pos += sizeof (data);
+}
+
+uint32_t ao_log_last_ground;
+uint32_t ao_log_last_done;
+
+uint8_t
+ao_log_micro_scan(void)
+{
+ uint32_t data;
+ ao_pos_t pos;
+
+ ao_storage_read(0, &data, sizeof (data));
+ if ((data & AO_LOG_MICRO_MASK) != AO_LOG_MICRO_GROUND)
+ return 0;
+
+ ao_log_last_ground = data & ~(AO_LOG_MICRO_MASK);
+ for (pos = 4; pos < ao_storage_total; pos += 4) {
+ ao_storage_read(pos, &data, sizeof (data));
+ if ((data & AO_LOG_MICRO_MASK) == AO_LOG_MICRO_GROUND) {
+ ao_log_last_done = data & ~(AO_LOG_MICRO_MASK);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void
+ao_log_micro_dump(void)
+{
+ ao_pos_t pos;
+ uint8_t data[4];
+ uint8_t i;
+
+ for (pos = 0; pos < ao_storage_total; pos += 4) {
+ ao_storage_read(pos, data, 4);
+ for (i = 0; i < 4; i++)
+ ao_async_byte(data[i]);
+ if (data[3] == (uint8_t) (AO_LOG_MICRO_GROUND >> 24))
+ break;
+ }
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_LOG_MICRO_H_
+#define _AO_LOG_MICRO_H_
+
+#define AO_LOG_MICRO_GROUND (0l << 24)
+#define AO_LOG_MICRO_DATA (1l << 24)
+#define AO_LOG_MICRO_DONE (0xaal << 24)
+#define AO_LOG_MICRO_MASK (0xffl << 24)
+
+void
+ao_log_micro_data(uint32_t data);
+
+extern uint32_t ao_log_last_ground;
+extern uint32_t ao_log_last_done;
+
+uint8_t
+ao_log_micro_scan(void);
+
+void
+ao_log_micro_dump(void);
+
+#endif /* _AO_LOG_MICRO_H_ */
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_ms5607.h>
+#include <ao_log_micro.h>
+
+static struct ao_ms5607_sample sample;
+static struct ao_ms5607_value value;
+
+static uint32_t pa;
+static uint32_t pa_sum;
+static uint32_t pa_avg;
+static int32_t pa_diff;
+static uint32_t pa_ground;
+static uint32_t pa_min;
+static uint32_t pa_interval_min, pa_interval_max;
+static alt_t ground_alt, max_alt;
+alt_t ao_max_height;
+
+static void
+ao_pa_get(void)
+{
+ ao_ms5607_sample(&sample);
+ ao_ms5607_convert(&sample, &value);
+ pa = value.pres;
+}
+
+#define FILTER_SHIFT 3
+#define SAMPLE_SLEEP AO_MS_TO_TICKS(96)
+
+/* 16 sample, or about two seconds worth */
+#define GROUND_AVG_SHIFT 4
+#define GROUND_AVG (1 << GROUND_AVG_SHIFT)
+
+static void
+ao_compute_height(void)
+{
+ ground_alt = ao_pa_to_altitude(pa_ground);
+ max_alt = ao_pa_to_altitude(pa_min);
+ ao_max_height = max_alt - ground_alt;
+}
+
+#if !HAS_EEPROM
+void
+ao_save_flight(void)
+{
+ ao_eeprom_write(0, &pa_ground, sizeof (pa_ground));
+ ao_eeprom_write(sizeof (pa_ground), &pa_min, sizeof (pa_min));
+}
+
+void
+ao_restore_flight(void)
+{
+ ao_eeprom_read(0, &pa_ground, sizeof (pa_ground));
+ ao_eeprom_read(sizeof (pa_ground), &pa_min, sizeof (pa_min));
+}
+#endif
+
+int
+main(void)
+{
+ int16_t sample_count;
+ uint16_t time;
+#if HAS_EEPROM
+ uint8_t dump_eeprom = 0;
+#endif
+ ao_led_init(LEDS_AVAILABLE);
+ ao_timer_init();
+
+#if HAS_EEPROM
+
+ /* Set MOSI and CLK as inputs with pull-ups */
+ DDRB &= ~(1 << 0) | (1 << 2);
+ PORTB |= (1 << 0) | (1 << 2);
+
+ /* Check to see if either MOSI or CLK are pulled low by the
+ * user shorting them to ground. If so, dump the eeprom out
+ * via the LED. Wait for the shorting wire to go away before
+ * continuing.
+ */
+ while ((PINB & ((1 << 0) | (1 << 2))) != ((1 << 0) | (1 << 2)))
+ dump_eeprom = 1;
+ PORTB &= ~(1 << 0) | (1 << 2);
+
+ ao_i2c_init();
+#endif
+ ao_restore_flight();
+ ao_compute_height();
+ ao_report_altitude();
+
+ ao_spi_init();
+ ao_ms5607_init();
+ ao_ms5607_setup();
+
+#if HAS_EEPROM
+ ao_storage_init();
+
+ /* Check to see if there's a flight recorded in memory */
+ if (dump_eeprom && ao_log_micro_scan())
+ ao_log_micro_dump();
+#endif
+
+ /* Wait for motion, averaging values to get ground pressure */
+ time = ao_time();
+ ao_pa_get();
+ pa_avg = pa_ground = pa << FILTER_SHIFT;
+ sample_count = 0;
+ for (;;) {
+ time += SAMPLE_SLEEP;
+ ao_delay_until(time);
+ if (sample_count == 0)
+ ao_led_on(AO_LED_BLUE);
+ ao_pa_get();
+ if (sample_count == 0)
+ ao_led_off(AO_LED_BLUE);
+ pa_avg = pa_avg - (pa_avg >> FILTER_SHIFT) + pa;
+ pa_diff = pa_ground - pa_avg;
+ if (pa_diff < 0)
+ pa_diff = -pa_diff;
+
+ /* about 2 meters at sea level, more if you're higher */
+ if (pa_diff > (24 << FILTER_SHIFT))
+ break;
+
+ if (sample_count < GROUND_AVG * 2) {
+ ao_led_off(AO_LED_BLUE);
+ if (sample_count < GROUND_AVG)
+ pa_sum += pa;
+ ++sample_count;
+ } else {
+ pa_ground = pa_sum >> (GROUND_AVG_SHIFT - FILTER_SHIFT);
+ pa_sum = 0;
+ sample_count = 0;
+ }
+ }
+
+ pa_ground >>= FILTER_SHIFT;
+
+#if HAS_EEPROM
+ ao_log_micro_data(AO_LOG_MICRO_GROUND | pa_ground);
+#endif
+
+ /* Now sit around until the pressure is stable again and record the max */
+
+ sample_count = 0;
+ pa_min = pa_avg;
+ pa_interval_min = pa_avg;
+ pa_interval_max = pa_avg;
+ for (;;) {
+ time += SAMPLE_SLEEP;
+ ao_delay_until(time);
+ if ((sample_count & 3) == 0)
+ ao_led_on(AO_LED_BLUE);
+ ao_pa_get();
+ if ((sample_count & 3) == 0)
+ ao_led_off(AO_LED_BLUE);
+#if HAS_EEPROM
+ ao_log_micro_data(AO_LOG_MICRO_DATA | pa);
+#endif
+ pa_avg = pa_avg - (pa_avg >> FILTER_SHIFT) + pa;
+ if (pa_avg < pa_min)
+ pa_min = pa_avg;
+
+ if (sample_count == (GROUND_AVG - 1)) {
+ pa_diff = pa_interval_max - pa_interval_min;
+ /* About 1m at sea level */
+ if (pa_diff < (12 << FILTER_SHIFT))
+ break;
+ sample_count = 0;
+ pa_interval_min = pa_avg;
+ pa_interval_max = pa_avg;
+ } else {
+ if (pa_avg < pa_interval_min)
+ pa_interval_min = pa_avg;
+ if (pa_avg > pa_interval_max)
+ pa_interval_max = pa_avg;
+ ++sample_count;
+ }
+ }
+ pa_min >>= FILTER_SHIFT;
+#if HAS_EEPROM
+ ao_log_micro_data(AO_LOG_MICRO_DONE | pa_min);
+#endif
+ ao_save_flight();
+ ao_compute_height();
+ ao_report_altitude();
+ for (;;) {
+ cli();
+ set_sleep_mode(SLEEP_MODE_PWR_DOWN);
+ sleep_mode();
+ }
+}
--- /dev/null
+static void
+pause(uint8_t j)
+{
+ int64_t i;
+
+ while (j--) {
+ for (i = 0; i < 2000; i++)
+ ao_arch_nop();
+ }
+}
+
+#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))
+
+#define ___ 1
+#define _ 0
+
+static const uint8_t morse[26] = {
+ MORSE2(0,1), /* A */
+ MORSE4(1,0,0,0), /* B */
+ MORSE4(1,0,1,0), /* C */
+ MORSE3(1,0,0), /* D */
+ MORSE1(0), /* E */
+ MORSE4(0,0,1,0), /* F */
+ MORSE3(1,1,0), /* G */
+ MORSE4(0,0,0,0), /* H */
+ MORSE2(0,0), /* I */
+ MORSE4(0,1,1,1), /* J */
+ MORSE3(1,0,1), /* K */
+ MORSE4(0,1,0,0), /* L */
+ MORSE2(1,1), /* M */
+ MORSE2(1,1), /* N */
+ MORSE3(1,1,1), /* O */
+ MORSE4(0,1,1,0), /* P */
+ MORSE4(1,1,0,1), /* Q */
+ MORSE3(0,1,0), /* R */
+ MORSE3(0,0,0), /* S */
+ MORSE1(1), /* T */
+ MORSE3(0,0,1), /* U */
+ MORSE4(0,0,0,1), /* V */
+ MORSE3(0,1,1), /* W */
+ MORSE4(1,0,0,1), /* X */
+ MORSE4(1,0,1,1), /* Y */
+ MORSE4(1,1,0,0), /* Z */
+};
+
+static void
+on(void)
+{
+ PORTB |= (1 << 4);
+}
+
+static void
+off(void)
+{
+ PORTB &= ~(1 << 4);
+}
+
+static void
+morse_char (char c)
+{
+ uint8_t r = morse[c - 'a'];
+ uint8_t l = r & 7;
+
+ if (!r)
+ return;
+ while (l--) {
+ on();
+ if (r & 8)
+ pause(3);
+ else
+ pause(1);
+ off();
+ pause(1);
+ r >>= 1;
+ }
+ pause(2);
+}
+
+static void
+morse_string(char *s) {
+ char c;
+
+ while ((c = *s++)) {
+ if (c == ' ')
+ pause(5);
+ else
+ morse_char(c);
+ }
+}
+
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+static volatile void *ao_wchan;
+
+uint8_t
+ao_sleep(__xdata void *wchan)
+{
+#if 1
+ ao_wchan = wchan;
+ ao_arch_cpu_idle();
+#else
+ uint8_t sreg;
+
+ ao_wchan = wchan;
+ asm("in %0,__SREG__" : "=&r" (sreg));
+ sei();
+ while (ao_wchan)
+ ao_arch_cpu_idle();
+ asm("out __SREG__,%0" : : "r" (sreg));
+#endif
+ return 0;
+}
+
+void
+ao_wakeup(__xdata void *wchan)
+{
+ ao_wchan = 0;
+}
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+#include <avr/pgmspace.h>
+
+#define AO_LED_BLUE (1<<4)
+#define AO_LED_SERIAL 4
+#define AO_LED_PANIC AO_LED_BLUE
+#define LEDS_AVAILABLE (AO_LED_BLUE)
+#define USE_SERIAL_1_STDIN 0
+#define HAS_USB 0
+#define PACKET_HAS_SLAVE 0
+#define HAS_SERIAL_1 0
+#define HAS_TASK 0
+#define HAS_MS5607 1
+#define HAS_MS5611 1
+#define HAS_EEPROM 0
+#define HAS_BEEP 0
+#define AVR_CLOCK 8000000UL
+
+/* SPI */
+#define SPI_PORT PORTB
+#define SPI_PIN PINB
+#define SPI_DIR DDRB
+#define AO_MS5607_CS_PORT PORTB
+#define AO_MS5607_CS_PIN 3
+
+#define AO_MS5607_SPI_INDEX 0
+#define AO_MS5607_MISO_PORT PORTB
+#define AO_MS5607_MISO_PIN 0
+
+/* I2C */
+#define I2C_PORT PORTB
+#define I2C_PIN PINB
+#define I2C_DIR DDRB
+#define I2C_PIN_SCL PINB2
+#define I2C_PIN_SDA PINB0
+
+#define AO_CONST_ATTRIB PROGMEM
+#define FETCH_ALT(o) ((alt_t) pgm_read_dword(&altitude_table[o]))
+
+#define AO_ALT_VALUE(x) ((x) * 10)
+
+#endif /* _AO_PINS_H_ */
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+#define mid(time) ao_led_for(AO_LED_BLUE, time)
+#define pause(time) ao_delay(time)
+
+static void
+ao_report_digit(uint8_t digit) __reentrant
+{
+ if (!digit) {
+ mid(AO_MS_TO_TICKS(600));
+ 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));
+}
+
+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);
+
+ i = ndigits;
+ do
+ ao_report_digit(digits[--i]);
+ while (i != 0);
+}
/* ao_spi_stm.c
*/
-#define AO_SPI_SPEED_FAST STM_SPI_CR1_BR_PCLK_4
+/* PCLK is set to 16MHz (HCLK 32MHz, APB prescaler 2) */
+
+#define AO_SPI_SPEED_8MHz STM_SPI_CR1_BR_PCLK_2 /* This doesn't appear to work */
+#define AO_SPI_SPEED_4MHz STM_SPI_CR1_BR_PCLK_4
+#define AO_SPI_SPEED_2MHz STM_SPI_CR1_BR_PCLK_8
#define AO_SPI_SPEED_1MHz STM_SPI_CR1_BR_PCLK_16
-#define AO_SPI_SPEED_200kHz STM_SPI_CR1_BR_PCLK_256
+#define AO_SPI_SPEED_500kHz STM_SPI_CR1_BR_PCLK_32
+#define AO_SPI_SPEED_250kHz STM_SPI_CR1_BR_PCLK_64
+#define AO_SPI_SPEED_125kHz STM_SPI_CR1_BR_PCLK_128
+#define AO_SPI_SPEED_62500Hz STM_SPI_CR1_BR_PCLK_256
+
+#define AO_SPI_SPEED_FAST AO_SPI_SPEED_4MHz
+
+/* Companion bus wants something no faster than 200kHz */
+
+#define AO_SPI_SPEED_200kHz AO_SPI_SPEED_125kHz
#define AO_SPI_CONFIG_1 0x00
#define AO_SPI_1_CONFIG_PA5_PA6_PA7 AO_SPI_CONFIG_1
#define PACKET_HAS_MASTER 0
#define PACKET_HAS_SLAVE 0
-#define AO_LED_CONTINUITY(c) (1 << (c))
-#define AO_LED_CONTINUITY_MASK (0xf)
+#define AO_LED_CONTINUITY(c) (1 << ((c) + 2))
+#define AO_LED_CONTINUITY_MASK (0xc)
#define AO_LED_RX 0x10
#define AO_LED_TX 0x20
#define AO_LED_ARMED 0x40
#define AO_PCA9922_CS_PIN 4
#define AO_PCA9922_CS P1_4
-#define AO_PAD_NUM 4
+#define AO_PAD_NUM 2
#define AO_PAD_PORT P1
#define AO_PAD_DIR P1DIR
-#define AO_PAD_PIN_0 0
-#define AO_PAD_0 P1_0
-#define AO_PAD_PIN_1 1
-#define AO_PAD_1 P1_1
-#define AO_PAD_PIN_2 2
-#define AO_PAD_2 P1_2
-#define AO_PAD_PIN_3 3
-#define AO_PAD_3 P1_3
-#define AO_PAD_ALL_PINS ((1 << AO_PAD_PIN_0) | (1 << AO_PAD_PIN_1) | (1 << AO_PAD_PIN_2) | (1 << AO_PAD_PIN_3))
+
+#define AO_PAD_PIN_0 2
+#define AO_PAD_0 P1_2
+#define AO_PAD_ADC_0 2
+
+#define AO_PAD_PIN_1 3
+#define AO_PAD_1 P1_3
+#define AO_PAD_ADC_1 3
+
+#define AO_PAD_ALL_PINS ((1 << AO_PAD_PIN_0) | (1 << AO_PAD_PIN_1))
+#define AO_PAD_ALL_CHANNELS ((1 << 0) | (1 << 1))
+
+#define AO_SIREN_PORT P1
+#define AO_SIREN_DIR P1DIR
+#define AO_SIREN_PIN 0
+#define AO_SIREN P1_0
+
+#define AO_STROBE_PORT P1
+#define AO_STROBE_DIR P1DIR
+#define AO_STROBE_PIN 1
+#define AO_STROBE P1_1
/* test these values with real igniters */
#define AO_PAD_RELAY_CLOSED 3524
#define AO_PAD_NO_IGNITER 16904
#define AO_PAD_GOOD_IGNITER 22514
+#define AO_PAD_ADC_PYRO 4
+#define AO_PAD_ADC_BATT 5
+
+#define AO_ADC_FIRST_PIN 2
+
struct ao_adc {
- int16_t sense[4];
+ int16_t sense[AO_PAD_NUM];
int16_t pyro;
int16_t batt;
};
#define AO_ADC_DUMP(p) \
- printf ("tick: %5u 0: %5d 1: %5d 2: %5d 3: %5d pyro: %5d batt %5d\n", \
+ printf ("tick: %5u 0: %5d 1: %5d pyro: %5d batt %5d\n", \
(p)->tick, \
(p)->adc.sense[0], \
(p)->adc.sense[1], \
- (p)->adc.sense[2], \
- (p)->adc.sense[3], \
(p)->adc.pyro, \
(p)->adc.batt)
-#define AO_ADC_PINS ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5))
+#define AO_ADC_PINS ((1 << AO_PAD_ADC_0) | (1 << AO_PAD_ADC_1) | (1 << AO_PAD_ADC_PYRO) | (1 << AO_PAD_ADC_BATT))
#endif /* _AO_PINS_H_ */
static uint8_t ao_lco_armed;
static uint8_t ao_lco_firing;
static uint8_t ao_lco_valid;
+static uint8_t ao_lco_got_channels;
+static uint16_t ao_lco_tick_offset;
+
+static struct ao_pad_query ao_pad_query;
static void
ao_lco_set_pad(void)
return (ao_lco_box_mask[MASK_ID(box)] >> MASK_SHIFT(box)) & 1;
}
+static uint8_t
+ao_lco_pad_present(uint8_t pad)
+{
+ if (!ao_lco_got_channels || !ao_pad_query.channels)
+ return pad == 0;
+ if (pad >= AO_PAD_MAX_CHANNELS)
+ return 0;
+ return (ao_pad_query.channels >> pad) & 1;
+}
+
+static uint8_t
+ao_lco_pad_first(void)
+{
+ uint8_t pad;
+
+ for (pad = 0; pad < AO_PAD_MAX_CHANNELS; pad++)
+ if (ao_lco_pad_present(pad))
+ return pad;
+ return 0;
+}
+
static void
ao_lco_input(void)
{
static struct ao_event event;
- int8_t dir;
+ int8_t dir, new_box, new_pad;
ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));
ao_lco_set_pad();
switch (event.unit) {
case AO_QUADRATURE_PAD:
if (!ao_lco_armed) {
- ao_lco_pad = event.value & 3;
- ao_quadrature_count[AO_QUADRATURE_PAD] = ao_lco_pad;
- ao_lco_set_pad();
+ if (event.value == ao_lco_pad)
+ break;
+ dir = ((int8_t) event.value - (int8_t) ao_lco_pad) > 0 ? 1 : -1;
+ new_pad = event.value;
+ while (!ao_lco_pad_present(new_pad)) {
+ new_pad += dir;
+ if (new_pad > AO_PAD_MAX_CHANNELS)
+ new_pad = 0;
+ else if (new_pad < 0)
+ new_pad = AO_PAD_MAX_CHANNELS - 1;
+ if (new_pad == ao_lco_pad)
+ break;
+ }
+ if (new_pad != ao_lco_pad) {
+ ao_lco_pad = new_pad;
+ ao_quadrature_count[AO_QUADRATURE_PAD] = ao_lco_pad;
+ ao_lco_set_pad();
+ }
}
break;
case AO_QUADRATURE_BOX:
if (!ao_lco_armed) {
if (event.value == ao_lco_box)
break;
- dir = (event.value - ao_lco_box) > 0 ? 1 : -1;
- ao_lco_box = event.value;
- while (!ao_lco_box_present(ao_lco_box)) {
- ao_lco_box += dir;
- if (ao_lco_box > ao_lco_max_box)
- ao_lco_box = ao_lco_min_box;
- else if (ao_lco_box < ao_lco_min_box)
- ao_lco_box = ao_lco_min_box;
+ dir = ((int8_t) event.value - (int8_t) ao_lco_box) > 0 ? 1 : -1;
+ new_box = event.value;
+ while (!ao_lco_box_present(new_box)) {
+ new_box += dir;
+ if (new_box > ao_lco_max_box)
+ new_box = ao_lco_min_box;
+ else if (new_box < ao_lco_min_box)
+ new_box = ao_lco_min_box;
+ if (new_box == ao_lco_box)
+ break;
+ }
+ ao_quadrature_count[AO_QUADRATURE_PAD] = new_box;
+ if (ao_lco_box != new_box) {
+ ao_lco_box = new_box;
+ ao_lco_got_channels = 0;
+ ao_lco_set_box();
}
- ao_quadrature_count[AO_QUADRATURE_PAD] = ao_lco_box;
- ao_lco_set_box();
}
break;
}
#endif
};
-static uint16_t ao_lco_tick_offset;
-
-static struct ao_pad_query ao_pad_query;
-
static void
ao_lco_update(void)
{
uint8_t c;
r = ao_lco_query(ao_lco_box, &ao_pad_query, &ao_lco_tick_offset);
- if (r == AO_RADIO_CMAC_OK)
+ if (r == AO_RADIO_CMAC_OK) {
+ c = ao_lco_got_channels;
+ ao_lco_got_channels = 1;
ao_lco_valid = 1;
+ if (!c) {
+ ao_lco_pad = ao_lco_pad_first();
+ ao_lco_set_pad();
+ }
+ } else
+ ao_lco_valid = 0;
#if 0
PRINTD("lco_query success arm_status %d i0 %d i1 %d i2 %d i3 %d\n",
ao_lco_min_box = 0xff;
ao_lco_max_box = 0x00;
for (ao_lco_box = 0; ao_lco_box < AO_PAD_MAX_BOXES; ao_lco_box++) {
- ao_lco_set_box();
+ if ((ao_lco_box % 10) == 0)
+ ao_lco_set_box();
r = ao_lco_query(ao_lco_box, &ao_pad_query, &ao_lco_tick_offset);
if (r == AO_RADIO_CMAC_OK) {
if (ao_lco_box < ao_lco_min_box)
ao_lco_box_set_present(ao_lco_box);
}
}
- ao_lco_box = ao_lco_min_box;
+ if (ao_lco_min_box <= ao_lco_max_box)
+ ao_lco_box = ao_lco_min_box;
+ else
+ ao_lco_min_box = ao_lco_max_box = ao_lco_box = 0;
+ ao_lco_valid = 0;
+ ao_lco_got_channels = 0;
ao_lco_pad = 0;
}
continue;
}
PRINTD("RSSI %d\n", ao_radio_cmac_rssi);
- if (ao_radio_cmac_rssi < -70)
+ if (ao_radio_cmac_rssi < -90)
ao_led_on(AO_LED_RED|AO_LED_GREEN);
else {
ao_led_on(AO_LED_GREEN);
vpath % ..:../core:../drivers:../util
-PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_flight_test_noisy_accel ao_gps_test ao_gps_test_skytraq ao_convert_test ao_convert_pa_test ao_fec_test
+PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_flight_test_noisy_accel ao_flight_test_mm \
+ ao_gps_test ao_gps_test_skytraq ao_convert_test ao_convert_pa_test ao_fec_test
+
+INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h
KALMAN=make-kalman
-CFLAGS=-I.. -I. -I../core -I../drivers -O3 -g -Wall
+CFLAGS=-I.. -I. -I../core -I../drivers -O0 -g -Wall
all: $(PROGS)
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
+ao_flight_test: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c altitude.h $(INCS)
cc $(CFLAGS) -o $@ $<
-ao_flight_test_noisy_accel: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c altitude.h ao_kalman.h
+ao_flight_test_noisy_accel: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c $(INCS)
cc -DNOISY_ACCEL=1 $(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
+ao_flight_test_baro: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c $(INCS)
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
+ao_flight_test_accel: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c $(INCS)
cc $(CFLAGS) -o $@ -DFORCE_ACCEL=1 ao_flight_test.c
+ao_flight_test_mm: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c $(INCS)
+ cc -DMEGAMETRUM=1 $(CFLAGS) -o $@ $<
+
ao_gps_test: ao_gps_test.c ao_gps_sirf.c ao_gps_print.c ao_host.h
cc $(CFLAGS) -o $@ $<
#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16))
#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16))
+#if MEGAMETRUM
+#define AO_ADC_NUM_SENSE 6
+#define HAS_MS5607 1
+#define HAS_MPU6000 1
+#define HAS_MMA655X 0
+
+struct ao_adc {
+ int16_t sense[AO_ADC_NUM_SENSE];
+ int16_t v_batt;
+ int16_t v_pbatt;
+ int16_t accel_ref;
+ int16_t accel;
+ int16_t temp;
+};
+#else
/*
* One set of samples read from the A/D converter
*/
int16_t sense_m; /* main continuity sense */
};
+#ifndef HAS_ACCEL
+#define HAS_ACCEL 1
+#define HAS_ACCEL_REF 0
+#endif
+
+#endif
+
#define __pdata
#define __data
#define __xdata
#define HAS_IGNITE 1
#define HAS_USB 1
#define HAS_GPS 1
-#ifndef HAS_ACCEL
-#define HAS_ACCEL 1
-#define HAS_ACCEL_REF 0
-#endif
#include <ao_data.h>
+#include <ao_log.h>
#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5))
#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5))
/*
* 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)
#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 ao_xmemcmp(d,s,c) memcmp(d,s,c)
#define AO_NEED_ALTITUDE_TO_PRES 1
+#if MEGAMETRUM
+#include "ao_convert_pa.c"
+#include <ao_ms5607.h>
+struct ao_ms5607_prom ms5607_prom;
+#include "ao_ms5607_convert.c"
+#else
#include "ao_convert.c"
+#endif
struct ao_config {
uint16_t main_deploy;
extern uint16_t ao_sample_tick;
-extern int16_t ao_sample_height;
+extern alt_t ao_sample_height;
extern accel_t ao_sample_accel;
extern int32_t ao_accel_scale;
-extern int16_t ao_ground_height;
-extern int16_t ao_sample_alt;
+extern alt_t ao_ground_height;
+extern alt_t ao_sample_alt;
int ao_sample_prev_tick;
uint16_t prev_tick;
static double landed_time;
static double landed_height;
+#if HAS_MPU6000
+static struct ao_mpu6000_sample ao_ground_mpu6000;
+#endif
+
void
ao_test_exit(void)
{
exit(0);
}
+#if HAS_MPU6000
+static double
+ao_mpu6000_accel(int16_t sensor)
+{
+ return sensor / 32767.0 * MPU6000_ACCEL_FULLSCALE * GRAVITY;
+}
+
+static double
+ao_mpu6000_gyro(int16_t sensor)
+{
+ return sensor / 32767.0 * MPU6000_GYRO_FULLSCALE;
+}
+#endif
+
void
ao_insert(void)
{
ao_data_ring[ao_data_head] = ao_data_static;
ao_data_head = ao_data_ring_next(ao_data_head);
if (ao_flight_state != ao_flight_startup) {
- double height = ao_pres_to_altitude(ao_data_static.adc.pres_real) - ao_ground_height;
- double accel = ((ao_flight_ground_accel - ao_data_static.adc.accel) * GRAVITY * 2.0) /
+#if HAS_ACCEL
+ double accel = ((ao_flight_ground_accel - ao_data_accel_cook(&ao_data_static)) * GRAVITY * 2.0) /
(ao_config.accel_minus_g - ao_config.accel_plus_g);
+#else
+ double accel = 0.0;
+#endif
+#if MEGAMETRUM
+ double height;
+
+ ao_ms5607_convert(&ao_data_static.ms5607_raw, &ao_data_static.ms5607_cooked);
+ height = ao_pa_to_altitude(ao_data_static.ms5607_cooked.pres) - ao_ground_height;
+#else
+ double height = ao_pres_to_altitude(ao_data_static.adc.pres_real) - ao_ground_height;
+#endif
if (!tick_offset)
tick_offset = -ao_data_static.tick;
}
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",
+ printf("%7.2f height %8.2f accel %8.3f "
+#if MEGAMETRUM
+ "accel_x %8.3f accel_y %8.3f accel_z %8.3f gyro_x %8.3f gyro_y %8.3f gyro_z %8.3f "
+#endif
+ "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,
+#if MEGAMETRUM
+ ao_mpu6000_accel(ao_data_static.mpu6000.accel_x),
+ ao_mpu6000_accel(ao_data_static.mpu6000.accel_y),
+ ao_mpu6000_accel(ao_data_static.mpu6000.accel_z),
+ ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_x - ao_ground_mpu6000.gyro_x),
+ ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_y - ao_ground_mpu6000.gyro_y),
+ ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_z - ao_ground_mpu6000.gyro_z),
+#endif
ao_state_names[ao_flight_state],
ao_k_height / 65536.0,
ao_k_speed / 65536.0 / 16.0,
uint16_t
uint16(uint8_t *bytes, int off)
{
- off++;
return (uint16_t) bytes[off] | (((uint16_t) bytes[off+1]) << 8);
}
return (int16_t) uint16(bytes, off);
}
+uint32_t
+uint32(uint8_t *bytes, int off)
+{
+ return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) |
+ (((uint32_t) bytes[off+2]) << 16) |
+ (((uint32_t) bytes[off+3]) << 24);
+}
+
+int32_t
+int32(uint8_t *bytes, int off)
+{
+ return (int32_t) uint32(bytes, off);
+}
+
+static int log_format;
+
void
ao_sleep(void *wchan)
{
for (;;) {
if (ao_records_read > 2 && ao_flight_state == ao_flight_startup)
{
+#if MEGAMETRUM
+ ao_data_static.mpu6000 = ao_ground_mpu6000;
+#else
ao_data_static.adc.accel = ao_flight_ground_accel;
+#endif
ao_insert();
return;
}
if (words[nword] == NULL)
break;
}
- if (nword == 4) {
+#if MEGAMETRUM
+ if (log_format == AO_LOG_FORMAT_MEGAMETRUM && nword == 30 && strlen(words[0]) == 1) {
+ int i;
+ struct ao_ms5607_value value;
+
+ type = words[0][0];
+ tick = strtoul(words[1], NULL, 16);
+// printf ("%c %04x", type, tick);
+ for (i = 2; i < nword; i++) {
+ bytes[i - 2] = strtoul(words[i], NULL, 16);
+// printf(" %02x", bytes[i-2]);
+ }
+// printf ("\n");
+ switch (type) {
+ case 'F':
+ ao_flight_ground_accel = int16(bytes, 2);
+ ao_flight_started = 1;
+ ao_ground_pres = int32(bytes, 4);
+ ao_ground_height = ao_pa_to_altitude(ao_ground_pres);
+ break;
+ case 'A':
+ ao_data_static.tick = tick;
+ ao_data_static.ms5607_raw.pres = int32(bytes, 0);
+ ao_data_static.ms5607_raw.temp = int32(bytes, 4);
+ ao_ms5607_convert(&ao_data_static.ms5607_raw, &value);
+ ao_data_static.mpu6000.accel_x = int16(bytes, 8);
+ ao_data_static.mpu6000.accel_y = -int16(bytes, 10);
+ ao_data_static.mpu6000.accel_z = int16(bytes, 12);
+ ao_data_static.mpu6000.gyro_x = int16(bytes, 14);
+ ao_data_static.mpu6000.gyro_y = -int16(bytes, 16);
+ ao_data_static.mpu6000.gyro_z = int16(bytes, 18);
+ if (ao_records_read == 0)
+ ao_ground_mpu6000 = ao_data_static.mpu6000;
+ else if (ao_records_read < 10) {
+#define f(f) ao_ground_mpu6000.f = ao_ground_mpu6000.f + ((ao_data_static.mpu6000.f - ao_ground_mpu6000.f) >> 2)
+ f(accel_x);
+ f(accel_y);
+ f(accel_z);
+ f(gyro_x);
+ f(gyro_y);
+ f(gyro_z);
+ }
+ ao_records_read++;
+ ao_insert();
+ return;
+ }
+ continue;
+ } else if (nword == 3 && strcmp(words[0], "ms5607") == 0) {
+ if (strcmp(words[1], "reserved:") == 0)
+ ms5607_prom.reserved = strtoul(words[2], NULL, 10);
+ else if (strcmp(words[1], "sens:") == 0)
+ ms5607_prom.sens = strtoul(words[2], NULL, 10);
+ else if (strcmp(words[1], "off:") == 0)
+ ms5607_prom.off = strtoul(words[2], NULL, 10);
+ else if (strcmp(words[1], "tcs:") == 0)
+ ms5607_prom.tcs = strtoul(words[2], NULL, 10);
+ else if (strcmp(words[1], "tco:") == 0)
+ ms5607_prom.tco = strtoul(words[2], NULL, 10);
+ else if (strcmp(words[1], "tref:") == 0)
+ ms5607_prom.tref = strtoul(words[2], NULL, 10);
+ else if (strcmp(words[1], "tempsens:") == 0)
+ ms5607_prom.tempsens = strtoul(words[2], NULL, 10);
+ else if (strcmp(words[1], "crc:") == 0)
+ ms5607_prom.crc = strtoul(words[2], NULL, 10);
+ continue;
+ }
+#else
+ if (nword == 4 && log_format != AO_LOG_FORMAT_MEGAMETRUM) {
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';
+ }
+#endif
+ else if (nword == 2 && strcmp(words[0], "log-format") == 0) {
+ log_format = strtoul(words[1], NULL, 10);
} 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 (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);
+ tick = uint16(bytes+1, 21);
+ ao_flight_ground_accel = int16(bytes+1, 7);
+ ao_config.accel_plus_g = int16(bytes+1, 17);
+ ao_config.accel_minus_g = int16(bytes+1, 19);
type = 'A';
- a = int16(bytes, 23);
- b = int16(bytes, 25);
+ a = int16(bytes+1, 23);
+ b = int16(bytes+1, 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);
+ tick = uint16(bytes+1, 20);
+ ao_flight_ground_accel = int16(bytes+1, 6);
+ ao_config.accel_plus_g = int16(bytes+1, 16);
+ ao_config.accel_minus_g = int16(bytes+1, 18);
type = 'A';
- a = int16(bytes, 22);
- b = int16(bytes, 24);
+ a = int16(bytes+1, 22);
+ b = int16(bytes+1, 24);
} else {
printf("unknown len %d\n", len);
continue;
if (type != 'F' && !ao_flight_started)
continue;
+#if MEGAMETRUM
+#else
switch (type) {
case 'F':
ao_flight_ground_accel = a;
case 'H':
break;
}
+#endif
}
}
real i_v;
r_v = sample * l.m + l.b;
- i_v = (round(alt_part[sub]) * (seg_len - off) + round(alt_part[sub+1]) * off) / seg_len;
- return i_v;
+ i_v = (round(alt_part[sub]*10) * (seg_len - off) + round(alt_part[sub+1]*10) * off) / seg_len;
+ return i_v/10;
}
real max_error = 0;
printf ("#define NALT %d\n", dim(alt_part));
printf ("#define ALT_SHIFT %d\n", pa_part_shift + pa_sample_shift);
-printf ("#ifndef SATURATE\n#define SATURATE(x) (x)\n#endif\n");
+printf ("#ifndef AO_ALT_VALUE\n#define AO_ALT_VALUE(x) (alt_t) (x)\n#endif\n");
for (int part = 0; part < dim(alt_part); part++) {
real kPa = sample_to_Pa(part_to_sample(part)) / 1000;
- printf ("SATURATE(%9d), /* %6.2f kPa error %6.2fm */\n",
- round (alt_part[part]), kPa,
+ printf ("AO_ALT_VALUE(%10.1f), /* %6.2f kPa error %6.2fm */\n",
+ round (alt_part[part]*10) / 10, kPa,
alt_error[part]);
}