diff options
| author | Keith Packard <keithp@keithp.com> | 2012-10-18 15:18:52 -0700 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2012-10-18 15:18:52 -0700 | 
| commit | 5a55501660ebab3b858a48483c5df1cfb4e858e4 (patch) | |
| tree | 9b5d8305d9c65b10f82f6839bb1b5c169681ef00 /src | |
| parent | 0361235c9ef56738ba0e97be88a85afef0ce8268 (diff) | |
| parent | 440365bd17d804c2f574c35164612cf1682397d7 (diff) | |
Merge branch 'master' into mm-ms5611
Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'src')
44 files changed, 2366 insertions, 249 deletions
| diff --git a/src/attiny/ao_arch.h b/src/attiny/ao_arch.h new file mode 100644 index 00000000..c34206e6 --- /dev/null +++ b/src/attiny/ao_arch.h @@ -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 index 00000000..8c9d1ae6 --- /dev/null +++ b/src/attiny/ao_arch_funcs.h @@ -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 index 00000000..a381b47f --- /dev/null +++ b/src/attiny/ao_clock.c @@ -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 index 00000000..83014183 --- /dev/null +++ b/src/attiny/ao_eeprom_tiny.c @@ -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 index 00000000..0ca10ca4 --- /dev/null +++ b/src/attiny/ao_exti.c @@ -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 index 00000000..2ea4f47d --- /dev/null +++ b/src/attiny/ao_exti.h @@ -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 index 00000000..2ee44fd2 --- /dev/null +++ b/src/attiny/ao_i2c_attiny.c @@ -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 index 00000000..27bbea69 --- /dev/null +++ b/src/attiny/ao_led.c @@ -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 index 00000000..064876d7 --- /dev/null +++ b/src/attiny/ao_spi_attiny.c @@ -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 */ +} diff --git a/src/avr/ao_spi_slave.c b/src/avr/ao_spi_slave.c index b742d29a..a400b8a0 100644 --- a/src/avr/ao_spi_slave.c +++ b/src/avr/ao_spi_slave.c @@ -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 diff --git a/src/cc1111/ao_adc.c b/src/cc1111/ao_adc.c index f7b52281..f8000410 100644 --- a/src/cc1111/ao_adc.c +++ b/src/cc1111/ao_adc.c @@ -20,6 +20,10 @@  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) diff --git a/src/core/ao.h b/src/core/ao.h index 31ec4686..e559e876 100644 --- a/src/core/ao.h +++ b/src/core/ao.h @@ -39,64 +39,13 @@  #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> diff --git a/src/core/ao_config.c b/src/core/ao_config.c index ce855ad1..e8ff95b7 100644 --- a/src/core/ao_config.c +++ b/src/core/ao_config.c @@ -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 diff --git a/src/core/ao_convert_pa.c b/src/core/ao_convert_pa.c index 0c93caea..55fe6e7d 100644 --- a/src/core/ao_convert_pa.c +++ b/src/core/ao_convert_pa.c @@ -19,14 +19,22 @@  #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 diff --git a/src/core/ao_convert_pa_test.c b/src/core/ao_convert_pa_test.c index 972a4d4c..7d5b1922 100644 --- a/src/core/ao_convert_pa_test.c +++ b/src/core/ao_convert_pa_test.c @@ -17,15 +17,17 @@  #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); diff --git a/src/core/ao_data.h b/src/core/ao_data.h index 30208dfb..6fdd19cb 100644 --- a/src/core/ao_data.h +++ b/src/core/ao_data.h @@ -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 diff --git a/src/core/ao_log.h b/src/core/ao_log.h index 04abeb7e..eaaca444 100644 --- a/src/core/ao_log.h +++ b/src/core/ao_log.h @@ -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; diff --git a/src/core/ao_panic.c b/src/core/ao_panic.c index 52433044..3c0b471e 100644 --- a/src/core/ao_panic.c +++ b/src/core/ao_panic.c @@ -29,6 +29,10 @@  #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 index 00000000..18edd866 --- /dev/null +++ b/src/core/ao_task.h @@ -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 index 00000000..2a23be3a --- /dev/null +++ b/src/drivers/ao_at24c.c @@ -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 diff --git a/src/drivers/ao_mpu6000.h b/src/drivers/ao_mpu6000.h index ab36d6f2..6aada9a9 100644 --- a/src/drivers/ao_mpu6000.h +++ b/src/drivers/ao_mpu6000.h @@ -145,6 +145,9 @@  /* 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; diff --git a/src/drivers/ao_ms5607.c b/src/drivers/ao_ms5607.c index 736e115b..077a40e6 100644 --- a/src/drivers/ao_ms5607.c +++ b/src/drivers/ao_ms5607.c @@ -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 diff --git a/src/drivers/ao_ms5607.h b/src/drivers/ao_ms5607.h index 4c29f6a7..b2f98a59 100644 --- a/src/drivers/ao_ms5607.h +++ b/src/drivers/ao_ms5607.h @@ -59,6 +59,9 @@ struct ao_ms5607_value {  extern struct ao_ms5607_sample	ao_ms5607_current;  void +ao_ms5607_setup(void); + +void  ao_ms5607_init(void);  void diff --git a/src/drivers/ao_ms5607_convert.c b/src/drivers/ao_ms5607_convert.c new file mode 100644 index 00000000..e61d19ed --- /dev/null +++ b/src/drivers/ao_ms5607_convert.c @@ -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; +} diff --git a/src/drivers/ao_pad.c b/src/drivers/ao_pad.c index 55e6289d..6cec98ab 100644 --- a/src/drivers/ao_pad.c +++ b/src/drivers/ao_pad.c @@ -40,24 +40,62 @@ static __pdata uint8_t	ao_pad_debug;  #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, @@ -349,6 +388,12 @@ ao_pad_init(void)  #if AO_PAD_NUM > 3  	ao_enable_output(AO_PAD_PORT, AO_PAD_PIN_3, AO_PAD_3, 0);  #endif +#ifdef AO_STROBE +	ao_enable_output(AO_STROBE_PORT, AO_STROBE_PIN, AO_STROBE, 0); +#endif +#ifdef AO_SIREN +	ao_enable_output(AO_SIREN_PORT, AO_SIREN_PIN, AO_SIREN, 0); +#endif  	ao_cmd_register(&ao_pad_cmds[0]);  	ao_add_task(&ao_pad_task, ao_pad, "pad listener");  	ao_add_task(&ao_pad_ignite_task, ao_pad_run, "pad igniter"); diff --git a/src/drivers/ao_radio_master.c b/src/drivers/ao_radio_master.c index 73ac3c03..4a37ace0 100644 --- a/src/drivers/ao_radio_master.c +++ b/src/drivers/ao_radio_master.c @@ -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 diff --git a/src/megametrum-v0.1/Makefile b/src/megametrum-v0.1/Makefile index a93f6f17..0e0534a5 100644 --- a/src/megametrum-v0.1/Makefile +++ b/src/megametrum-v0.1/Makefile @@ -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 index 00000000..91468368 --- /dev/null +++ b/src/micropeak/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +micropeak-* diff --git a/src/micropeak/Makefile b/src/micropeak/Makefile new file mode 100644 index 00000000..e0b2b80d --- /dev/null +++ b/src/micropeak/Makefile @@ -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 index 00000000..04bba9e8 --- /dev/null +++ b/src/micropeak/ao_async.c @@ -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 index 00000000..a06d2e1a --- /dev/null +++ b/src/micropeak/ao_async.h @@ -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 index 00000000..eda0d1d2 --- /dev/null +++ b/src/micropeak/ao_log_micro.c @@ -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 index 00000000..15b2d178 --- /dev/null +++ b/src/micropeak/ao_log_micro.h @@ -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 index 00000000..6ceec3b5 --- /dev/null +++ b/src/micropeak/ao_micropeak.c @@ -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 index 00000000..9a7f88e5 --- /dev/null +++ b/src/micropeak/ao_morse.c @@ -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 index 00000000..0aef9cf3 --- /dev/null +++ b/src/micropeak/ao_notask.c @@ -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 index 00000000..de9fc7f2 --- /dev/null +++ b/src/micropeak/ao_pins.h @@ -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 index 00000000..5937508b --- /dev/null +++ b/src/micropeak/ao_report_tiny.c @@ -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); +} diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index d4fbea37..e66d20d7 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -21,9 +21,22 @@  /* 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 diff --git a/src/telefire-v0.1/ao_pins.h b/src/telefire-v0.1/ao_pins.h index eecf783e..774d59f4 100644 --- a/src/telefire-v0.1/ao_pins.h +++ b/src/telefire-v0.1/ao_pins.h @@ -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 @@ -74,40 +74,55 @@  #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_ */ diff --git a/src/telelco-v0.1/ao_lco.c b/src/telelco-v0.1/ao_lco.c index 41bba0ba..79f3896b 100644 --- a/src/telelco-v0.1/ao_lco.c +++ b/src/telelco-v0.1/ao_lco.c @@ -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); diff --git a/src/test/Makefile b/src/test/Makefile index db3cc04b..44cee904 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -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 $@ $< diff --git a/src/test/ao_flight_test.c b/src/test/ao_flight_test.c index b9e291ce..0df9a5d7 100644 --- a/src/test/ao_flight_test.c +++ b/src/test/ao_flight_test.c @@ -35,6 +35,21 @@  #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  		}  	} diff --git a/src/util/make-altitude-pa b/src/util/make-altitude-pa index eae5ebe9..22831d50 100644 --- a/src/util/make-altitude-pa +++ b/src/util/make-altitude-pa @@ -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]);  } | 
