Merge branch 'master' into mm-ms5611
authorKeith Packard <keithp@keithp.com>
Thu, 18 Oct 2012 22:18:52 +0000 (15:18 -0700)
committerKeith Packard <keithp@keithp.com>
Thu, 18 Oct 2012 22:18:52 +0000 (15:18 -0700)
Signed-off-by: Keith Packard <keithp@keithp.com>
49 files changed:
altoslib/AltosConfigData.java
altosui/AltosDescent.java
altosui/AltosEepromDownload.java
altosui/AltosFlightUI.java
altosui/AltosUI.java
src/attiny/ao_arch.h [new file with mode: 0644]
src/attiny/ao_arch_funcs.h [new file with mode: 0644]
src/attiny/ao_clock.c [new file with mode: 0644]
src/attiny/ao_eeprom_tiny.c [new file with mode: 0644]
src/attiny/ao_exti.c [new file with mode: 0644]
src/attiny/ao_exti.h [new file with mode: 0644]
src/attiny/ao_i2c_attiny.c [new file with mode: 0644]
src/attiny/ao_led.c [new file with mode: 0644]
src/attiny/ao_spi_attiny.c [new file with mode: 0644]
src/avr/ao_spi_slave.c
src/cc1111/ao_adc.c
src/core/ao.h
src/core/ao_config.c
src/core/ao_convert_pa.c
src/core/ao_convert_pa_test.c
src/core/ao_data.h
src/core/ao_log.h
src/core/ao_panic.c
src/core/ao_task.h [new file with mode: 0644]
src/drivers/ao_at24c.c [new file with mode: 0644]
src/drivers/ao_mpu6000.h
src/drivers/ao_ms5607.c
src/drivers/ao_ms5607.h
src/drivers/ao_ms5607_convert.c [new file with mode: 0644]
src/drivers/ao_pad.c
src/drivers/ao_radio_master.c
src/megametrum-v0.1/Makefile
src/micropeak/.gitignore [new file with mode: 0644]
src/micropeak/Makefile [new file with mode: 0644]
src/micropeak/ao_async.c [new file with mode: 0644]
src/micropeak/ao_async.h [new file with mode: 0644]
src/micropeak/ao_log_micro.c [new file with mode: 0644]
src/micropeak/ao_log_micro.h [new file with mode: 0644]
src/micropeak/ao_micropeak.c [new file with mode: 0644]
src/micropeak/ao_morse.c [new file with mode: 0644]
src/micropeak/ao_notask.c [new file with mode: 0644]
src/micropeak/ao_pins.h [new file with mode: 0644]
src/micropeak/ao_report_tiny.c [new file with mode: 0644]
src/stm/ao_arch_funcs.h
src/telefire-v0.1/ao_pins.h
src/telelco-v0.1/ao_lco.c
src/test/Makefile
src/test/ao_flight_test.c
src/util/make-altitude-pa

index 6f343639e72680120b6c064f4e82db4fa188ae28..a962b1058ed5da60b9b4682a337839ba37ba2aeb 100644 (file)
@@ -134,6 +134,7 @@ public class AltosConfigData implements Iterable<String> {
                radio_setting = 0;
                radio_frequency = 0;
                stored_flight = 0;
+               serial = -1;
                for (;;) {
                        String line = link.get_reply();
                        if (line == null)
index e9ff590b735e6d79dbec25187ad421426bd9f8f0..a71cdc10c0fc97f2305951365294cc165f1d3580 100644 (file)
@@ -309,7 +309,10 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay {
 
        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) {
index a8cb24ff0c287f670c255a5524a12ded19a8c524..a5e99749d9c12cb25cd035af04398df4b30e1442 100644 (file)
@@ -314,7 +314,7 @@ public class AltosEepromDownload implements Runnable {
                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 */
index 533b1951f7c5cfdcb28840cc819d50c333a50e2a..43df705e96add4f6ff98777d586567c0db1dec8e 100644 (file)
@@ -138,7 +138,8 @@ public class AltosFlightUI extends AltosFrame implements AltosFlightDisplay, Alt
                        }
                }
                } catch (Exception e) {
-                       System.out.print("Show exception" + e);
+                       System.out.print("Show exception " + e + "\n");
+                       e.printStackTrace();
                }
        }
 
index b5cbefe73a352ae78362c3d1c4679b5eef21a8c9..dcc0de600817aab22666705581ffe42afa8de996 100644 (file)
@@ -444,6 +444,8 @@ public class AltosUI extends AltosFrame {
                //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);
                }
diff --git a/src/attiny/ao_arch.h b/src/attiny/ao_arch.h
new file mode 100644 (file)
index 0000000..c34206e
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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_ */
diff --git a/src/attiny/ao_arch_funcs.h b/src/attiny/ao_arch_funcs.h
new file mode 100644 (file)
index 0000000..8c9d1ae
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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);
+
diff --git a/src/attiny/ao_clock.c b/src/attiny/ao_clock.c
new file mode 100644 (file)
index 0000000..a381b47
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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);
+}
+
diff --git a/src/attiny/ao_eeprom_tiny.c b/src/attiny/ao_eeprom_tiny.c
new file mode 100644 (file)
index 0000000..8301418
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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++);
+}
diff --git a/src/attiny/ao_exti.c b/src/attiny/ao_exti.c
new file mode 100644 (file)
index 0000000..0ca10ca
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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);
+}
diff --git a/src/attiny/ao_exti.h b/src/attiny/ao_exti.h
new file mode 100644 (file)
index 0000000..2ea4f47
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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_ */
diff --git a/src/attiny/ao_i2c_attiny.c b/src/attiny/ao_i2c_attiny.c
new file mode 100644 (file)
index 0000000..2ee44fd
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * 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;
+}
diff --git a/src/attiny/ao_led.c b/src/attiny/ao_led.c
new file mode 100644 (file)
index 0000000..27bbea6
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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;
+}
diff --git a/src/attiny/ao_spi_attiny.c b/src/attiny/ao_spi_attiny.c
new file mode 100644 (file)
index 0000000..064876d
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * 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 */
+}
index b742d29aa6de10b73bb6d1ce8e60f756c0d7fc3f..a400b8a0a929f0485b8d8da894f43c17ec098f79 100644 (file)
@@ -44,9 +44,8 @@ ao_spi_slave_send(uint8_t *buf, uint8_t len)
 
 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
@@ -61,7 +60,6 @@ ISR(PCINT0_vect)
        } else {
                ao_spi_slave_running = 0;
        }
-       sei();
 }
 
 void
index f7b52281ae799855008bdcb1d296779e23e5024e..f80004104130c324c19cd4e68884edc4b5a208a4 100644 (file)
 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)
 {
@@ -29,7 +33,7 @@ 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
 }
@@ -141,7 +145,7 @@ ao_adc_isr(void) __interrupt 1
 #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)
index 31ec468695dc436e90176d9a53252c9688a8d872..e559e876b0209c62eece17b66785ca6e153606de 100644 (file)
 #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
@@ -136,7 +85,9 @@ ao_panic(uint8_t reason);
 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)
 
@@ -168,11 +119,13 @@ ao_clock_init(void);
  * 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
@@ -319,11 +272,13 @@ ao_temp_to_dC(int16_t temp) __reentrant;
  * 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>
index ce855ad1b51e1dcfdd6afb8d2d455fe45528e2d9..e8ff95b7f612da6da6864cfa3f838f43269adc6f 100644 (file)
@@ -102,6 +102,7 @@ _ao_config_get(void)
                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) {
@@ -131,7 +132,7 @@ _ao_config_get(void)
                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
index 0c93caea60550acd80dac0a879453774fd532050..55fe6e7da0e3a0ad5c4110b41f2722fc756bbc87 100644 (file)
 #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;
@@ -40,11 +48,12 @@ ao_pa_to_altitude(int32_t pa)
        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)
 {
@@ -70,3 +79,4 @@ ao_altitude_to_pa(int32_t alt)
                pa = 0;
        return pa;
 }
+#endif
index 972a4d4c7cad50042c9b2a82835ea70d0e18c602..7d5b1922a69a56abc29982a653c6d2a827abded9 100644 (file)
 
 #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;
@@ -49,9 +51,7 @@ main ()
 //             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);
index 30208dfbdef780852b9df5646e88630ccf23532f..6fdd19cb9b7ca88cc72d1b6fd52073cd3ac032a2 100644 (file)
@@ -52,6 +52,8 @@
 #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 {
@@ -65,6 +67,9 @@ 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;
@@ -95,6 +100,8 @@ extern volatile __data uint8_t               ao_data_count;
                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
@@ -103,7 +110,12 @@ extern volatile __data uint8_t             ao_data_count;
 #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)
 
@@ -128,6 +140,10 @@ typedef int16_t alt_t;
 
 #endif
 
+#if !HAS_BARO
+typedef int16_t alt_t;
+#endif
+
 /*
  * Need a few macros to pull data from the sensors:
  *
@@ -265,9 +281,9 @@ typedef int16_t accel_t;
 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
index 04abeb7e583ae25e296f35c25ff87e1d3a850651..eaaca444e1b504f220a89729c982f54b60804613 100644 (file)
@@ -138,17 +138,17 @@ ao_log_full(void);
 #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;
@@ -201,8 +201,7 @@ struct ao_log_mega {
                        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;
index 524330447b248b550c5ba068d2c3d74316a63ac9..3c0b471e922983e99b2356c9b4eafdbe8bb47b6d 100644 (file)
 #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)
 {
@@ -52,10 +56,10 @@ ao_panic(uint8_t reason)
        __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);
                }
@@ -66,18 +70,18 @@ ao_panic(uint8_t reason)
 #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);
                }
diff --git a/src/core/ao_task.h b/src/core/ao_task.h
new file mode 100644 (file)
index 0000000..18edd86
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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
diff --git a/src/drivers/ao_at24c.c b/src/drivers/ao_at24c.c
new file mode 100644 (file)
index 0000000..2a23be3
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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
index ab36d6f27aeacf801aeec6fe943bfea5dc84ab70..6aada9a927b9ac8da07165667fdab817cfb3b951 100644 (file)
 /* 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;
index 736e115bd560d6fa938dea948aaa3f917fd5719c..077a40e6a02e6b4478e39b9923e021df99d1f00e 100644 (file)
@@ -17,7 +17,7 @@
 
 #include <ao.h>
 #include <ao_exti.h>
-#include "ao_ms5607.h"
+#include <ao_ms5607.h>
 
 #if HAS_MS5607 || HAS_MS5611
 
@@ -27,12 +27,12 @@ static uint8_t                      ms5607_configured;
 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);
 }
 
@@ -53,7 +53,6 @@ ao_ms5607_crc(uint8_t *prom)
        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;
@@ -89,9 +88,11 @@ ao_ms5607_prom_read(struct ao_ms5607_prom *prom)
        }
        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);
        }
 
@@ -105,7 +106,7 @@ ao_ms5607_prom_read(struct ao_ms5607_prom *prom)
 #endif
 }
 
-static void
+void
 ao_ms5607_setup(void)
 {
        if (ms5607_configured)
@@ -115,33 +116,34 @@ ao_ms5607_setup(void)
        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);
@@ -165,48 +167,9 @@ ao_ms5607_sample(struct ao_ms5607_sample *sample)
        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
@@ -253,15 +216,18 @@ __code struct ao_cmds ao_ms5607_cmds[] = {
        { 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
@@ -272,12 +238,14 @@ ao_ms5607_init(void)
                      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
index 4c29f6a7448facf7d4e44c333a60108af2474146..b2f98a59d9677397fa60e6a0fa42b94c5c6a8ded 100644 (file)
@@ -58,6 +58,9 @@ struct ao_ms5607_value {
 
 extern struct ao_ms5607_sample ao_ms5607_current;
 
+void
+ao_ms5607_setup(void);
+
 void
 ao_ms5607_init(void);
 
diff --git a/src/drivers/ao_ms5607_convert.c b/src/drivers/ao_ms5607_convert.c
new file mode 100644 (file)
index 0000000..e61d19e
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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;
+}
index 55e6289d4108ca64ad0916c49e16ba9200206350..6cec98ab6e52bcc22ce3d68ee21d8579ae521973 100644 (file)
@@ -39,25 +39,63 @@ static __pdata uint8_t      ao_pad_debug;
 #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)
@@ -139,22 +177,27 @@ 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);
                }
        }
 }
@@ -181,7 +224,6 @@ ao_pad(void)
        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);
@@ -197,9 +239,6 @@ ao_pad(void)
                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) {
@@ -207,7 +246,7 @@ ao_pad(void)
                                break;
                        }
 
-                       if (command.channels & ~(AO_PAD_ALL_PINS))
+                       if (command.channels & ~(AO_PAD_ALL_CHANNELS))
                                break;
 
                        time_difference = command.tick - ao_time();
@@ -232,7 +271,7 @@ ao_pad(void)
 
                        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,
@@ -348,6 +387,12 @@ ao_pad_init(void)
 #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");
index 73ac3c03803e06425f3f711d59ff29fa6d022e28..4a37ace06c39aefd66501e79af0aea295244bd5d 100644 (file)
@@ -53,7 +53,7 @@ ao_radio_master_start(void)
 {
        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
index a93f6f1742d856ad19a36718a1590a4f04007ab1..0e0534a5036b5a47c56f29a932c4d1eea9d9196e 100644 (file)
@@ -13,7 +13,7 @@ INC = \
        ao_data.h \
        ao_sample.h \
        ao_pins.h \
-       altitude.h \
+       altitude-pa.h \
        ao_kalman.h \
        ao_product.h \
        ao_ms5607.h \
@@ -99,7 +99,7 @@ all: $(PROG)
 $(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)
diff --git a/src/micropeak/.gitignore b/src/micropeak/.gitignore
new file mode 100644 (file)
index 0000000..9146836
--- /dev/null
@@ -0,0 +1,2 @@
+ao_product.h
+micropeak-*
diff --git a/src/micropeak/Makefile b/src/micropeak/Makefile
new file mode 100644 (file)
index 0000000..e0b2b80
--- /dev/null
@@ -0,0 +1,105 @@
+#
+# 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)
diff --git a/src/micropeak/ao_async.c b/src/micropeak/ao_async.c
new file mode 100644 (file)
index 0000000..04bba9e
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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);
+       }
+}
diff --git a/src/micropeak/ao_async.h b/src/micropeak/ao_async.h
new file mode 100644 (file)
index 0000000..a06d2e1
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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_ */
diff --git a/src/micropeak/ao_log_micro.c b/src/micropeak/ao_log_micro.c
new file mode 100644 (file)
index 0000000..eda0d1d
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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
diff --git a/src/micropeak/ao_log_micro.h b/src/micropeak/ao_log_micro.h
new file mode 100644 (file)
index 0000000..15b2d17
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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_ */
diff --git a/src/micropeak/ao_micropeak.c b/src/micropeak/ao_micropeak.c
new file mode 100644 (file)
index 0000000..6ceec3b
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * 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();
+       }
+}
diff --git a/src/micropeak/ao_morse.c b/src/micropeak/ao_morse.c
new file mode 100644 (file)
index 0000000..9a7f88e
--- /dev/null
@@ -0,0 +1,95 @@
+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);
+       }
+}
+
diff --git a/src/micropeak/ao_notask.c b/src/micropeak/ao_notask.c
new file mode 100644 (file)
index 0000000..0aef9cf
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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;
+}
diff --git a/src/micropeak/ao_pins.h b/src/micropeak/ao_pins.h
new file mode 100644 (file)
index 0000000..de9fc7f
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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_ */
diff --git a/src/micropeak/ao_report_tiny.c b/src/micropeak/ao_report_tiny.c
new file mode 100644 (file)
index 0000000..5937508
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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);
+}
index d4fbea37ea8f0afe94fc8d0d44fad8b617d54d6d..e66d20d72cbc568ca9c74e443fc5a7e5d7a96112 100644 (file)
 /* 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
index eecf783e50790e29c7b20993134d85bb7eb1380e..774d59f45631ba155424df7a93f34ab48af58a76 100644 (file)
@@ -38,8 +38,8 @@
 #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_ */
index 41bba0ba090d7b23209419824369d2689cc2d411..79f3896baff9a5adcb0f96785a0b43be0b812c46 100644 (file)
@@ -43,6 +43,10 @@ static uint8_t       ao_lco_box;
 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)
@@ -71,11 +75,32 @@ ao_lco_box_present(uint8_t box)
        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();
@@ -89,26 +114,47 @@ ao_lco_input(void)
                        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;
                        }
@@ -160,10 +206,6 @@ static AO_LED_TYPE continuity_led[AO_LED_CONTINUITY_NUM] = {
 #endif
 };
 
-static uint16_t        ao_lco_tick_offset;
-
-static struct ao_pad_query     ao_pad_query;
-
 static void
 ao_lco_update(void)
 {
@@ -171,8 +213,16 @@ 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",
@@ -203,7 +253,8 @@ ao_lco_search(void)
        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)
@@ -213,7 +264,12 @@ ao_lco_search(void)
                        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;
 }
 
@@ -233,7 +289,7 @@ ao_lco_igniter_status(void)
                        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);
index db3cc04b006cd8e512e69b049ebeb914ba350767..44cee904ab642ee24d386fe37464966e6660a25f 100644 (file)
@@ -1,10 +1,13 @@
 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)
 
@@ -13,18 +16,21 @@ 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
+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 $@ $<
 
index b9e291cec1c2de71e9d53e52c04ea17cc93b34a8..0df9a5d79c0b9df7ca0a73be546f3029d59c1a82 100644 (file)
 #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
  */
@@ -48,6 +63,13 @@ struct ao_adc {
        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
@@ -58,12 +80,9 @@ struct ao_adc {
 #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))
@@ -72,7 +91,6 @@ struct ao_adc {
 /*
  * 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)
 
@@ -83,19 +101,6 @@ struct ao_adc {
 
 #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
@@ -190,7 +195,14 @@ struct ao_cmds {
 #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;
@@ -218,11 +230,11 @@ typedef int16_t   accel_t;
 
 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;
@@ -248,6 +260,10 @@ static int landed_set;
 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)
 {
@@ -285,6 +301,20 @@ 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)
 {
@@ -293,9 +323,20 @@ 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;
@@ -327,10 +368,22 @@ ao_insert(void)
                }
 
                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,
@@ -469,7 +522,6 @@ union ao_telemetry_all {
 uint16_t
 uint16(uint8_t *bytes, int off)
 {
-       off++;
        return (uint16_t) bytes[off] | (((uint16_t) bytes[off+1]) << 8);
 }
 
@@ -479,6 +531,22 @@ int16(uint8_t *bytes, int off)
        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)
 {
@@ -497,7 +565,11 @@ 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;
                        }
@@ -519,13 +591,84 @@ ao_sleep(void *wchan)
                                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]);
@@ -608,22 +751,22 @@ ao_sleep(void *wchan)
                                        }
                                } 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;
@@ -632,6 +775,8 @@ ao_sleep(void *wchan)
                        if (type != 'F' && !ao_flight_started)
                                continue;
 
+#if MEGAMETRUM
+#else
                        switch (type) {
                        case 'F':
                                ao_flight_ground_accel = a;
@@ -667,6 +812,7 @@ ao_sleep(void *wchan)
                        case 'H':
                                break;
                        }
+#endif
                }
 
        }
index eae5ebe9fcea84d81fb2b60e1bd317ee6dca7b93..22831d5091e8f3656dd1b7691455d8cacaf55b1a 100644 (file)
@@ -239,8 +239,8 @@ real sample_to_fit_altitude(int sample) {
        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;
@@ -279,11 +279,11 @@ printf ("/*max error %f at %7.3f kPa. Average error %f*/\n",
 
 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]);
 }