From 50dd268a715224a01f8a6b481670a4ae6621cb28 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 20 Mar 2013 23:21:37 -0700 Subject: Add telegps initial version Just lights up the GPS and USB Signed-off-by: Keith Packard --- src/telegps-v0.1/.gitignore | 2 + src/telegps-v0.1/Makefile | 79 +++++++++++++++++++++ src/telegps-v0.1/ao_pins.h | 158 ++++++++++++++++++++++++++++++++++++++++++ src/telegps-v0.1/ao_telegps.c | 56 +++++++++++++++ 4 files changed, 295 insertions(+) create mode 100644 src/telegps-v0.1/.gitignore create mode 100644 src/telegps-v0.1/Makefile create mode 100644 src/telegps-v0.1/ao_pins.h create mode 100644 src/telegps-v0.1/ao_telegps.c (limited to 'src') diff --git a/src/telegps-v0.1/.gitignore b/src/telegps-v0.1/.gitignore new file mode 100644 index 00000000..b1e261f5 --- /dev/null +++ b/src/telegps-v0.1/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +telegps-*.elf diff --git a/src/telegps-v0.1/Makefile b/src/telegps-v0.1/Makefile new file mode 100644 index 00000000..48caee4d --- /dev/null +++ b/src/telegps-v0.1/Makefile @@ -0,0 +1,79 @@ +# +# AltOS build +# +# + +include ../stm/Makefile.defs + +INC = \ + ao.h \ + ao_arch.h \ + ao_arch_funcs.h \ + ao_pins.h \ + ao_product.h \ + ao_task.h \ + ao_whiten.h \ + stm32l.h \ + Makefile + +#PROFILE=ao_profile.c +#PROFILE_DEF=-DAO_PROFILE=1 + +#SAMPLE_PROFILE=ao_sample_profile.c \ +# ao_sample_profile_timer.c +#SAMPLE_PROFILE_DEF=-DHAS_SAMPLE_PROFILE=1 + +#STACK_GUARD=ao_mpu_stm.c +#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1 + +ALTOS_SRC = \ + ao_interrupt.c \ + ao_product.c \ + ao_romconfig.c \ + ao_cmd.c \ + ao_config.c \ + ao_task.c \ + ao_led.c \ + ao_stdio.c \ + ao_panic.c \ + ao_timer.c \ + ao_mutex.c \ + ao_freq.c \ + ao_dma_stm.c \ + ao_spi_stm.c \ + ao_usb_stm.c \ + ao_exti_stm.c \ + ao_serial_stm.c \ + ao_gps_skytraq.c + +PRODUCT=TeleGPS-v0.1 +PRODUCT_DEF=-DTELEGPS +IDPRODUCT=0x0024 + +CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g + +PROGNAME=telegps-v0.1 +PROG=$(PROGNAME)-$(VERSION).elf + +SRC=$(ALTOS_SRC) ao_telegps.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) + +$(PROG): Makefile $(OBJ) altos.ld + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean: clean + +clean: + rm -f *.o $(PROGNAME)-*.elf + rm -f ao_product.h + +install: + +uninstall: diff --git a/src/telegps-v0.1/ao_pins.h b/src/telegps-v0.1/ao_pins.h new file mode 100644 index 00000000..77b2373d --- /dev/null +++ b/src/telegps-v0.1/ao_pins.h @@ -0,0 +1,158 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define HAS_TASK_QUEUE 1 + +/* 8MHz High speed external crystal */ +#define AO_HSE 8000000 + +/* PLLVCO = 96MHz (so that USB will work) */ +#define AO_PLLMUL 12 +#define AO_RCC_CFGR_PLLMUL (STM_RCC_CFGR_PLLMUL_12) + +/* SYSCLK = 32MHz (no need to go faster than CPU) */ +#define AO_PLLDIV 3 +#define AO_RCC_CFGR_PLLDIV (STM_RCC_CFGR_PLLDIV_3) + +/* HCLK = 32MHz (CPU clock) */ +#define AO_AHB_PRESCALER 1 +#define AO_RCC_CFGR_HPRE_DIV STM_RCC_CFGR_HPRE_DIV_1 + +/* Run APB1 at 16MHz (HCLK/2) */ +#define AO_APB1_PRESCALER 2 +#define AO_RCC_CFGR_PPRE1_DIV STM_RCC_CFGR_PPRE2_DIV_2 + +/* Run APB2 at 16MHz (HCLK/2) */ +#define AO_APB2_PRESCALER 2 +#define AO_RCC_CFGR_PPRE2_DIV STM_RCC_CFGR_PPRE2_DIV_2 + +#define HAS_SERIAL_1 1 +#define USE_SERIAL_1_STDIN 0 +#define SERIAL_1_PB6_PB7 1 +#define SERIAL_1_PA9_PA10 0 + +#define HAS_SERIAL_2 1 +#define USE_SERIAL_2_STDIN 0 +#define SERIAL_2_PA2_PA3 1 +#define SERIAL_2_PD5_PD6 0 + +#define HAS_SERIAL_3 0 +#define USE_SERIAL_3_STDIN 0 +#define SERIAL_3_PB10_PB11 0 +#define SERIAL_3_PC10_PC11 1 +#define SERIAL_3_PD8_PD9 0 + +#define ao_gps_getchar ao_serial2_getchar +#define ao_gps_putchar ao_serial2_putchar +#define ao_gps_set_speed ao_serial2_set_speed +#define ao_gps_fifo (ao_stm_usart2.rx_fifo) + +#define HAS_EEPROM 0 +#define USE_INTERNAL_FLASH 0 +#define HAS_USB 1 +#define HAS_BEEP 0 +#define HAS_RADIO 0 +#define HAS_TELEMETRY 0 + +#define HAS_SPI_1 0 +#define SPI_1_PA5_PA6_PA7 0 +#define SPI_1_PB3_PB4_PB5 0 +#define SPI_1_PE13_PE14_PE15 0 + +#define HAS_SPI_2 1 +#define SPI_2_PB13_PB14_PB15 1 /* CC115L */ +#define SPI_2_PD1_PD3_PD4 0 +#define SPI_2_OSPEEDR STM_OSPEEDR_10MHz + +#define SPI_2_PORT (&stm_gpiob) +#define SPI_2_SCK_PIN 13 +#define SPI_2_MISO_PIN 14 +#define SPI_2_MOSI_PIN 15 + +#define HAS_I2C_1 0 +#define I2C_1_PB8_PB9 1 + +#define HAS_I2C_2 0 +#define I2C_2_PB10_PB11 1 + +#define PACKET_HAS_SLAVE 0 +#define PACKET_HAS_MASTER 0 + +#define LOW_LEVEL_DEBUG 0 + +#define LED_PORT_0_ENABLE STM_RCC_AHBENR_GPIOAEN +#define LED_PORT_0 (&stm_gpioa) +#define LED_PORT_0_MASK (0xff) +#define LED_PORT_0_SHIFT 0 +#define LED_PIN_RED 0 +#define LED_PIN_GREEN 2 +#define AO_LED_RED (1 << LED_PIN_RED) +#define AO_LED_GREEN (1 << LED_PIN_GREEN) + +#define LEDS_AVAILABLE (AO_LED_RED | AO_LED_GREEN) + +#define HAS_GPS 0 +#define HAS_FLIGHT 0 +#define HAS_ADC 0 +#define HAS_LOG 0 + +/* + * Telemetry monitoring + */ +#define HAS_MONITOR 0 +#define LEGACY_MONITOR 0 +#define HAS_MONITOR_PUT 0 +#define AO_MONITOR_LED AO_LED_GREEN + +/* + * Radio (cc115) + */ + +/* gets pretty close to 434.550 */ + +#define AO_RADIO_CAL_DEFAULT 0x6ca333 + +#define AO_FEC_DEBUG 0 +#define AO_CC1120_SPI_CS_PORT (&stm_gpioa) +#define AO_CC1120_SPI_CS_PIN 0 +#define AO_CC1120_SPI_BUS AO_SPI_2_PB13_PB14_PB15 +#define AO_CC1120_SPI stm_spi2 + +#define AO_CC1120_INT_PORT (&stm_gpioc) +#define AO_CC1120_INT_PIN 13 + +#define AO_CC1120_MCU_WAKEUP_PORT (&stm_gpioc) +#define AO_CC1120_MCU_WAKEUP_PIN (0) + +#define AO_CC1120_INT_GPIO 2 +#define AO_CC1120_INT_GPIO_IOCFG CC1120_IOCFG2 + +#define AO_CC1120_MARC_GPIO 3 +#define AO_CC1120_MARC_GPIO_IOCFG CC1120_IOCFG3 + +/* + * Profiling Viterbi decoding + */ + +#ifndef AO_PROFILE +#define AO_PROFILE 0 +#endif + +#endif /* _AO_PINS_H_ */ diff --git a/src/telegps-v0.1/ao_telegps.c b/src/telegps-v0.1/ao_telegps.c new file mode 100644 index 00000000..9865674d --- /dev/null +++ b/src/telegps-v0.1/ao_telegps.c @@ -0,0 +1,56 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include + +int +main(void) +{ + ao_clock_init(); + +#if HAS_STACK_GUARD + ao_mpu_init(); +#endif + + ao_task_init(); +// ao_led_init(LEDS_AVAILABLE); +// ao_led_on(AO_LED_RED); + ao_timer_init(); + + ao_spi_init(); + ao_dma_init(); + ao_exti_init(); + + ao_serial_init(); + + ao_cmd_init(); + + ao_usb_init(); +// ao_radio_init(); +// ao_monitor_init(); +// ao_rssi_init(AO_LED_RED); +// ao_packet_master_init(); +// ao_send_packet_init(); + + ao_gps_init(); + + ao_config_init(); + + ao_start_scheduler(); + return 0; +} -- cgit v1.2.3 From 4ddfb3ea07c2073f8c4d79feaf262c9fb910cfce Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 24 Mar 2013 23:51:11 -0700 Subject: altos: Add cc115l driver (untested) Includes support for sending telemetry, RDF and APRS tones Signed-off-by: Keith Packard --- src/drivers/ao_cc115l.c | 796 +++++++++++++++++++++++++++++++++++++++++++++ src/drivers/ao_cc115l.h | 225 +++++++++++++ src/drivers/ao_rf_cc115l.h | 49 +++ 3 files changed, 1070 insertions(+) create mode 100644 src/drivers/ao_cc115l.c create mode 100644 src/drivers/ao_cc115l.h create mode 100644 src/drivers/ao_rf_cc115l.h (limited to 'src') diff --git a/src/drivers/ao_cc115l.c b/src/drivers/ao_cc115l.c new file mode 100644 index 00000000..fd8bb1f0 --- /dev/null +++ b/src/drivers/ao_cc115l.c @@ -0,0 +1,796 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include +#include + +#define AO_RADIO_MAX_SEND sizeof (struct ao_telemetry_generic) + +static uint8_t ao_radio_mutex; + +static uint8_t ao_radio_wake; /* radio ready. Also used as sleep address */ +static uint8_t ao_radio_abort; /* radio operation should abort */ +static uint8_t ao_radio_mcu_wake; /* MARC status change */ +static uint8_t ao_radio_marcstate; /* Last read MARC state value */ + +#define CC115L_DEBUG AO_FEC_DEBUG +#define CC115L_TRACE 1 + +extern const uint32_t ao_radio_cal; + +#define FOSC 26000000 + +#define ao_radio_select() ao_spi_get_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS,AO_SPI_SPEED_4MHz) +#define ao_radio_deselect() ao_spi_put_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS) +#define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC115L_SPI_BUS) +#define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC115L_SPI_BUS) +#define ao_radio_spi_recv(d,l) ao_spi_recv((d), (l), AO_CC115L_SPI_BUS) +#define ao_radio_duplex(o,i,l) ao_spi_duplex((o), (i), (l), AO_CC115L_SPI_BUS) + +static uint8_t +ao_radio_reg_read(uint16_t addr) +{ + uint8_t datao[2], datai[2]; + uint8_t d; + +#if CC115L_TRACE + printf("\t\tao_radio_reg_read (%04x): ", addr); flush(); +#endif + datao[0] = ((1 << CC115L_READ) | + (0 << CC115L_BURST) | + addr); + ao_radio_select(); + ao_radio_duplex(datao, datai, 2); + ao_radio_deselect(); +#if CC115L_TRACE + printf (" %02x\n", datai[1]); +#endif + return datai[1]; +} + +static void +ao_radio_reg_write(uint16_t addr, uint8_t value) +{ + uint8_t data[2]; + uint8_t d; + +#if CC115L_TRACE + printf("\t\tao_radio_reg_write (%04x): %02x\n", addr, value); +#endif + data[0] = ((0 << CC115L_READ) | + (0 << CC115L_BURST) | + addr); + data[1] = value; + ao_radio_select(); + ao_radio_spi_send(data, 2); + ao_radio_deselect(); +} + +static void +ao_radio_burst_read_start (uint16_t addr) +{ + uint8_t data[1]; + uint8_t d; + + data[0] = ((1 << CC115L_READ) | + (1 << CC115L_BURST) | + addr); + ao_radio_select(); + ao_radio_spi_send(data, 1); +} + +static void +ao_radio_burst_read_stop (void) +{ + ao_radio_deselect(); +} + + +static uint8_t +ao_radio_strobe(uint8_t addr) +{ + uint8_t in; + +#if CC115L_TRACE + printf("\t\tao_radio_strobe (%02x): ", addr); flush(); +#endif + ao_radio_select(); + ao_radio_duplex(&addr, &in, 1); + ao_radio_deselect(); +#if CC115L_TRACE + printf("%02x\n", in); flush(); +#endif + return in; +} + +static uint8_t +ao_radio_fifo_write_start(void) +{ + uint8_t addr = ((0 << CC115L_READ) | + (1 << CC115L_BURST) | + CC115L_FIFO); + uint8_t status; + + ao_radio_select(); + ao_radio_duplex(&addr, &status, 1); + return status; +} + +static inline uint8_t ao_radio_fifo_write_stop(uint8_t status) { + ao_radio_deselect(); + return status; +} + +static uint8_t +ao_radio_fifo_write(uint8_t *data, uint8_t len) +{ + uint8_t status = ao_radio_fifo_write_start(); + ao_radio_spi_send(data, len); + return ao_radio_fifo_write_stop(status); +} + +static uint8_t +ao_radio_fifo_write_fixed(uint8_t data, uint8_t len) +{ + uint8_t status = ao_radio_fifo_write_start(); + ao_radio_spi_send_fixed(data, len); + return ao_radio_fifo_write_stop(status); +} + +static uint8_t +ao_radio_tx_fifo_space(void) +{ + return CC115L_FIFO_SIZE - (ao_radio_reg_read(CC115L_TXBYTES) & CC115L_TXBYTES_NUM_TX_BYTES_MASK); +} + +static uint8_t +ao_radio_status(void) +{ + return ao_radio_strobe (CC115L_SNOP); +} + +#define ao_radio_rdf_value 0x55 + +static uint8_t +ao_radio_get_marcstate(void) +{ + return ao_radio_reg_read(CC115L_MARCSTATE) & CC115L_MARCSTATE_MASK; +} + +static void +ao_radio_mcu_wakeup_isr(void) +{ + ao_radio_mcu_wake = 1; + ao_wakeup(&ao_radio_wake); +} + + +static void +ao_radio_check_marcstate(void) +{ + ao_radio_mcu_wake = 0; + ao_radio_marcstate = ao_radio_get_marcstate(); + + /* Anyt other than 'tx finished' means an error occurred */ + if (ao_radio_marcstate != CC115L_MARCSTATE_TX_END) + ao_radio_abort = 1; +} + +static void +ao_radio_isr(void) +{ + ao_exti_disable(AO_CC115L_INT_PORT, AO_CC115L_INT_PIN); + ao_radio_wake = 1; + ao_wakeup(&ao_radio_wake); +} + +static void +ao_radio_start_tx(void) +{ + ao_exti_set_callback(AO_CC115L_INT_PORT, AO_CC115L_INT_PIN, ao_radio_isr); + ao_exti_enable(AO_CC115L_INT_PORT, AO_CC115L_INT_PIN); + ao_exti_enable(AO_CC115L_MCU_WAKEUP_PORT, AO_CC115L_MCU_WAKEUP_PIN); + ao_radio_strobe(CC115L_STX); +} + +static void +ao_radio_idle(void) +{ + for (;;) { + uint8_t state = ao_radio_strobe(CC115L_SIDLE); + if ((state >> CC115L_STATUS_STATE) == CC115L_STATUS_STATE_IDLE) + break; + } + /* Flush any pending TX bytes */ + ao_radio_strobe(CC115L_SFTX); +} + +/* + * Packet deviation is 20.5kHz + * + * fdev = fosc >> 17 * (8 + dev_m) << dev_e + * + * 26e6 / (2 ** 17) * (8 + 5) * (2 ** 3) = 20630Hz + */ + +#define PACKET_DEV_E 3 +#define PACKET_DEV_M 5 + +/* + * For our packet data, set the symbol rate to 38400 Baud + * + * (256 + DATARATE_M) * 2 ** DATARATE_E + * Rdata = -------------------------------------- * fosc + * 2 ** 28 + * + * (256 + 131) * (2 ** 10) / (2**28) * 26e6 = 38383 + * + * DATARATE_M = 131 + * DATARATE_E = 10 + */ +#define PACKET_DRATE_E 10 +#define PACKET_DRATE_M 131 + +static const uint16_t packet_setup[] = { + CC115L_DEVIATN, ((PACKET_DEV_E << CC115L_DEVIATN_DEVIATION_E) | + (PACKET_DEV_M << CC115L_DEVIATN_DEVIATION_M)), + CC115L_MDMCFG4, ((0xf << 4) | + (PACKET_DRATE_E << CC115L_MDMCFG4_DRATE_E)), + CC115L_MDMCFG3, (PACKET_DRATE_M), +}; + + +/* + * RDF deviation is 5kHz + * + * fdev = fosc >> 17 * (8 + dev_m) << dev_e + * + * 26e6 / (2 ** 17) * (8 + 4) * (2 ** 1) = 4761Hz + */ + +#define RDF_DEV_E 1 +#define RDF_DEV_M 4 + +/* + * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone) + * + * (256 + DATARATE_M) * 2 ** DATARATE_E + * Rdata = -------------------------------------- * fosc + * 2 ** 28 + * + * (256 + 67) * (2 ** 6) / (2**28) * 26e6 = 2002 + * + * DATARATE_M = 67 + * DATARATE_E = 6 + * + * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes + */ +#define RDF_DRATE_E 6 +#define RDF_DRATE_M 67 +#define RDF_PACKET_LEN 50 + +static const uint16_t rdf_setup[] = { + CC115L_DEVIATN, ((RDF_DEV_E << CC115L_DEVIATN_DEVIATION_E) | + (RDF_DEV_M << CC115L_DEVIATN_DEVIATION_M)), + CC115L_MDMCFG4, ((0xf << 4) | + (RDF_DRATE_E << CC115L_MDMCFG4_DRATE_E)), + CC115L_MDMCFG3, (RDF_DRATE_M), +}; + +/* + * APRS deviation is the same as RDF + */ + +#define APRS_DEV_E RDF_DEV_E +#define APRS_DEV_M RDF_DEV_E + +/* + * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate) + * + * (256 + DATARATE_M) * 2 ** DATARATE_E + * Rdata = -------------------------------------- * fosc + * 2 ** 28 + * + * (256 + 131) * (2 ** 8) / (2**28) * 26e6 = 9596 + * + * DATARATE_M = 131 + * DATARATE_E = 8 + * + */ +#define APRS_DRATE_E 8 +#define APRS_DRATE_M 131 + +static const uint16_t aprs_setup[] = { + CC115L_DEVIATN, ((APRS_DEV_E << CC115L_DEVIATN_DEVIATION_E) | + (APRS_DEV_M << CC115L_DEVIATN_DEVIATION_M)), + CC115L_MDMCFG4, ((0xf << 4) | + (APRS_DRATE_E << CC115L_MDMCFG4_DRATE_E)), + CC115L_MDMCFG3, (APRS_DRATE_M), +}; + +#define AO_PKTCTRL0_INFINITE ((CC115L_PKTCTRL0_PKT_FORMAT_NORMAL << CC115L_PKTCTRL0_PKT_FORMAT) | \ + (0 << CC115L_PKTCTRL0_PKT_CRC_EN) | \ + (CC115L_PKTCTRL0_PKT_LENGTH_CONFIG_INFINITE << CC115L_PKTCTRL0_PKT_LENGTH_CONFIG)) +#define AO_PKTCTRL0_FIXED ((CC115L_PKTCTRL0_PKT_FORMAT_NORMAL << CC115L_PKTCTRL0_PKT_FORMAT) | \ + (0 << CC115L_PKTCTRL0_PKT_CRC_EN) | \ + (CC115L_PKTCTRL0_PKT_LENGTH_CONFIG_FIXED << CC115L_PKTCTRL0_PKT_LENGTH_CONFIG)) + +static uint16_t ao_radio_mode; + +#define AO_RADIO_MODE_BITS_PACKET_TX 1 +#define AO_RADIO_MODE_BITS_TX_BUF 2 +#define AO_RADIO_MODE_BITS_TX_FINISH 4 +#define AO_RADIO_MODE_BITS_RDF 8 +#define AO_RADIO_MODE_BITS_APRS 16 +#define AO_RADIO_MODE_BITS_INFINITE 32 +#define AO_RADIO_MODE_BITS_FIXED 64 + +#define AO_RADIO_MODE_NONE 0 +#define AO_RADIO_MODE_PACKET_TX_BUF (AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_BUF) +#define AO_RADIO_MODE_PACKET_TX_FINISH (AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_FINISH) +#define AO_RADIO_MODE_RDF (AO_RADIO_MODE_BITS_RDF | AO_RADIO_MODE_BITS_TX_FINISH) +#define AO_RADIO_MODE_APRS_BUF (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF) +#define AO_RADIO_MODE_APRS_LAST_BUF (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_BUF) +#define AO_RADIO_MODE_APRS_FINISH (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_FINISH) + +static void +ao_radio_set_mode(uint16_t new_mode) +{ + uint16_t changes; + int i; + + if (new_mode == ao_radio_mode) + return; + + changes = new_mode & (~ao_radio_mode); + if (changes & AO_RADIO_MODE_BITS_PACKET_TX) + for (i = 0; i < sizeof (packet_setup) / sizeof (packet_setup[0]); i += 2) + ao_radio_reg_write(packet_setup[i], packet_setup[i+1]); + + if (changes & AO_RADIO_MODE_BITS_TX_BUF) + ao_radio_reg_write(AO_CC115L_INT_GPIO_IOCFG, CC115L_IOCFG_GPIO_CFG_TXFIFO_THR); + + if (changes & AO_RADIO_MODE_BITS_TX_FINISH) + ao_radio_reg_write(AO_CC115L_INT_GPIO_IOCFG, CC115L_IOCFG_GPIO_CFG_PKT_SYNC_TX | (1 << CC115L_IOCFG_GPIO_INV)); + + if (changes & AO_RADIO_MODE_BITS_RDF) + for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2) + ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]); + + if (changes & AO_RADIO_MODE_BITS_APRS) + for (i = 0; i < sizeof (aprs_setup) / sizeof (aprs_setup[0]); i += 2) + ao_radio_reg_write(aprs_setup[i], aprs_setup[i+1]); + + if (changes & AO_RADIO_MODE_BITS_INFINITE) + ao_radio_reg_write(CC115L_PKTCTRL0, AO_PKTCTRL0_INFINITE); + + if (changes & AO_RADIO_MODE_BITS_FIXED) + ao_radio_reg_write(CC115L_PKTCTRL0, AO_PKTCTRL0_FIXED); + + ao_radio_mode = new_mode; +} + +static const uint16_t radio_setup[] = { +#include "ao_rf_cc115l.h" +}; + +static uint8_t ao_radio_configured = 0; + +static void +ao_radio_setup(void) +{ + int i; + + ao_radio_strobe(CC115L_SRES); + + for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2) + ao_radio_reg_write(radio_setup[i], radio_setup[i+1]); + + ao_radio_mode = 0; + + ao_config_get(); + + ao_radio_configured = 1; +} + +static void +ao_radio_set_len(uint8_t len) +{ + static uint8_t last_len; + + if (len != last_len) { + ao_radio_reg_write(CC115L_PKTLEN, len); + last_len = len; + } +} + +static void +ao_radio_get(uint8_t len) +{ + static uint32_t last_radio_setting; + + ao_mutex_get(&ao_radio_mutex); + if (!ao_radio_configured) + ao_radio_setup(); + if (ao_config.radio_setting != last_radio_setting) { + ao_radio_reg_write(CC115L_FREQ2, ao_config.radio_setting >> 16); + ao_radio_reg_write(CC115L_FREQ1, ao_config.radio_setting >> 8); + ao_radio_reg_write(CC115L_FREQ0, ao_config.radio_setting); + last_radio_setting = ao_config.radio_setting; + } + ao_radio_set_len(len); +} + +#define ao_radio_put() ao_mutex_put(&ao_radio_mutex) + +static void +ao_rdf_start(uint8_t len) +{ + ao_radio_abort = 0; + ao_radio_get(len); + + ao_radio_set_mode(AO_RADIO_MODE_RDF); + ao_radio_wake = 0; + +} + +static void +ao_rdf_run(void) +{ + ao_radio_start_tx(); + + ao_arch_block_interrupts(); + while (!ao_radio_wake && !ao_radio_abort && !ao_radio_mcu_wake) + ao_sleep(&ao_radio_wake); + ao_arch_release_interrupts(); + if (ao_radio_mcu_wake) + ao_radio_check_marcstate(); + if (!ao_radio_wake) + ao_radio_idle(); + ao_radio_put(); +} + +void +ao_radio_rdf(void) +{ + ao_rdf_start(AO_RADIO_RDF_LEN); + + ao_radio_fifo_write_fixed(ao_radio_rdf_value, AO_RADIO_RDF_LEN); + + ao_rdf_run(); +} + +void +ao_radio_continuity(uint8_t c) +{ + uint8_t i; + uint8_t status; + + ao_rdf_start(AO_RADIO_CONT_TOTAL_LEN); + + status = ao_radio_fifo_write_start(); + for (i = 0; i < 3; i++) { + ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN); + if (i < c) + ao_radio_spi_send_fixed(ao_radio_rdf_value, AO_RADIO_CONT_TONE_LEN); + else + ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_TONE_LEN); + } + ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN); + status = ao_radio_fifo_write_stop(status); + (void) status; + ao_rdf_run(); +} + +void +ao_radio_rdf_abort(void) +{ + ao_radio_abort = 1; + ao_wakeup(&ao_radio_wake); +} + +static void +ao_radio_test_cmd(void) +{ + uint8_t mode = 2; + static uint8_t radio_on; + ao_cmd_white(); + if (ao_cmd_lex_c != '\n') { + ao_cmd_decimal(); + mode = (uint8_t) ao_cmd_lex_u32; + } + mode++; + if ((mode & 2) && !radio_on) { +#if HAS_MONITOR + ao_monitor_disable(); +#endif +#if PACKET_HAS_SLAVE + ao_packet_slave_stop(); +#endif + ao_radio_get(0xff); + ao_radio_strobe(CC115L_STX); +#if CC115L_TRACE + { int t; + for (t = 0; t < 10; t++) { + printf ("status: %02x\n", ao_radio_status()); + ao_delay(AO_MS_TO_TICKS(100)); + } + } +#endif + radio_on = 1; + } + if (mode == 3) { + printf ("Hit a character to stop..."); flush(); + getchar(); + putchar('\n'); + } + if ((mode & 1) && radio_on) { + ao_radio_idle(); + ao_radio_put(); + radio_on = 0; +#if HAS_MONITOR + ao_monitor_enable(); +#endif + } +} + +static void +ao_radio_wait_isr(void) +{ + ao_arch_block_interrupts(); + while (!ao_radio_wake && !ao_radio_mcu_wake && !ao_radio_abort) + ao_sleep(&ao_radio_wake); + ao_arch_release_interrupts(); + if (ao_radio_mcu_wake) + ao_radio_check_marcstate(); +} + +static uint8_t +ao_radio_wait_tx(uint8_t wait_fifo) +{ + uint8_t fifo_space = 0; + + do { + ao_radio_wait_isr(); + if (!wait_fifo) + return 0; + fifo_space = ao_radio_tx_fifo_space(); + } while (!fifo_space && !ao_radio_abort); + return fifo_space; +} + +static uint8_t tx_data[(AO_RADIO_MAX_SEND + 4) * 2]; + +void +ao_radio_send(const void *d, uint8_t size) +{ + uint8_t marc_status; + uint8_t *e = tx_data; + uint8_t encode_len; + uint8_t this_len; + uint8_t started = 0; + uint8_t fifo_space; + + encode_len = ao_fec_encode(d, size, tx_data); + + ao_radio_get(encode_len); + + started = 0; + fifo_space = CC115L_FIFO_SIZE; + while (encode_len) { + this_len = encode_len; + + ao_radio_wake = 0; + if (this_len > fifo_space) { + this_len = fifo_space; + ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_BUF); + } else { + ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_FINISH); + } + + ao_radio_fifo_write(e, this_len); + e += this_len; + encode_len -= this_len; + + if (!started) { + ao_radio_start_tx(); + started = 1; + } else { + ao_exti_enable(AO_CC115L_INT_PORT, AO_CC115L_INT_PIN); + } + + fifo_space = ao_radio_wait_tx(encode_len != 0); + if (ao_radio_abort) { + ao_radio_idle(); + break; + } + } + ao_radio_put(); +} + +#define AO_RADIO_LOTS 64 + +void +ao_radio_send_lots(ao_radio_fill_func fill) +{ + uint8_t buf[AO_RADIO_LOTS], *b; + int cnt; + int total = 0; + uint8_t done = 0; + uint8_t started = 0; + uint8_t fifo_space; + + ao_radio_get(0xff); + fifo_space = CC115L_FIFO_SIZE; + while (!done) { + cnt = (*fill)(buf, sizeof(buf)); + if (cnt < 0) { + done = 1; + cnt = -cnt; + } + total += cnt; + + /* At the last buffer, set the total length */ + if (done) + ao_radio_set_len(total & 0xff); + + b = buf; + while (cnt) { + uint8_t this_len = cnt; + + /* Wait for some space in the fifo */ + while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) { + ao_radio_wake = 0; + ao_radio_wait_isr(); + } + if (ao_radio_abort) + break; + if (this_len > fifo_space) + this_len = fifo_space; + + cnt -= this_len; + + if (done) { + if (cnt) + ao_radio_set_mode(AO_RADIO_MODE_APRS_LAST_BUF); + else + ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH); + } else + ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF); + + ao_radio_fifo_write(b, this_len); + b += this_len; + + if (!started) { + ao_radio_start_tx(); + started = 1; + } else + ao_exti_enable(AO_CC115L_INT_PORT, AO_CC115L_INT_PIN); + } + if (ao_radio_abort) { + ao_radio_idle(); + break; + } + /* Wait for the transmitter to go idle */ + ao_radio_wake = 0; + ao_radio_wait_isr(); + } + ao_radio_put(); +} + +static char *cc115l_state_name[] = { + [CC115L_STATUS_STATE_IDLE] = "IDLE", + [CC115L_STATUS_STATE_TX] = "TX", + [CC115L_STATUS_STATE_FSTXON] = "FSTXON", + [CC115L_STATUS_STATE_CALIBRATE] = "CALIBRATE", + [CC115L_STATUS_STATE_SETTLING] = "SETTLING", + [CC115L_STATUS_STATE_TX_FIFO_UNDERFLOW] = "TX_FIFO_UNDERFLOW", +}; + +static void ao_radio_show(void) { + uint8_t status = ao_radio_status(); + int i; + + ao_radio_get(0xff); + status = ao_radio_status(); + printf ("Status: %02x\n", status); + printf ("CHIP_RDY: %d\n", (status >> CC115L_STATUS_CHIP_RDY) & 1); + printf ("STATE: %s\n", cc115l_state_name[(status >> CC115L_STATUS_STATE) & CC115L_STATUS_STATE_MASK]); + printf ("MARC: %02x\n", ao_radio_get_marcstate()); + + ao_radio_put(); +} + +static void ao_radio_beep(void) { + ao_radio_rdf(); +} + +static void ao_radio_packet(void) { + static const uint8_t packet[] = { +#if 1 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +#else + 3, 1, 2, 3 +#endif + }; + + ao_radio_send(packet, sizeof (packet)); +} + +#if HAS_APRS +#include + +static void +ao_radio_aprs() +{ + ao_packet_slave_stop(); + ao_aprs_send(); +} +#endif + +static const struct ao_cmds ao_radio_cmds[] = { + { ao_radio_test_cmd, "C <1 start, 0 stop, none both>\0Radio carrier test" }, +#if CC115L_DEBUG +#if HAS_APRS + { ao_radio_aprs, "G\0Send APRS packet" }, +#endif + { ao_radio_show, "R\0Show CC115L status" }, + { ao_radio_beep, "b\0Emit an RDF beacon" }, + { ao_radio_packet, "p\0Send a test packet" }, +#endif + { 0, NULL } +}; + +void +ao_radio_init(void) +{ + int i; + + ao_radio_configured = 0; + ao_spi_init_cs (AO_CC115L_SPI_CS_PORT, (1 << AO_CC115L_SPI_CS_PIN)); + +#if 0 + AO_CC115L_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC115L_SPI_CS_PIN)); + for (i = 0; i < 10000; i++) { + if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0) + break; + } + AO_CC115L_SPI_CS_PORT->bsrr = (1 << AO_CC115L_SPI_CS_PIN); + if (i == 10000) + ao_panic(AO_PANIC_SELF_TEST_CC115L); +#endif + + /* Enable the EXTI interrupt for the appropriate pin */ + ao_enable_port(AO_CC115L_INT_PORT); + ao_exti_setup(AO_CC115L_INT_PORT, AO_CC115L_INT_PIN, + AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH, + ao_radio_isr); + + /* Enable the hacked up GPIO3 pin */ + ao_enable_port(AO_CC115L_MCU_WAKEUP_PORT); + ao_exti_setup(AO_CC115L_MCU_WAKEUP_PORT, AO_CC115L_MCU_WAKEUP_PIN, + AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED, + ao_radio_mcu_wakeup_isr); + + ao_cmd_register(&ao_radio_cmds[0]); +} diff --git a/src/drivers/ao_cc115l.h b/src/drivers/ao_cc115l.h new file mode 100644 index 00000000..34e3f0ba --- /dev/null +++ b/src/drivers/ao_cc115l.h @@ -0,0 +1,225 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_CC115L_H_ +#define _AO_CC115L_H_ + +#define CC115L_BURST 6 +#define CC115L_READ 7 + +/* Register space */ +#define CC115L_IOCFG2 0x00 /* GDO2 Output Pin Configuration */ +#define CC115L_IOCFG1 0x01 /* GDO1 Output Pin Configuration */ +#define CC115L_IOCFG0 0x02 /* GDO0 Output Pin Configuration */ + +#define CC115L_IOCFG_GPIO1_DS 7 +#define CC115L_IOCFG_GPIO_INV 6 + +#define CC115L_IOCFG_GPIO_CFG 0 +#define CC115L_IOCFG_GPIO_CFG_TXFIFO_THR 2 +#define CC115L_IOCFG_GPIO_CFG_TXFIFO_THR_PKT 3 +#define CC115L_IOCFG_GPIO_CFG_TXFIFO_UNDERFLOW 5 +#define CC115L_IOCFG_GPIO_CFG_PKT_SYNC_TX 6 +#define CC115L_IOCFG_GPIO_CFG_PLL_LOCKED 10 +#define CC115L_IOCFG_GPIO_CFG_SERIAL_CLK 11 +#define CC115L_IOCFG_GPIO_CFG_SYNC_DATA 12 +#define CC115L_IOCFG_GPIO_CFG_ASYNC_DATA 13 +#define CC115L_IOCFG_GPIO_CFG_PA_PD 27 +#define CC115L_IOCFG_GPIO_CFG_CHIP_RDYn 41 +#define CC115L_IOCFG_GPIO_CFG_XOSC_STABLE 43 +#define CC115L_IOCFG_GPIO_CFG_HIGHZ 46 +#define CC115L_IOCFG_GPIO_CFG_HW_0 47 +#define CC115L_IOCFG_GPIO_CFG_CLK_XOSC_1 48 +#define CC115L_IOCFG_GPIO_CFG_CLK_XOSC_1_5 49 +#define CC115L_IOCFG_GPIO_CFG_CLK_XOSC_2 50 +#define CC115L_IOCFG_GPIO_CFG_CLK_XOSC_3 51 +#define CC115L_IOCFG_GPIO_CFG_CLK_XOSC_4 52 +#define CC115L_IOCFG_GPIO_CFG_CLK_XOSC_6 53 +#define CC115L_IOCFG_GPIO_CFG_CLK_XOSC_8 54 +#define CC115L_IOCFG_GPIO_CFG_CLK_XOSC_12 55 +#define CC115L_IOCFG_GPIO_CFG_CLK_XOSC_16 56 +#define CC115L_IOCFG_GPIO_CFG_CLK_XOSC_24 57 +#define CC115L_IOCFG_GPIO_CFG_CLK_XOSC_32 58 +#define CC115L_IOCFG_GPIO_CFG_CLK_XOSC_48 59 +#define CC115L_IOCFG_GPIO_CFG_CLK_XOSC_64 60 +#define CC115L_IOCFG_GPIO_CFG_CLK_XOSC_96 61 +#define CC115L_IOCFG_GPIO_CFG_CLK_XOSC_128 62 +#define CC115L_IOCFG_GPIO_CFG_CLK_XOSC_192 63 +#define CC115L_IOCFG_GPIO_CFG_MASK 0x3f + +#define CC115L_FIFOTHR 0x03 /* TX FIFO Thresholds */ +#define CC115L_FIFOTHR_THR_MASK 0x0f +#define CC115L_FIFOTHR_THR_61 0 +#define CC115L_FIFOTHR_THR_57 1 +#define CC115L_FIFOTHR_THR_53 2 +#define CC115L_FIFOTHR_THR_49 3 +#define CC115L_FIFOTHR_THR_45 4 +#define CC115L_FIFOTHR_THR_41 5 +#define CC115L_FIFOTHR_THR_37 6 +#define CC115L_FIFOTHR_THR_33 7 +#define CC115L_FIFOTHR_THR_29 8 +#define CC115L_FIFOTHR_THR_25 9 +#define CC115L_FIFOTHR_THR_21 10 +#define CC115L_FIFOTHR_THR_17 11 +#define CC115L_FIFOTHR_THR_13 12 +#define CC115L_FIFOTHR_THR_9 13 +#define CC115L_FIFOTHR_THR_5 14 +#define CC115L_FIFOTHR_THR_1 15 + +#define CC115L_SYNC1 0x04 /* Sync Word, High Byte */ +#define CC115L_SYNC0 0x05 /* Sync Word, Low Byte */ +#define CC115L_PKTLEN 0x06 /* Packet Length */ +#define CC115L_PKTCTRL0 0x08 /* Packet Automation Control */ +#define CC115L_PKTCTRL0_PKT_FORMAT 4 +#define CC115L_PKTCTRL0_PKT_FORMAT_NORMAL 0 +#define CC115L_PKTCTRL0_PKT_FORMAT_SYNC_SERIAL 1 +#define CC115L_PKTCTRL0_PKT_FORMAT_RANDOM 2 +#define CC115L_PKTCTRL0_PKT_FORMAT_ASYNC_SERIAL 3 +#define CC115L_PKTCTRL0_PKT_FORMAT_MASK 3 +#define CC115L_PKTCTRL0_PKT_CRC_EN 2 +#define CC115L_PKTCTRL0_PKT_LENGTH_CONFIG 0 +#define CC115L_PKTCTRL0_PKT_LENGTH_CONFIG_FIXED 0 +#define CC115L_PKTCTRL0_PKT_LENGTH_CONFIG_VARIABLE 1 +#define CC115L_PKTCTRL0_PKT_LENGTH_CONFIG_INFINITE 2 +#define CC115L_PKTCTRL0_PKT_LENGTH_CONFIG_MASK 3 +#define CC115L_CHANNR 0x0a /* Channel Number */ +#define CC115L_FSCTRL0 0x0c /* Frequency Synthesizer Control */ +#define CC115L_FREQ2 0x0d /* Frequency Control Word, High Byte */ +#define CC115L_FREQ1 0x0e /* Frequency Control Word, Middle Byte */ +#define CC115L_FREQ0 0x0f /* Frequency Control Word, Low Byte */ +#define CC115L_MDMCFG4 0x10 /* Modem Configuration */ +#define CC115L_MDMCFG4_DRATE_E 0 +#define CC115L_MDMCFG3 0x11 /* Modem Configuration */ +#define CC115L_MDMCFG2 0x12 /* Modem Configuration */ +#define CC115L_MDMCFG2_MOD_FORMAT 4 +#define CC115L_MDMCFG2_MOD_FORMAT_2FSK 0 +#define CC115L_MDMCFG2_MOD_FORMAT_GFSK 1 +#define CC115L_MDMCFG2_MOD_FORMAT_OOK 3 +#define CC115L_MDMCFG2_MOD_FORMAT_4FSK 4 +#define CC115L_MDMCFG2_MOD_FORMAT_MASK 7 +#define CC115L_MDMCFG2_MANCHESTER_EN 3 +#define CC115L_MDMCFG2_SYNC_MODE 0 +#define CC115L_MDMCFG2_SYNC_MODE_NONE 0 +#define CC115L_MDMCFG2_SYNC_MODE_16BITS 1 +#define CC115L_MDMCFG2_SYNC_MODE_32BITS 3 +#define CC115L_MDMCFG2_SYNC_MODE_MASK 3 +#define CC115L_MDMCFG1 0x13 /* Modem Configuration */ +#define CC115L_MDMCFG1_NUM_PREAMBLE 4 +#define CC115L_MDMCFG1_NUM_PREAMBLE_2 0 +#define CC115L_MDMCFG1_NUM_PREAMBLE_3 1 +#define CC115L_MDMCFG1_NUM_PREAMBLE_4 2 +#define CC115L_MDMCFG1_NUM_PREAMBLE_6 3 +#define CC115L_MDMCFG1_NUM_PREAMBLE_8 4 +#define CC115L_MDMCFG1_NUM_PREAMBLE_12 5 +#define CC115L_MDMCFG1_NUM_PREAMBLE_16 6 +#define CC115L_MDMCFG1_NUM_PREAMBLE_24 7 +#define CC115L_MDMCFG1_NUM_PREAMBLE_MASK 7 +#define CC115L_MDMCFG1_CHANSPC_E 0 +#define CC115L_MDMCFG0 0x14 /* Modem Configuration */ +#define CC115L_DEVIATN 0x15 /* Modem Deviation Setting */ +#define CC115L_DEVIATN_DEVIATION_E 4 +#define CC115L_DEVIATN_DEVIATION_E_MASK 7 +#define CC115L_DEVIATN_DEVIATION_M 0 +#define CC115L_DEVIATN_DEVIATION_M_MASK 7 +#define CC115L_MCSM1 0x17 /* Main Radio Control State Machine Configuration */ +#define CC115L_MCSM1_TXOFF_MODE 0 +#define CC115L_MCSM1_TXOFF_MODE_IDLE 0 +#define CC115L_MCSM1_TXOFF_MODE_FSTXON 1 +#define CC115L_MCSM1_TXOFF_MODE_TX 2 +#define CC115L_MCSM1_TXOFF_MODE_MASK 3 +#define CC115L_MCSM0 0x18 /* Main Radio Control State Machine Configuration */ +#define CC115L_MCSM0_FS_AUTOCAL 4 +#define CC115L_MCSM0_FS_AUTOCAL_NEVER 0 +#define CC115L_MCSM0_FS_AUTOCAL_IDLE_TO_TX 1 +#define CC115L_MCSM0_FS_AUTOCAL_TX_TO_IDLE 2 +#define CC115L_MCSM0_FS_AUTOCAL_4TH_TX_TO_IDLE 3 +#define CC115L_MCSM0_FS_AUTOCAL_MASK 3 +#define CC115L_MCSM0_PO_TIMEOUT 2 +#define CC115L_MCSM0_PO_TIMEOUT_1 0 +#define CC115L_MCSM0_PO_TIMEOUT_16 1 +#define CC115L_MCSM0_PO_TIMEOUT_64 2 +#define CC115L_MCSM0_PO_TIMEOUT_256 3 +#define CC115L_MCSM0_PO_TIMEOUT_MASK 3 +#define CC115L_MCSM0_XOSC_FORCE_ON 0 +#define CC115L_RESERVED_0X20 0x20 /* Use setting from SmartRF Studio */ +#define CC115L_FREND0 0x22 /* Front End TX Configuration */ +#define CC115L_FSCAL3 0x23 /* Frequency Synthesizer Calibration */ +#define CC115L_FSCAL2 0x24 /* Frequency Synthesizer Calibration */ +#define CC115L_FSCAL1 0x25 /* Frequency Synthesizer Calibration */ +#define CC115L_FSCAL0 0x26 /* Frequency Synthesizer Calibration */ +#define CC115L_RESERVED_0X29 0x29 /* Use setting from SmartRF Studio */ +#define CC115L_RESERVED_0X2A 0x2a /* Use setting from SmartRF Studio */ +#define CC115L_RESERVED_0X2B 0x2b /* Use setting from SmartRF Studio */ +#define CC115L_TEST2 0x2c /* Various Test Settings */ +#define CC115L_TEST1 0x2d /* Various Test Settings */ +#define CC115L_TEST0 0x2e /* Various Test Settings */ + +/* Status registers (use BURST bit to select these) */ +#define CC115L_PARTNUM (0x30|(1< Date: Sun, 24 Mar 2013 23:52:14 -0700 Subject: altos/telegps: Hook up cc115l driver Doesn't actually do anything yet, but should initialize the chip at least Signed-off-by: Keith Packard --- src/telegps-v0.1/Makefile | 6 +++++- src/telegps-v0.1/ao_pins.h | 35 ++++++++++++++--------------------- src/telegps-v0.1/ao_telegps.c | 6 +----- 3 files changed, 20 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/telegps-v0.1/Makefile b/src/telegps-v0.1/Makefile index 48caee4d..26d9eaa0 100644 --- a/src/telegps-v0.1/Makefile +++ b/src/telegps-v0.1/Makefile @@ -13,6 +13,8 @@ INC = \ ao_product.h \ ao_task.h \ ao_whiten.h \ + ao_cc115l.h \ + ao_fec.h \ stm32l.h \ Makefile @@ -44,7 +46,9 @@ ALTOS_SRC = \ ao_usb_stm.c \ ao_exti_stm.c \ ao_serial_stm.c \ - ao_gps_skytraq.c + ao_gps_skytraq.c \ + ao_cc115l.c \ + ao_fec_tx.c PRODUCT=TeleGPS-v0.1 PRODUCT_DEF=-DTELEGPS diff --git a/src/telegps-v0.1/ao_pins.h b/src/telegps-v0.1/ao_pins.h index 77b2373d..46d0b9f2 100644 --- a/src/telegps-v0.1/ao_pins.h +++ b/src/telegps-v0.1/ao_pins.h @@ -122,37 +122,30 @@ #define AO_MONITOR_LED AO_LED_GREEN /* - * Radio (cc115) + * Radio (cc115l) */ /* gets pretty close to 434.550 */ -#define AO_RADIO_CAL_DEFAULT 0x6ca333 +#define AO_RADIO_CAL_DEFAULT 0x10b6a5 #define AO_FEC_DEBUG 0 -#define AO_CC1120_SPI_CS_PORT (&stm_gpioa) -#define AO_CC1120_SPI_CS_PIN 0 -#define AO_CC1120_SPI_BUS AO_SPI_2_PB13_PB14_PB15 -#define AO_CC1120_SPI stm_spi2 +#define AO_CC115L_SPI_CS_PORT (&stm_gpiob) +#define AO_CC115L_SPI_CS_PIN 12 +#define AO_CC115L_SPI_BUS AO_SPI_2_PB13_PB14_PB15 +#define AO_CC115L_SPI stm_spi2 -#define AO_CC1120_INT_PORT (&stm_gpioc) -#define AO_CC1120_INT_PIN 13 +#define AO_CC115L_INT_PORT (&stm_gpioa) +#define AO_CC115L_INT_PIN (9) -#define AO_CC1120_MCU_WAKEUP_PORT (&stm_gpioc) -#define AO_CC1120_MCU_WAKEUP_PIN (0) +#define AO_CC115L_MCU_WAKEUP_PORT (&stm_gpioa) +#define AO_CC115L_MCU_WAKEUP_PIN (10) -#define AO_CC1120_INT_GPIO 2 -#define AO_CC1120_INT_GPIO_IOCFG CC1120_IOCFG2 +#define AO_CC115L_INT_GPIO 2 +#define AO_CC115L_INT_GPIO_IOCFG CC115L_IOCFG2 -#define AO_CC1120_MARC_GPIO 3 -#define AO_CC1120_MARC_GPIO_IOCFG CC1120_IOCFG3 +#define AO_CC115L_MARC_GPIO 0 +#define AO_CC115L_MARC_GPIO_IOCFG CC115L_IOCFG0 -/* - * Profiling Viterbi decoding - */ - -#ifndef AO_PROFILE -#define AO_PROFILE 0 -#endif #endif /* _AO_PINS_H_ */ diff --git a/src/telegps-v0.1/ao_telegps.c b/src/telegps-v0.1/ao_telegps.c index 9865674d..fdf365e3 100644 --- a/src/telegps-v0.1/ao_telegps.c +++ b/src/telegps-v0.1/ao_telegps.c @@ -41,11 +41,7 @@ main(void) ao_cmd_init(); ao_usb_init(); -// ao_radio_init(); -// ao_monitor_init(); -// ao_rssi_init(AO_LED_RED); -// ao_packet_master_init(); -// ao_send_packet_init(); + ao_radio_init(); ao_gps_init(); -- cgit v1.2.3 From 4889b33af9700b9d872364f0cadaf9425cf84a7d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 26 Mar 2013 14:24:45 -0700 Subject: altos: Add RFPA0133 amplifier driver No configuration of power level yet, just the bare driver. Signed-off-by: Keith Packard --- src/core/ao.h | 19 +++++++++++++++++++ src/drivers/ao_rfpa0133.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++ src/drivers/ao_rfpa0133.h | 30 +++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 src/drivers/ao_rfpa0133.c create mode 100644 src/drivers/ao_rfpa0133.h (limited to 'src') diff --git a/src/core/ao.h b/src/core/ao.h index ce0bf5d1..133d9118 100644 --- a/src/core/ao.h +++ b/src/core/ao.h @@ -534,6 +534,25 @@ typedef int16_t (*ao_radio_fill_func)(uint8_t *buffer, int16_t len); void ao_radio_send_lots(ao_radio_fill_func fill); +/* + * ao_radio_pa + */ + +#if AO_RADIO_HAS_PA +void +ao_radio_pa_on(void); + +void +ao_radio_pa_off(void); + +void +ao_radio_pa_init(void); +#else +#define ao_radio_pa_on() +#define ao_radio_pa_off() +#define ao_radio_pa_init() +#endif + /* * Compute the packet length as follows: * diff --git a/src/drivers/ao_rfpa0133.c b/src/drivers/ao_rfpa0133.c new file mode 100644 index 00000000..70d5edba --- /dev/null +++ b/src/drivers/ao_rfpa0133.c @@ -0,0 +1,48 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +static uint8_t power = 0; + +static void +ao_rfpa0133_set_power(void) +{ + ao_gpio_set(AO_PA_GAIN_8_GPIO, AO_PA_GAIN_8_PIN, AO_PA_GAIN_8, power & 1); + ao_gpio_set(AO_PA_GAIN_16_GPIO, AO_PA_GAIN_16_PIN, AO_PA_GAIN_16, (power >> 1) & 1); +} + +void +ao_radio_pa_on(void) +{ + ao_rfpa0133_set_power(); + ao_gpio_set(AO_PA_POWER_GPIO, AO_PA_POWER_PIN, AO_PA_POWER, 1); +} + +void +ao_radio_pa_off(void) +{ + ao_gpio_set(AO_PA_POWER_GPIO, AO_PA_POWER_PIN, AO_PA_POWER, 0); +} + +void +ao_radio_pa_init(void) +{ + ao_enable_output(AO_PA_POWER_GPIO, AO_PA_POWER_PIN, AO_PA_POWER, 0); + ao_enable_output(AO_PA_GAIN_8_GPIO, AO_PA_GAIN_8_PIN, AO_PA_GAIN_8, 0); + ao_enable_output(AO_PA_GAIN_16_GPIO, AO_PA_GAIN_16_PIN, AO_PA_GAIN_16, 0); +} diff --git a/src/drivers/ao_rfpa0133.h b/src/drivers/ao_rfpa0133.h new file mode 100644 index 00000000..2ba7f699 --- /dev/null +++ b/src/drivers/ao_rfpa0133.h @@ -0,0 +1,30 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_RFPA0133_H_ +#define _AO_RFPA0133_H_ + +void +ao_rfpa0133_on(void); + +void +ao_rfpa0133_off(void); + +void +ao_rfpa0133_init(void); + +#endif /* _AO_RFPA0133_H_ */ -- cgit v1.2.3 From 136ca0922e968d650e9e420a47d228611a3cb45e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 26 Mar 2013 14:25:48 -0700 Subject: altos: Improve CC115L driver. Generates carrier now. Still no data, but at least the carrier comes up on frequency now. Signed-off-by: Keith Packard --- src/drivers/ao_cc115l.c | 110 ++++++++++++++++++++++++++++++++++++++++----- src/drivers/ao_cc115l.h | 1 + src/drivers/ao_rf_cc115l.h | 34 ++++++++++++++ 3 files changed, 133 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_cc115l.c b/src/drivers/ao_cc115l.c index fd8bb1f0..feff82af 100644 --- a/src/drivers/ao_cc115l.c +++ b/src/drivers/ao_cc115l.c @@ -30,14 +30,12 @@ static uint8_t ao_radio_abort; /* radio operation should abort */ static uint8_t ao_radio_mcu_wake; /* MARC status change */ static uint8_t ao_radio_marcstate; /* Last read MARC state value */ -#define CC115L_DEBUG AO_FEC_DEBUG +#define CC115L_DEBUG 1 #define CC115L_TRACE 1 -extern const uint32_t ao_radio_cal; - #define FOSC 26000000 -#define ao_radio_select() ao_spi_get_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS,AO_SPI_SPEED_4MHz) +#define ao_radio_select() ao_spi_get_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS,AO_SPI_SPEED_1MHz) #define ao_radio_deselect() ao_spi_put_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS) #define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC115L_SPI_BUS) #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC115L_SPI_BUS) @@ -47,22 +45,23 @@ extern const uint32_t ao_radio_cal; static uint8_t ao_radio_reg_read(uint16_t addr) { - uint8_t datao[2], datai[2]; + uint8_t data[1]; uint8_t d; #if CC115L_TRACE printf("\t\tao_radio_reg_read (%04x): ", addr); flush(); #endif - datao[0] = ((1 << CC115L_READ) | - (0 << CC115L_BURST) | - addr); + data[0] = ((1 << CC115L_READ) | + (0 << CC115L_BURST) | + addr); ao_radio_select(); - ao_radio_duplex(datao, datai, 2); + ao_radio_spi_send(data, 1); + ao_radio_spi_recv(data, 1); ao_radio_deselect(); #if CC115L_TRACE - printf (" %02x\n", datai[1]); + printf (" %02x\n", data[0]); #endif - return datai[1]; + return data[0]; } static void @@ -142,6 +141,9 @@ static uint8_t ao_radio_fifo_write(uint8_t *data, uint8_t len) { uint8_t status = ao_radio_fifo_write_start(); +#if CC115L_TRACE + printf ("fifo_write %d\n", len); +#endif ao_radio_spi_send(data, len); return ao_radio_fifo_write_stop(status); } @@ -150,6 +152,10 @@ static uint8_t ao_radio_fifo_write_fixed(uint8_t data, uint8_t len) { uint8_t status = ao_radio_fifo_write_start(); + +#if CC115L_TRACE + printf ("fifo_write_fixed %02x %d\n", data, len); +#endif ao_radio_spi_send_fixed(data, len); return ao_radio_fifo_write_stop(status); } @@ -204,6 +210,7 @@ ao_radio_isr(void) static void ao_radio_start_tx(void) { + ao_radio_pa_on(); ao_exti_set_callback(AO_CC115L_INT_PORT, AO_CC115L_INT_PIN, ao_radio_isr); ao_exti_enable(AO_CC115L_INT_PORT, AO_CC115L_INT_PIN); ao_exti_enable(AO_CC115L_MCU_WAKEUP_PORT, AO_CC115L_MCU_WAKEUP_PIN); @@ -213,6 +220,7 @@ ao_radio_start_tx(void) static void ao_radio_idle(void) { + ao_radio_pa_off(); for (;;) { uint8_t state = ao_radio_strobe(CC115L_SIDLE); if ((state >> CC115L_STATUS_STATE) == CC115L_STATUS_STATE_IDLE) @@ -398,10 +406,29 @@ ao_radio_setup(void) { int i; +#if 0 + ao_gpio_set(AO_CC115L_SPI_CS_PORT, AO_CC115L_SPI_CS_PIN, AO_CC115L_SPI_CS, 0); + for (i = 0; i < 10000; i++) { + if (ao_gpio_get(SPI_2_PORT, SPI_2_MISO_PIN, SPI_2_MISO) == 0) { + printf ("Chip clock alive\n"); + break; + } + } + ao_gpio_set(AO_CC115L_SPI_CS_PORT, AO_CC115L_SPI_CS_PIN, AO_CC115L_SPI_CS, 1); + if (i == 10000) + printf ("Chip clock not alive\n"); +#endif + ao_radio_strobe(CC115L_SRES); + ao_delay(AO_MS_TO_TICKS(10)); - for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2) + printf ("Part %x\n", ao_radio_reg_read(CC115L_PARTNUM)); + printf ("Version %x\n", ao_radio_reg_read(CC115L_VERSION)); + + for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2) { ao_radio_reg_write(radio_setup[i], radio_setup[i+1]); + ao_radio_reg_read(radio_setup[i]); + } ao_radio_mode = 0; @@ -462,6 +489,7 @@ ao_rdf_run(void) ao_arch_release_interrupts(); if (ao_radio_mcu_wake) ao_radio_check_marcstate(); + ao_radio_pa_off(); if (!ao_radio_wake) ao_radio_idle(); ao_radio_put(); @@ -525,6 +553,7 @@ ao_radio_test_cmd(void) ao_packet_slave_stop(); #endif ao_radio_get(0xff); + ao_radio_pa_on(); ao_radio_strobe(CC115L_STX); #if CC115L_TRACE { int t; @@ -622,6 +651,7 @@ ao_radio_send(const void *d, uint8_t size) break; } } + ao_radio_pa_off(); ao_radio_put(); } @@ -692,6 +722,7 @@ ao_radio_send_lots(ao_radio_fill_func fill) ao_radio_wake = 0; ao_radio_wait_isr(); } + ao_radio_pa_off(); ao_radio_put(); } @@ -704,6 +735,55 @@ static char *cc115l_state_name[] = { [CC115L_STATUS_STATE_TX_FIFO_UNDERFLOW] = "TX_FIFO_UNDERFLOW", }; +struct ao_cc115l_reg { + uint16_t addr; + char *name; +}; + +const static struct ao_cc115l_reg ao_cc115l_reg[] = { + { .addr = CC115L_IOCFG2, .name = "IOCFG2" }, + { .addr = CC115L_IOCFG1, .name = "IOCFG1" }, + { .addr = CC115L_IOCFG0, .name = "IOCFG0" }, + { .addr = CC115L_FIFOTHR, .name = "FIFOTHR" }, + { .addr = CC115L_SYNC1, .name = "SYNC1" }, + { .addr = CC115L_SYNC0, .name = "SYNC0" }, + { .addr = CC115L_PKTLEN, .name = "PKTLEN" }, + { .addr = CC115L_PKTCTRL0, .name = "PKTCTRL0" }, + { .addr = CC115L_CHANNR, .name = "CHANNR" }, + { .addr = CC115L_FSCTRL0, .name = "FSCTRL0" }, + { .addr = CC115L_FREQ2, .name = "FREQ2" }, + { .addr = CC115L_FREQ1, .name = "FREQ1" }, + { .addr = CC115L_FREQ0, .name = "FREQ0" }, + { .addr = CC115L_MDMCFG4, .name = "MDMCFG4" }, + { .addr = CC115L_MDMCFG3, .name = "MDMCFG3" }, + { .addr = CC115L_MDMCFG2, .name = "MDMCFG2" }, + { .addr = CC115L_MDMCFG1, .name = "MDMCFG1" }, + { .addr = CC115L_MDMCFG0, .name = "MDMCFG0" }, + { .addr = CC115L_DEVIATN, .name = "DEVIATN" }, + { .addr = CC115L_MCSM1, .name = "MCSM1" }, + { .addr = CC115L_MCSM0, .name = "MCSM0" }, + { .addr = CC115L_RESERVED_0X20, .name = "RESERVED_0X20" }, + { .addr = CC115L_FREND0, .name = "FREND0" }, + { .addr = CC115L_FSCAL3, .name = "FSCAL3" }, + { .addr = CC115L_FSCAL2, .name = "FSCAL2" }, + { .addr = CC115L_FSCAL1, .name = "FSCAL1" }, + { .addr = CC115L_FSCAL0, .name = "FSCAL0" }, + { .addr = CC115L_RESERVED_0X29, .name = "RESERVED_0X29" }, + { .addr = CC115L_RESERVED_0X2A, .name = "RESERVED_0X2A" }, + { .addr = CC115L_RESERVED_0X2B, .name = "RESERVED_0X2B" }, + { .addr = CC115L_TEST2, .name = "TEST2" }, + { .addr = CC115L_TEST1, .name = "TEST1" }, + { .addr = CC115L_TEST0, .name = "TEST0" }, + { .addr = CC115L_PARTNUM, .name = "PARTNUM" }, + { .addr = CC115L_VERSION, .name = "VERSION" }, + { .addr = CC115L_MARCSTATE, .name = "MARCSTATE" }, + { .addr = CC115L_PKTSTATUS, .name = "PKTSTATUS" }, + { .addr = CC115L_TXBYTES, .name = "TXBYTES" }, + { .addr = CC115L_PA, .name = "PA" }, +}; + +#define AO_NUM_CC115L_REG (sizeof ao_cc115l_reg / sizeof ao_cc115l_reg[0]) + static void ao_radio_show(void) { uint8_t status = ao_radio_status(); int i; @@ -715,6 +795,8 @@ static void ao_radio_show(void) { printf ("STATE: %s\n", cc115l_state_name[(status >> CC115L_STATUS_STATE) & CC115L_STATUS_STATE_MASK]); printf ("MARC: %02x\n", ao_radio_get_marcstate()); + for (i = 0; i < AO_NUM_CC115L_REG; i++) + printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc115l_reg[i].addr), ao_cc115l_reg[i].name); ao_radio_put(); } @@ -743,7 +825,9 @@ static void ao_radio_packet(void) { static void ao_radio_aprs() { +#if PACKET_HAS_SLAVE ao_packet_slave_stop(); +#endif ao_aprs_send(); } #endif @@ -792,5 +876,7 @@ ao_radio_init(void) AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED, ao_radio_mcu_wakeup_isr); + ao_radio_pa_init(); + ao_cmd_register(&ao_radio_cmds[0]); } diff --git a/src/drivers/ao_cc115l.h b/src/drivers/ao_cc115l.h index 34e3f0ba..811c14aa 100644 --- a/src/drivers/ao_cc115l.h +++ b/src/drivers/ao_cc115l.h @@ -206,6 +206,7 @@ #define CC115L_SFTX 0x3b #define CC115L_SNOP 0x3d +#define CC115L_PA 0x3e #define CC115L_FIFO 0x3f #define CC115L_FIFO_SIZE 64 diff --git a/src/drivers/ao_rf_cc115l.h b/src/drivers/ao_rf_cc115l.h index ab80150e..6eb30bf2 100644 --- a/src/drivers/ao_rf_cc115l.h +++ b/src/drivers/ao_rf_cc115l.h @@ -8,6 +8,7 @@ ***************************************************************/ +#if 0 CC115L_IOCFG2, 0x2e, /* GDO2 Output Pin Configuration */ CC115L_IOCFG1, 0x2e, /* GDO1 Output Pin Configuration */ CC115L_IOCFG0, 0x06, /* GDO0 Output Pin Configuration */ @@ -46,4 +47,37 @@ CC115L_MARCSTATE, 0x00, /* Main Radio Control State Machine State */ CC115L_PKTSTATUS, 0x00, /* Current GDOx Status and Packet Status */ CC115L_TXBYTES, 0x00, /* Underflow and Number of Bytes */ +#endif + +/*************************************************************** + * SmartRF Studio(tm) Export + * + * Radio register settings specifed with address, value + * + * RF device: CC115L + * + ***************************************************************/ + + + CC115L_IOCFG0, 0x06, /* GDO0 Output Pin Configuration */ + CC115L_FIFOTHR, 0x47, /* TX FIFO Thresholds */ + CC115L_PKTCTRL0, 0x05, /* Packet Automation Control */ + CC115L_FREQ2, 0x10, /* Frequency Control Word, High Byte */ + CC115L_FREQ1, 0xb6, /* Frequency Control Word, Middle Byte */ + CC115L_FREQ0, 0xa5, /* Frequency Control Word, Low Byte */ + CC115L_MDMCFG4, 0xfa, /* Modem Configuration */ + CC115L_MDMCFG3, 0x83, /* Modem Configuration */ + CC115L_MDMCFG2, 0x13, /* Modem Configuration */ + CC115L_MDMCFG1, 0x21, /* Modem Configuration */ + CC115L_DEVIATN, 0x35, /* Modem Deviation Setting */ + CC115L_MCSM0, 0x18, /* Main Radio Control State Machine Configuration */ + CC115L_RESERVED_0X20, 0xfb, /* Use setting from SmartRF Studio */ + CC115L_FSCAL3, 0xe9, /* Frequency Synthesizer Calibration */ + CC115L_FSCAL2, 0x2a, /* Frequency Synthesizer Calibration */ + CC115L_FSCAL1, 0x00, /* Frequency Synthesizer Calibration */ + CC115L_FSCAL0, 0x1f, /* Frequency Synthesizer Calibration */ + CC115L_TEST2, 0x81, /* Various Test Settings */ + CC115L_TEST1, 0x35, /* Various Test Settings */ + CC115L_TEST0, 0x09, /* Various Test Settings */ + CC115L_PA, 0x60, /* Power setting (0dBm) */ -- cgit v1.2.3 From 4d187460bdcb97bf6d0a3550e4e03c4c223e4cc1 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 26 Mar 2013 14:26:38 -0700 Subject: altos/stm: Ensure SPI always sends 0xff during receive SD cards require 0xff when fetching data Signed-off-by: Keith Packard --- src/stm/ao_spi_stm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/stm/ao_spi_stm.c b/src/stm/ao_spi_stm.c index 7b4af964..56329c24 100644 --- a/src/stm/ao_spi_stm.c +++ b/src/stm/ao_spi_stm.c @@ -160,6 +160,8 @@ ao_spi_recv(void *block, uint16_t len, uint8_t spi_index) uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index; uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index; + spi_dev_null = 0xff; + /* Set up transmit DMA to make the SPI hardware actually run */ ao_dma_set_transfer(mosi_dma_index, &stm_spi->dr, -- cgit v1.2.3 From 237e853b820b01409562b93b82684e5147286806 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 26 Mar 2013 14:27:46 -0700 Subject: altos: Allow radio recv and xmit to be separately configured The CC115L is xmit only, so split out the functions and provide defines to check for xmit or recv separately as needed. Signed-off-by: Keith Packard --- src/core/ao.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src') diff --git a/src/core/ao.h b/src/core/ao.h index 133d9118..6cfdcba8 100644 --- a/src/core/ao.h +++ b/src/core/ao.h @@ -514,17 +514,28 @@ extern __xdata uint8_t ao_radio_dma; #define AO_RADIO_STATUS_CRC_OK AO_FEC_DECODE_CRC_OK #endif +#ifndef HAS_RADIO_RECV +#define HAS_RADIO_RECV HAS_RADIO +#endif +#ifndef HAS_RADIO_XMIT +#define HAS_RADIO_XMIT HAS_RADIO +#endif + void ao_radio_general_isr(void) ao_arch_interrupt(16); +#if HAS_RADIO_XMIT void ao_radio_send(const __xdata void *d, uint8_t size) __reentrant; +#endif +#if HAS_RADIO_RECV uint8_t ao_radio_recv(__xdata void *d, uint8_t size) __reentrant; void ao_radio_recv_abort(void); +#endif void ao_radio_test(uint8_t on); -- cgit v1.2.3 From 747114786512339211d4981a7828c8c6f1f46c20 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 26 Mar 2013 14:28:37 -0700 Subject: altos: Fix config to not abort radio recv when no recv is available Use the new radio recv define to skip disabling the receiver when there isn't a receiver. Signed-off-by: Keith Packard --- src/core/ao_config.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/core/ao_config.c b/src/core/ao_config.c index 0aac16a6..9c84fe60 100644 --- a/src/core/ao_config.c +++ b/src/core/ao_config.c @@ -210,6 +210,7 @@ ao_config_callsign_set(void) __reentrant } #if HAS_RADIO + void ao_config_frequency_show(void) __reentrant { @@ -227,7 +228,9 @@ ao_config_frequency_set(void) __reentrant ao_config.frequency = ao_cmd_lex_u32; ao_config_set_radio(); _ao_config_edit_finish(); +#if HAS_RADIO_RECV ao_radio_recv_abort(); +#endif } #endif -- cgit v1.2.3 From e14834817f78a04b4d9b44a8373119dffd42c966 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 27 Mar 2013 01:12:33 -0700 Subject: altos: Add SDCARD and FAT16 filesystem support This adds a fairly primitive FAT16 file system implementation along with support for SD cards. Signed-off-by: Keith Packard --- src/drivers/ao_bufio.c | 298 +++++++++++++++++++++ src/drivers/ao_bufio.h | 36 +++ src/drivers/ao_fat.c | 674 ++++++++++++++++++++++++++++++++++++++++++++++++ src/drivers/ao_fat.h | 73 ++++++ src/drivers/ao_sdcard.c | 398 ++++++++++++++++++++++++++++ src/drivers/ao_sdcard.h | 75 ++++++ src/test/Makefile | 5 +- src/test/ao_fat_test.c | 118 +++++++++ 8 files changed, 1676 insertions(+), 1 deletion(-) create mode 100644 src/drivers/ao_bufio.c create mode 100644 src/drivers/ao_bufio.h create mode 100644 src/drivers/ao_fat.c create mode 100644 src/drivers/ao_fat.h create mode 100644 src/drivers/ao_sdcard.c create mode 100644 src/drivers/ao_sdcard.h create mode 100644 src/test/ao_fat_test.c (limited to 'src') diff --git a/src/drivers/ao_bufio.c b/src/drivers/ao_bufio.c new file mode 100644 index 00000000..9a5e801b --- /dev/null +++ b/src/drivers/ao_bufio.c @@ -0,0 +1,298 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef AO_FAT_TEST +#include "ao.h" +#endif + +#include "ao_sdcard.h" +#include "ao_bufio.h" + +#define AO_NUM_BUF 4 +#define AO_BUFSIZ 512 + +struct ao_bufio { + uint32_t block; + int16_t seqno; + uint8_t busy; + uint8_t dirty; +}; + +static struct ao_bufio ao_bufio[AO_NUM_BUF]; +static uint8_t ao_buffer[AO_NUM_BUF][AO_BUFSIZ]; +static int16_t ao_seqno; +static uint8_t ao_bufio_mutex; + +#if 0 +#define DBG(...) printf(__VA_ARGS__) +#else +#define DBG(...) +#endif + +static inline void +ao_bufio_lock(void) +{ + ao_mutex_get(&ao_bufio_mutex); +} + +static inline void +ao_bufio_unlock(void) +{ + ao_mutex_put(&ao_bufio_mutex); +} + +static inline int16_t +ao_seqno_age(int16_t s) +{ + return ao_seqno - s; +} + +static inline int16_t +ao_seqno_next(void) +{ + return ++ao_seqno; +} + +static inline int +ao_seqno_older(int16_t a, int16_t b) +{ + return ao_seqno_age(a) > ao_seqno_age(b); +} + +static inline void +ao_validate_bufno(int b) +{ + if (b < 0 || AO_NUM_BUF <= b) + ao_panic(AO_PANIC_BUFIO); +} + +static inline int +ao_buf_to_num(uint8_t *buf) +{ + int b = (buf - &ao_buffer[0][0]) / AO_BUFSIZ; + + ao_validate_bufno(b); + return b; +} + +static inline int +ao_bufio_to_num(struct ao_bufio *bufio) +{ + int b = (bufio - ao_bufio); + + ao_validate_bufno(b); + return b; +} + +static inline struct ao_bufio * +ao_buf_to_bufio(uint8_t *buf) +{ + int b = ao_buf_to_num(buf); + struct ao_bufio *bufio; + + bufio = &ao_bufio[b]; + DBG ("buf %08x is %d bufio %08x\n", buf, b, bufio); + return bufio; +} + +static inline uint8_t * +ao_bufio_to_buf(struct ao_bufio *bufio) +{ + int b = ao_bufio_to_num(bufio); + uint8_t *buf; + + buf = &ao_buffer[b][0]; + DBG ("bufio %08x is %d buf %08x\n", bufio, b, buf); + return buf; +} + +/* + * Write a buffer to storage if it is dirty + */ +static void +ao_bufio_write(struct ao_bufio *bufio) +{ + if (bufio->dirty) { + ao_sdcard_write_block(bufio->block, ao_bufio_to_buf(bufio)); + bufio->dirty = 0; + } +} + +/* + * Read a buffer from storage + */ +static uint8_t +ao_bufio_read(struct ao_bufio *bufio) +{ + uint8_t *buf = ao_bufio_to_buf(bufio); + + return ao_sdcard_read_block(bufio->block, buf); +} + +/* + * Find a buffer containing the specified block + */ +static struct ao_bufio * +ao_bufio_find_block(uint32_t block) +{ + int b; + + for (b = 0; b < AO_NUM_BUF; b++) { + struct ao_bufio *bufio = &ao_bufio[b]; + if (bufio->block == block) { + DBG ("Found existing buffer %d (seqno %d)\n", + ao_bufio_to_num(bufio), bufio->seqno); + return bufio; + } + } + return NULL; +} + +/* + * Find the least recently used idle buffer + */ +static struct ao_bufio * +ao_bufio_find_idle(void) +{ + int b; + struct ao_bufio *oldest = NULL; + + for (b = 0; b < AO_NUM_BUF; b++) { + struct ao_bufio *bufio = &ao_bufio[b]; + if (!bufio->busy) + if (!oldest || ao_seqno_older(bufio->seqno, oldest->seqno)) + oldest = bufio; + } + if (oldest) + DBG ("Using idle buffer %d (seqno %d)\n", + ao_bufio_to_num(oldest), oldest->seqno); + return oldest; +} + +/* + * Return a pointer to a buffer containing + * the contents of the specified block + */ +uint8_t * +ao_bufio_get(uint32_t block) +{ + struct ao_bufio *bufio; + uint8_t *buf = NULL; + + ao_bufio_lock(); + bufio = ao_bufio_find_block(block); + if (!bufio) { + bufio = ao_bufio_find_idle(); + if (bufio) { + ao_bufio_write(bufio); + bufio->block = block; + DBG ("read buffer\n"); + if (!ao_bufio_read(bufio)) { + bufio->block = 0xffffffff; + bufio = NULL; + } + } + } + if (bufio) { + bufio->busy++; + buf = ao_bufio_to_buf(bufio); + } + ao_bufio_unlock(); + return buf; +} + +/* + * Release a buffer, marking it dirty + * if it has been written to + */ +void +ao_bufio_put(uint8_t *buf, uint8_t write) +{ + struct ao_bufio *bufio; + + ao_bufio_lock(); + bufio = ao_buf_to_bufio(buf); + + DBG ("idle buffer %d write %d\n", ao_bufio_to_num(bufio), write); + bufio->dirty |= write; + if (!--bufio->busy) { + bufio->seqno = ao_seqno_next(); + DBG ("not busy, seqno %d\n", bufio->seqno); + } + ao_bufio_unlock(); +} + +/* + * Flush a single buffer immediately. Useful + * if write order is important + */ +void +ao_bufio_flush_one(uint8_t *buf) +{ + ao_bufio_lock(); + ao_bufio_write(ao_buf_to_bufio(buf)); + ao_bufio_unlock(); +} + +/* + * Flush all buffers to storage + */ +void +ao_bufio_flush(void) +{ + int b; + + ao_bufio_lock(); + for (b = 0; b < AO_NUM_BUF; b++) + ao_bufio_write(&ao_bufio[b]); + ao_bufio_unlock(); +} + +static void +ao_bufio_test_read(void) +{ + uint8_t *buf; + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + if ((buf = ao_bufio_get(ao_cmd_lex_u32))) { + int i; + for (i = 0; i < 512; i++) { + printf (" %02x", buf[i]); + if ((i & 0xf) == 0xf) + printf("\n"); + } + ao_bufio_put(buf, 0); + } +} + +static const struct ao_cmds ao_bufio_cmds[] = { + { ao_bufio_test_read, "q\0Test bufio read" }, + { 0, NULL }, +}; + +void +ao_bufio_init(void) +{ + int b; + + for (b = 0; b < AO_NUM_BUF; b++) + ao_bufio[b].block = 0xffffffff; + ao_sdcard_init(); + + ao_cmd_register(&ao_bufio_cmds[0]); +} diff --git a/src/drivers/ao_bufio.h b/src/drivers/ao_bufio.h new file mode 100644 index 00000000..c3bee906 --- /dev/null +++ b/src/drivers/ao_bufio.h @@ -0,0 +1,36 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_BUFIO_H_ +#define _AO_BUFIO_H_ + +uint8_t * +ao_bufio_get(uint32_t block); + +void +ao_bufio_put(uint8_t *buf, uint8_t write); + +void +ao_bufio_flush_one(uint8_t *buf); + +void +ao_bufio_flush(void); + +void +ao_bufio_init(void); + +#endif /* _AO_BUFIO_H_ */ diff --git a/src/drivers/ao_fat.c b/src/drivers/ao_fat.c new file mode 100644 index 00000000..a1476168 --- /dev/null +++ b/src/drivers/ao_fat.c @@ -0,0 +1,674 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef AO_FAT_TEST +#include "ao.h" +#endif + +#include "ao_fat.h" +#include "ao_bufio.h" + +/* Partition information, block numbers */ + +static uint8_t partition_type; +static uint32_t partition_start, partition_end; + +/* File system parameters */ +static uint8_t sectors_per_cluster; +static uint32_t bytes_per_cluster; +static uint16_t reserved_sector_count; +static uint8_t number_fat; +static uint16_t root_entries; +static uint16_t sectors_per_fat; +static uint32_t fat_start; +static uint32_t root_start; +static uint32_t data_start; + +static uint32_t +get_u32(uint8_t *base) +{ + return ((uint32_t) base[0] | + ((uint32_t) base[1] << 8) | + ((uint32_t) base[2] << 16) | + ((uint32_t) base[3] << 24)); +} + +static void +put_u32(uint8_t *base, uint32_t value) +{ + base[0] = value; + base[1] = value >> 8; + base[2] = value >> 16; + base[3] = value >> 24; +} + +static uint16_t +get_u16(uint8_t *base) +{ + return ((uint16_t) base[0] | ((uint16_t) base[1] << 8)); +} + +static void +put_u16(uint8_t *base, uint16_t value) +{ + base[0] = value; + base[1] = value >> 8; +} + +static uint8_t +ao_fat_cluster_valid(uint16_t cluster) +{ + return (2 <= cluster && cluster < 0xfff0); +} + +/* Start using a block */ +static uint8_t * +ao_fat_block_get(uint32_t block) +{ + block += partition_start; + if (block >= partition_end) + return NULL; + return ao_bufio_get(block); +} + +/* Finish using a block, 'w' is 1 if modified */ +#define ao_fat_block_put(b,w) ao_bufio_put(b,w) + +/* Start using a root directory entry */ +static uint8_t * +ao_fat_root_get(uint16_t e) +{ + uint32_t byte = e * 0x20; + uint32_t sector = byte >> 9; + uint16_t offset = byte & 0x1ff; + uint8_t *buf; + + buf = ao_fat_block_get(root_start + sector); + if (!buf) + return NULL; + return buf + offset; +} + +/* Finish using a root directory entry, 'w' is 1 if modified */ +static void +ao_fat_root_put(uint8_t *root, uint16_t e, uint8_t write) +{ + uint16_t offset = ((e * 0x20) & 0x1ff); + uint8_t *buf = root - offset; + + ao_fat_block_put(buf, write); +} + +/* Get the next cluster entry in the chain */ +static uint16_t +ao_fat_entry_read(uint16_t cluster) +{ + uint32_t sector; + uint16_t offset; + uint8_t *buf; + uint16_t ret; + + if (!ao_fat_cluster_valid(cluster)) + return 0xfff7; + + cluster -= 2; + sector = cluster >> 8; + offset = (cluster << 1) & 0x1ff; + buf = ao_fat_block_get(fat_start + sector); + if (!buf) + return 0; + ret = buf[offset] | (buf[offset+1] << 8); + ao_fat_block_put(buf, 0); + return ret; +} + +static uint16_t +ao_fat_entry_replace(uint16_t cluster, uint16_t new_value) +{ + uint32_t sector; + uint16_t offset; + uint8_t *buf; + uint16_t ret; + uint8_t other_fats; + + if (!ao_fat_cluster_valid(cluster)) + return 0; + + cluster -= 2; + sector = cluster >> 8; + offset = (cluster << 1) & 0x1ff; + buf = ao_fat_block_get(fat_start + sector); + if (!buf) + return 0; + ret = get_u16(buf + offset); + put_u16(buf + offset, new_value); + ao_fat_block_put(buf, 1); + for (other_fats = 1; other_fats < number_fat; other_fats++) { + buf = ao_fat_block_get(fat_start + other_fats * sectors_per_fat); + if (buf) { + put_u16(buf + offset, new_value); + ao_fat_block_put(buf, 1); + } + } + return ret; + +} + +static void +ao_fat_clear_cluster_chain(uint16_t cluster) +{ + while (ao_fat_cluster_valid(cluster)) + cluster = ao_fat_entry_replace(cluster, 0x0000); +} + +static uint16_t +ao_fat_cluster_seek(uint16_t cluster, uint16_t distance) +{ + while (distance) { + cluster = ao_fat_entry_read(cluster); + if (!ao_fat_cluster_valid(cluster)) + break; + distance--; + } + return cluster; +} + +static uint32_t +ao_fat_sector_seek(uint16_t cluster, uint32_t sector) +{ + cluster = ao_fat_cluster_seek(cluster, sector / sectors_per_cluster); + if (!ao_fat_cluster_valid(cluster)) + return 0xffffffff; + return data_start + (cluster-2) * sectors_per_cluster + sector % sectors_per_cluster; +} + +/* Load the boot block and find the first partition */ +static uint8_t +ao_fat_setup_partition(void) +{ + uint8_t *mbr; + uint8_t *partition; + uint32_t partition_size; + + mbr = ao_bufio_get(0); + if (!mbr) + return 0; + + /* Check the signature */ + if (mbr[0x1fe] != 0x55 || mbr[0x1ff] != 0xaa) { + printf ("Invalid MBR signature %02x %02x\n", + mbr[0x1fe], mbr[0x1ff]); + ao_bufio_put(mbr, 0); + return 0; + } + + /* Just use the first partition */ + partition = &mbr[0x1be]; + + partition_type = partition[4]; + switch (partition_type) { + case 4: /* FAT16 up to 32M */ + case 6: /* FAT16 over 32M */ + break; + case 0x0b: /* FAT32 up to 2047GB */ + case 0x0c: /* FAT32 LBA */ + break; + default: + printf ("Invalid partition type %02x\n", partition_type); + ao_bufio_put(mbr, 0); + return 0; + } + + partition_start = get_u32(partition+8); + partition_size = get_u32(partition+12); + if (partition_size == 0) { + printf ("Zero-sized partition\n"); + ao_bufio_put(mbr, 0); + return 0; + } + partition_end = partition_start + partition_size; + printf ("Partition type %02x start %08x end %08x\n", + partition_type, partition_start, partition_end); + ao_bufio_put(mbr, 0); + return 1; +} + +static uint8_t +ao_fat_setup_fs(void) +{ + uint8_t *boot = ao_fat_block_get(0); + + if (!boot) + return 0; + + /* Check the signature */ + if (boot[0x1fe] != 0x55 || boot[0x1ff] != 0xaa) { + printf ("Invalid BOOT signature %02x %02x\n", + boot[0x1fe], boot[0x1ff]); + ao_bufio_put(boot, 0); + return 0; + } + + /* Check the sector size */ + if (get_u16(boot + 0xb) != 0x200) { + printf ("Invalid sector size %d\n", + get_u16(boot + 0xb)); + ao_bufio_put(boot, 0); + return 0; + } + + sectors_per_cluster = boot[0xd]; + bytes_per_cluster = sectors_per_cluster << 9; + reserved_sector_count = get_u16(boot+0xe); + number_fat = boot[0x10]; + root_entries = get_u16(boot + 0x11); + sectors_per_fat = get_u16(boot+0x16); + + printf ("sectors per cluster %d\n", sectors_per_cluster); + printf ("reserved sectors %d\n", reserved_sector_count); + printf ("number of FATs %d\n", number_fat); + printf ("root entries %d\n", root_entries); + printf ("sectors per fat %d\n", sectors_per_fat); + + fat_start = reserved_sector_count;; + root_start = fat_start + number_fat * sectors_per_fat; + data_start = root_start + ((root_entries * 0x20 + 0x1ff) >> 9); + + printf ("fat start %d\n", fat_start); + printf ("root start %d\n", root_start); + printf ("data start %d\n", data_start); + + return 1; +} + +static uint8_t +ao_fat_setup(void) +{ + if (!ao_fat_setup_partition()) + return 0; + if (!ao_fat_setup_fs()) + return 0; + return 1; +} + +/* + * Low-level directory operations + */ + +/* + * Basic file operations + */ + +static struct ao_fat_dirent ao_file_dirent; +static uint32_t ao_file_offset; + +static uint32_t +ao_file_offset_to_sector(uint32_t offset) +{ + if (offset > ao_file_dirent.size) + return 0xffffffff; + return ao_fat_sector_seek(ao_file_dirent.cluster, offset >> 9); +} + +uint8_t +ao_fat_open(char name[11]) +{ + uint16_t entry = 0; + struct ao_fat_dirent dirent; + + while (ao_fat_readdir(&entry, &dirent)) { + if (!memcmp(name, dirent.name, 11)) { + ao_file_dirent = dirent; + ao_file_offset = 0; + return 1; + } + } + return 0; +} + + + +static uint8_t +ao_fat_set_size(uint32_t size) +{ + uint16_t clear_cluster = 0; + uint8_t *dent; + uint16_t first_cluster; + + first_cluster = ao_file_dirent.cluster; + printf ("set size to %d\n", size); + if (size == ao_file_dirent.size) + return 1; + if (size == 0) { + printf ("erase file\n"); + clear_cluster = ao_file_dirent.cluster; + first_cluster = 0; + } else { + uint16_t new_num; + uint16_t old_num; + + new_num = (size + bytes_per_cluster - 1) / bytes_per_cluster; + old_num = (ao_file_dirent.size + bytes_per_cluster - 1) / bytes_per_cluster; + if (new_num < old_num) { + uint16_t last_cluster; + + printf("Remove %d clusters\n", old_num - new_num); + /* Go find the last cluster we want to preserve in the file */ + last_cluster = ao_fat_cluster_seek(ao_file_dirent.cluster, new_num - 1); + + printf ("Last cluster is now %04x\n", last_cluster); + /* Rewrite that cluster entry with 0xffff to mark the end of the chain */ + clear_cluster = ao_fat_entry_replace(last_cluster, 0xffff); + } else if (new_num > old_num) { + uint16_t need; + uint16_t free; + uint16_t last_cluster; + + if (old_num) + last_cluster = ao_fat_cluster_seek(ao_file_dirent.cluster, old_num - 1); + else + last_cluster = 0; + + need = new_num - old_num; + printf ("Need %d clusters\n", need); + /* See if there are enough free clusters in the file system */ + for (free = 2; need > 0 && (free - 2) < sectors_per_fat * 256; free++) { + if (!ao_fat_entry_read(free)) { + printf ("\tCluster %04x available\n", free); + need--; + } + } + /* Still need some, tell the user that we've failed */ + if (need) { + printf ("File system full\n"); + return 0; + } + + need = new_num - old_num; + /* Now go allocate those clusters */ + for (free = 2; need > 0 && (free - 2) < sectors_per_fat * 256; free++) { + if (!ao_fat_entry_read(free)) { + printf ("\tAllocate %04x\n", free); + if (last_cluster) + ao_fat_entry_replace(last_cluster, free); + else + first_cluster = free; + last_cluster = free; + need--; + } + } + /* Mark the new end of the chain */ + ao_fat_entry_replace(last_cluster, 0xffff); + } + } + + /* Deallocate clusters off the end of the file */ + if (ao_fat_cluster_valid(clear_cluster)) { + printf ("Clear clusters starting with %04x\n", clear_cluster); + ao_fat_clear_cluster_chain(clear_cluster); + } + + dent = ao_fat_root_get(ao_file_dirent.entry); + if (!dent) + return 0; + put_u32(dent + 0x1c, size); + put_u16(dent + 0x1a, first_cluster); + ao_fat_root_put(dent, ao_file_dirent.entry, 1); + ao_file_dirent.size = size; + ao_file_dirent.cluster = first_cluster; + return 1; +} + +uint8_t +ao_fat_creat(char name[11]) +{ + uint16_t entry; + + if (ao_fat_open(name)) + return ao_fat_set_size(0); + + for (entry = 0; entry < root_entries; entry++) { + uint8_t *dent = ao_fat_root_get(entry); + + if (dent[0] == AO_FAT_DENT_EMPTY || + dent[0] == AO_FAT_DENT_END) { + memmove(dent, name, 11); + dent[0x0b] = 0x00; + dent[0x0c] = 0x00; + dent[0x0d] = 0x00; + /* XXX fix time */ + put_u16(dent + 0x0e, 0); + /* XXX fix date */ + put_u16(dent + 0x10, 0); + /* XXX fix date */ + put_u16(dent + 0x12, 0); + /* XXX FAT32 high cluster bytes */ + put_u16(dent + 0x14, 0); + /* XXX fix time */ + put_u16(dent + 0x16, 0); + /* XXX fix date */ + put_u16(dent + 0x18, 0); + /* cluster number */ + put_u16(dent + 0x1a, 0); + /* size */ + put_u32(dent + 0x1c, 0); + ao_fat_root_put(dent, entry, 1); + return ao_fat_open(name); + } + } + return 0; +} + +void +ao_fat_close(void) +{ + memset(&ao_file_dirent, '\0', sizeof (struct ao_fat_dirent)); + ao_bufio_flush(); +} + +int +ao_fat_read(uint8_t *dest, int len) +{ + uint32_t sector; + uint16_t this_time; + uint16_t offset; + uint8_t *buf; + int ret = 0; + + if (ao_file_offset + len > ao_file_dirent.size) + len = ao_file_dirent.size - ao_file_offset; + + while (len) { + offset = ao_file_offset & 0x1ff; + if (offset + len < 512) + this_time = len; + else + this_time = 512 - offset; + + sector = ao_file_offset_to_sector(ao_file_offset); + if (sector == 0xffffffff) + break; + buf = ao_fat_block_get(sector); + if (!buf) + break; + memcpy(dest, buf + offset, this_time); + ao_fat_block_put(buf, 0); + + ret += this_time; + len -= this_time; + dest += this_time; + ao_file_offset += this_time; + } + return ret; +} + +int +ao_fat_write(uint8_t *src, int len) +{ + uint32_t sector; + uint16_t this_time; + uint16_t offset; + uint8_t *buf; + int ret = 0; + + if (ao_file_offset + len > ao_file_dirent.size) { + if (!ao_fat_set_size(ao_file_offset + len)) + return 0; + } + + while (len) { + offset = ao_file_offset & 0x1ff; + if (offset + len < 512) + this_time = len; + else + this_time = 512 - offset; + + sector = ao_file_offset_to_sector(ao_file_offset); + if (sector == 0xffffffff) + break; + buf = ao_fat_block_get(sector); + if (!buf) + break; + memcpy(buf + offset, src, this_time); + ao_fat_block_put(buf, 1); + + ret += this_time; + len -= this_time; + src += this_time; + ao_file_offset += this_time; + } + return 0; +} + +uint32_t +ao_fat_seek(int32_t pos, uint8_t whence) +{ + switch (whence) { + case AO_FAT_SEEK_SET: + ao_file_offset = pos; + break; + case AO_FAT_SEEK_CUR: + ao_file_offset += pos; + break; + case AO_FAT_SEEK_END: + ao_file_offset = ao_file_dirent.size + pos; + break; + } + if (ao_file_offset > ao_file_dirent.size) + ao_fat_set_size(ao_file_offset); + return ao_file_offset; +} + +uint8_t +ao_fat_unlink(char name[11]) +{ + uint16_t entry = 0; + struct ao_fat_dirent dirent; + + while (ao_fat_readdir(&entry, &dirent)) { + if (memcmp(name, dirent.name, 11) == 0) { + uint8_t *next; + uint8_t *ent; + uint8_t delete; + ao_fat_clear_cluster_chain(dirent.cluster); + next = ao_fat_root_get(dirent.entry + 1); + if (next && next[0] != AO_FAT_DENT_END) + delete = AO_FAT_DENT_EMPTY; + else + delete = AO_FAT_DENT_END; + if (next) + ao_fat_root_put(next, dirent.entry + 1, 0); + ent = ao_fat_root_get(dirent.entry); + if (ent) { + memset(ent, '\0', 0x20); + *ent = delete; + ao_fat_root_put(ent, dirent.entry, 1); + } + ao_bufio_flush(); + return 1; + } + } + return 0; +} + +uint8_t +ao_fat_rename(char old[11], char new[11]) +{ + return 0; +} + +uint8_t +ao_fat_readdir(uint16_t *entry, struct ao_fat_dirent *dirent) +{ + uint8_t *dent; + + if (*entry >= root_entries) + return 0; + for (;;) { + dent = ao_fat_root_get(*entry); + + if (dent[0] == AO_FAT_DENT_END) { + ao_fat_root_put(dent, *entry, 0); + return 0; + } + if (dent[0] != AO_FAT_DENT_EMPTY && + (dent[0x0b] & (AO_FAT_FILE_DIRECTORY|AO_FAT_FILE_VOLUME_LABEL)) == 0) + break; + ao_fat_root_put(dent, *entry, 0); + (*entry)++; + } + memcpy(dirent->name, dent, 11); + dirent->attr = dent[0xb]; + dirent->size = get_u32(dent+0x1c); + dirent->cluster = get_u16(dent+0x1a); + dirent->entry = *entry; + ao_fat_root_put(dent, *entry, 0); + (*entry)++; + return 1; +} + +static void +ao_fat_list(void) +{ + uint16_t entry = 0; + struct ao_fat_dirent dirent; + + while (ao_fat_readdir(&entry, &dirent)) { + printf ("%-8.8s.%-3.3s %02x %d\n", + dirent.name, dirent.name + 8, dirent.attr, dirent.size); + } +} + +static void +ao_fat_test(void) +{ + ao_fat_setup(); + ao_fat_list(); +} + +static const struct ao_cmds ao_fat_cmds[] = { + { ao_fat_test, "F\0Test FAT" }, + { 0, NULL }, +}; + +void +ao_fat_init(void) +{ + ao_bufio_init(); + ao_cmd_register(&ao_fat_cmds[0]); +} + diff --git a/src/drivers/ao_fat.h b/src/drivers/ao_fat.h new file mode 100644 index 00000000..2bf6222e --- /dev/null +++ b/src/drivers/ao_fat.h @@ -0,0 +1,73 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_FAT_H_ +#define _AO_FAT_H_ + +void +ao_fat_init(void); + +#define AO_FAT_FILE_READ_ONLY 0x01 +#define AO_FAT_FILE_HIDDEN 0x02 +#define AO_FAT_FILE_SYSTEM 0x04 +#define AO_FAT_FILE_VOLUME_LABEL 0x08 +#define AO_FAT_FILE_DIRECTORY 0x10 +#define AO_FAT_FILE_ARCHIVE 0x20 + +#define AO_FAT_DENT_EMPTY 0xe5 +#define AO_FAT_DENT_END 0x00 + +uint8_t +ao_fat_open(char name[11]); + +uint8_t +ao_fat_creat(char name[11]); + +void +ao_fat_close(void); + +int +ao_fat_read(uint8_t *dest, int len); + +int +ao_fat_write(uint8_t *buf, int len); + +#define AO_FAT_SEEK_SET 0 +#define AO_FAT_SEEK_CUR 1 +#define AO_FAT_SEEK_END 2 + +uint32_t +bao_fat_seek(int32_t pos, uint8_t whence); + +uint8_t +ao_fat_unlink(char name[11]); + +uint8_t +ao_fat_rename(char old[11], char new[11]); + +struct ao_fat_dirent { + char name[11]; + uint8_t attr; + uint32_t size; + uint16_t cluster; + uint16_t entry; +}; + +uint8_t +ao_fat_readdir(uint16_t *entry, struct ao_fat_dirent *dirent); + +#endif /* _AO_FAT_H_ */ diff --git a/src/drivers/ao_sdcard.c b/src/drivers/ao_sdcard.c new file mode 100644 index 00000000..2174af1e --- /dev/null +++ b/src/drivers/ao_sdcard.c @@ -0,0 +1,398 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" +#include "ao_sdcard.h" + +#define ao_sdcard_get_slow() ao_spi_get(AO_SDCARD_SPI_BUS, AO_SPI_SPEED_250kHz) +#define ao_sdcard_get() ao_spi_get(AO_SDCARD_SPI_BUS, AO_SPI_SPEED_FAST) +#define ao_sdcard_put() ao_spi_put(AO_SDCARD_SPI_BUS) +#define ao_sdcard_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_SDCARD_SPI_BUS) +#define ao_sdcard_send(d,l) ao_spi_send((d), (l), AO_SDCARD_SPI_BUS) +#define ao_sdcard_recv(d,l) ao_spi_recv((d), (l), AO_SDCARD_SPI_BUS) +#define ao_sdcard_select() ao_gpio_set(AO_SDCARD_SPI_CS_PORT,AO_SDCARD_SPI_CS_PIN,AO_SDCARD_SPI_CS,0) +#define ao_sdcard_deselect() ao_gpio_set(AO_SDCARD_SPI_CS_PORT,AO_SDCARD_SPI_CS_PIN,AO_SDCARD_SPI_CS,1) + + +static uint8_t initialized; +static uint8_t present; +static uint8_t mutex; +static enum ao_sdtype sdtype; + +#define ao_sdcard_lock() ao_mutex_get(&mutex) +#define ao_sdcard_unlock() ao_mutex_put(&mutex) + +#if 0 +#define DBG(...) printf(__VA_ARGS__) +#else +#define DBG(...) +#endif + +/* + * Send an SD command and await the status reply + */ + +static uint8_t +ao_sdcard_send_cmd(uint8_t cmd, uint32_t arg) +{ + uint8_t data[6]; + uint8_t reply; + int i; + + DBG ("\tsend_cmd %d arg %08x\n", cmd, arg); + if (cmd != SDCARD_GO_IDLE_STATE) { + for (i = 0; i < SDCARD_CMD_TIMEOUT; i++) { + ao_sdcard_recv(&reply, 1); + if (reply == 0xff) + break; + } + if (i == SDCARD_CMD_TIMEOUT) + return SDCARD_STATUS_TIMEOUT; + } + + data[0] = cmd & 0x3f | 0x40; + data[1] = arg >> 24; + data[2] = arg >> 16; + data[3] = arg >> 8; + data[4] = arg; + if (cmd == SDCARD_GO_IDLE_STATE) + data[5] = 0x95; /* Valid for 0 arg */ + else if (cmd == SDCARD_SEND_IF_COND) + data[5] = 0x87; /* Valid for 0x1aa arg */ + else + data[5] = 0xff; /* no CRC */ + ao_sdcard_send(data, 6); + + /* The first reply byte will be the status, + * which must have the high bit clear + */ + for (i = 0; i < SDCARD_CMD_TIMEOUT; i++) { + ao_sdcard_recv(&reply, 1); + DBG ("\t\tgot byte %02x\n", reply); + if ((reply & 0x80) == 0) + return reply; + } + return SDCARD_STATUS_TIMEOUT; +} + +/* + * Retrieve any reply, discarding the trailing CRC byte + */ +static void +ao_sdcard_recv_reply(uint8_t *reply, int len) +{ + uint8_t discard; + + if (len) + ao_sdcard_recv(reply, len); + /* trailing byte */ + ao_sdcard_recv(&discard, 1); +} + +/* + * Wait while the card is busy. The + * card will return a stream of 0xff + * until it isn't busy anymore + */ +static void +ao_sdcard_wait_busy(void) +{ + uint8_t v; + + do { + ao_sdcard_recv(&v, 1); + } while (v != 0xff); + ao_sdcard_send_fixed(0xff, 1); +} + +static uint8_t +ao_sdcard_go_idle_state(void) +{ + uint8_t ret; + + DBG ("go_idle_state\n"); + ao_sdcard_select(); + ret = ao_sdcard_send_cmd(SDCARD_GO_IDLE_STATE, 0); + ao_sdcard_recv_reply(NULL, 0); + ao_sdcard_deselect(); + DBG ("\tgo_idle_state status %02x\n", ret); + return ret; +} + +static uint8_t +ao_sdcard_send_op_cond(void) +{ + uint8_t ret; + + DBG ("send_op_cond\n"); + ao_sdcard_select(); + ret = ao_sdcard_send_cmd(SDCARD_SEND_OP_COND, 0); + ao_sdcard_recv_reply(NULL, 0); + ao_sdcard_deselect(); + DBG ("\tsend_op_cond %02x\n", ret); + return ret; +} + +static uint8_t +ao_sdcard_send_if_cond(uint32_t arg, uint8_t send_if_cond_response[4]) +{ + uint8_t ret; + + DBG ("send_if_cond\n"); + ao_sdcard_select(); + ret = ao_sdcard_send_cmd(SDCARD_SEND_IF_COND, arg); + if (ret != SDCARD_STATUS_IDLE_STATE) { + DBG ("\tsend_if_cond failed %02x\n", ret); + return ret; + } + ao_sdcard_recv_reply(send_if_cond_response, 4); + DBG ("send_if_cond status %02x response %02x %02x %02x %02x\n", + ret, + send_if_cond_response[0], + send_if_cond_response[1], + send_if_cond_response[2], + send_if_cond_response[3]); + ao_sdcard_deselect(); + return ret; +} + +static uint8_t +ao_sdcard_set_blocklen(uint32_t blocklen) +{ + uint8_t ret; + + DBG ("set_blocklen %d\n", blocklen); + ao_sdcard_select(); + ret = ao_sdcard_send_cmd(SDCARD_SET_BLOCKLEN, blocklen); + ao_sdcard_recv_reply(NULL, 0); + if (ret != SDCARD_STATUS_READY_STATE) + DBG ("\tsend_if_cond failed %02x\n", ret); + return ret; + +} + +static uint8_t +ao_sdcard_app_cmd(void) +{ + uint8_t ret; + + DBG ("app_cmd\n"); + ao_sdcard_select(); + ret = ao_sdcard_send_cmd(SDCARD_APP_CMD, 0); + ao_sdcard_recv_reply(NULL, 0); + ao_sdcard_deselect(); + DBG ("\tapp_cmd status %02x\n"); + return ret; +} + +static uint8_t +ao_sdcard_app_send_op_cond(uint32_t arg) +{ + uint8_t ret; + + ret = ao_sdcard_app_cmd(); + if (ret != SDCARD_STATUS_IDLE_STATE) + return ret; + DBG("send_op_comd\n"); + ao_sdcard_select(); + ret = ao_sdcard_send_cmd(SDCARD_APP_SEND_OP_COMD, arg); + ao_sdcard_recv_reply(NULL, 0); + ao_sdcard_deselect(); + DBG ("\tapp_send_op_cond status %02x\n", ret); + return ret; +} + +static uint8_t +ao_sdcard_read_ocr(uint8_t read_ocr_response[4]) +{ + uint8_t ret; + + DBG ("read_ocr\n"); + ao_sdcard_select(); + ret = ao_sdcard_send_cmd(SDCARD_READ_OCR, 0); + if (ret != SDCARD_STATUS_READY_STATE) + DBG ("\tread_ocr failed %02x\n", ret); + else { + ao_sdcard_recv_reply(read_ocr_response, 4); + DBG ("\tread_ocr status %02x response %02x %02x %02x %02x\n", ret, + read_ocr_response[0], read_ocr_response[1], + read_ocr_response[2], read_ocr_response[3]); + } + ao_sdcard_deselect(); + return ret; +} + +static void +ao_sdcard_setup(void) +{ + int i; + uint8_t ret; + uint8_t response[10]; + + DBG ("Testing sdcard\n"); + + ao_sdcard_get_slow(); + /* + * min 74 clocks with CS high + */ + ao_sdcard_send_fixed(0xff, 10); + + ao_delay(AO_MS_TO_TICKS(10)); + + /* Reset the card and get it into SPI mode */ + + for (i = 0; i < SDCARD_IDLE_WAIT; i++) { + if (ao_sdcard_go_idle_state() == SDCARD_STATUS_IDLE_STATE) + break; + } + if (i == SDCARD_IDLE_WAIT) + goto bail; + + /* Figure out what kind of card we have */ + + sdtype = ao_sdtype_unknown; + + if (ao_sdcard_send_if_cond(0x1aa, response) == SDCARD_STATUS_IDLE_STATE) { + uint32_t arg = 0; + uint8_t sdver2 = 0; + + /* Check for SD version 2 */ + if ((response[2] & 0xf) == 1 && response[3] == 0xaa) { + arg = 0x40000000; + sdver2 = 1; + } + + for (i = 0; i < SDCARD_IDLE_WAIT; i++) { + ret = ao_sdcard_app_send_op_cond(arg); + if (ret != SDCARD_STATUS_IDLE_STATE) + break; + } + if (ret != SDCARD_STATUS_READY_STATE) { + /* MMC */ + for (i = 0; i < SDCARD_IDLE_WAIT; i++) { + ret = ao_sdcard_send_op_cond(); + if (ret != SDCARD_STATUS_IDLE_STATE) + break; + } + if (ret != SDCARD_STATUS_READY_STATE) + goto bail; + sdtype = ao_sdtype_mmc3; + } else { + /* SD */ + if (sdver2 != 0) { + ret = ao_sdcard_read_ocr(response); + if (ret != SDCARD_STATUS_READY_STATE) + goto bail; + if ((response[0] & 0xc0) == 0xc0) + sdtype = ao_sdtype_sd2block; + else + sdtype = ao_sdtype_sd2byte; + } else { + sdtype = ao_sdtype_sd1; + } + } + + /* For everything but SDHC cards, set the block length */ + if (sdtype != ao_sdtype_sd2block) { + ret = ao_sdcard_set_blocklen(512); + if (ret != SDCARD_STATUS_READY_STATE) + DBG ("set_blocklen failed, ignoring\n"); + } + } + + DBG ("SD card detected, type %d\n", sdtype); +bail: + ao_sdcard_put(); +} + +static uint8_t +ao_sdcard_wait_block_start(void) +{ + int i; + uint8_t v; + + DBG ("\twait_block_start\n"); + for (i = 0; i < SDCARD_BLOCK_TIMEOUT; i++) { + ao_sdcard_recv(&v, 1); + DBG("\t\trecv %02x\n", v); + if (v != 0xff) + break; + } + return v; +} + +/* + * Read a block of 512 bytes from the card + */ +uint8_t +ao_sdcard_read_block(uint32_t block, uint8_t *data) +{ + uint8_t ret; + uint8_t crc[2]; + + ao_sdcard_lock(); + if (!initialized) { + ao_sdcard_setup(); + initialized = 1; + if (sdtype != ao_sdtype_unknown) + present = 1; + } + if (!present) { + ao_sdcard_unlock(); + return 0; + } + if (sdtype != ao_sdtype_sd2block) + block <<= 9; + ao_sdcard_get(); + ao_sdcard_select(); + ret = ao_sdcard_send_cmd(SDCARD_READ_BLOCK, block); + ao_sdcard_recv_reply(NULL, 0); + if (ret != SDCARD_STATUS_READY_STATE) + goto bail; + + if (ao_sdcard_wait_block_start() != 0xfe) { + ret = 0x3f; + goto bail; + } + + ao_sdcard_recv(data, 512); + ao_sdcard_recv(crc, 2); +bail: + ao_sdcard_deselect(); + ao_sdcard_put(); + ao_sdcard_unlock(); + return ret == SDCARD_STATUS_READY_STATE; +} + +/* + * Write a block of 512 bytes to the card + */ +uint8_t +ao_sdcard_write_block(uint32_t block, uint8_t *data) +{ + /* Not doing anything until the file system code seems reasonable + */ + return 1; +} + +void +ao_sdcard_init(void) +{ + ao_spi_init_cs(AO_SDCARD_SPI_CS_PORT, (1 << AO_SDCARD_SPI_CS_PIN)); +} + + diff --git a/src/drivers/ao_sdcard.h b/src/drivers/ao_sdcard.h new file mode 100644 index 00000000..b9f737c5 --- /dev/null +++ b/src/drivers/ao_sdcard.h @@ -0,0 +1,75 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_SDCARD_H_ +#define _AO_SDCARD_H_ + +uint8_t +ao_sdcard_read_block(uint32_t block, uint8_t *data); + +uint8_t +ao_sdcard_write_block(uint32_t block, uint8_t *data); + +void +ao_sdcard_init(void); + +/* Commands */ +#define SDCARD_GO_IDLE_STATE 0 +#define SDCARD_SEND_OP_COND 1 +#define SDCARD_SEND_IF_COND 8 +#define SDCARD_SEND_CSD 9 +#define SDCARD_SEND_CID 10 +#define SDCARD_SEND_STATUS 13 +#define SDCARD_SET_BLOCKLEN 16 +#define SDCARD_READ_BLOCK 17 +#define SDCARD_WRITE_BLOCK 24 +#define SDCARD_WRITE_MULTIPLE_BLOCK 25 +#define SDCARD_ERASE_WR_BLK_START 32 +#define SDCARD_ERASE_WR_BLK_END 33 +#define SDCARD_ERASE 38 +#define SDCARD_APP_CMD 55 +#define SDCARD_READ_OCR 58 + +/* App commands */ +#define SDCARD_APP_SET_WR_BLK_ERASE_COUNT 23 +#define SDCARD_APP_SEND_OP_COMD 41 + +/* Status */ +#define SDCARD_STATUS_READY_STATE 0 +#define SDCARD_STATUS_IDLE_STATE 1 +#define SDCARD_STATUS_ILLEGAL_COMMAND 4 +#define SDCARD_STATUS_TIMEOUT 0xff + +#define SDCARD_DATA_START_BLOCK 0xfe +#define SDCARD_STOP_TRAN_TOKEN 0xfd +#define SDCARD_WRITE_MULTIPLE_TOKEN 0xfc +#define SDCARD_DATA_RES_MASK 0x1f +#define SDCARD_DATA_RES_ACCEPTED 0x05 + +#define SDCARD_CMD_TIMEOUT 100 +#define SDCARD_IDLE_WAIT 100 +#define SDCARD_BLOCK_TIMEOUT 100 + +enum ao_sdtype { + ao_sdtype_unknown, + ao_sdtype_mmc3, + ao_sdtype_sd1, + ao_sdtype_sd2byte, + ao_sdtype_sd2block, +}; + +#endif /* _AO_SDCARD_H_ */ diff --git a/src/test/Makefile b/src/test/Makefile index fccc7937..96170cc1 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -2,7 +2,7 @@ vpath % ..:../core:../drivers:../util:../micropeak 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 \ - ao_aprs_test ao_micropeak_test + ao_aprs_test ao_micropeak_test ao_fat_test INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h @@ -64,3 +64,6 @@ check: ao_fec_test ao_flight_test ao_flight_test_baro run-tests ao_micropeak_test: ao_micropeak_test.c ao_microflight.c ao_kalman.h cc $(CFLAGS) -o $@ ao_micropeak_test.c -lm + +ao_fat_test: ao_fat_test.c ao_fat.c ao_bufio.c + cc $(CFLAGS) -o $@ ao_fat_test.c diff --git a/src/test/ao_fat_test.c b/src/test/ao_fat_test.c new file mode 100644 index 00000000..22ac03ad --- /dev/null +++ b/src/test/ao_fat_test.c @@ -0,0 +1,118 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define AO_FAT_TEST + +void +ao_mutex_get(uint8_t *mutex) +{ +} + +void +ao_mutex_put(uint8_t *mutex) +{ +} + +void +ao_panic(uint8_t panic) +{ + printf ("panic %d\n", panic); + exit(1); +} + +#define AO_PANIC_BUFIO 15 + +#define ao_cmd_success 0 + +uint8_t ao_cmd_status; +uint32_t ao_cmd_lex_u32; + +void +ao_cmd_decimal() +{ +} + +#define ao_cmd_register(x) + +struct ao_cmds { + void (*func)(void); + const char *help; +}; + +int fs_fd; + +uint8_t +ao_sdcard_read_block(uint32_t block, uint8_t *data) +{ + lseek(fs_fd, block * 512, 0); + return read(fs_fd, data, 512) == 512; +} + +uint8_t +ao_sdcard_write_block(uint32_t block, uint8_t *data) +{ + lseek(fs_fd, block * 512, 0); + return write(fs_fd, data, 512) == 512; +} + +void +ao_sdcard_init(void) +{ + fs_fd = open("fat.fs", 2); +} + +#include "ao_bufio.c" +#include "ao_fat.c" + +int +main(int argc, char **argv) +{ + uint8_t data[15]; + int len; + ao_fat_init(); + ao_fat_test(); + if (ao_fat_open("DATALOG TXT")) { + printf ("DATALOG.TXT\n"); + while ((len = ao_fat_read(data, sizeof (data))) > 0) { + write(1, data, len); + } + ao_fat_close(); +// ao_fat_unlink("DATALOG TXT"); + } + if (ao_fat_open("NEWFILE TXT")) { + printf ("NEWFILE.TXT\n"); + while ((len = ao_fat_read(data, sizeof (data))) > 0) { + write(1, data, len); + } + ao_fat_close(); + } + if (ao_fat_creat ("NEWFILE TXT")) { + for (len = 0; len < 4095; len++) + ao_fat_write((uint8_t *) "hello, world!\n", 14); + ao_fat_close(); + } + return 0; +} -- cgit v1.2.3 From bd43955ff0c4d39a685b79e91cb62898a5f1b875 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 27 Mar 2013 01:14:15 -0700 Subject: altos: Hook up the FAT16 and SD card support to telegps Signed-off-by: Keith Packard --- src/telegps-v0.1/Makefile | 10 +++++++++- src/telegps-v0.1/ao_pins.h | 38 +++++++++++++++++++++++++++++++------- src/telegps-v0.1/ao_telegps.c | 6 ++++++ 3 files changed, 46 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/telegps-v0.1/Makefile b/src/telegps-v0.1/Makefile index 26d9eaa0..c8ab8a9a 100644 --- a/src/telegps-v0.1/Makefile +++ b/src/telegps-v0.1/Makefile @@ -14,6 +14,7 @@ INC = \ ao_task.h \ ao_whiten.h \ ao_cc115l.h \ + ao_rf_cc115l.h \ ao_fec.h \ stm32l.h \ Makefile @@ -48,7 +49,14 @@ ALTOS_SRC = \ ao_serial_stm.c \ ao_gps_skytraq.c \ ao_cc115l.c \ - ao_fec_tx.c + ao_fec_tx.c \ + ao_rfpa0133.c \ + ao_aprs.c \ + ao_storage.c \ + ao_eeprom_stm.c \ + ao_sdcard.c \ + ao_bufio.c \ + ao_fat.c PRODUCT=TeleGPS-v0.1 PRODUCT_DEF=-DTELEGPS diff --git a/src/telegps-v0.1/ao_pins.h b/src/telegps-v0.1/ao_pins.h index 46d0b9f2..01f4a303 100644 --- a/src/telegps-v0.1/ao_pins.h +++ b/src/telegps-v0.1/ao_pins.h @@ -64,17 +64,20 @@ #define ao_gps_set_speed ao_serial2_set_speed #define ao_gps_fifo (ao_stm_usart2.rx_fifo) -#define HAS_EEPROM 0 -#define USE_INTERNAL_FLASH 0 +#define HAS_EEPROM 1 +#define USE_INTERNAL_FLASH 1 #define HAS_USB 1 #define HAS_BEEP 0 -#define HAS_RADIO 0 -#define HAS_TELEMETRY 0 +#define HAS_RADIO 1 +#define HAS_TELEMETRY 1 +#define HAS_APRS 1 +#define HAS_RADIO_RECV 0 -#define HAS_SPI_1 0 -#define SPI_1_PA5_PA6_PA7 0 +#define HAS_SPI_1 1 +#define SPI_1_PA5_PA6_PA7 1 /* SD card */ #define SPI_1_PB3_PB4_PB5 0 #define SPI_1_PE13_PE14_PE15 0 +#define SPI_1_OSPEEDR STM_OSPEEDR_10MHz #define HAS_SPI_2 1 #define SPI_2_PB13_PB14_PB15 1 /* CC115L */ @@ -108,7 +111,7 @@ #define LEDS_AVAILABLE (AO_LED_RED | AO_LED_GREEN) -#define HAS_GPS 0 +#define HAS_GPS 1 #define HAS_FLIGHT 0 #define HAS_ADC 0 #define HAS_LOG 0 @@ -147,5 +150,26 @@ #define AO_CC115L_MARC_GPIO 0 #define AO_CC115L_MARC_GPIO_IOCFG CC115L_IOCFG0 +#define AO_RADIO_HAS_PA 1 + +/* + * Power amplifier (RFPA0133) + */ + +#define AO_PA_POWER_GPIO (&stm_gpiob) +#define AO_PA_POWER_PIN 1 +#define AO_PA_GAIN_8_GPIO (&stm_gpiob) +#define AO_PA_GAIN_8_PIN 10 +#define AO_PA_GAIN_16_GPIO (&stm_gpiob) +#define AO_PA_GAIN_16_PIN 11 + +/* + * SD card + */ + +#define AO_SDCARD_SPI_BUS AO_SPI_1_PA5_PA6_PA7 +#define AO_SDCARD_SPI_CS_PORT (&stm_gpioa) +#define AO_SDCARD_SPI_CS_PIN 4 +#define AO_SDCARD_SPI stm_spi1 #endif /* _AO_PINS_H_ */ diff --git a/src/telegps-v0.1/ao_telegps.c b/src/telegps-v0.1/ao_telegps.c index fdf365e3..2f1f38f2 100644 --- a/src/telegps-v0.1/ao_telegps.c +++ b/src/telegps-v0.1/ao_telegps.c @@ -17,6 +17,7 @@ #include #include +#include int main(void) @@ -32,10 +33,13 @@ main(void) // ao_led_on(AO_LED_RED); ao_timer_init(); + ao_spi_init(); ao_dma_init(); ao_exti_init(); + ao_storage_init(); + ao_serial_init(); ao_cmd_init(); @@ -45,6 +49,8 @@ main(void) ao_gps_init(); + ao_fat_init(); + ao_config_init(); ao_start_scheduler(); -- cgit v1.2.3 From 561175afebc63ec3d2f8f7305235c9812ceaf501 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 27 Mar 2013 01:15:04 -0700 Subject: altos: Add new panic flag for bufio misuse Allow the bufio code to signal a fatal error if someone misuses the API Signed-off-by: Keith Packard --- src/core/ao.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/core/ao.h b/src/core/ao.h index 6cfdcba8..6d617cfc 100644 --- a/src/core/ao.h +++ b/src/core/ao.h @@ -65,6 +65,7 @@ #define AO_PANIC_STACK 12 /* Stack overflow */ #define AO_PANIC_SPI 13 /* SPI communication failure */ #define AO_PANIC_CRASH 14 /* Processor crashed */ +#define AO_PANIC_BUFIO 15 /* Mis-using bufio API */ #define AO_PANIC_SELF_TEST_CC1120 0x40 | 1 /* Self test failure */ #define AO_PANIC_SELF_TEST_HMC5883 0x40 | 2 /* Self test failure */ #define AO_PANIC_SELF_TEST_MPU6000 0x40 | 3 /* Self test failure */ -- cgit v1.2.3 From 4a68878a66508e6f1523cd813b2e37bcf2e90ab3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 27 Mar 2013 01:25:24 -0700 Subject: altos: Teleshield has a radio, set HAS_RADIO in ao_pins.h Otherwise, lots of random code won't know about the radio.. Signed-off-by: Keith Packard --- src/teleshield-v0.1/ao_pins.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/teleshield-v0.1/ao_pins.h b/src/teleshield-v0.1/ao_pins.h index 701e25fc..888512b1 100644 --- a/src/teleshield-v0.1/ao_pins.h +++ b/src/teleshield-v0.1/ao_pins.h @@ -60,6 +60,7 @@ #define LEGACY_MONITOR 0 #define HAS_RSSI 0 #define HAS_AES 0 + #define HAS_RADIO 1 #endif #if DBG_ON_P1 -- cgit v1.2.3 From 985cd22b941415b1ae2709ae1ab6b60c3d815ec1 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 27 Mar 2013 18:43:42 -0700 Subject: altos: Use FTDW, clear DATA bit. Disable backup write protection The newer(?) chips in telegps didn't like the previous programming scheme, so go back to fixed time for write, which does an implicit erase before every write. Also clear the DATA bit, which is only needed for double word erase/programming. Signed-off-by: Keith Packard --- src/stm/ao_eeprom_stm.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/stm/ao_eeprom_stm.c b/src/stm/ao_eeprom_stm.c index 5a75a97d..58783f1a 100644 --- a/src/stm/ao_eeprom_stm.c +++ b/src/stm/ao_eeprom_stm.c @@ -55,10 +55,16 @@ ao_storage_erase(ao_pos_t pos) __reentrant static void ao_intflash_unlock(void) { + /* Disable backup write protection */ + stm_pwr.cr |= (1 << STM_PWR_CR_DBP); + /* Unlock Data EEPROM and FLASH_PECR register */ stm_flash.pekeyr = STM_FLASH_PEKEYR_PEKEY1; stm_flash.pekeyr = STM_FLASH_PEKEYR_PEKEY2; + if (stm_flash.pecr & (1 << STM_FLASH_PECR_PELOCK)) + printf ("eeprom unlock failed\n"); + /* Configure the FTDW bit (FLASH_PECR[8]) to execute * word write, whatever the previous value of the word * being written to @@ -68,8 +74,8 @@ ao_intflash_unlock(void) (0 << STM_FLASH_PECR_EOPIE) | (0 << STM_FLASH_PECR_FPRG) | (0 << STM_FLASH_PECR_ERASE) | - (0 << STM_FLASH_PECR_FTDW) | - (1 << STM_FLASH_PECR_DATA) | + (1 << STM_FLASH_PECR_FTDW) | + (0 << STM_FLASH_PECR_DATA) | (0 << STM_FLASH_PECR_PROG) | (0 << STM_FLASH_PECR_OPTLOCK) | (0 << STM_FLASH_PECR_PRGLOCK) | @@ -97,15 +103,9 @@ ao_intflash_write32(uint16_t pos, uint32_t w) addr = (uint32_t *) (stm_eeprom + pos); - /* Erase previous word */ - *addr = 0; + /* Write a word to a valid address in the data EEPROM */ + *addr = w; ao_intflash_wait(); - - if (w) { - /* Write a word to a valid address in the data EEPROM */ - *addr = w; - ao_intflash_wait(); - } } static void -- cgit v1.2.3 From d1fe0654b45cc8f944394308cf29945b537becc4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 28 Mar 2013 15:55:35 -0700 Subject: altos: Add sanity checking to busy counts in bufio driver Make sure the busy counts don't underflow or overflow. Signed-off-by: Keith Packard --- src/drivers/ao_bufio.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/drivers/ao_bufio.c b/src/drivers/ao_bufio.c index 9a5e801b..10b32ceb 100644 --- a/src/drivers/ao_bufio.c +++ b/src/drivers/ao_bufio.c @@ -205,10 +205,13 @@ ao_bufio_get(uint32_t block) bufio->block = 0xffffffff; bufio = NULL; } - } + } else + ao_panic(AO_PANIC_BUFIO); } if (bufio) { bufio->busy++; + if (!bufio->busy) + ao_panic(AO_PANIC_BUFIO); buf = ao_bufio_to_buf(bufio); } ao_bufio_unlock(); @@ -227,6 +230,9 @@ ao_bufio_put(uint8_t *buf, uint8_t write) ao_bufio_lock(); bufio = ao_buf_to_bufio(buf); + if (!bufio->busy) + ao_panic(AO_PANIC_BUFIO); + DBG ("idle buffer %d write %d\n", ao_bufio_to_num(bufio), write); bufio->dirty |= write; if (!--bufio->busy) { -- cgit v1.2.3 From c7b606e93a4e4fbd2c0e883352ed74619ee24cf7 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 28 Mar 2013 16:05:24 -0700 Subject: altos: Clean up fat driver API. Improve fat test Make FAT api provide reasonable error return values, change the tests to write and then read a pile of files, checking that the contents are correct (using md5sum). Signed-off-by: Keith Packard --- src/drivers/ao_fat.c | 602 +++++++++++++++++++++++++++++++++---------------- src/drivers/ao_fat.h | 45 +++- src/test/Makefile | 2 +- src/test/ao_fat_test.c | 310 +++++++++++++++++++++++-- 4 files changed, 732 insertions(+), 227 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_fat.c b/src/drivers/ao_fat.c index a1476168..c0412380 100644 --- a/src/drivers/ao_fat.c +++ b/src/drivers/ao_fat.c @@ -22,11 +22,17 @@ #include "ao_fat.h" #include "ao_bufio.h" -/* Partition information, block numbers */ +/* Partition information, sector numbers */ static uint8_t partition_type; static uint32_t partition_start, partition_end; +#define SECTOR_SIZE 512 +#define SECTOR_MASK (SECTOR_SIZE - 1) +#define SECTOR_SHIFT 9 + +#define DIRENT_SIZE 32 + /* File system parameters */ static uint8_t sectors_per_cluster; static uint32_t bytes_per_cluster; @@ -34,10 +40,15 @@ static uint16_t reserved_sector_count; static uint8_t number_fat; static uint16_t root_entries; static uint16_t sectors_per_fat; +static uint16_t number_cluster; static uint32_t fat_start; static uint32_t root_start; static uint32_t data_start; +static uint16_t first_free_cluster; +/* + * Deal with LSB FAT data structures + */ static uint32_t get_u32(uint8_t *base) { @@ -72,32 +83,32 @@ put_u16(uint8_t *base, uint16_t value) static uint8_t ao_fat_cluster_valid(uint16_t cluster) { - return (2 <= cluster && cluster < 0xfff0); + return (2 <= cluster && cluster < number_cluster); } -/* Start using a block */ +/* Start using a sector */ static uint8_t * -ao_fat_block_get(uint32_t block) +ao_fat_sector_get(uint32_t sector) { - block += partition_start; - if (block >= partition_end) + sector += partition_start; + if (sector >= partition_end) return NULL; - return ao_bufio_get(block); + return ao_bufio_get(sector); } -/* Finish using a block, 'w' is 1 if modified */ -#define ao_fat_block_put(b,w) ao_bufio_put(b,w) +/* Finish using a sector, 'w' is 1 if modified */ +#define ao_fat_sector_put(b,w) ao_bufio_put(b,w) /* Start using a root directory entry */ static uint8_t * ao_fat_root_get(uint16_t e) { - uint32_t byte = e * 0x20; - uint32_t sector = byte >> 9; - uint16_t offset = byte & 0x1ff; + uint32_t byte = e * DIRENT_SIZE; + uint32_t sector = byte >> SECTOR_SHIFT; + uint16_t offset = byte & SECTOR_MASK; uint8_t *buf; - buf = ao_fat_block_get(root_start + sector); + buf = ao_fat_sector_get(root_start + sector); if (!buf) return NULL; return buf + offset; @@ -107,10 +118,10 @@ ao_fat_root_get(uint16_t e) static void ao_fat_root_put(uint8_t *root, uint16_t e, uint8_t write) { - uint16_t offset = ((e * 0x20) & 0x1ff); + uint16_t offset = ((e * DIRENT_SIZE) & SECTOR_MASK); uint8_t *buf = root - offset; - ao_fat_block_put(buf, write); + ao_fat_sector_put(buf, write); } /* Get the next cluster entry in the chain */ @@ -125,17 +136,20 @@ ao_fat_entry_read(uint16_t cluster) if (!ao_fat_cluster_valid(cluster)) return 0xfff7; - cluster -= 2; - sector = cluster >> 8; - offset = (cluster << 1) & 0x1ff; - buf = ao_fat_block_get(fat_start + sector); +// cluster -= 2; + sector = cluster >> (SECTOR_SHIFT - 1); + offset = (cluster << 1) & SECTOR_MASK; + buf = ao_fat_sector_get(fat_start + sector); if (!buf) return 0; - ret = buf[offset] | (buf[offset+1] << 8); - ao_fat_block_put(buf, 0); + ret = get_u16(buf + offset); + ao_fat_sector_put(buf, 0); return ret; } +/* Replace the referenced cluster entry in the chain with + * 'new_value'. Return the previous value. + */ static uint16_t ao_fat_entry_replace(uint16_t cluster, uint16_t new_value) { @@ -148,33 +162,50 @@ ao_fat_entry_replace(uint16_t cluster, uint16_t new_value) if (!ao_fat_cluster_valid(cluster)) return 0; - cluster -= 2; - sector = cluster >> 8; - offset = (cluster << 1) & 0x1ff; - buf = ao_fat_block_get(fat_start + sector); +// cluster -= 2; + sector = cluster >> (SECTOR_SHIFT - 1); + offset = (cluster << 1) & SECTOR_MASK; + buf = ao_fat_sector_get(fat_start + sector); if (!buf) return 0; ret = get_u16(buf + offset); put_u16(buf + offset, new_value); - ao_fat_block_put(buf, 1); + ao_fat_sector_put(buf, 1); + + /* + * Keep the other FATs in sync + */ for (other_fats = 1; other_fats < number_fat; other_fats++) { - buf = ao_fat_block_get(fat_start + other_fats * sectors_per_fat); + buf = ao_fat_sector_get(fat_start + other_fats * sectors_per_fat + sector); if (buf) { put_u16(buf + offset, new_value); - ao_fat_block_put(buf, 1); + ao_fat_sector_put(buf, 1); } } return ret; } +/* + * Walk a cluster chain and mark + * all of them as free + */ static void -ao_fat_clear_cluster_chain(uint16_t cluster) +ao_fat_free_cluster_chain(uint16_t cluster) { - while (ao_fat_cluster_valid(cluster)) + while (ao_fat_cluster_valid(cluster)) { + if (cluster < first_free_cluster) + first_free_cluster = cluster; cluster = ao_fat_entry_replace(cluster, 0x0000); + } } +/* + * ao_fat_cluster_seek + * + * Walk a cluster chain the specified distance and return what we find + * there. If distance is zero, return the provided cluster. + */ static uint16_t ao_fat_cluster_seek(uint16_t cluster, uint16_t distance) { @@ -187,16 +218,39 @@ ao_fat_cluster_seek(uint16_t cluster, uint16_t distance) return cluster; } +/* + * ao_fat_sector_seek + * + * The basic file system operation -- map a file sector number to a + * partition sector number. Done by computing the cluster number and + * then walking that many clusters from the first cluster, then + * adding the sector offset from the start of the cluster. Returns + * 0xffffffff if we walk off the end of the file or the cluster chain + * is damaged somehow + */ static uint32_t ao_fat_sector_seek(uint16_t cluster, uint32_t sector) { - cluster = ao_fat_cluster_seek(cluster, sector / sectors_per_cluster); + uint16_t distance; + uint16_t offset; + + distance = sector / sectors_per_cluster; + offset = sector % sectors_per_cluster; + + cluster = ao_fat_cluster_seek(cluster, distance); + if (!ao_fat_cluster_valid(cluster)) return 0xffffffff; - return data_start + (cluster-2) * sectors_per_cluster + sector % sectors_per_cluster; + + /* Compute the sector within the partition and return it */ + return data_start + (uint32_t) (cluster-2) * sectors_per_cluster + offset; } -/* Load the boot block and find the first partition */ +/* + * ao_fat_setup_partition + * + * Load the boot block and find the first partition + */ static uint8_t ao_fat_setup_partition(void) { @@ -216,29 +270,40 @@ ao_fat_setup_partition(void) return 0; } - /* Just use the first partition */ - partition = &mbr[0x1be]; + /* Check to see if it's actually a boot block, in which + * case it's presumably not a paritioned device + */ + + if (mbr[0] == 0xeb) { + partition_start = 0; + partition_size = get_u16(mbr + 0x13); + if (partition_size == 0) + partition_size = get_u32(mbr + 0x20); + } else { + /* Just use the first partition */ + partition = &mbr[0x1be]; - partition_type = partition[4]; - switch (partition_type) { - case 4: /* FAT16 up to 32M */ - case 6: /* FAT16 over 32M */ - break; - case 0x0b: /* FAT32 up to 2047GB */ - case 0x0c: /* FAT32 LBA */ - break; - default: - printf ("Invalid partition type %02x\n", partition_type); - ao_bufio_put(mbr, 0); - return 0; - } + partition_type = partition[4]; + switch (partition_type) { + case 4: /* FAT16 up to 32M */ + case 6: /* FAT16 over 32M */ + break; + case 0x0b: /* FAT32 up to 2047GB */ + case 0x0c: /* FAT32 LBA */ + break; + default: + printf ("Invalid partition type %02x\n", partition_type); + ao_bufio_put(mbr, 0); + return 0; + } - partition_start = get_u32(partition+8); - partition_size = get_u32(partition+12); - if (partition_size == 0) { - printf ("Zero-sized partition\n"); - ao_bufio_put(mbr, 0); - return 0; + partition_start = get_u32(partition+8); + partition_size = get_u32(partition+12); + if (partition_size == 0) { + printf ("Zero-sized partition\n"); + ao_bufio_put(mbr, 0); + return 0; + } } partition_end = partition_start + partition_size; printf ("Partition type %02x start %08x end %08x\n", @@ -250,7 +315,8 @@ ao_fat_setup_partition(void) static uint8_t ao_fat_setup_fs(void) { - uint8_t *boot = ao_fat_block_get(0); + uint8_t *boot = ao_fat_sector_get(0); + uint32_t data_sectors; if (!boot) return 0; @@ -259,39 +325,45 @@ ao_fat_setup_fs(void) if (boot[0x1fe] != 0x55 || boot[0x1ff] != 0xaa) { printf ("Invalid BOOT signature %02x %02x\n", boot[0x1fe], boot[0x1ff]); - ao_bufio_put(boot, 0); + ao_fat_sector_put(boot, 0); return 0; } /* Check the sector size */ - if (get_u16(boot + 0xb) != 0x200) { + if (get_u16(boot + 0xb) != SECTOR_SIZE) { printf ("Invalid sector size %d\n", get_u16(boot + 0xb)); - ao_bufio_put(boot, 0); + ao_fat_sector_put(boot, 0); return 0; } sectors_per_cluster = boot[0xd]; - bytes_per_cluster = sectors_per_cluster << 9; + bytes_per_cluster = sectors_per_cluster << SECTOR_SHIFT; reserved_sector_count = get_u16(boot+0xe); number_fat = boot[0x10]; root_entries = get_u16(boot + 0x11); sectors_per_fat = get_u16(boot+0x16); + fat_start = reserved_sector_count;; + root_start = fat_start + number_fat * sectors_per_fat; + data_start = root_start + ((root_entries * DIRENT_SIZE + SECTOR_MASK) >> SECTOR_SHIFT); + + data_sectors = (partition_end - partition_start) - data_start; + + number_cluster = data_sectors / sectors_per_cluster; + printf ("sectors per cluster %d\n", sectors_per_cluster); printf ("reserved sectors %d\n", reserved_sector_count); printf ("number of FATs %d\n", number_fat); printf ("root entries %d\n", root_entries); printf ("sectors per fat %d\n", sectors_per_fat); - fat_start = reserved_sector_count;; - root_start = fat_start + number_fat * sectors_per_fat; - data_start = root_start + ((root_entries * 0x20 + 0x1ff) >> 9); - printf ("fat start %d\n", fat_start); printf ("root start %d\n", root_start); printf ("data start %d\n", data_start); + ao_fat_sector_put(boot, 0); + return 1; } @@ -300,49 +372,36 @@ ao_fat_setup(void) { if (!ao_fat_setup_partition()) return 0; + check_bufio("partition setup"); if (!ao_fat_setup_fs()) return 0; + check_bufio("fs setup"); return 1; } -/* - * Low-level directory operations - */ - /* * Basic file operations */ static struct ao_fat_dirent ao_file_dirent; static uint32_t ao_file_offset; +static uint8_t ao_file_opened; static uint32_t -ao_file_offset_to_sector(uint32_t offset) +ao_fat_offset_to_sector(uint32_t offset) { if (offset > ao_file_dirent.size) return 0xffffffff; - return ao_fat_sector_seek(ao_file_dirent.cluster, offset >> 9); -} - -uint8_t -ao_fat_open(char name[11]) -{ - uint16_t entry = 0; - struct ao_fat_dirent dirent; - - while (ao_fat_readdir(&entry, &dirent)) { - if (!memcmp(name, dirent.name, 11)) { - ao_file_dirent = dirent; - ao_file_offset = 0; - return 1; - } - } - return 0; + return ao_fat_sector_seek(ao_file_dirent.cluster, offset >> SECTOR_SHIFT); } - - -static uint8_t +/* + * ao_fat_set_size + * + * Set the size of the current file, truncating or extending + * the cluster chain as needed + */ +static int8_t ao_fat_set_size(uint32_t size) { uint16_t clear_cluster = 0; @@ -350,11 +409,9 @@ ao_fat_set_size(uint32_t size) uint16_t first_cluster; first_cluster = ao_file_dirent.cluster; - printf ("set size to %d\n", size); if (size == ao_file_dirent.size) - return 1; + return AO_FAT_SUCCESS; if (size == 0) { - printf ("erase file\n"); clear_cluster = ao_file_dirent.cluster; first_cluster = 0; } else { @@ -366,43 +423,50 @@ ao_fat_set_size(uint32_t size) if (new_num < old_num) { uint16_t last_cluster; - printf("Remove %d clusters\n", old_num - new_num); /* Go find the last cluster we want to preserve in the file */ last_cluster = ao_fat_cluster_seek(ao_file_dirent.cluster, new_num - 1); - printf ("Last cluster is now %04x\n", last_cluster); /* Rewrite that cluster entry with 0xffff to mark the end of the chain */ clear_cluster = ao_fat_entry_replace(last_cluster, 0xffff); } else if (new_num > old_num) { uint16_t need; uint16_t free; uint16_t last_cluster; + uint16_t highest_allocated = 0; if (old_num) last_cluster = ao_fat_cluster_seek(ao_file_dirent.cluster, old_num - 1); else last_cluster = 0; - need = new_num - old_num; - printf ("Need %d clusters\n", need); + if (first_free_cluster < 2 || number_cluster <= first_free_cluster) + first_free_cluster = 2; + /* See if there are enough free clusters in the file system */ - for (free = 2; need > 0 && (free - 2) < sectors_per_fat * 256; free++) { - if (!ao_fat_entry_read(free)) { - printf ("\tCluster %04x available\n", free); + need = new_num - old_num; + +#define loop_cluster for (free = first_free_cluster; need > 0;) +#define next_cluster \ + if (++free == number_cluster) \ + free = 2; \ + if (free == first_free_cluster) \ + break; \ + + loop_cluster { + if (!ao_fat_entry_read(free)) need--; - } + next_cluster; } /* Still need some, tell the user that we've failed */ - if (need) { - printf ("File system full\n"); - return 0; - } + if (need) + return -AO_FAT_ENOSPC; - need = new_num - old_num; /* Now go allocate those clusters */ - for (free = 2; need > 0 && (free - 2) < sectors_per_fat * 256; free++) { + need = new_num - old_num; + loop_cluster { if (!ao_fat_entry_read(free)) { - printf ("\tAllocate %04x\n", free); + if (free > highest_allocated) + highest_allocated = free; if (last_cluster) ao_fat_entry_replace(last_cluster, free); else @@ -410,153 +474,297 @@ ao_fat_set_size(uint32_t size) last_cluster = free; need--; } + next_cluster; } + first_free_cluster = highest_allocated + 1; + if (first_free_cluster >= number_cluster) + first_free_cluster = 2; + /* Mark the new end of the chain */ ao_fat_entry_replace(last_cluster, 0xffff); } } /* Deallocate clusters off the end of the file */ - if (ao_fat_cluster_valid(clear_cluster)) { - printf ("Clear clusters starting with %04x\n", clear_cluster); - ao_fat_clear_cluster_chain(clear_cluster); - } + if (ao_fat_cluster_valid(clear_cluster)) + ao_fat_free_cluster_chain(clear_cluster); + /* Update the directory entry */ dent = ao_fat_root_get(ao_file_dirent.entry); if (!dent) - return 0; + return -AO_FAT_EIO; put_u32(dent + 0x1c, size); put_u16(dent + 0x1a, first_cluster); ao_fat_root_put(dent, ao_file_dirent.entry, 1); ao_file_dirent.size = size; ao_file_dirent.cluster = first_cluster; - return 1; + return AO_FAT_SUCCESS; +} + +/* + * ao_fat_root_init + * + * Initialize a root directory entry + */ +void +ao_fat_root_init(uint8_t *dent, char name[11], uint8_t attr) +{ + memset(dent, '\0', 0x20); + memmove(dent, name, 11); + + dent[0x0b] = 0x00; + dent[0x0c] = 0x00; + dent[0x0d] = 0x00; + + /* XXX fix time */ + put_u16(dent + 0x0e, 0); + /* XXX fix date */ + put_u16(dent + 0x10, 0); + /* XXX fix date */ + put_u16(dent + 0x12, 0); + + /* XXX fix time */ + put_u16(dent + 0x16, 0); + /* XXX fix date */ + put_u16(dent + 0x18, 0); + + /* cluster number */ + /* Low cluster bytes */ + put_u16(dent + 0x1a, 0); + /* FAT32 high cluster bytes */ + put_u16(dent + 0x14, 0); + + /* size */ + put_u32(dent + 0x1c, 0); +} + + +static void +ao_fat_dirent_init(uint8_t *dent, uint16_t entry, struct ao_fat_dirent *dirent) +{ + memcpy(dirent->name, dent + 0x00, 11); + dirent->attr = dent[0x0b]; + dirent->size = get_u32(dent+0x1c); + dirent->cluster = get_u16(dent+0x1a); + dirent->entry = entry; +} + +/* + * Public API + */ + +/* + * ao_fat_open + * + * Open an existing file. + */ +int8_t +ao_fat_open(char name[11], uint8_t mode) +{ + uint16_t entry = 0; + struct ao_fat_dirent dirent; + + if (ao_file_opened) + return -AO_FAT_EMFILE; + + while (ao_fat_readdir(&entry, &dirent)) { + if (!memcmp(name, dirent.name, 11)) { + if (AO_FAT_IS_DIR(dirent.attr)) + return -AO_FAT_EISDIR; + if (!AO_FAT_IS_FILE(dirent.attr)) + return -AO_FAT_EPERM; + if (mode > AO_FAT_OPEN_READ && (dirent.attr & AO_FAT_FILE_READ_ONLY)) + return -AO_FAT_EACCESS; + ao_file_dirent = dirent; + ao_file_offset = 0; + ao_file_opened = 1; + return AO_FAT_SUCCESS; + } + } + return -AO_FAT_ENOENT; } -uint8_t +/* + * ao_fat_creat + * + * Open and truncate an existing file or + * create a new file + */ +int8_t ao_fat_creat(char name[11]) { uint16_t entry; + int8_t status; + + if (ao_file_opened) + return -AO_FAT_EMFILE; + + status = ao_fat_open(name, AO_FAT_OPEN_WRITE); - if (ao_fat_open(name)) - return ao_fat_set_size(0); - - for (entry = 0; entry < root_entries; entry++) { - uint8_t *dent = ao_fat_root_get(entry); - - if (dent[0] == AO_FAT_DENT_EMPTY || - dent[0] == AO_FAT_DENT_END) { - memmove(dent, name, 11); - dent[0x0b] = 0x00; - dent[0x0c] = 0x00; - dent[0x0d] = 0x00; - /* XXX fix time */ - put_u16(dent + 0x0e, 0); - /* XXX fix date */ - put_u16(dent + 0x10, 0); - /* XXX fix date */ - put_u16(dent + 0x12, 0); - /* XXX FAT32 high cluster bytes */ - put_u16(dent + 0x14, 0); - /* XXX fix time */ - put_u16(dent + 0x16, 0); - /* XXX fix date */ - put_u16(dent + 0x18, 0); - /* cluster number */ - put_u16(dent + 0x1a, 0); - /* size */ - put_u32(dent + 0x1c, 0); - ao_fat_root_put(dent, entry, 1); - return ao_fat_open(name); + switch (status) { + case -AO_FAT_SUCCESS: + status = ao_fat_set_size(0); + break; + case -AO_FAT_ENOENT: + for (entry = 0; entry < root_entries; entry++) { + uint8_t *dent = ao_fat_root_get(entry); + + if (!dent) { + status = -AO_FAT_EIO; + ao_fat_root_put(dent, entry, 0); + break; + } + + if (dent[0] == AO_FAT_DENT_EMPTY || dent[0] == AO_FAT_DENT_END) { + ao_fat_root_init(dent, name, AO_FAT_FILE_REGULAR); + ao_fat_dirent_init(dent, entry, &ao_file_dirent); + ao_fat_root_put(dent, entry, 1); + ao_file_opened = 1; + status = -AO_FAT_SUCCESS; + break; + } else { + ao_fat_root_put(dent, entry, 0); + } } + if (entry == root_entries) + status = -AO_FAT_ENOSPC; } - return 0; + return status; } -void +/* + * ao_fat_close + * + * Close the currently open file + */ +int8_t ao_fat_close(void) { + if (!ao_file_opened) + return -AO_FAT_EBADF; + memset(&ao_file_dirent, '\0', sizeof (struct ao_fat_dirent)); + ao_file_offset = 0; + ao_file_opened = 0; ao_bufio_flush(); + return AO_FAT_SUCCESS; } +/* + * ao_fat_read + * + * Read from the file + */ int -ao_fat_read(uint8_t *dest, int len) +ao_fat_read(void *dst, int len) { + uint8_t *dst_b = dst; uint32_t sector; uint16_t this_time; uint16_t offset; uint8_t *buf; int ret = 0; + if (!ao_file_opened) + return -AO_FAT_EBADF; + if (ao_file_offset + len > ao_file_dirent.size) len = ao_file_dirent.size - ao_file_offset; + if (len < 0) + len = 0; + while (len) { - offset = ao_file_offset & 0x1ff; - if (offset + len < 512) + offset = ao_file_offset & SECTOR_MASK; + if (offset + len < SECTOR_SIZE) this_time = len; else - this_time = 512 - offset; + this_time = SECTOR_SIZE - offset; - sector = ao_file_offset_to_sector(ao_file_offset); + sector = ao_fat_offset_to_sector(ao_file_offset); if (sector == 0xffffffff) break; - buf = ao_fat_block_get(sector); - if (!buf) + buf = ao_fat_sector_get(sector); + if (!buf) { + ret = -AO_FAT_EIO; break; - memcpy(dest, buf + offset, this_time); - ao_fat_block_put(buf, 0); + } + memcpy(dst_b, buf + offset, this_time); + ao_fat_sector_put(buf, 0); ret += this_time; len -= this_time; - dest += this_time; + dst_b += this_time; ao_file_offset += this_time; } return ret; } +/* + * ao_fat_write + * + * Write to the file, extended as necessary + */ int -ao_fat_write(uint8_t *src, int len) +ao_fat_write(void *src, int len) { + uint8_t *src_b = src; uint32_t sector; uint16_t this_time; uint16_t offset; uint8_t *buf; int ret = 0; + if (!ao_file_opened) + return -AO_FAT_EBADF; + if (ao_file_offset + len > ao_file_dirent.size) { - if (!ao_fat_set_size(ao_file_offset + len)) - return 0; + ret = ao_fat_set_size(ao_file_offset + len); + if (ret < 0) + return ret; } while (len) { - offset = ao_file_offset & 0x1ff; - if (offset + len < 512) + offset = ao_file_offset & SECTOR_MASK; + if (offset + len < SECTOR_SIZE) this_time = len; else - this_time = 512 - offset; + this_time = SECTOR_SIZE - offset; - sector = ao_file_offset_to_sector(ao_file_offset); + sector = ao_fat_offset_to_sector(ao_file_offset); if (sector == 0xffffffff) break; - buf = ao_fat_block_get(sector); - if (!buf) + buf = ao_fat_sector_get(sector); + if (!buf) { + ret = -AO_FAT_EIO; break; - memcpy(buf + offset, src, this_time); - ao_fat_block_put(buf, 1); + } + memcpy(buf + offset, src_b, this_time); + ao_fat_sector_put(buf, 1); ret += this_time; len -= this_time; - src += this_time; + src_b += this_time; ao_file_offset += this_time; } - return 0; + return ret; } -uint32_t +/* + * ao_fat_seek + * + * Set the position for the next I/O operation + * Note that this doesn't actually change the size + * of the file if the requested position is beyond + * the current file length, that would take a future + * write + */ +int32_t ao_fat_seek(int32_t pos, uint8_t whence) { + if (!ao_file_opened) + return -AO_FAT_EBADF; + switch (whence) { case AO_FAT_SEEK_SET: ao_file_offset = pos; @@ -568,12 +776,16 @@ ao_fat_seek(int32_t pos, uint8_t whence) ao_file_offset = ao_file_dirent.size + pos; break; } - if (ao_file_offset > ao_file_dirent.size) - ao_fat_set_size(ao_file_offset); return ao_file_offset; } -uint8_t +/* + * ao_fat_unlink + * + * Remove a file from the directory, marking + * all clusters as free + */ +int8_t ao_fat_unlink(char name[11]) { uint16_t entry = 0; @@ -584,7 +796,13 @@ ao_fat_unlink(char name[11]) uint8_t *next; uint8_t *ent; uint8_t delete; - ao_fat_clear_cluster_chain(dirent.cluster); + + if (AO_FAT_IS_DIR(dirent.attr)) + return -AO_FAT_EISDIR; + if (!AO_FAT_IS_FILE(dirent.attr)) + return -AO_FAT_EPERM; + + ao_fat_free_cluster_chain(dirent.cluster); next = ao_fat_root_get(dirent.entry + 1); if (next && next[0] != AO_FAT_DENT_END) delete = AO_FAT_DENT_EMPTY; @@ -594,24 +812,24 @@ ao_fat_unlink(char name[11]) ao_fat_root_put(next, dirent.entry + 1, 0); ent = ao_fat_root_get(dirent.entry); if (ent) { - memset(ent, '\0', 0x20); + memset(ent, '\0', DIRENT_SIZE); *ent = delete; ao_fat_root_put(ent, dirent.entry, 1); } ao_bufio_flush(); - return 1; + return AO_FAT_SUCCESS; } } - return 0; + return -AO_FAT_ENOENT; } -uint8_t +int8_t ao_fat_rename(char old[11], char new[11]) { - return 0; + return -AO_FAT_EIO; } -uint8_t +int8_t ao_fat_readdir(uint16_t *entry, struct ao_fat_dirent *dirent) { uint8_t *dent; @@ -625,20 +843,15 @@ ao_fat_readdir(uint16_t *entry, struct ao_fat_dirent *dirent) ao_fat_root_put(dent, *entry, 0); return 0; } - if (dent[0] != AO_FAT_DENT_EMPTY && - (dent[0x0b] & (AO_FAT_FILE_DIRECTORY|AO_FAT_FILE_VOLUME_LABEL)) == 0) - break; + if (dent[0] != AO_FAT_DENT_EMPTY && (dent[0xb] & 0xf) != 0xf) { + ao_fat_dirent_init(dent, *entry, dirent); + ao_fat_root_put(dent, *entry, 0); + (*entry)++; + return 1; + } ao_fat_root_put(dent, *entry, 0); (*entry)++; } - memcpy(dirent->name, dent, 11); - dirent->attr = dent[0xb]; - dirent->size = get_u32(dent+0x1c); - dirent->cluster = get_u16(dent+0x1a); - dirent->entry = *entry; - ao_fat_root_put(dent, *entry, 0); - (*entry)++; - return 1; } static void @@ -648,8 +861,12 @@ ao_fat_list(void) struct ao_fat_dirent dirent; while (ao_fat_readdir(&entry, &dirent)) { - printf ("%-8.8s.%-3.3s %02x %d\n", - dirent.name, dirent.name + 8, dirent.attr, dirent.size); + printf ("%-8.8s.%-3.3s %02x %04x %d\n", + dirent.name, + dirent.name + 8, + dirent.attr, + dirent.cluster, + dirent.size); } } @@ -671,4 +888,3 @@ ao_fat_init(void) ao_bufio_init(); ao_cmd_register(&ao_fat_cmds[0]); } - diff --git a/src/drivers/ao_fat.h b/src/drivers/ao_fat.h index 2bf6222e..5b9b300f 100644 --- a/src/drivers/ao_fat.h +++ b/src/drivers/ao_fat.h @@ -21,6 +21,7 @@ void ao_fat_init(void); +#define AO_FAT_FILE_REGULAR 0x00 #define AO_FAT_FILE_READ_ONLY 0x01 #define AO_FAT_FILE_HIDDEN 0x02 #define AO_FAT_FILE_SYSTEM 0x04 @@ -31,32 +32,52 @@ ao_fat_init(void); #define AO_FAT_DENT_EMPTY 0xe5 #define AO_FAT_DENT_END 0x00 -uint8_t -ao_fat_open(char name[11]); - -uint8_t +#define AO_FAT_IS_FILE(attr) (((attr) & (AO_FAT_FILE_VOLUME_LABEL|AO_FAT_FILE_DIRECTORY|AO_FAT_FILE_ARCHIVE)) == 0) +#define AO_FAT_IS_DIR(attr) (((attr) & (AO_FAT_FILE_DIRECTORY)) == AO_FAT_FILE_DIRECTORY) + +#define AO_FAT_SUCCESS 0 +#define AO_FAT_EPERM 1 +#define AO_FAT_ENOENT 2 +#define AO_FAT_EIO 4 +#define AO_FAT_EBADF 9 +#define AO_FAT_EACCESS 13 +#define AO_FAT_EEXIST 17 +#define AO_FAT_ENOTDIR 20 +#define AO_FAT_EISDIR 21 +#define AO_FAT_EMFILE 24 +#define AO_FAT_EFBIG 27 +#define AO_FAT_ENOSPC 28 + +int8_t +ao_fat_open(char name[11], uint8_t mode); + +#define AO_FAT_OPEN_READ 0 +#define AO_FAT_OPEN_WRITE 1 +#define AO_FAT_OPEN_RW 2 + +int8_t ao_fat_creat(char name[11]); -void +int8_t ao_fat_close(void); int -ao_fat_read(uint8_t *dest, int len); +ao_fat_read(void *dest, int len); int -ao_fat_write(uint8_t *buf, int len); +ao_fat_write(void *src, int len); #define AO_FAT_SEEK_SET 0 #define AO_FAT_SEEK_CUR 1 #define AO_FAT_SEEK_END 2 -uint32_t -bao_fat_seek(int32_t pos, uint8_t whence); +int32_t +ao_fat_seek(int32_t pos, uint8_t whence); -uint8_t +int8_t ao_fat_unlink(char name[11]); -uint8_t +int8_t ao_fat_rename(char old[11], char new[11]); struct ao_fat_dirent { @@ -67,7 +88,7 @@ struct ao_fat_dirent { uint16_t entry; }; -uint8_t +int8_t ao_fat_readdir(uint16_t *entry, struct ao_fat_dirent *dirent); #endif /* _AO_FAT_H_ */ diff --git a/src/test/Makefile b/src/test/Makefile index 96170cc1..991bdbfc 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -66,4 +66,4 @@ ao_micropeak_test: ao_micropeak_test.c ao_microflight.c ao_kalman.h cc $(CFLAGS) -o $@ ao_micropeak_test.c -lm ao_fat_test: ao_fat_test.c ao_fat.c ao_bufio.c - cc $(CFLAGS) -o $@ ao_fat_test.c + cc $(CFLAGS) -o $@ ao_fat_test.c -lssl diff --git a/src/test/ao_fat_test.c b/src/test/ao_fat_test.c index 22ac03ad..3f947034 100644 --- a/src/test/ao_fat_test.c +++ b/src/test/ao_fat_test.c @@ -18,11 +18,13 @@ #include #include #include +#include #include #include #include #include #include +#include #define AO_FAT_TEST @@ -40,7 +42,7 @@ void ao_panic(uint8_t panic) { printf ("panic %d\n", panic); - exit(1); + abort(); } #define AO_PANIC_BUFIO 15 @@ -64,9 +66,12 @@ struct ao_cmds { int fs_fd; +uint64_t total_reads, total_writes; + uint8_t ao_sdcard_read_block(uint32_t block, uint8_t *data) { + ++total_reads; lseek(fs_fd, block * 512, 0); return read(fs_fd, data, 512) == 512; } @@ -74,45 +79,308 @@ ao_sdcard_read_block(uint32_t block, uint8_t *data) uint8_t ao_sdcard_write_block(uint32_t block, uint8_t *data) { + ++total_writes; lseek(fs_fd, block * 512, 0); return write(fs_fd, data, 512) == 512; } +char *fs = "fs.fat"; + void ao_sdcard_init(void) { - fs_fd = open("fat.fs", 2); + char cmd[1024]; + + snprintf(cmd, sizeof(cmd), "rm -f %s && mkfs.vfat -C %s 16384", fs, fs); + if (system (cmd) != 0) { + fprintf(stderr, "'%s' failed\n", cmd); + exit(1); + } + fs_fd = open(fs, 2); + if (fs_fd < 0) { + perror (fs); + exit(1); + } } #include "ao_bufio.c" +void +check_bufio(char *where) +{ + int b; + + for (b = 0; b < AO_NUM_BUF; b++) { + if (ao_bufio[b].busy) { + printf ("%s: buffer %d busy. block %d seqno %u\n", + where, b, ao_bufio[b].block, ao_bufio[b].seqno & 0xffff); + abort(); + } + } +} + + +void +check_fat(void); + #include "ao_fat.c" +/* Get the next cluster entry in the chain */ +static uint16_t +ao_fat_entry_raw_read(uint16_t cluster, uint8_t fat) +{ + uint32_t sector; + uint16_t offset; + uint8_t *buf; + uint16_t ret; + +// cluster -= 2; + sector = cluster >> (SECTOR_SHIFT - 1); + offset = (cluster << 1) & SECTOR_MASK; + buf = ao_fat_sector_get(fat_start + fat * sectors_per_fat + sector); + if (!buf) + return 0; + ret = get_u16(buf + offset); + ao_fat_sector_put(buf, 0); + return ret; +} + +void +dump_fat(void) +{ + int e; + + printf ("\n **** FAT ****\n\n"); + for (e = 0; e < number_cluster; e++) { + if ((e & 0xf) == 0x0) + printf ("%04x: ", e); + printf (" %04x", ao_fat_entry_raw_read(e, 0)); + if ((e & 0xf) == 0xf) + putchar ('\n'); + } +} + +void +fat_list(void) +{ + uint16_t entry = 0; + struct ao_fat_dirent dirent; + + printf (" **** Root directory ****\n"); + while (ao_fat_readdir(&entry, &dirent)) { + printf ("%04x: %-8.8s.%-3.3s %02x %04x %d\n", + entry, + dirent.name, + dirent.name + 8, + dirent.attr, + dirent.cluster, + dirent.size); + } + + printf (" **** End of root directory ****\n"); +} + +void +fatal(char *msg, ...) +{ + dump_fat(); + fat_list(); + + va_list l; + va_start(l, msg); + vfprintf(stderr, msg, l); + va_end(l); + + abort(); +} + +void +check_fat(void) +{ + int e; + int f; + + for (e = 0; e < number_cluster; e++) { + uint16_t v = ao_fat_entry_raw_read(e, 0); + for (f = 1; f < number_fat; f++) { + if (ao_fat_entry_raw_read(e, f) != v) + fatal ("fats differ at %d\n", e); + } + } +} + +uint16_t +check_file(uint16_t dent, uint16_t first_cluster, uint8_t *used) +{ + uint16_t clusters = 0; + uint16_t cluster; + + if (!first_cluster) + return 0; + + for (cluster = first_cluster; + (cluster & 0xfff8) != 0xfff8; + cluster = ao_fat_entry_raw_read(cluster, 0)) + { + if (!ao_fat_cluster_valid(cluster)) + fatal("file %d: invalid cluster %04x\n", dent, cluster); + if (used[cluster]) + fatal("file %d: duplicate cluster %04x\n", dent, cluster); + used[cluster] = 1; + clusters++; + } + return clusters; +} + +void +check_fs(void) +{ + uint16_t r; + uint16_t cluster, chain; + uint8_t *used; + + check_fat(); + + used = calloc(1, number_cluster); + + for (r = 0; r < root_entries; r++) { + uint8_t *dent = ao_fat_root_get(r); + uint16_t clusters; + uint32_t size; + uint16_t first_cluster; + uint8_t name[11]; + + if (!dent) + fatal("cannot map dent %d\n", r); + memcpy(name, dent+0, 11); + first_cluster = get_u16(dent + 0x1a); + size = get_u32(dent + 0x1c); + ao_fat_root_put(dent, r, 0); + + if (name[0] == AO_FAT_DENT_END) { + break; + } + + clusters = check_file(r, first_cluster, used); + if (size > clusters * bytes_per_cluster) + fatal("file %d: size %u beyond clusters %d (%u)\n", + r, size, clusters, clusters * bytes_per_cluster); + if (size <= (clusters - 1) * bytes_per_cluster) + fatal("file %d: size %u too small clusters %d (%u)\n", + r, size, clusters, clusters * bytes_per_cluster); + } + for (; r < root_entries; r++) { + uint8_t *dent = ao_fat_root_get(r); + if (!dent) + fatal("cannot map dent %d\n", r); + if (dent[0] != AO_FAT_DENT_END) + fatal("found non-zero dent past end %d\n", r); + ao_fat_root_put(dent, r, 0); + } + + for (cluster = 0; cluster < 2; cluster++) { + chain = ao_fat_entry_raw_read(cluster, 0); + + if ((chain & 0xfff8) != 0xfff8) + fatal("cluster %d: not marked busy\n", cluster); + } + for (; cluster < number_cluster; cluster++) { + chain = ao_fat_entry_raw_read(cluster, 0); + + if (chain != 0) { + if (used[cluster] == 0) + fatal("cluster %d: marked busy, but not in any file\n", cluster); + } else { + if (used[cluster] != 0) + fatal("cluster %d: marked free, but foudn in file\n", cluster); + } + } +} + +#define NUM_FILES 512 +#define LINES_FILE 1000 + +uint32_t sizes[NUM_FILES]; + +unsigned char md5[NUM_FILES][MD5_DIGEST_LENGTH]; + int main(int argc, char **argv) { - uint8_t data[15]; - int len; + char name[12]; + int id; + MD5_CTX ctx; + unsigned char md5_check[MD5_DIGEST_LENGTH]; + + if (argv[1]) + fs = argv[1]; + ao_fat_init(); - ao_fat_test(); - if (ao_fat_open("DATALOG TXT")) { - printf ("DATALOG.TXT\n"); - while ((len = ao_fat_read(data, sizeof (data))) > 0) { - write(1, data, len); + + check_bufio("top"); + ao_fat_setup(); + + check_fs(); + check_bufio("after setup"); + printf (" **** Creating %d files\n", NUM_FILES); + + for (id = 0; id < NUM_FILES; id++) { + sprintf(name, "D%07dTXT", id); + if (ao_fat_creat(name) == AO_FAT_SUCCESS) { + int j; + char line[64]; + check_bufio("file created"); + MD5_Init(&ctx); + for (j = 0; j < 1000; j++) { + int len; + sprintf (line, "Hello, world %d %d\r\n", id, j); + len = strlen(line); + ao_fat_write((uint8_t *) line, len); + MD5_Update(&ctx, line, len); + sizes[id] += len; + } + ao_fat_close(); + MD5_Final(&md5[id][0], &ctx); + if (id == 0) { + printf ("MD5 write %d:", id); + for (j = 0; j < MD5_DIGEST_LENGTH; j++) + printf(" %02x", md5[id][j]); + printf ("\n"); + } + check_bufio("file written"); } - ao_fat_close(); -// ao_fat_unlink("DATALOG TXT"); } - if (ao_fat_open("NEWFILE TXT")) { - printf ("NEWFILE.TXT\n"); - while ((len = ao_fat_read(data, sizeof (data))) > 0) { - write(1, data, len); + + check_bufio("all files created"); + printf (" **** All done creating files\n"); + check_fs(); + + printf (" **** Comparing %d files\n", NUM_FILES); + + for (id = 0; id < NUM_FILES; id++) { + char buf[337]; + sprintf(name, "D%07dTXT", id); + if (ao_fat_open(name, AO_FAT_OPEN_READ) == AO_FAT_SUCCESS) { + int len; + + MD5_Init(&ctx); + while ((len = ao_fat_read((uint8_t *) buf, sizeof(buf))) > 0) { + MD5_Update(&ctx, buf, len); + } + ao_fat_close(); + MD5_Final(md5_check, &ctx); + if (id == 0) { + int j; + printf ("MD5 read %d:", id); + for (j = 0; j < MD5_DIGEST_LENGTH; j++) + printf(" %02x", md5_check[j]); + printf ("\n"); + } + if (memcmp(md5_check, &md5[id][0], sizeof (md5_check)) != 0) + fatal ("checksum failed file %d\n", id); + check_bufio("file shown"); } - ao_fat_close(); - } - if (ao_fat_creat ("NEWFILE TXT")) { - for (len = 0; len < 4095; len++) - ao_fat_write((uint8_t *) "hello, world!\n", 14); - ao_fat_close(); } + + printf ("\n **** Total IO: read %llu write %llu\n", total_reads, total_writes); return 0; } -- cgit v1.2.3 From 8101e4af199a3d79bff434f788cce9f97aeac53a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 28 Mar 2013 16:57:02 -0700 Subject: altos: Add a simple cache for the FAT position->cluster computation This improves read/write performance with large files by not re-walking the cluster chain for every operation Signed-off-by: Keith Packard --- src/drivers/ao_fat.c | 101 ++++++++++++++++++++++++++++--------------------- src/test/ao_fat_test.c | 58 ++++++++++++++-------------- 2 files changed, 88 insertions(+), 71 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_fat.c b/src/drivers/ao_fat.c index c0412380..65c5ea7c 100644 --- a/src/drivers/ao_fat.c +++ b/src/drivers/ao_fat.c @@ -136,7 +136,6 @@ ao_fat_entry_read(uint16_t cluster) if (!ao_fat_cluster_valid(cluster)) return 0xfff7; -// cluster -= 2; sector = cluster >> (SECTOR_SHIFT - 1); offset = (cluster << 1) & SECTOR_MASK; buf = ao_fat_sector_get(fat_start + sector); @@ -162,7 +161,6 @@ ao_fat_entry_replace(uint16_t cluster, uint16_t new_value) if (!ao_fat_cluster_valid(cluster)) return 0; -// cluster -= 2; sector = cluster >> (SECTOR_SHIFT - 1); offset = (cluster << 1) & SECTOR_MASK; buf = ao_fat_sector_get(fat_start + sector); @@ -203,8 +201,11 @@ ao_fat_free_cluster_chain(uint16_t cluster) /* * ao_fat_cluster_seek * - * Walk a cluster chain the specified distance and return what we find - * there. If distance is zero, return the provided cluster. + * The basic file system operation -- map a file cluster index to a + * partition cluster number. Done by computing the cluster number and + * then walking that many clusters from the first cluster. Returns + * 0xffff if we walk off the end of the file or the cluster chain + * is damaged somehow */ static uint16_t ao_fat_cluster_seek(uint16_t cluster, uint16_t distance) @@ -218,34 +219,6 @@ ao_fat_cluster_seek(uint16_t cluster, uint16_t distance) return cluster; } -/* - * ao_fat_sector_seek - * - * The basic file system operation -- map a file sector number to a - * partition sector number. Done by computing the cluster number and - * then walking that many clusters from the first cluster, then - * adding the sector offset from the start of the cluster. Returns - * 0xffffffff if we walk off the end of the file or the cluster chain - * is damaged somehow - */ -static uint32_t -ao_fat_sector_seek(uint16_t cluster, uint32_t sector) -{ - uint16_t distance; - uint16_t offset; - - distance = sector / sectors_per_cluster; - offset = sector % sectors_per_cluster; - - cluster = ao_fat_cluster_seek(cluster, distance); - - if (!ao_fat_cluster_valid(cluster)) - return 0xffffffff; - - /* Compute the sector within the partition and return it */ - return data_start + (uint32_t) (cluster-2) * sectors_per_cluster + offset; -} - /* * ao_fat_setup_partition * @@ -385,14 +358,51 @@ ao_fat_setup(void) static struct ao_fat_dirent ao_file_dirent; static uint32_t ao_file_offset; +static uint32_t ao_file_cluster_offset; +static uint16_t ao_file_cluster; static uint8_t ao_file_opened; static uint32_t -ao_fat_offset_to_sector(uint32_t offset) +ao_fat_current_sector(void) { - if (offset > ao_file_dirent.size) + uint16_t cluster_offset; + uint32_t sector_offset; + uint16_t sector_index; + uint16_t cluster; + + if (ao_file_offset > ao_file_dirent.size) return 0xffffffff; - return ao_fat_sector_seek(ao_file_dirent.cluster, offset >> SECTOR_SHIFT); + + sector_offset = ao_file_offset >> SECTOR_SHIFT; + + if (!ao_file_cluster) { + cluster_offset = sector_offset / sectors_per_cluster; + + cluster = ao_fat_cluster_seek(ao_file_dirent.cluster, cluster_offset); + if (!ao_fat_cluster_valid(cluster)) + return 0xffffffff; + ao_file_cluster = cluster; + ao_file_cluster_offset = cluster_offset * bytes_per_cluster; + } + + sector_index = sector_offset % sectors_per_cluster; + return data_start + (uint32_t) (ao_file_cluster-2) * sectors_per_cluster + sector_index; +} + +static void +ao_fat_set_offset(uint32_t offset) +{ + + if (offset == 0) { + ao_file_cluster = ao_file_dirent.cluster; + ao_file_cluster_offset = 0; + } + else if (offset < ao_file_cluster_offset || + ao_file_cluster_offset + bytes_per_cluster <= offset) + { + ao_file_cluster = 0; + } + ao_file_offset = offset; } /* @@ -576,7 +586,7 @@ ao_fat_open(char name[11], uint8_t mode) if (mode > AO_FAT_OPEN_READ && (dirent.attr & AO_FAT_FILE_READ_ONLY)) return -AO_FAT_EACCESS; ao_file_dirent = dirent; - ao_file_offset = 0; + ao_fat_set_offset(0); ao_file_opened = 1; return AO_FAT_SUCCESS; } @@ -620,6 +630,7 @@ ao_fat_creat(char name[11]) ao_fat_dirent_init(dent, entry, &ao_file_dirent); ao_fat_root_put(dent, entry, 1); ao_file_opened = 1; + ao_fat_set_offset(0); status = -AO_FAT_SUCCESS; break; } else { @@ -645,6 +656,7 @@ ao_fat_close(void) memset(&ao_file_dirent, '\0', sizeof (struct ao_fat_dirent)); ao_file_offset = 0; + ao_file_cluster = 0; ao_file_opened = 0; ao_bufio_flush(); return AO_FAT_SUCCESS; @@ -681,7 +693,7 @@ ao_fat_read(void *dst, int len) else this_time = SECTOR_SIZE - offset; - sector = ao_fat_offset_to_sector(ao_file_offset); + sector = ao_fat_current_sector(); if (sector == 0xffffffff) break; buf = ao_fat_sector_get(sector); @@ -695,7 +707,7 @@ ao_fat_read(void *dst, int len) ret += this_time; len -= this_time; dst_b += this_time; - ao_file_offset += this_time; + ao_fat_set_offset(ao_file_offset + this_time); } return ret; } @@ -731,7 +743,7 @@ ao_fat_write(void *src, int len) else this_time = SECTOR_SIZE - offset; - sector = ao_fat_offset_to_sector(ao_file_offset); + sector = ao_fat_current_sector(); if (sector == 0xffffffff) break; buf = ao_fat_sector_get(sector); @@ -745,7 +757,7 @@ ao_fat_write(void *src, int len) ret += this_time; len -= this_time; src_b += this_time; - ao_file_offset += this_time; + ao_fat_set_offset(ao_file_offset + this_time); } return ret; } @@ -762,20 +774,23 @@ ao_fat_write(void *src, int len) int32_t ao_fat_seek(int32_t pos, uint8_t whence) { + uint32_t new_offset = ao_file_offset; + if (!ao_file_opened) return -AO_FAT_EBADF; switch (whence) { case AO_FAT_SEEK_SET: - ao_file_offset = pos; + new_offset = pos; break; case AO_FAT_SEEK_CUR: - ao_file_offset += pos; + new_offset += pos; break; case AO_FAT_SEEK_END: - ao_file_offset = ao_file_dirent.size + pos; + new_offset = ao_file_dirent.size + pos; break; } + ao_fat_set_offset(new_offset); return ao_file_offset; } diff --git a/src/test/ao_fat_test.c b/src/test/ao_fat_test.c index 3f947034..fffd5af4 100644 --- a/src/test/ao_fat_test.c +++ b/src/test/ao_fat_test.c @@ -261,12 +261,17 @@ check_fs(void) } clusters = check_file(r, first_cluster, used); - if (size > clusters * bytes_per_cluster) - fatal("file %d: size %u beyond clusters %d (%u)\n", - r, size, clusters, clusters * bytes_per_cluster); - if (size <= (clusters - 1) * bytes_per_cluster) - fatal("file %d: size %u too small clusters %d (%u)\n", - r, size, clusters, clusters * bytes_per_cluster); + if (size == 0) { + if (clusters != 0) + fatal("file %d: zero sized, but %d clusters\n", clusters); + } else { + if (size > clusters * bytes_per_cluster) + fatal("file %d: size %u beyond clusters %d (%u)\n", + r, size, clusters, clusters * bytes_per_cluster); + if (size <= (clusters - 1) * bytes_per_cluster) + fatal("file %d: size %u too small clusters %d (%u)\n", + r, size, clusters, clusters * bytes_per_cluster); + } } for (; r < root_entries; r++) { uint8_t *dent = ao_fat_root_get(r); @@ -296,8 +301,8 @@ check_fs(void) } } -#define NUM_FILES 512 -#define LINES_FILE 1000 +#define NUM_FILES 10 +#define LINES_FILE 80000 uint32_t sizes[NUM_FILES]; @@ -330,22 +335,20 @@ main(int argc, char **argv) char line[64]; check_bufio("file created"); MD5_Init(&ctx); - for (j = 0; j < 1000; j++) { - int len; + for (j = 0; j < LINES_FILE; j++) { + int len, ret; sprintf (line, "Hello, world %d %d\r\n", id, j); len = strlen(line); - ao_fat_write((uint8_t *) line, len); - MD5_Update(&ctx, line, len); - sizes[id] += len; + ret = ao_fat_write((uint8_t *) line, len); + if (ret <= 0) + break; + MD5_Update(&ctx, line, ret); + sizes[id] += ret; + if (ret != len) + printf ("write failed %d\n", ret); } ao_fat_close(); MD5_Final(&md5[id][0], &ctx); - if (id == 0) { - printf ("MD5 write %d:", id); - for (j = 0; j < MD5_DIGEST_LENGTH; j++) - printf(" %02x", md5[id][j]); - printf ("\n"); - } check_bufio("file written"); } } @@ -357,26 +360,25 @@ main(int argc, char **argv) printf (" **** Comparing %d files\n", NUM_FILES); for (id = 0; id < NUM_FILES; id++) { - char buf[337]; + char buf[337]; + uint32_t size; sprintf(name, "D%07dTXT", id); + size = 0; if (ao_fat_open(name, AO_FAT_OPEN_READ) == AO_FAT_SUCCESS) { int len; MD5_Init(&ctx); while ((len = ao_fat_read((uint8_t *) buf, sizeof(buf))) > 0) { MD5_Update(&ctx, buf, len); + size += len; } ao_fat_close(); MD5_Final(md5_check, &ctx); - if (id == 0) { - int j; - printf ("MD5 read %d:", id); - for (j = 0; j < MD5_DIGEST_LENGTH; j++) - printf(" %02x", md5_check[j]); - printf ("\n"); - } + if (size != sizes[id]) + fatal("file %d: size differs %d written %d read\n", + id, sizes[id], size); if (memcmp(md5_check, &md5[id][0], sizeof (md5_check)) != 0) - fatal ("checksum failed file %d\n", id); + fatal ("file %d: checksum failed\n", id); check_bufio("file shown"); } } -- cgit v1.2.3 From 44e418bbecd3a3deae942803141cf115d92f29d2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 28 Mar 2013 17:38:14 -0700 Subject: altos: seek forward on FAT cluster chain instead of restarting This improves sequential file performance by taking advantage of any previous cached cluster/offset pair and starting from there when the cluster changes rather than starting from scratch at the begining again. Signed-off-by: Keith Packard --- src/drivers/ao_fat.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_fat.c b/src/drivers/ao_fat.c index 65c5ea7c..98f57d67 100644 --- a/src/drivers/ao_fat.c +++ b/src/drivers/ao_fat.c @@ -375,10 +375,20 @@ ao_fat_current_sector(void) sector_offset = ao_file_offset >> SECTOR_SHIFT; - if (!ao_file_cluster) { + if (!ao_file_cluster || ao_file_offset < ao_file_cluster_offset) { + ao_file_cluster = ao_file_dirent.cluster; + ao_file_cluster_offset = 0; + } + + if (ao_file_cluster_offset + bytes_per_cluster <= ao_file_offset) { + uint16_t cluster_distance; + cluster_offset = sector_offset / sectors_per_cluster; - cluster = ao_fat_cluster_seek(ao_file_dirent.cluster, cluster_offset); + cluster_distance = cluster_offset - ao_file_cluster_offset / bytes_per_cluster; + + cluster = ao_fat_cluster_seek(ao_file_cluster, cluster_distance); + if (!ao_fat_cluster_valid(cluster)) return 0xffffffff; ao_file_cluster = cluster; @@ -392,16 +402,6 @@ ao_fat_current_sector(void) static void ao_fat_set_offset(uint32_t offset) { - - if (offset == 0) { - ao_file_cluster = ao_file_dirent.cluster; - ao_file_cluster_offset = 0; - } - else if (offset < ao_file_cluster_offset || - ao_file_cluster_offset + bytes_per_cluster <= offset) - { - ao_file_cluster = 0; - } ao_file_offset = offset; } -- cgit v1.2.3 From 86e1039e14304ac13db540f2ee3afd4ff170b8b4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 29 Mar 2013 00:32:23 -0700 Subject: altos: Add FAT32 support. And lots more testing. Generalizes the FAT code to deal with either 16-bit or 32-bit versions. The testing code now runs over a variety of disk images to check for compatibility on all of them. Signed-off-by: Keith Packard --- src/drivers/ao_bufio.c | 16 +- src/drivers/ao_bufio.h | 3 + src/drivers/ao_fat.c | 569 ++++++++++++++++++++++++++++++++++--------------- src/drivers/ao_fat.h | 39 +++- src/test/ao_fat_test.c | 236 ++++++++++++++------ 5 files changed, 612 insertions(+), 251 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_bufio.c b/src/drivers/ao_bufio.c index 10b32ceb..87de457f 100644 --- a/src/drivers/ao_bufio.c +++ b/src/drivers/ao_bufio.c @@ -22,7 +22,7 @@ #include "ao_sdcard.h" #include "ao_bufio.h" -#define AO_NUM_BUF 4 +#define AO_NUM_BUF 16 #define AO_BUFSIZ 512 struct ao_bufio { @@ -292,13 +292,21 @@ static const struct ao_cmds ao_bufio_cmds[] = { }; void -ao_bufio_init(void) +ao_bufio_setup(void) { int b; - for (b = 0; b < AO_NUM_BUF; b++) + for (b = 0; b < AO_NUM_BUF; b++) { + ao_bufio[b].dirty = 0; + ao_bufio[b].busy = 0; ao_bufio[b].block = 0xffffffff; - ao_sdcard_init(); + } +} +void +ao_bufio_init(void) +{ + ao_bufio_setup(); + ao_sdcard_init(); ao_cmd_register(&ao_bufio_cmds[0]); } diff --git a/src/drivers/ao_bufio.h b/src/drivers/ao_bufio.h index c3bee906..6629f143 100644 --- a/src/drivers/ao_bufio.h +++ b/src/drivers/ao_bufio.h @@ -30,6 +30,9 @@ ao_bufio_flush_one(uint8_t *buf); void ao_bufio_flush(void); +void +ao_bufio_setup(void); + void ao_bufio_init(void); diff --git a/src/drivers/ao_fat.c b/src/drivers/ao_fat.c index 98f57d67..a19eff70 100644 --- a/src/drivers/ao_fat.c +++ b/src/drivers/ao_fat.c @@ -22,10 +22,26 @@ #include "ao_fat.h" #include "ao_bufio.h" +/* + * Basic file system types + */ + +typedef ao_fat_offset_t offset_t; +typedef ao_fat_sector_t sector_t; +typedef ao_fat_cluster_t cluster_t; +typedef ao_fat_dirent_t dirent_t; +typedef ao_fat_cluster_offset_t cluster_offset_t; + /* Partition information, sector numbers */ -static uint8_t partition_type; -static uint32_t partition_start, partition_end; +static uint8_t partition_type; +static sector_t partition_start, partition_end; + +#define AO_FAT_BAD_CLUSTER 0xffffff7 +#define AO_FAT_LAST_CLUSTER 0xfffffff +#define AO_FAT_IS_LAST_CLUSTER(c) (((c) & 0xffffff8) == 0xffffff8) +#define AO_FAT_IS_LAST_CLUSTER16(c) (((c) & 0xfff8) == 0xfff8) + #define SECTOR_SIZE 512 #define SECTOR_MASK (SECTOR_SIZE - 1) @@ -34,17 +50,25 @@ static uint32_t partition_start, partition_end; #define DIRENT_SIZE 32 /* File system parameters */ -static uint8_t sectors_per_cluster; -static uint32_t bytes_per_cluster; -static uint16_t reserved_sector_count; -static uint8_t number_fat; -static uint16_t root_entries; -static uint16_t sectors_per_fat; -static uint16_t number_cluster; -static uint32_t fat_start; -static uint32_t root_start; -static uint32_t data_start; -static uint16_t first_free_cluster; +static uint8_t sectors_per_cluster; +static uint32_t bytes_per_cluster; +static sector_t reserved_sector_count; +static uint8_t number_fat; +static dirent_t root_entries; +static sector_t sectors_per_fat; +static cluster_t number_cluster; +static sector_t fat_start; +static sector_t root_start; +static sector_t data_start; +static cluster_t next_free; +static uint8_t filesystem_full; + +/* FAT32 extra data */ +static uint8_t fat32; +static uint8_t fsinfo_dirty; +static cluster_t root_cluster; +static sector_t fsinfo_sector; +static cluster_t free_count; /* * Deal with LSB FAT data structures @@ -81,14 +105,14 @@ put_u16(uint8_t *base, uint16_t value) } static uint8_t -ao_fat_cluster_valid(uint16_t cluster) +ao_fat_cluster_valid(cluster_t cluster) { return (2 <= cluster && cluster < number_cluster); } /* Start using a sector */ static uint8_t * -ao_fat_sector_get(uint32_t sector) +ao_fat_sector_get(sector_t sector) { sector += partition_start; if (sector >= partition_end) @@ -99,49 +123,36 @@ ao_fat_sector_get(uint32_t sector) /* Finish using a sector, 'w' is 1 if modified */ #define ao_fat_sector_put(b,w) ao_bufio_put(b,w) -/* Start using a root directory entry */ -static uint8_t * -ao_fat_root_get(uint16_t e) -{ - uint32_t byte = e * DIRENT_SIZE; - uint32_t sector = byte >> SECTOR_SHIFT; - uint16_t offset = byte & SECTOR_MASK; - uint8_t *buf; - - buf = ao_fat_sector_get(root_start + sector); - if (!buf) - return NULL; - return buf + offset; -} - -/* Finish using a root directory entry, 'w' is 1 if modified */ -static void -ao_fat_root_put(uint8_t *root, uint16_t e, uint8_t write) -{ - uint16_t offset = ((e * DIRENT_SIZE) & SECTOR_MASK); - uint8_t *buf = root - offset; - - ao_fat_sector_put(buf, write); -} - /* Get the next cluster entry in the chain */ -static uint16_t -ao_fat_entry_read(uint16_t cluster) +static cluster_t +ao_fat_entry_read(cluster_t cluster) { - uint32_t sector; - uint16_t offset; + sector_t sector; + cluster_t offset; uint8_t *buf; - uint16_t ret; + cluster_t ret; if (!ao_fat_cluster_valid(cluster)) - return 0xfff7; - - sector = cluster >> (SECTOR_SHIFT - 1); - offset = (cluster << 1) & SECTOR_MASK; + return 0xfffffff7; + + if (fat32) + cluster <<= 2; + else + cluster <<= 1; + sector = cluster >> (SECTOR_SHIFT); + offset = cluster & SECTOR_MASK; buf = ao_fat_sector_get(fat_start + sector); if (!buf) return 0; - ret = get_u16(buf + offset); + + if (fat32) { + ret = get_u32(buf + offset); + ret &= 0xfffffff; + } else { + ret = get_u16(buf + offset); + if (AO_FAT_IS_LAST_CLUSTER16(ret)) + ret |= 0xfff0000; + } ao_fat_sector_put(buf, 0); return ret; } @@ -149,36 +160,60 @@ ao_fat_entry_read(uint16_t cluster) /* Replace the referenced cluster entry in the chain with * 'new_value'. Return the previous value. */ -static uint16_t -ao_fat_entry_replace(uint16_t cluster, uint16_t new_value) +static cluster_t +ao_fat_entry_replace(cluster_t cluster, cluster_t new_value) { - uint32_t sector; - uint16_t offset; - uint8_t *buf; - uint16_t ret; - uint8_t other_fats; + sector_t sector; + cluster_offset_t offset; + uint8_t *buf; + cluster_t ret; + cluster_t old_value; + uint8_t fat; if (!ao_fat_cluster_valid(cluster)) - return 0; - - sector = cluster >> (SECTOR_SHIFT - 1); - offset = (cluster << 1) & SECTOR_MASK; - buf = ao_fat_sector_get(fat_start + sector); - if (!buf) - return 0; - ret = get_u16(buf + offset); - put_u16(buf + offset, new_value); - ao_fat_sector_put(buf, 1); - - /* - * Keep the other FATs in sync - */ - for (other_fats = 1; other_fats < number_fat; other_fats++) { - buf = ao_fat_sector_get(fat_start + other_fats * sectors_per_fat + sector); - if (buf) { + return 0xfffffff7; + + /* Convert from cluster index to byte index */ + if (fat32) + cluster <<= 2; + else + cluster <<= 1; + sector = cluster >> SECTOR_SHIFT; + offset = cluster & SECTOR_MASK; + + new_value &= 0xfffffff; + for (fat = 0; fat < number_fat; fat++) { + buf = ao_fat_sector_get(fat_start + fat * sectors_per_fat + sector); + if (!buf) + return 0; + if (fat32) { + old_value = get_u32(buf + offset); + put_u32(buf + offset, new_value | (old_value & 0xf0000000)); + if (fat == 0) { + ret = old_value & 0xfffffff; + + /* Track the free count if it wasn't marked + * invalid when we mounted the file system + */ + if (free_count != 0xffffffff) { + if (new_value && !ret) { + --free_count; + fsinfo_dirty = 1; + } else if (!new_value && ret) { + ++free_count; + fsinfo_dirty = 1; + } + } + } + } else { + if (fat == 0) { + ret = get_u16(buf + offset); + if (AO_FAT_IS_LAST_CLUSTER16(ret)) + ret |= 0xfff0000; + } put_u16(buf + offset, new_value); - ao_fat_sector_put(buf, 1); } + ao_fat_sector_put(buf, 1); } return ret; @@ -189,12 +224,14 @@ ao_fat_entry_replace(uint16_t cluster, uint16_t new_value) * all of them as free */ static void -ao_fat_free_cluster_chain(uint16_t cluster) +ao_fat_free_cluster_chain(cluster_t cluster) { while (ao_fat_cluster_valid(cluster)) { - if (cluster < first_free_cluster) - first_free_cluster = cluster; - cluster = ao_fat_entry_replace(cluster, 0x0000); + if (cluster < next_free) { + next_free = cluster; + fsinfo_dirty = 1; + } + cluster = ao_fat_entry_replace(cluster, 0x00000000); } } @@ -207,8 +244,8 @@ ao_fat_free_cluster_chain(uint16_t cluster) * 0xffff if we walk off the end of the file or the cluster chain * is damaged somehow */ -static uint16_t -ao_fat_cluster_seek(uint16_t cluster, uint16_t distance) +static cluster_t +ao_fat_cluster_seek(cluster_t cluster, cluster_t distance) { while (distance) { cluster = ao_fat_entry_read(cluster); @@ -219,6 +256,176 @@ ao_fat_cluster_seek(uint16_t cluster, uint16_t distance) return cluster; } +/* + * ao_fat_cluster_set_size + * + * Set the number of clusters in the specified chain, + * freeing extra ones or alocating new ones as needed + * + * Returns AO_FAT_BAD_CLUSTER on allocation failure + */ + +static cluster_t +ao_fat_cluster_set_size(cluster_t first_cluster, cluster_t size) +{ + cluster_t clear_cluster = 0; + + if (size == 0) { + clear_cluster = first_cluster; + first_cluster = 0; + } else { + cluster_t have; + cluster_t last_cluster = 0; + cluster_t next_cluster; + + /* Walk the cluster chain to the + * spot where it needs to change. That + * will either be the end of the chain (in case it needs to grow), + * or after the desired number of clusters, in which case it needs to shrink + */ + next_cluster = first_cluster; + for (have = 0; have < size; have++) { + last_cluster = next_cluster; + next_cluster = ao_fat_entry_read(last_cluster); + if (!ao_fat_cluster_valid(next_cluster)) + break; + } + + if (have == size) { + /* The file is large enough, truncate as needed */ + if (ao_fat_cluster_valid(next_cluster)) { + /* Rewrite that cluster entry with 0xffff to mark the end of the chain */ + clear_cluster = ao_fat_entry_replace(last_cluster, AO_FAT_LAST_CLUSTER); + filesystem_full = 0; + } else { + /* The chain is already the right length, don't mess with it */ + ; + } + } else { + cluster_t need; + cluster_t free; + + if (filesystem_full) + return AO_FAT_BAD_CLUSTER; + + if (next_free < 2 || number_cluster <= next_free) { + next_free = 2; + fsinfo_dirty = 1; + } + + /* See if there are enough free clusters in the file system */ + need = size - have; + +#define loop_cluster for (free = next_free; need > 0;) +#define next_cluster \ + if (++free == number_cluster) \ + free = 2; \ + if (free == next_free) \ + break; \ + + loop_cluster { + if (!ao_fat_entry_read(free)) + need--; + next_cluster; + } + /* Still need some, tell the user that we've failed */ + if (need) { + filesystem_full = 1; + return AO_FAT_BAD_CLUSTER; + } + + /* Now go allocate those clusters and + * thread them onto the chain + */ + need = size - have; + loop_cluster { + if (!ao_fat_entry_read(free)) { + next_free = free + 1; + if (next_free >= number_cluster) + next_free = 2; + fsinfo_dirty = 1; + if (last_cluster) + ao_fat_entry_replace(last_cluster, free); + else + first_cluster = free; + last_cluster = free; + need--; + } + next_cluster; + } +#undef loop_cluster +#undef next_cluster + /* Mark the new end of the chain */ + ao_fat_entry_replace(last_cluster, AO_FAT_LAST_CLUSTER); + } + } + + /* Deallocate clusters off the end of the file */ + if (ao_fat_cluster_valid(clear_cluster)) + ao_fat_free_cluster_chain(clear_cluster); + return first_cluster; +} + +/* Start using a root directory entry */ +static uint8_t * +ao_fat_root_get(dirent_t e) +{ + offset_t byte = e * DIRENT_SIZE; + sector_t sector = byte >> SECTOR_SHIFT; + cluster_offset_t offset = byte & SECTOR_MASK; + uint8_t *buf; + + if (fat32) { + cluster_t cluster_distance = sector / sectors_per_cluster; + sector_t sector_index = sector % sectors_per_cluster; + cluster_t cluster = ao_fat_cluster_seek(root_cluster, cluster_distance); + + if (ao_fat_cluster_valid(cluster)) + sector = data_start + (cluster-2) * sectors_per_cluster + sector_index; + else + return NULL; + } else { + if (e >= root_entries) + return NULL; + sector = root_start + sector; + } + + buf = ao_fat_sector_get(sector); + if (!buf) + return NULL; + return buf + offset; +} + +/* Finish using a root directory entry, 'w' is 1 if modified */ +static void +ao_fat_root_put(uint8_t *root, dirent_t e, uint8_t write) +{ + cluster_offset_t offset = ((e * DIRENT_SIZE) & SECTOR_MASK); + uint8_t *buf = root - offset; + + ao_fat_sector_put(buf, write); +} + +/* + * ao_fat_root_extend + * + * On FAT32, make the + */ +static int8_t +ao_fat_root_extend(dirent_t ents) +{ + offset_t byte_size; + cluster_t cluster_size; + if (!fat32) + return 0; + + byte_size = ents * 0x20; + cluster_size = byte_size / bytes_per_cluster; + if (ao_fat_cluster_set_size(root_cluster, cluster_size) != AO_FAT_BAD_CLUSTER) + return 1; + return 0; +} + /* * ao_fat_setup_partition * @@ -316,6 +523,26 @@ ao_fat_setup_fs(void) number_fat = boot[0x10]; root_entries = get_u16(boot + 0x11); sectors_per_fat = get_u16(boot+0x16); + fat32 = 0; + if (sectors_per_fat == 0) { + fat32 = 1; + sectors_per_fat = get_u32(boot+0x24); + root_cluster = get_u32(boot+0x2c); + fsinfo_sector = get_u16(boot + 0x30); + } + ao_fat_sector_put(boot, 0); + + free_count = 0xffffffff; + next_free = 0; + if (fat32 && fsinfo_sector) { + uint8_t *fsinfo = ao_fat_sector_get(fsinfo_sector); + + if (fsinfo) { + free_count = get_u32(fsinfo + 0x1e8); + next_free = get_u32(fsinfo + 0x1ec); + ao_fat_sector_put(fsinfo, 0); + } + } fat_start = reserved_sector_count;; root_start = fat_start + number_fat * sectors_per_fat; @@ -325,6 +552,7 @@ ao_fat_setup_fs(void) number_cluster = data_sectors / sectors_per_cluster; + printf ("fat32: %d\n", fat32); printf ("sectors per cluster %d\n", sectors_per_cluster); printf ("reserved sectors %d\n", reserved_sector_count); printf ("number of FATs %d\n", number_fat); @@ -335,20 +563,35 @@ ao_fat_setup_fs(void) printf ("root start %d\n", root_start); printf ("data start %d\n", data_start); - ao_fat_sector_put(boot, 0); - return 1; } +/* + * State for the current opened file + */ +static struct ao_fat_dirent ao_file_dirent; +static uint32_t ao_file_offset; +static uint32_t ao_file_cluster_offset; +static cluster_t ao_file_cluster; +static uint8_t ao_file_opened; + static uint8_t ao_fat_setup(void) { + ao_bufio_setup(); + + partition_type = partition_start = partition_end = 0; + sectors_per_cluster = bytes_per_cluster = reserved_sector_count = 0; + number_fat = root_entries = sectors_per_fat = 0; + number_cluster = fat_start = root_start = data_start = 0; + next_free = filesystem_full = 0; + fat32 = fsinfo_dirty = root_cluster = fsinfo_sector = free_count = 0; + memset(&ao_file_dirent, '\0', sizeof (ao_file_dirent)); + ao_file_offset = ao_file_cluster_offset = ao_file_cluster = ao_file_opened = 0; if (!ao_fat_setup_partition()) return 0; - check_bufio("partition setup"); if (!ao_fat_setup_fs()) return 0; - check_bufio("fs setup"); return 1; } @@ -356,19 +599,13 @@ ao_fat_setup(void) * Basic file operations */ -static struct ao_fat_dirent ao_file_dirent; -static uint32_t ao_file_offset; -static uint32_t ao_file_cluster_offset; -static uint16_t ao_file_cluster; -static uint8_t ao_file_opened; - static uint32_t ao_fat_current_sector(void) { - uint16_t cluster_offset; + cluster_t cluster_offset; uint32_t sector_offset; uint16_t sector_index; - uint16_t cluster; + cluster_t cluster; if (ao_file_offset > ao_file_dirent.size) return 0xffffffff; @@ -381,7 +618,7 @@ ao_fat_current_sector(void) } if (ao_file_cluster_offset + bytes_per_cluster <= ao_file_offset) { - uint16_t cluster_distance; + cluster_t cluster_distance; cluster_offset = sector_offset / sectors_per_cluster; @@ -414,98 +651,44 @@ ao_fat_set_offset(uint32_t offset) static int8_t ao_fat_set_size(uint32_t size) { - uint16_t clear_cluster = 0; uint8_t *dent; - uint16_t first_cluster; + cluster_t first_cluster; + cluster_t have_clusters, need_clusters; - first_cluster = ao_file_dirent.cluster; if (size == ao_file_dirent.size) return AO_FAT_SUCCESS; - if (size == 0) { - clear_cluster = ao_file_dirent.cluster; - first_cluster = 0; - } else { - uint16_t new_num; - uint16_t old_num; - - new_num = (size + bytes_per_cluster - 1) / bytes_per_cluster; - old_num = (ao_file_dirent.size + bytes_per_cluster - 1) / bytes_per_cluster; - if (new_num < old_num) { - uint16_t last_cluster; - - /* Go find the last cluster we want to preserve in the file */ - last_cluster = ao_fat_cluster_seek(ao_file_dirent.cluster, new_num - 1); - - /* Rewrite that cluster entry with 0xffff to mark the end of the chain */ - clear_cluster = ao_fat_entry_replace(last_cluster, 0xffff); - } else if (new_num > old_num) { - uint16_t need; - uint16_t free; - uint16_t last_cluster; - uint16_t highest_allocated = 0; - - if (old_num) - last_cluster = ao_fat_cluster_seek(ao_file_dirent.cluster, old_num - 1); - else - last_cluster = 0; - if (first_free_cluster < 2 || number_cluster <= first_free_cluster) - first_free_cluster = 2; + first_cluster = ao_file_dirent.cluster; + have_clusters = (ao_file_dirent.size + bytes_per_cluster - 1) / bytes_per_cluster; + need_clusters = (size + bytes_per_cluster - 1) / bytes_per_cluster; - /* See if there are enough free clusters in the file system */ - need = new_num - old_num; + if (have_clusters != need_clusters) { + if (ao_file_cluster && size >= ao_file_cluster_offset) { + cluster_t offset_clusters = (ao_file_cluster_offset + bytes_per_cluster) / bytes_per_cluster; + cluster_t extra_clusters = need_clusters - offset_clusters; + cluster_t next_cluster; -#define loop_cluster for (free = first_free_cluster; need > 0;) -#define next_cluster \ - if (++free == number_cluster) \ - free = 2; \ - if (free == first_free_cluster) \ - break; \ - - loop_cluster { - if (!ao_fat_entry_read(free)) - need--; - next_cluster; - } - /* Still need some, tell the user that we've failed */ - if (need) + next_cluster = ao_fat_cluster_set_size(ao_file_cluster, extra_clusters); + if (next_cluster == AO_FAT_BAD_CLUSTER) return -AO_FAT_ENOSPC; + } else { + first_cluster = ao_fat_cluster_set_size(first_cluster, need_clusters); - /* Now go allocate those clusters */ - need = new_num - old_num; - loop_cluster { - if (!ao_fat_entry_read(free)) { - if (free > highest_allocated) - highest_allocated = free; - if (last_cluster) - ao_fat_entry_replace(last_cluster, free); - else - first_cluster = free; - last_cluster = free; - need--; - } - next_cluster; - } - first_free_cluster = highest_allocated + 1; - if (first_free_cluster >= number_cluster) - first_free_cluster = 2; - - /* Mark the new end of the chain */ - ao_fat_entry_replace(last_cluster, 0xffff); + if (first_cluster == AO_FAT_BAD_CLUSTER) + return -AO_FAT_ENOSPC; } } - /* Deallocate clusters off the end of the file */ - if (ao_fat_cluster_valid(clear_cluster)) - ao_fat_free_cluster_chain(clear_cluster); - /* Update the directory entry */ dent = ao_fat_root_get(ao_file_dirent.entry); if (!dent) return -AO_FAT_EIO; put_u32(dent + 0x1c, size); put_u16(dent + 0x1a, first_cluster); + if (fat32) + put_u16(dent + 0x14, first_cluster >> 16); ao_fat_root_put(dent, ao_file_dirent.entry, 1); + ao_file_dirent.size = size; ao_file_dirent.cluster = first_cluster; return AO_FAT_SUCCESS; @@ -556,9 +739,39 @@ ao_fat_dirent_init(uint8_t *dent, uint16_t entry, struct ao_fat_dirent *dirent) dirent->attr = dent[0x0b]; dirent->size = get_u32(dent+0x1c); dirent->cluster = get_u16(dent+0x1a); + if (fat32) + dirent->cluster |= (cluster_t) get_u16(dent + 0x14) << 16; dirent->entry = entry; } +/* + * ao_fat_flush_fsinfo + * + * Write out any fsinfo changes to disk + */ + +void +ao_fat_flush_fsinfo(void) +{ + uint8_t *fsinfo; + + if (!fat32) + return; + + if (!fsinfo_dirty) + return; + fsinfo_dirty = 0; + if (!fsinfo_sector) + return; + + fsinfo = ao_fat_sector_get(fsinfo_sector); + if (fsinfo) { + put_u32(fsinfo + 0x1e8, free_count); + put_u32(fsinfo + 0x1ec, next_free); + ao_fat_sector_put(fsinfo, 1); + } +} + /* * Public API */ @@ -605,6 +818,7 @@ ao_fat_creat(char name[11]) { uint16_t entry; int8_t status; + uint8_t *dent; if (ao_file_opened) return -AO_FAT_EMFILE; @@ -616,12 +830,14 @@ ao_fat_creat(char name[11]) status = ao_fat_set_size(0); break; case -AO_FAT_ENOENT: - for (entry = 0; entry < root_entries; entry++) { - uint8_t *dent = ao_fat_root_get(entry); - + entry = 0; + for (;;) { + dent = ao_fat_root_get(entry); if (!dent) { - status = -AO_FAT_EIO; - ao_fat_root_put(dent, entry, 0); + + if (ao_fat_root_extend(entry)) + continue; + status = -AO_FAT_ENOSPC; break; } @@ -636,9 +852,8 @@ ao_fat_creat(char name[11]) } else { ao_fat_root_put(dent, entry, 0); } + entry++; } - if (entry == root_entries) - status = -AO_FAT_ENOSPC; } return status; } @@ -658,6 +873,8 @@ ao_fat_close(void) ao_file_offset = 0; ao_file_cluster = 0; ao_file_opened = 0; + + ao_fat_flush_fsinfo(); ao_bufio_flush(); return AO_FAT_SUCCESS; } @@ -849,10 +1066,10 @@ ao_fat_readdir(uint16_t *entry, struct ao_fat_dirent *dirent) { uint8_t *dent; - if (*entry >= root_entries) - return 0; for (;;) { dent = ao_fat_root_get(*entry); + if (!dent) + return 0; if (dent[0] == AO_FAT_DENT_END) { ao_fat_root_put(dent, *entry, 0); diff --git a/src/drivers/ao_fat.h b/src/drivers/ao_fat.h index 5b9b300f..cfe98a76 100644 --- a/src/drivers/ao_fat.h +++ b/src/drivers/ao_fat.h @@ -32,8 +32,8 @@ ao_fat_init(void); #define AO_FAT_DENT_EMPTY 0xe5 #define AO_FAT_DENT_END 0x00 -#define AO_FAT_IS_FILE(attr) (((attr) & (AO_FAT_FILE_VOLUME_LABEL|AO_FAT_FILE_DIRECTORY|AO_FAT_FILE_ARCHIVE)) == 0) -#define AO_FAT_IS_DIR(attr) (((attr) & (AO_FAT_FILE_DIRECTORY)) == AO_FAT_FILE_DIRECTORY) +#define AO_FAT_IS_FILE(attr) (((attr) & (AO_FAT_FILE_VOLUME_LABEL|AO_FAT_FILE_DIRECTORY)) == 0) +#define AO_FAT_IS_DIR(attr) (((attr) & (AO_FAT_FILE_DIRECTORY|AO_FAT_FILE_VOLUME_LABEL)) == AO_FAT_FILE_DIRECTORY) #define AO_FAT_SUCCESS 0 #define AO_FAT_EPERM 1 @@ -80,12 +80,37 @@ ao_fat_unlink(char name[11]); int8_t ao_fat_rename(char old[11], char new[11]); +/* + * Byte offset within a file. Supports files up to 2GB in size + */ +typedef int32_t ao_fat_offset_t; + +/* + * Cluster index in partition data space + */ +typedef uint32_t ao_fat_cluster_t; + +/* + * Sector offset within partition + */ +typedef uint32_t ao_fat_sector_t; + +/* + * Index within the root directory + */ +typedef uint16_t ao_fat_dirent_t; + +/* + * Offset within a cluster (or sector) + */ +typedef uint16_t ao_fat_cluster_offset_t; + struct ao_fat_dirent { - char name[11]; - uint8_t attr; - uint32_t size; - uint16_t cluster; - uint16_t entry; + char name[11]; + uint8_t attr; + uint32_t size; + ao_fat_cluster_t cluster; + uint16_t entry; }; int8_t diff --git a/src/test/ao_fat_test.c b/src/test/ao_fat_test.c index fffd5af4..48d5d8a4 100644 --- a/src/test/ao_fat_test.c +++ b/src/test/ao_fat_test.c @@ -84,14 +84,33 @@ ao_sdcard_write_block(uint32_t block, uint8_t *data) return write(fs_fd, data, 512) == 512; } -char *fs = "fs.fat"; +struct fs_param { + int fat; + int blocks; +} fs_params[] = { + { .fat = 16, .blocks = 16384 }, + { .fat = 32, .blocks = 16384 }, + { .fat = 16, .blocks = 65536 }, + { .fat = 32, .blocks = 65536 }, + { .fat = 16, .blocks = 1048576 }, + { .fat = 32, .blocks = 1048576 }, + { .fat = 0, .blocks = 0 }, +}; + +char *fs = "fs.fat"; +struct fs_param *param; void ao_sdcard_init(void) { char cmd[1024]; - snprintf(cmd, sizeof(cmd), "rm -f %s && mkfs.vfat -C %s 16384", fs, fs); + if (fs_fd) { + close(fs_fd); + fs_fd = 0; + } + snprintf(cmd, sizeof(cmd), "rm -f %s && mkfs.vfat -F %d -C %s %d", + fs, param->fat, fs, param->blocks); if (system (cmd) != 0) { fprintf(stderr, "'%s' failed\n", cmd); exit(1); @@ -125,21 +144,27 @@ check_fat(void); #include "ao_fat.c" /* Get the next cluster entry in the chain */ -static uint16_t -ao_fat_entry_raw_read(uint16_t cluster, uint8_t fat) +static cluster_t +ao_fat_entry_raw_read(cluster_t cluster, uint8_t fat) { - uint32_t sector; - uint16_t offset; - uint8_t *buf; - uint16_t ret; - -// cluster -= 2; - sector = cluster >> (SECTOR_SHIFT - 1); - offset = (cluster << 1) & SECTOR_MASK; + sector_t sector; + cluster_offset_t offset; + uint8_t *buf; + cluster_t ret; + + if (fat32) + cluster <<= 2; + else + cluster <<= 1; + sector = cluster >> SECTOR_SHIFT; + offset = cluster & SECTOR_MASK; buf = ao_fat_sector_get(fat_start + fat * sectors_per_fat + sector); if (!buf) return 0; - ret = get_u16(buf + offset); + if (fat32) + ret = get_u32(buf + offset); + else + ret = get_u16(buf + offset); ao_fat_sector_put(buf, 0); return ret; } @@ -153,16 +178,21 @@ dump_fat(void) for (e = 0; e < number_cluster; e++) { if ((e & 0xf) == 0x0) printf ("%04x: ", e); - printf (" %04x", ao_fat_entry_raw_read(e, 0)); + if (fat32) + printf (" %08x", ao_fat_entry_raw_read(e, 0)); + else + printf (" %04x", ao_fat_entry_raw_read(e, 0)); if ((e & 0xf) == 0xf) putchar ('\n'); } + if (e & 0xf) + putchar('\n'); } void fat_list(void) { - uint16_t entry = 0; + dirent_t entry = 0; struct ao_fat_dirent dirent; printf (" **** Root directory ****\n"); @@ -182,8 +212,8 @@ fat_list(void) void fatal(char *msg, ...) { - dump_fat(); - fat_list(); +// dump_fat(); +// fat_list(); va_list l; va_start(l, msg); @@ -200,7 +230,7 @@ check_fat(void) int f; for (e = 0; e < number_cluster; e++) { - uint16_t v = ao_fat_entry_raw_read(e, 0); + cluster_t v = ao_fat_entry_raw_read(e, 0); for (f = 1; f < number_fat; f++) { if (ao_fat_entry_raw_read(e, f) != v) fatal ("fats differ at %d\n", e); @@ -208,24 +238,24 @@ check_fat(void) } } -uint16_t -check_file(uint16_t dent, uint16_t first_cluster, uint8_t *used) +cluster_t +check_file(dirent_t dent, cluster_t first_cluster, dirent_t *used) { - uint16_t clusters = 0; - uint16_t cluster; + cluster_t clusters = 0; + cluster_t cluster; if (!first_cluster) return 0; for (cluster = first_cluster; - (cluster & 0xfff8) != 0xfff8; + fat32 ? !AO_FAT_IS_LAST_CLUSTER(cluster) : !AO_FAT_IS_LAST_CLUSTER16(cluster); cluster = ao_fat_entry_raw_read(cluster, 0)) { if (!ao_fat_cluster_valid(cluster)) - fatal("file %d: invalid cluster %04x\n", dent, cluster); + fatal("file %d: invalid cluster %08x\n", dent, cluster); if (used[cluster]) - fatal("file %d: duplicate cluster %04x\n", dent, cluster); - used[cluster] = 1; + fatal("file %d: duplicate cluster %08x also in file %d\n", dent, cluster, used[cluster]-1); + used[cluster] = dent; clusters++; } return clusters; @@ -234,25 +264,27 @@ check_file(uint16_t dent, uint16_t first_cluster, uint8_t *used) void check_fs(void) { - uint16_t r; - uint16_t cluster, chain; - uint8_t *used; + dirent_t r; + cluster_t cluster, chain; + dirent_t *used; + uint8_t *dent; check_fat(); - used = calloc(1, number_cluster); + used = calloc(sizeof (dirent_t), number_cluster); - for (r = 0; r < root_entries; r++) { - uint8_t *dent = ao_fat_root_get(r); - uint16_t clusters; - uint32_t size; - uint16_t first_cluster; - uint8_t name[11]; + for (r = 0; (dent = ao_fat_root_get(r)); r++) { + cluster_t clusters; + offset_t size; + cluster_t first_cluster; + char name[11]; if (!dent) fatal("cannot map dent %d\n", r); memcpy(name, dent+0, 11); first_cluster = get_u16(dent + 0x1a); + if (fat32) + first_cluster |= (cluster_t) get_u16(dent + 0x14) << 16; size = get_u32(dent + 0x1c); ao_fat_root_put(dent, r, 0); @@ -260,7 +292,7 @@ check_fs(void) break; } - clusters = check_file(r, first_cluster, used); + clusters = check_file(r + 1, first_cluster, used); if (size == 0) { if (clusters != 0) fatal("file %d: zero sized, but %d clusters\n", clusters); @@ -273,20 +305,29 @@ check_fs(void) r, size, clusters, clusters * bytes_per_cluster); } } - for (; r < root_entries; r++) { - uint8_t *dent = ao_fat_root_get(r); - if (!dent) - fatal("cannot map dent %d\n", r); - if (dent[0] != AO_FAT_DENT_END) - fatal("found non-zero dent past end %d\n", r); - ao_fat_root_put(dent, r, 0); + if (!fat32) { + for (; r < root_entries; r++) { + uint8_t *dent = ao_fat_root_get(r); + if (!dent) + fatal("cannot map dent %d\n", r); + if (dent[0] != AO_FAT_DENT_END) + fatal("found non-zero dent past end %d\n", r); + ao_fat_root_put(dent, r, 0); + } + } else { + check_file((dirent_t) -1, root_cluster, used); } for (cluster = 0; cluster < 2; cluster++) { chain = ao_fat_entry_raw_read(cluster, 0); - if ((chain & 0xfff8) != 0xfff8) - fatal("cluster %d: not marked busy\n", cluster); + if (fat32) { + if ((chain & 0xffffff8) != 0xffffff8) + fatal("cluster %d: not marked busy\n", cluster); + } else { + if ((chain & 0xfff8) != 0xfff8) + fatal("cluster %d: not marked busy\n", cluster); + } } for (; cluster < number_cluster; cluster++) { chain = ao_fat_entry_raw_read(cluster, 0); @@ -296,40 +337,66 @@ check_fs(void) fatal("cluster %d: marked busy, but not in any file\n", cluster); } else { if (used[cluster] != 0) - fatal("cluster %d: marked free, but foudn in file\n", cluster); + fatal("cluster %d: marked free, but found in file %d\n", cluster, used[cluster]-1); } } } -#define NUM_FILES 10 -#define LINES_FILE 80000 +#define NUM_FILES 100 +#define LINES_FILE 500000 uint32_t sizes[NUM_FILES]; unsigned char md5[NUM_FILES][MD5_DIGEST_LENGTH]; -int -main(int argc, char **argv) +void +short_test_fs(void) +{ + int len; + char buf[345]; + + if (ao_fat_open("HELLO TXT",AO_FAT_OPEN_READ) == AO_FAT_SUCCESS) { + printf ("File contents for HELLO.TXT\n"); + while ((len = ao_fat_read(buf, sizeof(buf)))) + write(1, buf, len); + ao_fat_close(); + } + + if (ao_fat_creat("NEWFILE TXT") == AO_FAT_SUCCESS) { + printf ("Create new file\n"); + for (len = 0; len < 2; len++) + ao_fat_write("hello, world!\n", 14); + ao_fat_seek(0, AO_FAT_SEEK_SET); + printf ("read new file\n"); + while ((len = ao_fat_read(buf, sizeof (buf)))) + write (1, buf, len); + ao_fat_close(); + } + + check_fs(); +} + +void +long_test_fs(void) { char name[12]; int id; MD5_CTX ctx; unsigned char md5_check[MD5_DIGEST_LENGTH]; + char buf[337]; + int len; + uint64_t total_file_size = 0; - if (argv[1]) - fs = argv[1]; - - ao_fat_init(); - - check_bufio("top"); - ao_fat_setup(); + total_reads = total_writes = 0; - check_fs(); - check_bufio("after setup"); printf (" **** Creating %d files\n", NUM_FILES); + memset(sizes, '\0', sizeof (sizes)); for (id = 0; id < NUM_FILES; id++) { sprintf(name, "D%07dTXT", id); + if ((id % (NUM_FILES/50)) == 0) { + printf ("."); fflush(stdout); + } if (ao_fat_creat(name) == AO_FAT_SUCCESS) { int j; char line[64]; @@ -342,6 +409,7 @@ main(int argc, char **argv) ret = ao_fat_write((uint8_t *) line, len); if (ret <= 0) break; + total_file_size += ret; MD5_Update(&ctx, line, ret); sizes[id] += ret; if (ret != len) @@ -353,20 +421,24 @@ main(int argc, char **argv) } } + printf ("\n **** Write IO: read %llu write %llu data sectors %llu\n", total_reads, total_writes, (total_file_size + 511) / 512); + check_bufio("all files created"); printf (" **** All done creating files\n"); check_fs(); + total_reads = total_writes = 0; + printf (" **** Comparing %d files\n", NUM_FILES); for (id = 0; id < NUM_FILES; id++) { - char buf[337]; uint32_t size; sprintf(name, "D%07dTXT", id); size = 0; + if ((id % (NUM_FILES/50)) == 0) { + printf ("."); fflush(stdout); + } if (ao_fat_open(name, AO_FAT_OPEN_READ) == AO_FAT_SUCCESS) { - int len; - MD5_Init(&ctx); while ((len = ao_fat_read((uint8_t *) buf, sizeof(buf))) > 0) { MD5_Update(&ctx, buf, len); @@ -382,7 +454,43 @@ main(int argc, char **argv) check_bufio("file shown"); } } + printf ("\n **** Read IO: read %llu write %llu\n", total_reads, total_writes); +} + +char *params[] = { + "-F 16 -C %s 16384", + "-F 32 -C %s 16384", + "-F 16 -C %s 65536", + "-F 32 -C %s 65536", + "-F 16 -C %s 1048576", + "-F 32 -C %s 1048576", + NULL +}; + +int +main(int argc, char **argv) +{ + int p; + + if (argv[1]) + fs = argv[1]; + + for (p = 0; fs_params[p].fat; p++) { + param = &fs_params[p]; + ao_fat_init(); + + check_bufio("top"); + ao_fat_setup(); + + check_fs(); + check_bufio("after setup"); + +#ifdef SIMPLE_TEST + short_test_fs(); +#else + long_test_fs(); +#endif + } - printf ("\n **** Total IO: read %llu write %llu\n", total_reads, total_writes); return 0; } -- cgit v1.2.3 From 9aeed244879f90b5b6dab1c7ca095cc001b03fe5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 29 Mar 2013 12:13:59 -0700 Subject: altos: Add temporary RF power settings These expose the raw cc115l and rfpa0133 register settings so that we can calibrate them against measured power outputs. I've tested them to verify that they change how much power the board consumes, so they're clearly doing something... Signed-off-by: Keith Packard --- src/core/ao.h | 10 ++++++-- src/core/ao_config.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++ src/drivers/ao_cc115l.c | 5 ++++ src/drivers/ao_rf_cc115l.h | 2 +- src/drivers/ao_rfpa0133.c | 7 +++--- src/telegps-v0.1/ao_pins.h | 4 +++- 6 files changed, 80 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/core/ao.h b/src/core/ao.h index 6d617cfc..7c5c69b8 100644 --- a/src/core/ao.h +++ b/src/core/ao.h @@ -550,7 +550,7 @@ ao_radio_send_lots(ao_radio_fill_func fill); * ao_radio_pa */ -#if AO_RADIO_HAS_PA +#if HAS_RADIO_AMP void ao_radio_pa_on(void); @@ -715,7 +715,7 @@ extern __xdata uint8_t ao_force_freq; #endif #define AO_CONFIG_MAJOR 1 -#define AO_CONFIG_MINOR 13 +#define AO_CONFIG_MINOR 14 #define AO_AES_LEN 16 @@ -743,6 +743,12 @@ struct ao_config { struct ao_pyro pyro[AO_PYRO_NUM]; /* minor version 12 */ #endif uint16_t aprs_interval; /* minor version 13 */ +#if HAS_RADIO_POWER + uint8_t radio_power; /* minor version 14 */ +#endif +#if HAS_RADIO_AMP + uint8_t radio_amp; /* minor version 14 */ +#endif }; #define AO_IGNITE_MODE_DUAL 0 diff --git a/src/core/ao_config.c b/src/core/ao_config.c index 9c84fe60..73608a55 100644 --- a/src/core/ao_config.c +++ b/src/core/ao_config.c @@ -47,6 +47,8 @@ __xdata uint8_t ao_config_mutex; #define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX ((uint32_t) 192 * (uint32_t) 1024) #endif #endif +#define AO_CONFIG_DEFAULT_RADIO_POWER 0x60 +#define AO_CONFIG_DEFAULT_RADIO_AMP 0 #if HAS_EEPROM static void @@ -141,6 +143,14 @@ _ao_config_get(void) #endif if (minor < 13) ao_config.aprs_interval = 0; +#if HAS_RADIO_POWER + if (minor < 14) + ao_config.radio_power = AO_CONFIG_DEFAULT_RADIO_POWER; + #endif +#if HAS_RADIO_AMP + if (minor < 14) + ao_config.radio_amp = AO_CONFIG_DEFAULT_RADIO_AMP; +#endif ao_config.minor = AO_CONFIG_MINOR; ao_config_dirty = 1; } @@ -524,6 +534,48 @@ ao_config_aprs_set(void) #endif /* HAS_APRS */ +#if HAS_RADIO_AMP + +void +ao_config_radio_amp_show(void) +{ + printf ("Radio amp setting: %d\n", ao_config.radio_amp); +} + +void +ao_config_radio_amp_set(void) +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_config.radio_amp = ao_cmd_lex_i; + _ao_config_edit_finish(); +} + +#endif + +#if HAS_RADIO_POWER + +void +ao_config_radio_power_show(void) +{ + printf ("Radio power setting: %d\n", ao_config.radio_power); +} + +void +ao_config_radio_power_set(void) +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_config.radio_power = ao_cmd_lex_i; + _ao_config_edit_finish(); +} + +#endif + struct ao_config_var { __code char *str; void (*set)(void) __reentrant; @@ -557,6 +609,14 @@ __code struct ao_config_var ao_config_vars[] = { ao_config_radio_enable_set, ao_config_radio_enable_show }, { "f \0Radio calib (cal = rf/(xtal/2^16))", ao_config_radio_cal_set, ao_config_radio_cal_show }, +#if HAS_RADIO_POWER + { "p \0Radio power setting (0-255)", + ao_config_radio_power_set, ao_config_radio_power_show }, +#endif +#if HAS_RADIO_AMP + { "d \0Radio amplifier setting (0-3)", + ao_config_radio_amp_set, ao_config_radio_amp_show }, +#endif #endif /* HAS_RADIO */ #if HAS_ACCEL { "a <+g> <-g>\0Accel calib (0 for auto)", diff --git a/src/drivers/ao_cc115l.c b/src/drivers/ao_cc115l.c index feff82af..5b0ec3d7 100644 --- a/src/drivers/ao_cc115l.c +++ b/src/drivers/ao_cc115l.c @@ -452,6 +452,7 @@ static void ao_radio_get(uint8_t len) { static uint32_t last_radio_setting; + static uint8_t last_power_setting; ao_mutex_get(&ao_radio_mutex); if (!ao_radio_configured) @@ -462,6 +463,10 @@ ao_radio_get(uint8_t len) ao_radio_reg_write(CC115L_FREQ0, ao_config.radio_setting); last_radio_setting = ao_config.radio_setting; } + if (ao_config.radio_power != last_power_setting) { + ao_radio_reg_write(CC115L_PA, ao_config.radio_power); + last_power_setting = ao_config.radio_power; + } ao_radio_set_len(len); } diff --git a/src/drivers/ao_rf_cc115l.h b/src/drivers/ao_rf_cc115l.h index 6eb30bf2..50a730ab 100644 --- a/src/drivers/ao_rf_cc115l.h +++ b/src/drivers/ao_rf_cc115l.h @@ -80,4 +80,4 @@ CC115L_TEST1, 0x35, /* Various Test Settings */ CC115L_TEST0, 0x09, /* Various Test Settings */ - CC115L_PA, 0x60, /* Power setting (0dBm) */ + CC115L_PA, 0x00, /* Power setting (0dBm) */ diff --git a/src/drivers/ao_rfpa0133.c b/src/drivers/ao_rfpa0133.c index 70d5edba..a98e261a 100644 --- a/src/drivers/ao_rfpa0133.c +++ b/src/drivers/ao_rfpa0133.c @@ -17,10 +17,8 @@ #include "ao.h" -static uint8_t power = 0; - static void -ao_rfpa0133_set_power(void) +ao_rfpa0133_set_power(uint8_t power) { ao_gpio_set(AO_PA_GAIN_8_GPIO, AO_PA_GAIN_8_PIN, AO_PA_GAIN_8, power & 1); ao_gpio_set(AO_PA_GAIN_16_GPIO, AO_PA_GAIN_16_PIN, AO_PA_GAIN_16, (power >> 1) & 1); @@ -29,7 +27,7 @@ ao_rfpa0133_set_power(void) void ao_radio_pa_on(void) { - ao_rfpa0133_set_power(); + ao_rfpa0133_set_power(ao_config.radio_amp); ao_gpio_set(AO_PA_POWER_GPIO, AO_PA_POWER_PIN, AO_PA_POWER, 1); } @@ -37,6 +35,7 @@ void ao_radio_pa_off(void) { ao_gpio_set(AO_PA_POWER_GPIO, AO_PA_POWER_PIN, AO_PA_POWER, 0); + ao_rfpa0133_set_power(0); } void diff --git a/src/telegps-v0.1/ao_pins.h b/src/telegps-v0.1/ao_pins.h index 01f4a303..09574568 100644 --- a/src/telegps-v0.1/ao_pins.h +++ b/src/telegps-v0.1/ao_pins.h @@ -132,6 +132,8 @@ #define AO_RADIO_CAL_DEFAULT 0x10b6a5 +#define HAS_RADIO_POWER 1 + #define AO_FEC_DEBUG 0 #define AO_CC115L_SPI_CS_PORT (&stm_gpiob) #define AO_CC115L_SPI_CS_PIN 12 @@ -150,7 +152,7 @@ #define AO_CC115L_MARC_GPIO 0 #define AO_CC115L_MARC_GPIO_IOCFG CC115L_IOCFG0 -#define AO_RADIO_HAS_PA 1 +#define HAS_RADIO_AMP 1 /* * Power amplifier (RFPA0133) -- cgit v1.2.3 From 93a9aa703a0173e13b327ed432e6d52e90ebfa1b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 29 Mar 2013 17:05:36 -0700 Subject: altos: Get CC115L radio working. This involved figuring out which GPIO signal would reliably indicate that the transmitter was finished; I ended up using the PA_PD bit for this. This also converts all of the radio users to the long packet support as the CC115L has only a 64-byte fifo, not large enough to hold either an RDF tone or a regular AltOS telemetry packet. This also renames the public API for sending APRS packets from ao_radio_send_lots to ao_radio_send_aprs, which is at least more accurate. The workings of that API haven't changed, just the name. Signed-off-by: Keith Packard --- src/core/ao.h | 2 +- src/drivers/ao_aprs.c | 2 +- src/drivers/ao_cc1120.c | 2 +- src/drivers/ao_cc115l.c | 544 +++++++++++++++++++++++++-------------------- src/drivers/ao_rf_cc115l.h | 83 ------- src/telegps-v0.1/Makefile | 1 - src/telegps-v0.1/ao_pins.h | 16 +- src/test/ao_aprs_test.c | 2 +- 8 files changed, 312 insertions(+), 340 deletions(-) delete mode 100644 src/drivers/ao_rf_cc115l.h (limited to 'src') diff --git a/src/core/ao.h b/src/core/ao.h index 7c5c69b8..e3161b4c 100644 --- a/src/core/ao.h +++ b/src/core/ao.h @@ -544,7 +544,7 @@ ao_radio_test(uint8_t on); typedef int16_t (*ao_radio_fill_func)(uint8_t *buffer, int16_t len); void -ao_radio_send_lots(ao_radio_fill_func fill); +ao_radio_send_aprs(ao_radio_fill_func fill); /* * ao_radio_pa diff --git a/src/drivers/ao_aprs.c b/src/drivers/ao_aprs.c index 03bcab05..6ab61e6a 100644 --- a/src/drivers/ao_aprs.c +++ b/src/drivers/ao_aprs.c @@ -593,7 +593,7 @@ void ao_aprs_send(void) tncIndex = 0; tncMode = TNC_TX_SYNC; - ao_radio_send_lots(tncFill); + ao_radio_send_aprs(tncFill); } /** @} */ diff --git a/src/drivers/ao_cc1120.c b/src/drivers/ao_cc1120.c index 53bb5a62..a26eccbc 100644 --- a/src/drivers/ao_cc1120.c +++ b/src/drivers/ao_cc1120.c @@ -747,7 +747,7 @@ ao_radio_send(const void *d, uint8_t size) #define AO_RADIO_LOTS 64 void -ao_radio_send_lots(ao_radio_fill_func fill) +ao_radio_send_aprs(ao_radio_fill_func fill) { uint8_t buf[AO_RADIO_LOTS], *b; int cnt; diff --git a/src/drivers/ao_cc115l.c b/src/drivers/ao_cc115l.c index 5b0ec3d7..1d8211f6 100644 --- a/src/drivers/ao_cc115l.c +++ b/src/drivers/ao_cc115l.c @@ -25,13 +25,18 @@ static uint8_t ao_radio_mutex; -static uint8_t ao_radio_wake; /* radio ready. Also used as sleep address */ +static uint8_t ao_radio_fifo; /* fifo drained interrupt received */ +static uint8_t ao_radio_done; /* tx done interrupt received */ +static uint8_t ao_radio_wake; /* sleep address for radio interrupts */ static uint8_t ao_radio_abort; /* radio operation should abort */ static uint8_t ao_radio_mcu_wake; /* MARC status change */ static uint8_t ao_radio_marcstate; /* Last read MARC state value */ +/* Debugging commands */ #define CC115L_DEBUG 1 -#define CC115L_TRACE 1 + +/* Runtime tracing */ +#define CC115L_TRACE 0 #define FOSC 26000000 @@ -42,15 +47,67 @@ static uint8_t ao_radio_marcstate; /* Last read MARC state value */ #define ao_radio_spi_recv(d,l) ao_spi_recv((d), (l), AO_CC115L_SPI_BUS) #define ao_radio_duplex(o,i,l) ao_spi_duplex((o), (i), (l), AO_CC115L_SPI_BUS) +struct ao_cc115l_reg { + uint16_t addr; + char *name; +}; + +#if CC115L_TRACE + +const static struct ao_cc115l_reg ao_cc115l_reg[]; +const static char *cc115l_state_name[]; + +enum ao_cc115l_trace_type { + trace_strobe, + trace_read, + trace_write, + trace_dma, + trace_line, +}; + +struct ao_cc115l_trace { + enum ao_cc115l_trace_type type; + int16_t addr; + int16_t value; + const char *comment; +}; + +#define NUM_TRACE 256 + +static struct ao_cc115l_trace trace[NUM_TRACE]; +static int trace_i; +static int trace_disable; + +static void trace_add(enum ao_cc115l_trace_type type, int16_t addr, int16_t value, const char *comment) +{ + if (trace_disable) + return; + switch (type) { + case trace_read: + case trace_write: + comment = ao_cc115l_reg[addr].name; + break; + case trace_strobe: + comment = cc115l_state_name[(value >> 4) & 0x7]; + break; + } + trace[trace_i].type = type; + trace[trace_i].addr = addr; + trace[trace_i].value = value; + trace[trace_i].comment = comment; + if (++trace_i == NUM_TRACE) + trace_i = 0; +} +#else +#define trace_add(t,a,v,c) +#endif + static uint8_t -ao_radio_reg_read(uint16_t addr) +ao_radio_reg_read(uint8_t addr) { uint8_t data[1]; uint8_t d; -#if CC115L_TRACE - printf("\t\tao_radio_reg_read (%04x): ", addr); flush(); -#endif data[0] = ((1 << CC115L_READ) | (0 << CC115L_BURST) | addr); @@ -58,21 +115,17 @@ ao_radio_reg_read(uint16_t addr) ao_radio_spi_send(data, 1); ao_radio_spi_recv(data, 1); ao_radio_deselect(); -#if CC115L_TRACE - printf (" %02x\n", data[0]); -#endif + trace_add(trace_read, addr, data[0], NULL); return data[0]; } static void -ao_radio_reg_write(uint16_t addr, uint8_t value) +ao_radio_reg_write(uint8_t addr, uint8_t value) { uint8_t data[2]; uint8_t d; -#if CC115L_TRACE - printf("\t\tao_radio_reg_write (%04x): %02x\n", addr, value); -#endif + trace_add(trace_write, addr, value, NULL); data[0] = ((0 << CC115L_READ) | (0 << CC115L_BURST) | addr); @@ -107,15 +160,10 @@ ao_radio_strobe(uint8_t addr) { uint8_t in; -#if CC115L_TRACE - printf("\t\tao_radio_strobe (%02x): ", addr); flush(); -#endif ao_radio_select(); ao_radio_duplex(&addr, &in, 1); ao_radio_deselect(); -#if CC115L_TRACE - printf("%02x\n", in); flush(); -#endif + trace_add(trace_strobe, addr, in, NULL); return in; } @@ -141,25 +189,11 @@ static uint8_t ao_radio_fifo_write(uint8_t *data, uint8_t len) { uint8_t status = ao_radio_fifo_write_start(); -#if CC115L_TRACE - printf ("fifo_write %d\n", len); -#endif + trace_add(trace_dma, CC115L_FIFO, len, NULL); ao_radio_spi_send(data, len); return ao_radio_fifo_write_stop(status); } -static uint8_t -ao_radio_fifo_write_fixed(uint8_t data, uint8_t len) -{ - uint8_t status = ao_radio_fifo_write_start(); - -#if CC115L_TRACE - printf ("fifo_write_fixed %02x %d\n", data, len); -#endif - ao_radio_spi_send_fixed(data, len); - return ao_radio_fifo_write_stop(status); -} - static uint8_t ao_radio_tx_fifo_space(void) { @@ -179,42 +213,28 @@ ao_radio_get_marcstate(void) { return ao_radio_reg_read(CC115L_MARCSTATE) & CC115L_MARCSTATE_MASK; } - + static void -ao_radio_mcu_wakeup_isr(void) +ao_radio_done_isr(void) { - ao_radio_mcu_wake = 1; + ao_exti_disable(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN); + trace_add(trace_line, __LINE__, 0, "done_isr"); + ao_radio_done = 1; ao_wakeup(&ao_radio_wake); } - -static void -ao_radio_check_marcstate(void) -{ - ao_radio_mcu_wake = 0; - ao_radio_marcstate = ao_radio_get_marcstate(); - - /* Anyt other than 'tx finished' means an error occurred */ - if (ao_radio_marcstate != CC115L_MARCSTATE_TX_END) - ao_radio_abort = 1; -} - static void -ao_radio_isr(void) +ao_radio_fifo_isr(void) { - ao_exti_disable(AO_CC115L_INT_PORT, AO_CC115L_INT_PIN); - ao_radio_wake = 1; + ao_exti_disable(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN); + trace_add(trace_line, __LINE__, 0, "fifo_isr"); + ao_radio_fifo = 1; ao_wakeup(&ao_radio_wake); } static void ao_radio_start_tx(void) { - ao_radio_pa_on(); - ao_exti_set_callback(AO_CC115L_INT_PORT, AO_CC115L_INT_PIN, ao_radio_isr); - ao_exti_enable(AO_CC115L_INT_PORT, AO_CC115L_INT_PIN); - ao_exti_enable(AO_CC115L_MCU_WAKEUP_PORT, AO_CC115L_MCU_WAKEUP_PIN); - ao_radio_strobe(CC115L_STX); } static void @@ -287,12 +307,9 @@ static const uint16_t packet_setup[] = { * * DATARATE_M = 67 * DATARATE_E = 6 - * - * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes */ #define RDF_DRATE_E 6 #define RDF_DRATE_M 67 -#define RDF_PACKET_LEN 50 static const uint16_t rdf_setup[] = { CC115L_DEVIATN, ((RDF_DEV_E << CC115L_DEVIATN_DEVIATION_E) | @@ -307,7 +324,7 @@ static const uint16_t rdf_setup[] = { */ #define APRS_DEV_E RDF_DEV_E -#define APRS_DEV_M RDF_DEV_E +#define APRS_DEV_M RDF_DEV_M /* * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate) @@ -342,21 +359,27 @@ static const uint16_t aprs_setup[] = { static uint16_t ao_radio_mode; + +/* + * These set the data rate and modulation parameters + */ #define AO_RADIO_MODE_BITS_PACKET_TX 1 -#define AO_RADIO_MODE_BITS_TX_BUF 2 -#define AO_RADIO_MODE_BITS_TX_FINISH 4 -#define AO_RADIO_MODE_BITS_RDF 8 -#define AO_RADIO_MODE_BITS_APRS 16 -#define AO_RADIO_MODE_BITS_INFINITE 32 -#define AO_RADIO_MODE_BITS_FIXED 64 +#define AO_RADIO_MODE_BITS_RDF 2 +#define AO_RADIO_MODE_BITS_APRS 4 + +/* + * Flips between infinite packet mode and fixed packet mode; + * we use infinite mode until the sender gives us the + * last chunk of data + */ +#define AO_RADIO_MODE_BITS_INFINITE 40 +#define AO_RADIO_MODE_BITS_FIXED 80 #define AO_RADIO_MODE_NONE 0 -#define AO_RADIO_MODE_PACKET_TX_BUF (AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_BUF) -#define AO_RADIO_MODE_PACKET_TX_FINISH (AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_FINISH) -#define AO_RADIO_MODE_RDF (AO_RADIO_MODE_BITS_RDF | AO_RADIO_MODE_BITS_TX_FINISH) -#define AO_RADIO_MODE_APRS_BUF (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF) -#define AO_RADIO_MODE_APRS_LAST_BUF (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_BUF) -#define AO_RADIO_MODE_APRS_FINISH (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_FINISH) + +#define AO_RADIO_MODE_RDF AO_RADIO_MODE_BITS_RDF +#define AO_RADIO_MODE_PACKET_TX AO_RADIO_MODE_BITS_PACKET_TX +#define AO_RADIO_MODE_APRS AO_RADIO_MODE_BITS_APRS static void ao_radio_set_mode(uint16_t new_mode) @@ -372,12 +395,6 @@ ao_radio_set_mode(uint16_t new_mode) for (i = 0; i < sizeof (packet_setup) / sizeof (packet_setup[0]); i += 2) ao_radio_reg_write(packet_setup[i], packet_setup[i+1]); - if (changes & AO_RADIO_MODE_BITS_TX_BUF) - ao_radio_reg_write(AO_CC115L_INT_GPIO_IOCFG, CC115L_IOCFG_GPIO_CFG_TXFIFO_THR); - - if (changes & AO_RADIO_MODE_BITS_TX_FINISH) - ao_radio_reg_write(AO_CC115L_INT_GPIO_IOCFG, CC115L_IOCFG_GPIO_CFG_PKT_SYNC_TX | (1 << CC115L_IOCFG_GPIO_INV)); - if (changes & AO_RADIO_MODE_BITS_RDF) for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2) ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]); @@ -395,8 +412,44 @@ ao_radio_set_mode(uint16_t new_mode) ao_radio_mode = new_mode; } +/*************************************************************** + * SmartRF Studio(tm) Export + * + * Radio register settings specifed with address, value + * + * RF device: CC115L + * + ***************************************************************/ + static const uint16_t radio_setup[] = { -#include "ao_rf_cc115l.h" + + /* High when FIFO is above threshold, low when fifo is below threshold */ + AO_CC115L_FIFO_INT_GPIO_IOCFG, CC115L_IOCFG_GPIO_CFG_TXFIFO_THR, + + /* High when transmitter is running, low when off */ + AO_CC115L_DONE_INT_GPIO_IOCFG, CC115L_IOCFG_GPIO_CFG_PA_PD | (1 << CC115L_IOCFG_GPIO_INV), + + CC115L_FIFOTHR, 0x47, /* TX FIFO Thresholds */ + CC115L_PKTCTRL0, 0x05, /* Packet Automation Control */ + CC115L_FREQ2, 0x10, /* Frequency Control Word, High Byte */ + CC115L_FREQ1, 0xb6, /* Frequency Control Word, Middle Byte */ + CC115L_FREQ0, 0xa5, /* Frequency Control Word, Low Byte */ + CC115L_MDMCFG4, 0xfa, /* Modem Configuration */ + CC115L_MDMCFG3, 0x83, /* Modem Configuration */ + CC115L_MDMCFG2, 0x13, /* Modem Configuration */ + CC115L_MDMCFG1, 0x21, /* Modem Configuration */ + CC115L_DEVIATN, 0x35, /* Modem Deviation Setting */ + CC115L_MCSM0, 0x18, /* Main Radio Control State Machine Configuration */ + CC115L_RESERVED_0X20, 0xfb, /* Use setting from SmartRF Studio */ + CC115L_FSCAL3, 0xe9, /* Frequency Synthesizer Calibration */ + CC115L_FSCAL2, 0x2a, /* Frequency Synthesizer Calibration */ + CC115L_FSCAL1, 0x00, /* Frequency Synthesizer Calibration */ + CC115L_FSCAL0, 0x1f, /* Frequency Synthesizer Calibration */ + CC115L_TEST2, 0x81, /* Various Test Settings */ + CC115L_TEST1, 0x35, /* Various Test Settings */ + CC115L_TEST0, 0x09, /* Various Test Settings */ + + CC115L_PA, 0x00, /* Power setting (0dBm) */ }; static uint8_t ao_radio_configured = 0; @@ -406,29 +459,11 @@ ao_radio_setup(void) { int i; -#if 0 - ao_gpio_set(AO_CC115L_SPI_CS_PORT, AO_CC115L_SPI_CS_PIN, AO_CC115L_SPI_CS, 0); - for (i = 0; i < 10000; i++) { - if (ao_gpio_get(SPI_2_PORT, SPI_2_MISO_PIN, SPI_2_MISO) == 0) { - printf ("Chip clock alive\n"); - break; - } - } - ao_gpio_set(AO_CC115L_SPI_CS_PORT, AO_CC115L_SPI_CS_PIN, AO_CC115L_SPI_CS, 1); - if (i == 10000) - printf ("Chip clock not alive\n"); -#endif - ao_radio_strobe(CC115L_SRES); ao_delay(AO_MS_TO_TICKS(10)); - printf ("Part %x\n", ao_radio_reg_read(CC115L_PARTNUM)); - printf ("Version %x\n", ao_radio_reg_read(CC115L_VERSION)); - - for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2) { + for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2) ao_radio_reg_write(radio_setup[i], radio_setup[i+1]); - ao_radio_reg_read(radio_setup[i]); - } ao_radio_mode = 0; @@ -449,7 +484,7 @@ ao_radio_set_len(uint8_t len) } static void -ao_radio_get(uint8_t len) +ao_radio_get(void) { static uint32_t last_radio_setting; static uint8_t last_power_setting; @@ -467,69 +502,100 @@ ao_radio_get(uint8_t len) ao_radio_reg_write(CC115L_PA, ao_config.radio_power); last_power_setting = ao_config.radio_power; } - ao_radio_set_len(len); } +static void +ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode); + #define ao_radio_put() ao_mutex_put(&ao_radio_mutex) -static void -ao_rdf_start(uint8_t len) +struct ao_radio_tone { + uint8_t value; + uint8_t len; +}; + +struct ao_radio_tone *ao_radio_tone; +uint8_t ao_radio_tone_count; +uint8_t ao_radio_tone_current; +uint8_t ao_radio_tone_offset; + +int16_t +ao_radio_tone_fill(uint8_t *buf, int16_t len) { - ao_radio_abort = 0; - ao_radio_get(len); + int16_t ret = 0; + + while (len) { + int16_t this_time; + struct ao_radio_tone *t; + + /* Figure out how many to send of the current value */ + t = &ao_radio_tone[ao_radio_tone_current]; + this_time = t->len - ao_radio_tone_offset; + if (this_time > len) + this_time = len; - ao_radio_set_mode(AO_RADIO_MODE_RDF); - ao_radio_wake = 0; + /* queue the data */ + memset(buf, t->value, this_time); + /* mark as sent */ + len -= this_time; + ao_radio_tone_offset += this_time; + ret += this_time; + + if (ao_radio_tone_offset >= t->len) { + ao_radio_tone_offset = 0; + ao_radio_tone_current++; + if (ao_radio_tone_current >= ao_radio_tone_count) { + trace_add(trace_line, __LINE__, ret, "done with tone"); + return -ret; + } + } + } + trace_add(trace_line, __LINE__, ret, "got some tone"); + return ret; } static void -ao_rdf_run(void) +ao_radio_tone_run(struct ao_radio_tone *tones, int ntones) { - ao_radio_start_tx(); - - ao_arch_block_interrupts(); - while (!ao_radio_wake && !ao_radio_abort && !ao_radio_mcu_wake) - ao_sleep(&ao_radio_wake); - ao_arch_release_interrupts(); - if (ao_radio_mcu_wake) - ao_radio_check_marcstate(); - ao_radio_pa_off(); - if (!ao_radio_wake) - ao_radio_idle(); - ao_radio_put(); + ao_radio_tone = tones; + ao_radio_tone_current = 0; + ao_radio_tone_offset = 0; + ao_radio_send_lots(ao_radio_tone_fill, AO_RADIO_MODE_RDF); } void ao_radio_rdf(void) { - ao_rdf_start(AO_RADIO_RDF_LEN); - - ao_radio_fifo_write_fixed(ao_radio_rdf_value, AO_RADIO_RDF_LEN); + struct ao_radio_tone tone; - ao_rdf_run(); + tone.value = ao_radio_rdf_value; + tone.len = AO_RADIO_RDF_LEN; + ao_radio_tone_run(&tone, 1); } void ao_radio_continuity(uint8_t c) { - uint8_t i; - uint8_t status; - - ao_rdf_start(AO_RADIO_CONT_TOTAL_LEN); + struct ao_radio_tone tones[7]; + uint8_t count = 0; + uint8_t i; - status = ao_radio_fifo_write_start(); for (i = 0; i < 3; i++) { - ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN); + tones[count].value = 0x00; + tones[count].len = AO_RADIO_CONT_PAUSE_LEN; + count++; if (i < c) - ao_radio_spi_send_fixed(ao_radio_rdf_value, AO_RADIO_CONT_TONE_LEN); + tones[count].value = ao_radio_rdf_value; else - ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_TONE_LEN); + tones[count].value = 0x00; + tones[count].len = AO_RADIO_CONT_TONE_LEN; + count++; } - ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN); - status = ao_radio_fifo_write_stop(status); - (void) status; - ao_rdf_run(); + tones[count].value = 0x00; + tones[count].len = AO_RADIO_CONT_PAUSE_LEN; + count++; + ao_radio_tone_run(tones, count); } void @@ -557,17 +623,12 @@ ao_radio_test_cmd(void) #if PACKET_HAS_SLAVE ao_packet_slave_stop(); #endif - ao_radio_get(0xff); + ao_radio_get(); + ao_radio_set_len(0xff); + ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX | AO_RADIO_MODE_BITS_FIXED); + ao_radio_strobe(CC115L_SFTX); ao_radio_pa_on(); ao_radio_strobe(CC115L_STX); -#if CC115L_TRACE - { int t; - for (t = 0; t < 10; t++) { - printf ("status: %02x\n", ao_radio_status()); - ao_delay(AO_MS_TO_TICKS(100)); - } - } -#endif radio_on = 1; } if (mode == 3) { @@ -585,85 +646,76 @@ ao_radio_test_cmd(void) } } +static inline int16_t +ao_radio_gpio_bits(void) +{ + return AO_CC115L_DONE_INT_PORT->idr & ((1 << AO_CC115L_FIFO_INT_PIN) | + (1 << AO_CC115L_DONE_INT_PIN)); +} + static void -ao_radio_wait_isr(void) +ao_radio_wait_fifo(void) { ao_arch_block_interrupts(); - while (!ao_radio_wake && !ao_radio_mcu_wake && !ao_radio_abort) + while (!ao_radio_fifo && !ao_radio_done && !ao_radio_abort) { + trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wait_fifo"); ao_sleep(&ao_radio_wake); + } ao_arch_release_interrupts(); - if (ao_radio_mcu_wake) - ao_radio_check_marcstate(); + trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wake bits"); + trace_add(trace_line, __LINE__, ao_radio_fifo, "wake fifo"); + trace_add(trace_line, __LINE__, ao_radio_done, "wake done"); + trace_add(trace_line, __LINE__, ao_radio_abort, "wake abort"); } -static uint8_t -ao_radio_wait_tx(uint8_t wait_fifo) +static void +ao_radio_wait_done(void) { - uint8_t fifo_space = 0; - - do { - ao_radio_wait_isr(); - if (!wait_fifo) - return 0; - fifo_space = ao_radio_tx_fifo_space(); - } while (!fifo_space && !ao_radio_abort); - return fifo_space; + ao_arch_block_interrupts(); + while (!ao_radio_done && !ao_radio_abort) { + trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wait_done"); + ao_sleep(&ao_radio_wake); + } + ao_arch_release_interrupts(); + trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wake bits"); + trace_add(trace_line, __LINE__, ao_radio_fifo, "wake fifo"); + trace_add(trace_line, __LINE__, ao_radio_done, "wake done"); + trace_add(trace_line, __LINE__, ao_radio_abort, "wake abort"); } static uint8_t tx_data[(AO_RADIO_MAX_SEND + 4) * 2]; -void -ao_radio_send(const void *d, uint8_t size) -{ - uint8_t marc_status; - uint8_t *e = tx_data; - uint8_t encode_len; - uint8_t this_len; - uint8_t started = 0; - uint8_t fifo_space; - - encode_len = ao_fec_encode(d, size, tx_data); +static uint8_t *ao_radio_send_buf; +static int16_t ao_radio_send_len; - ao_radio_get(encode_len); - - started = 0; - fifo_space = CC115L_FIFO_SIZE; - while (encode_len) { - this_len = encode_len; - - ao_radio_wake = 0; - if (this_len > fifo_space) { - this_len = fifo_space; - ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_BUF); - } else { - ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_FINISH); - } +static int16_t +ao_radio_send_fill(uint8_t *buf, int16_t len) +{ + int16_t this_time; - ao_radio_fifo_write(e, this_len); - e += this_len; - encode_len -= this_len; + this_time = ao_radio_send_len; + if (this_time > len) + this_time = len; + memcpy(buf, ao_radio_send_buf, this_time); + ao_radio_send_buf += this_time; + ao_radio_send_len -= this_time; + if (ao_radio_send_len == 0) + return -this_time; + return this_time; +} - if (!started) { - ao_radio_start_tx(); - started = 1; - } else { - ao_exti_enable(AO_CC115L_INT_PORT, AO_CC115L_INT_PIN); - } - - fifo_space = ao_radio_wait_tx(encode_len != 0); - if (ao_radio_abort) { - ao_radio_idle(); - break; - } - } - ao_radio_pa_off(); - ao_radio_put(); +void +ao_radio_send(const void *d, uint8_t size) +{ + ao_radio_send_len = ao_fec_encode(d, size, tx_data); + ao_radio_send_buf = tx_data; + ao_radio_send_lots(ao_radio_send_fill, AO_RADIO_MODE_PACKET_TX); } #define AO_RADIO_LOTS 64 -void -ao_radio_send_lots(ao_radio_fill_func fill) +static void +ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode) { uint8_t buf[AO_RADIO_LOTS], *b; int cnt; @@ -672,10 +724,13 @@ ao_radio_send_lots(ao_radio_fill_func fill) uint8_t started = 0; uint8_t fifo_space; - ao_radio_get(0xff); + ao_radio_get(); fifo_space = CC115L_FIFO_SIZE; + ao_radio_done = 0; + ao_radio_fifo = 0; while (!done) { cnt = (*fill)(buf, sizeof(buf)); + trace_add(trace_line, __LINE__, cnt, "send data count"); if (cnt < 0) { done = 1; cnt = -cnt; @@ -683,8 +738,13 @@ ao_radio_send_lots(ao_radio_fill_func fill) total += cnt; /* At the last buffer, set the total length */ - if (done) + if (done) { ao_radio_set_len(total & 0xff); + ao_radio_set_mode(mode | AO_RADIO_MODE_BITS_FIXED); + } else { + ao_radio_set_len(0xff); + ao_radio_set_mode(mode | AO_RADIO_MODE_BITS_INFINITE); + } b = buf; while (cnt) { @@ -692,46 +752,49 @@ ao_radio_send_lots(ao_radio_fill_func fill) /* Wait for some space in the fifo */ while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) { - ao_radio_wake = 0; - ao_radio_wait_isr(); + trace_add(trace_line, __LINE__, this_len, "wait for space"); + ao_radio_wait_fifo(); } - if (ao_radio_abort) + if (ao_radio_abort || ao_radio_done) break; + trace_add(trace_line, __LINE__, fifo_space, "got space"); if (this_len > fifo_space) this_len = fifo_space; cnt -= this_len; - if (done) { - if (cnt) - ao_radio_set_mode(AO_RADIO_MODE_APRS_LAST_BUF); - else - ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH); - } else - ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF); - + ao_radio_done = 0; + ao_radio_fifo = 0; ao_radio_fifo_write(b, this_len); b += this_len; + ao_exti_enable(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN); + ao_exti_enable(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN); + if (!started) { - ao_radio_start_tx(); + ao_radio_pa_on(); + ao_radio_strobe(CC115L_STX); started = 1; - } else - ao_exti_enable(AO_CC115L_INT_PORT, AO_CC115L_INT_PIN); + } } - if (ao_radio_abort) { - ao_radio_idle(); + if (ao_radio_abort || ao_radio_done) break; - } - /* Wait for the transmitter to go idle */ - ao_radio_wake = 0; - ao_radio_wait_isr(); } + if (ao_radio_abort) + ao_radio_idle(); + ao_radio_wait_done(); ao_radio_pa_off(); ao_radio_put(); } -static char *cc115l_state_name[] = { +void +ao_radio_send_aprs(ao_radio_fill_func fill) +{ + ao_radio_send_lots(fill, AO_RADIO_MODE_APRS); +} + +#if CC115L_DEBUG +const static char *cc115l_state_name[] = { [CC115L_STATUS_STATE_IDLE] = "IDLE", [CC115L_STATUS_STATE_TX] = "TX", [CC115L_STATUS_STATE_FSTXON] = "FSTXON", @@ -740,11 +803,6 @@ static char *cc115l_state_name[] = { [CC115L_STATUS_STATE_TX_FIFO_UNDERFLOW] = "TX_FIFO_UNDERFLOW", }; -struct ao_cc115l_reg { - uint16_t addr; - char *name; -}; - const static struct ao_cc115l_reg ao_cc115l_reg[] = { { .addr = CC115L_IOCFG2, .name = "IOCFG2" }, { .addr = CC115L_IOCFG1, .name = "IOCFG1" }, @@ -793,7 +851,7 @@ static void ao_radio_show(void) { uint8_t status = ao_radio_status(); int i; - ao_radio_get(0xff); + ao_radio_get(); status = ao_radio_status(); printf ("Status: %02x\n", status); printf ("CHIP_RDY: %d\n", (status >> CC115L_STATUS_CHIP_RDY) & 1); @@ -824,6 +882,8 @@ static void ao_radio_packet(void) { ao_radio_send(packet, sizeof (packet)); } +#endif /* CC115L_DEBUG */ + #if HAS_APRS #include @@ -869,17 +929,17 @@ ao_radio_init(void) ao_panic(AO_PANIC_SELF_TEST_CC115L); #endif - /* Enable the EXTI interrupt for the appropriate pin */ - ao_enable_port(AO_CC115L_INT_PORT); - ao_exti_setup(AO_CC115L_INT_PORT, AO_CC115L_INT_PIN, + /* Enable the fifo threhold interrupt pin */ + ao_enable_port(AO_CC115L_FIFO_INT_PORT); + ao_exti_setup(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN, AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH, - ao_radio_isr); + ao_radio_fifo_isr); - /* Enable the hacked up GPIO3 pin */ - ao_enable_port(AO_CC115L_MCU_WAKEUP_PORT); - ao_exti_setup(AO_CC115L_MCU_WAKEUP_PORT, AO_CC115L_MCU_WAKEUP_PIN, + /* Enable the tx done interrupt pin */ + ao_enable_port(AO_CC115L_DONE_INT_PORT); + ao_exti_setup(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN, AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED, - ao_radio_mcu_wakeup_isr); + ao_radio_done_isr); ao_radio_pa_init(); diff --git a/src/drivers/ao_rf_cc115l.h b/src/drivers/ao_rf_cc115l.h deleted file mode 100644 index 50a730ab..00000000 --- a/src/drivers/ao_rf_cc115l.h +++ /dev/null @@ -1,83 +0,0 @@ -/*************************************************************** - * SmartRF Studio(tm) Export - * - * Radio register settings specifed with address, value - * - * RF device: CC115L - * - ***************************************************************/ - - -#if 0 - CC115L_IOCFG2, 0x2e, /* GDO2 Output Pin Configuration */ - CC115L_IOCFG1, 0x2e, /* GDO1 Output Pin Configuration */ - CC115L_IOCFG0, 0x06, /* GDO0 Output Pin Configuration */ - CC115L_FIFOTHR, 0x47, /* TX FIFO Thresholds */ - CC115L_SYNC1, 0xd3, /* Sync Word, High Byte */ - CC115L_SYNC0, 0x91, /* Sync Word, Low Byte */ - CC115L_PKTLEN, 0xff, /* Packet Length */ - CC115L_PKTCTRL0, 0x05, /* Packet Automation Control */ - CC115L_CHANNR, 0x00, /* Channel number */ - CC115L_FSCTRL0, 0x00, /* Frequency Synthesizer Control */ - CC115L_FREQ2, 0x10, /* Frequency Control Word, High Byte */ - CC115L_FREQ1, 0xb6, /* Frequency Control Word, Middle Byte */ - CC115L_FREQ0, 0xa5, /* Frequency Control Word, Low Byte */ - CC115L_MDMCFG4, 0xfa, /* Modem Configuration */ - CC115L_MDMCFG3, 0x83, /* Modem Configuration */ - CC115L_MDMCFG2, 0x13, /* Modem Configuration */ - CC115L_MDMCFG1, 0x21, /* Modem Configuration */ - CC115L_MDMCFG0, 0xf8, /* Modem Configuration */ - CC115L_DEVIATN, 0x35, /* Modem Deviation Setting */ - CC115L_MCSM1, 0x30, /* Main Radio Control State Machine Configuration */ - CC115L_MCSM0, 0x18, /* Main Radio Control State Machine Configuration */ - CC115L_RESERVED_0X20, 0xfb, /* Use setting from SmartRF Studio */ - CC115L_FREND0, 0x10, /* Front End TX Configuration */ - CC115L_FSCAL3, 0xe9, /* Frequency Synthesizer Calibration */ - CC115L_FSCAL2, 0x2a, /* Frequency Synthesizer Calibration */ - CC115L_FSCAL1, 0x00, /* Frequency Synthesizer Calibration */ - CC115L_FSCAL0, 0x1f, /* Frequency Synthesizer Calibration */ - CC115L_RESERVED_0X29, 0x89, /* Use setting from SmartRF Studio */ - CC115L_RESERVED_0X2A, 0x127, /* Use setting from SmartRF Studio */ - CC115L_RESERVED_0X2B, 0x63, /* Use setting from SmartRF Studio */ - CC115L_TEST2, 0x81, /* Various Test Settings */ - CC115L_TEST1, 0x35, /* Various Test Settings */ - CC115L_TEST0, 0x09, /* Various Test Settings */ - CC115L_PARTNUM, 0x00, /* Chip ID */ - CC115L_VERSION, 0x09, /* Chip ID */ - CC115L_MARCSTATE, 0x00, /* Main Radio Control State Machine State */ - CC115L_PKTSTATUS, 0x00, /* Current GDOx Status and Packet Status */ - CC115L_TXBYTES, 0x00, /* Underflow and Number of Bytes */ -#endif - -/*************************************************************** - * SmartRF Studio(tm) Export - * - * Radio register settings specifed with address, value - * - * RF device: CC115L - * - ***************************************************************/ - - - CC115L_IOCFG0, 0x06, /* GDO0 Output Pin Configuration */ - CC115L_FIFOTHR, 0x47, /* TX FIFO Thresholds */ - CC115L_PKTCTRL0, 0x05, /* Packet Automation Control */ - CC115L_FREQ2, 0x10, /* Frequency Control Word, High Byte */ - CC115L_FREQ1, 0xb6, /* Frequency Control Word, Middle Byte */ - CC115L_FREQ0, 0xa5, /* Frequency Control Word, Low Byte */ - CC115L_MDMCFG4, 0xfa, /* Modem Configuration */ - CC115L_MDMCFG3, 0x83, /* Modem Configuration */ - CC115L_MDMCFG2, 0x13, /* Modem Configuration */ - CC115L_MDMCFG1, 0x21, /* Modem Configuration */ - CC115L_DEVIATN, 0x35, /* Modem Deviation Setting */ - CC115L_MCSM0, 0x18, /* Main Radio Control State Machine Configuration */ - CC115L_RESERVED_0X20, 0xfb, /* Use setting from SmartRF Studio */ - CC115L_FSCAL3, 0xe9, /* Frequency Synthesizer Calibration */ - CC115L_FSCAL2, 0x2a, /* Frequency Synthesizer Calibration */ - CC115L_FSCAL1, 0x00, /* Frequency Synthesizer Calibration */ - CC115L_FSCAL0, 0x1f, /* Frequency Synthesizer Calibration */ - CC115L_TEST2, 0x81, /* Various Test Settings */ - CC115L_TEST1, 0x35, /* Various Test Settings */ - CC115L_TEST0, 0x09, /* Various Test Settings */ - - CC115L_PA, 0x00, /* Power setting (0dBm) */ diff --git a/src/telegps-v0.1/Makefile b/src/telegps-v0.1/Makefile index c8ab8a9a..ae36c9fd 100644 --- a/src/telegps-v0.1/Makefile +++ b/src/telegps-v0.1/Makefile @@ -14,7 +14,6 @@ INC = \ ao_task.h \ ao_whiten.h \ ao_cc115l.h \ - ao_rf_cc115l.h \ ao_fec.h \ stm32l.h \ Makefile diff --git a/src/telegps-v0.1/ao_pins.h b/src/telegps-v0.1/ao_pins.h index 09574568..eea050c9 100644 --- a/src/telegps-v0.1/ao_pins.h +++ b/src/telegps-v0.1/ao_pins.h @@ -140,17 +140,13 @@ #define AO_CC115L_SPI_BUS AO_SPI_2_PB13_PB14_PB15 #define AO_CC115L_SPI stm_spi2 -#define AO_CC115L_INT_PORT (&stm_gpioa) -#define AO_CC115L_INT_PIN (9) +#define AO_CC115L_FIFO_INT_GPIO_IOCFG CC115L_IOCFG2 +#define AO_CC115L_FIFO_INT_PORT (&stm_gpioa) +#define AO_CC115L_FIFO_INT_PIN (9) -#define AO_CC115L_MCU_WAKEUP_PORT (&stm_gpioa) -#define AO_CC115L_MCU_WAKEUP_PIN (10) - -#define AO_CC115L_INT_GPIO 2 -#define AO_CC115L_INT_GPIO_IOCFG CC115L_IOCFG2 - -#define AO_CC115L_MARC_GPIO 0 -#define AO_CC115L_MARC_GPIO_IOCFG CC115L_IOCFG0 +#define AO_CC115L_DONE_INT_GPIO_IOCFG CC115L_IOCFG0 +#define AO_CC115L_DONE_INT_PORT (&stm_gpioa) +#define AO_CC115L_DONE_INT_PIN (10) #define HAS_RADIO_AMP 1 diff --git a/src/test/ao_aprs_test.c b/src/test/ao_aprs_test.c index 3b31f2d3..dd5eac4d 100644 --- a/src/test/ao_aprs_test.c +++ b/src/test/ao_aprs_test.c @@ -107,7 +107,7 @@ int main(int argc, char **argv) } void -ao_radio_send_lots(ao_radio_fill_func fill) +ao_radio_send_aprs(ao_radio_fill_func fill) { int16_t len; uint8_t done = 0; -- cgit v1.2.3 From bd32140df2a595ce66d603b98516bae519327c5d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 30 Mar 2013 01:30:18 -0700 Subject: altos: Configure cc115l sync byte count for each radio mode two sync bytes for packet mode, disable sync for rdf/aprs mode. Signed-off-by: Keith Packard --- src/drivers/ao_cc115l.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_cc115l.c b/src/drivers/ao_cc115l.c index 1d8211f6..6da1a678 100644 --- a/src/drivers/ao_cc115l.c +++ b/src/drivers/ao_cc115l.c @@ -282,6 +282,10 @@ static const uint16_t packet_setup[] = { CC115L_MDMCFG4, ((0xf << 4) | (PACKET_DRATE_E << CC115L_MDMCFG4_DRATE_E)), CC115L_MDMCFG3, (PACKET_DRATE_M), + CC115L_MDMCFG2, (0x00 | + (CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) | + (0 << CC115L_MDMCFG2_MANCHESTER_EN) | + (CC115L_MDMCFG2_SYNC_MODE_16BITS << CC115L_MDMCFG2_SYNC_MODE)), }; @@ -317,6 +321,10 @@ static const uint16_t rdf_setup[] = { CC115L_MDMCFG4, ((0xf << 4) | (RDF_DRATE_E << CC115L_MDMCFG4_DRATE_E)), CC115L_MDMCFG3, (RDF_DRATE_M), + CC115L_MDMCFG2, (0x00 | + (CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) | + (0 << CC115L_MDMCFG2_MANCHESTER_EN) | + (CC115L_MDMCFG2_SYNC_MODE_NONE << CC115L_MDMCFG2_SYNC_MODE)), }; /* @@ -348,6 +356,10 @@ static const uint16_t aprs_setup[] = { CC115L_MDMCFG4, ((0xf << 4) | (APRS_DRATE_E << CC115L_MDMCFG4_DRATE_E)), CC115L_MDMCFG3, (APRS_DRATE_M), + CC115L_MDMCFG2, (0x00 | + (CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) | + (0 << CC115L_MDMCFG2_MANCHESTER_EN) | + (CC115L_MDMCFG2_SYNC_MODE_NONE << CC115L_MDMCFG2_SYNC_MODE)), }; #define AO_PKTCTRL0_INFINITE ((CC115L_PKTCTRL0_PKT_FORMAT_NORMAL << CC115L_PKTCTRL0_PKT_FORMAT) | \ @@ -430,16 +442,16 @@ static const uint16_t radio_setup[] = { AO_CC115L_DONE_INT_GPIO_IOCFG, CC115L_IOCFG_GPIO_CFG_PA_PD | (1 << CC115L_IOCFG_GPIO_INV), CC115L_FIFOTHR, 0x47, /* TX FIFO Thresholds */ - CC115L_PKTCTRL0, 0x05, /* Packet Automation Control */ CC115L_FREQ2, 0x10, /* Frequency Control Word, High Byte */ CC115L_FREQ1, 0xb6, /* Frequency Control Word, Middle Byte */ CC115L_FREQ0, 0xa5, /* Frequency Control Word, Low Byte */ - CC115L_MDMCFG4, 0xfa, /* Modem Configuration */ - CC115L_MDMCFG3, 0x83, /* Modem Configuration */ CC115L_MDMCFG2, 0x13, /* Modem Configuration */ - CC115L_MDMCFG1, 0x21, /* Modem Configuration */ + CC115L_MDMCFG1, (0x00 | + (CC115L_MDMCFG1_NUM_PREAMBLE_4 << CC115L_MDMCFG1_NUM_PREAMBLE) | + (1 << CC115L_MDMCFG1_CHANSPC_E)), + CC115L_MDMCFG0, 248, /* Channel spacing M value (100kHz channels) */ CC115L_DEVIATN, 0x35, /* Modem Deviation Setting */ - CC115L_MCSM0, 0x18, /* Main Radio Control State Machine Configuration */ + CC115L_MCSM0, 0x38, /* Main Radio Control State Machine Configuration */ CC115L_RESERVED_0X20, 0xfb, /* Use setting from SmartRF Studio */ CC115L_FSCAL3, 0xe9, /* Frequency Synthesizer Calibration */ CC115L_FSCAL2, 0x2a, /* Frequency Synthesizer Calibration */ @@ -448,8 +460,7 @@ static const uint16_t radio_setup[] = { CC115L_TEST2, 0x81, /* Various Test Settings */ CC115L_TEST1, 0x35, /* Various Test Settings */ CC115L_TEST0, 0x09, /* Various Test Settings */ - - CC115L_PA, 0x00, /* Power setting (0dBm) */ + CC115L_PA, 0x00, /* Power setting (as low as possible) */ }; static uint8_t ao_radio_configured = 0; -- cgit v1.2.3 From 7455a892e8bf5402e7ff2c4bd2ddad05dfe76638 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 30 Mar 2013 01:31:12 -0700 Subject: altos: Lock cc115l radio mutex when using global radio values This moves the locking up above the global state variable uses so that multiple radio users (as if we had any) won't collide. Signed-off-by: Keith Packard --- src/drivers/ao_cc115l.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_cc115l.c b/src/drivers/ao_cc115l.c index 6da1a678..0e019bc0 100644 --- a/src/drivers/ao_cc115l.c +++ b/src/drivers/ao_cc115l.c @@ -516,7 +516,7 @@ ao_radio_get(void) } static void -ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode); +_ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode); #define ao_radio_put() ao_mutex_put(&ao_radio_mutex) @@ -569,10 +569,12 @@ ao_radio_tone_fill(uint8_t *buf, int16_t len) static void ao_radio_tone_run(struct ao_radio_tone *tones, int ntones) { + ao_radio_get(); ao_radio_tone = tones; ao_radio_tone_current = 0; ao_radio_tone_offset = 0; - ao_radio_send_lots(ao_radio_tone_fill, AO_RADIO_MODE_RDF); + _ao_radio_send_lots(ao_radio_tone_fill, AO_RADIO_MODE_RDF); + ao_radio_put(); } void @@ -718,15 +720,19 @@ ao_radio_send_fill(uint8_t *buf, int16_t len) void ao_radio_send(const void *d, uint8_t size) { + int i; + + ao_radio_get(); ao_radio_send_len = ao_fec_encode(d, size, tx_data); ao_radio_send_buf = tx_data; - ao_radio_send_lots(ao_radio_send_fill, AO_RADIO_MODE_PACKET_TX); + _ao_radio_send_lots(ao_radio_send_fill, AO_RADIO_MODE_PACKET_TX); + ao_radio_put(); } #define AO_RADIO_LOTS 64 static void -ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode) +_ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode) { uint8_t buf[AO_RADIO_LOTS], *b; int cnt; @@ -735,7 +741,6 @@ ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode) uint8_t started = 0; uint8_t fifo_space; - ao_radio_get(); fifo_space = CC115L_FIFO_SIZE; ao_radio_done = 0; ao_radio_fifo = 0; @@ -795,13 +800,14 @@ ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode) ao_radio_idle(); ao_radio_wait_done(); ao_radio_pa_off(); - ao_radio_put(); } void ao_radio_send_aprs(ao_radio_fill_func fill) { - ao_radio_send_lots(fill, AO_RADIO_MODE_APRS); + ao_radio_get(); + _ao_radio_send_lots(fill, AO_RADIO_MODE_APRS); + ao_radio_put(); } #if CC115L_DEBUG -- cgit v1.2.3 From b3d8956df3a3ecb3918b5db4d78b057d68541c33 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 30 Mar 2013 01:32:30 -0700 Subject: altos: Export ao_fat_sync and ao_fat_full functions ao_fat_sync() flushes the bufio data to disk along with any fsinfo changes. ao_fat_full() returns whether the file system is full. Signed-off-by: Keith Packard --- src/drivers/ao_fat.c | 95 ++++++++++++++++++++++++++++++++++++++-------------- src/drivers/ao_fat.h | 6 ++++ 2 files changed, 75 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_fat.c b/src/drivers/ao_fat.c index a19eff70..7d9bcd81 100644 --- a/src/drivers/ao_fat.c +++ b/src/drivers/ao_fat.c @@ -574,25 +574,36 @@ static uint32_t ao_file_offset; static uint32_t ao_file_cluster_offset; static cluster_t ao_file_cluster; static uint8_t ao_file_opened; +static uint8_t ao_filesystem_available; +static uint8_t ao_filesystem_setup; static uint8_t ao_fat_setup(void) { - ao_bufio_setup(); + if (!ao_filesystem_setup) { + + ao_filesystem_setup = 1; + ao_bufio_setup(); - partition_type = partition_start = partition_end = 0; - sectors_per_cluster = bytes_per_cluster = reserved_sector_count = 0; - number_fat = root_entries = sectors_per_fat = 0; - number_cluster = fat_start = root_start = data_start = 0; - next_free = filesystem_full = 0; - fat32 = fsinfo_dirty = root_cluster = fsinfo_sector = free_count = 0; - memset(&ao_file_dirent, '\0', sizeof (ao_file_dirent)); - ao_file_offset = ao_file_cluster_offset = ao_file_cluster = ao_file_opened = 0; - if (!ao_fat_setup_partition()) - return 0; - if (!ao_fat_setup_fs()) - return 0; - return 1; + /* Re-initialize all global state; this will help to allow the + * file system to get swapped someday + */ + partition_type = partition_start = partition_end = 0; + sectors_per_cluster = bytes_per_cluster = reserved_sector_count = 0; + number_fat = root_entries = sectors_per_fat = 0; + number_cluster = fat_start = root_start = data_start = 0; + next_free = filesystem_full = 0; + fat32 = fsinfo_dirty = root_cluster = fsinfo_sector = free_count = 0; + memset(&ao_file_dirent, '\0', sizeof (ao_file_dirent)); + + ao_file_offset = ao_file_cluster_offset = ao_file_cluster = ao_file_opened = 0; + if (!ao_fat_setup_partition()) + return 0; + if (!ao_fat_setup_fs()) + return 0; + ao_filesystem_available = 1; + } + return ao_filesystem_available; } /* @@ -699,7 +710,7 @@ ao_fat_set_size(uint32_t size) * * Initialize a root directory entry */ -void +static void ao_fat_root_init(uint8_t *dent, char name[11], uint8_t attr) { memset(dent, '\0', 0x20); @@ -750,7 +761,7 @@ ao_fat_dirent_init(uint8_t *dent, uint16_t entry, struct ao_fat_dirent *dirent) * Write out any fsinfo changes to disk */ -void +static void ao_fat_flush_fsinfo(void) { uint8_t *fsinfo; @@ -776,6 +787,36 @@ ao_fat_flush_fsinfo(void) * Public API */ +/* + * ao_fat_sync + * + * Flush any pending I/O to storage + */ + +void +ao_fat_sync(void) +{ + if (!ao_fat_setup()) + return; + ao_fat_flush_fsinfo(); + ao_bufio_flush(); +} + +/* + * ao_fat_full + * + * Returns TRUE if the filesystem cannot take + * more data + */ + +int8_t +ao_fat_full(void) +{ + if (!ao_fat_setup()) + return -AO_FAT_EIO; + return filesystem_full; +} + /* * ao_fat_open * @@ -787,6 +828,9 @@ ao_fat_open(char name[11], uint8_t mode) uint16_t entry = 0; struct ao_fat_dirent dirent; + if (!ao_fat_setup()) + return -AO_FAT_EIO; + if (ao_file_opened) return -AO_FAT_EMFILE; @@ -820,6 +864,9 @@ ao_fat_creat(char name[11]) int8_t status; uint8_t *dent; + if (!ao_fat_setup()) + return -AO_FAT_EIO; + if (ao_file_opened) return -AO_FAT_EMFILE; @@ -874,8 +921,7 @@ ao_fat_close(void) ao_file_cluster = 0; ao_file_opened = 0; - ao_fat_flush_fsinfo(); - ao_bufio_flush(); + ao_fat_sync(); return AO_FAT_SUCCESS; } @@ -1023,6 +1069,8 @@ ao_fat_unlink(char name[11]) uint16_t entry = 0; struct ao_fat_dirent dirent; + if (!ao_fat_setup()) + return -AO_FAT_EIO; while (ao_fat_readdir(&entry, &dirent)) { if (memcmp(name, dirent.name, 11) == 0) { uint8_t *next; @@ -1066,6 +1114,8 @@ ao_fat_readdir(uint16_t *entry, struct ao_fat_dirent *dirent) { uint8_t *dent; + if (!ao_fat_setup()) + return -AO_FAT_EIO; for (;;) { dent = ao_fat_root_get(*entry); if (!dent) @@ -1102,15 +1152,8 @@ ao_fat_list(void) } } -static void -ao_fat_test(void) -{ - ao_fat_setup(); - ao_fat_list(); -} - static const struct ao_cmds ao_fat_cmds[] = { - { ao_fat_test, "F\0Test FAT" }, + { ao_fat_list, "F\0List FAT" }, { 0, NULL }, }; diff --git a/src/drivers/ao_fat.h b/src/drivers/ao_fat.h index cfe98a76..e460c22a 100644 --- a/src/drivers/ao_fat.h +++ b/src/drivers/ao_fat.h @@ -48,6 +48,12 @@ ao_fat_init(void); #define AO_FAT_EFBIG 27 #define AO_FAT_ENOSPC 28 +void +ao_fat_sync(void); + +int8_t +ao_fat_full(void); + int8_t ao_fat_open(char name[11], uint8_t mode); -- cgit v1.2.3 From 649999863c7228ead0225968752d068dc0d30091 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 30 Mar 2013 01:33:49 -0700 Subject: altos: Add logging and telem to telegps This turns on telemetry, APRS, RDF and data logging for telegps. Data is logged as soon as GPS has a date to create the right filename, using files of the form YYYYMMDD.LOG which just barely fits in a FAT filename. Telemetry/RDF/APRS are all separately controllable. Signed-off-by: Keith Packard --- ao-tools/ao-telem/ao-telem.c | 9 ++++-- src/core/ao_gps_report_mega.c | 1 + src/core/ao_telemetry.c | 3 ++ src/drivers/ao_log_fat.c | 74 +++++++++++++++++++++++++++++++++++++++++++ src/telegps-v0.1/Makefile | 5 ++- src/telegps-v0.1/ao_telegps.c | 9 +++++- 6 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 src/drivers/ao_log_fat.c (limited to 'src') diff --git a/ao-tools/ao-telem/ao-telem.c b/ao-tools/ao-telem/ao-telem.c index e7fc8e26..d2dae5a7 100644 --- a/ao-tools/ao-telem/ao-telem.c +++ b/ao-tools/ao-telem/ao-telem.c @@ -24,6 +24,7 @@ #include "cc.h" static const struct option options[] = { + { .name = "crc", .has_arg = 0, .val = 'c' }, { 0, 0, 0, 0}, }; @@ -44,8 +45,12 @@ main (int argc, char **argv) char *s; FILE *file; int serial; - while ((c = getopt_long(argc, argv, "", options, NULL)) != -1) { + int ignore_crc = 0; + while ((c = getopt_long(argc, argv, "c", options, NULL)) != -1) { switch (c) { + case 'c': + ignore_crc = 1; + break; default: usage(argv[0]); break; @@ -74,7 +79,7 @@ main (int argc, char **argv) printf ("serial %5d rssi %d status %02x tick %5d type %3d ", telem.generic.serial, rssi, telem.generic.status, telem.generic.tick, telem.generic.type); - if ((telem.generic.status & (1 << 7)) == 0) { + if (!ignore_crc && (telem.generic.status & (1 << 7)) == 0) { printf ("CRC error\n"); continue; } diff --git a/src/core/ao_gps_report_mega.c b/src/core/ao_gps_report_mega.c index 47891cab..e3af4307 100644 --- a/src/core/ao_gps_report_mega.c +++ b/src/core/ao_gps_report_mega.c @@ -16,6 +16,7 @@ */ #include "ao.h" +#include "ao_log.h" void ao_gps_report_mega(void) diff --git a/src/core/ao_telemetry.c b/src/core/ao_telemetry.c index 8d440e15..3aa315c7 100644 --- a/src/core/ao_telemetry.c +++ b/src/core/ao_telemetry.c @@ -16,6 +16,7 @@ */ #include "ao.h" +#include "ao_log.h" #include "ao_product.h" static __pdata uint16_t ao_telemetry_interval; @@ -306,12 +307,14 @@ ao_telemetry(void) #ifdef AO_SEND_ALL_BARO ao_send_baro(); #endif +#if HAS_FLIGHT #ifdef AO_SEND_MEGA ao_send_mega_sensor(); ao_send_mega_data(); #else ao_send_sensor(); #endif +#endif #if HAS_COMPANION if (ao_companion_running) diff --git a/src/drivers/ao_log_fat.c b/src/drivers/ao_log_fat.c new file mode 100644 index 00000000..684148b7 --- /dev/null +++ b/src/drivers/ao_log_fat.c @@ -0,0 +1,74 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" +#include "ao_log.h" +#include "ao_fat.h" + +static uint8_t log_year, log_month, log_day; +static uint8_t log_running; +static uint8_t log_mutex; + +static void +ao_log_open(void) +{ + char name[12]; + + sprintf(name,"%04d%02d%02dLOG", 2000 + log_year, log_month, log_day); + if (ao_fat_open(name, AO_FAT_OPEN_WRITE) == AO_FAT_SUCCESS) + log_running = 1; +} + +static void +ao_log_close(void) +{ + log_running = 0; + ao_fat_close(); +} + +uint8_t +ao_log_full(void) +{ + return ao_fat_full(); +} + +uint8_t +ao_log_mega(struct ao_log_mega *log) +{ + uint8_t wrote = 0; + ao_mutex_get(&log_mutex); + if (log->type == AO_LOG_GPS_TIME) { + if (log_running && + (log_year != log->u.gps.year || + log_month != log->u.gps.month || + log_day != log->u.gps.day)) { + ao_log_close(); + } + if (!log_running) { + log_year = log->u.gps.year; + log_month = log->u.gps.month; + log_day = log->u.gps.day; + ao_log_open(); + } + } + if (log_running) { + wrote = ao_fat_write(log, sizeof (*log)) == AO_FAT_SUCCESS; + ao_fat_sync(); + } + ao_mutex_put(&log_mutex); + return wrote; +} diff --git a/src/telegps-v0.1/Makefile b/src/telegps-v0.1/Makefile index ae36c9fd..8e610db7 100644 --- a/src/telegps-v0.1/Makefile +++ b/src/telegps-v0.1/Makefile @@ -55,7 +55,10 @@ ALTOS_SRC = \ ao_eeprom_stm.c \ ao_sdcard.c \ ao_bufio.c \ - ao_fat.c + ao_fat.c \ + ao_log_fat.c \ + ao_gps_report_mega.c \ + ao_telemetry.c PRODUCT=TeleGPS-v0.1 PRODUCT_DEF=-DTELEGPS diff --git a/src/telegps-v0.1/ao_telegps.c b/src/telegps-v0.1/ao_telegps.c index 2f1f38f2..91796c21 100644 --- a/src/telegps-v0.1/ao_telegps.c +++ b/src/telegps-v0.1/ao_telegps.c @@ -19,6 +19,8 @@ #include #include +uint16_t ao_flight_number = 1; + int main(void) { @@ -47,9 +49,14 @@ main(void) ao_usb_init(); ao_radio_init(); + ao_fat_init(); + ao_gps_init(); + ao_gps_report_mega_init(); - ao_fat_init(); + ao_telemetry_init(); + ao_telemetry_set_interval(AO_SEC_TO_TICKS(1)); + ao_rdf_set(1); ao_config_init(); -- cgit v1.2.3 From d8826b1ad5487de9345b7dcaf6c75a45117ff538 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 31 Mar 2013 10:35:47 -0700 Subject: altos: Add SD card writing function Now that the FAT code seems to be operational, go back and add SD writing. Signed-off-by: Keith Packard --- src/drivers/ao_sdcard.c | 124 +++++++++++++++++++++++++++++++++++++++++++++--- src/drivers/ao_sdcard.h | 1 + 2 files changed, 118 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_sdcard.c b/src/drivers/ao_sdcard.c index 2174af1e..4eef6625 100644 --- a/src/drivers/ao_sdcard.c +++ b/src/drivers/ao_sdcard.c @@ -27,6 +27,7 @@ #define ao_sdcard_select() ao_gpio_set(AO_SDCARD_SPI_CS_PORT,AO_SDCARD_SPI_CS_PIN,AO_SDCARD_SPI_CS,0) #define ao_sdcard_deselect() ao_gpio_set(AO_SDCARD_SPI_CS_PORT,AO_SDCARD_SPI_CS_PIN,AO_SDCARD_SPI_CS,1) +#define SDCARD_DEBUG 0 static uint8_t initialized; static uint8_t present; @@ -170,6 +171,20 @@ ao_sdcard_send_if_cond(uint32_t arg, uint8_t send_if_cond_response[4]) return ret; } +static uint8_t +ao_sdcard_send_status(void) +{ + uint8_t ret; + + DBG ("send_status\n"); + ao_sdcard_select(); + ret = ao_sdcard_send_cmd(SDCARD_SEND_STATUS, 0); + ao_sdcard_recv_reply(NULL, 0); + if (ret != SDCARD_STATUS_READY_STATE) + DBG ("\tsend_if_cond failed %02x\n", ret); + return ret; +} + static uint8_t ao_sdcard_set_blocklen(uint32_t blocklen) { @@ -182,7 +197,6 @@ ao_sdcard_set_blocklen(uint32_t blocklen) if (ret != SDCARD_STATUS_READY_STATE) DBG ("\tsend_if_cond failed %02x\n", ret); return ret; - } static uint8_t @@ -364,7 +378,8 @@ ao_sdcard_read_block(uint32_t block, uint8_t *data) if (ret != SDCARD_STATUS_READY_STATE) goto bail; - if (ao_sdcard_wait_block_start() != 0xfe) { + /* Wait for the data start block marker */ + if (ao_sdcard_wait_block_start() != SDCARD_DATA_START_BLOCK) { ret = 0x3f; goto bail; } @@ -384,15 +399,110 @@ bail: uint8_t ao_sdcard_write_block(uint32_t block, uint8_t *data) { - /* Not doing anything until the file system code seems reasonable - */ - return 1; + uint8_t ret; + uint8_t response; + uint8_t start_block[2]; + int i; + + ao_sdcard_lock(); + if (!initialized) { + ao_sdcard_setup(); + initialized = 1; + if (sdtype != ao_sdtype_unknown) + present = 1; + } + if (!present) { + ao_sdcard_unlock(); + return 0; + } + if (sdtype != ao_sdtype_sd2block) + block <<= 9; + ao_sdcard_get(); + ao_sdcard_select(); + + ret = ao_sdcard_send_cmd(SDCARD_WRITE_BLOCK, block); + ao_sdcard_recv_reply(NULL, 0); + if (ret != SDCARD_STATUS_READY_STATE) + goto bail; + + /* Write a pad byte followed by the data start block marker */ + start_block[0] = 0xff; + start_block[1] = SDCARD_DATA_START_BLOCK; + ao_sdcard_send(start_block, 2); + + /* Send the data */ + ao_sdcard_send(data, 512); + + /* Fake the CRC */ + ao_sdcard_send_fixed(0xff, 2); + + /* See if the card liked the data */ + ao_sdcard_recv(&response, 1); + if ((response & SDCARD_DATA_RES_MASK) != SDCARD_DATA_RES_ACCEPTED) { + ret = 0x3f; + goto bail; + } + + /* Wait for the bus to go idle (should be done with an interrupt) */ + for (i = 0; i < SDCARD_IDLE_TIMEOUT; i++) { + ao_sdcard_recv(&response, 1); + if (response == 0xff) + break; + } + if (i == SDCARD_IDLE_TIMEOUT) + ret = 0x3f; +bail: + ao_sdcard_deselect(); + ao_sdcard_put(); + ao_sdcard_unlock(); + return ret == SDCARD_STATUS_READY_STATE; +} + +#if SDCARD_DEBUG +static uint8_t test_data[512]; + +static void +ao_sdcard_test_read(void) +{ + int i; + if (!ao_sdcard_read_block(1, test_data)) { + printf ("read error\n"); + return; + } + printf ("data:"); + for (i = 0; i < 18; i++) + printf (" %02x", test_data[i]); + printf ("\n"); } +static void +ao_sdcard_test_write(void) +{ + int i; + printf ("data:"); + for (i = 0; i < 16; i++) { + test_data[i]++; + printf (" %02x", test_data[i]); + } + printf ("\n"); + if (!ao_sdcard_write_block(1, test_data)) { + printf ("write error\n"); + return; + } +} + +static const struct ao_cmds ao_sdcard_cmds[] = { + { ao_sdcard_test_read, "x\0Test read" }, + { ao_sdcard_test_write, "y\0Test read" }, + { 0, NULL }, +}; +#endif + void ao_sdcard_init(void) { ao_spi_init_cs(AO_SDCARD_SPI_CS_PORT, (1 << AO_SDCARD_SPI_CS_PIN)); +#if SDCARD_DEBUG + ao_cmd_register(&ao_sdcard_cmds[0]); +#endif } - - diff --git a/src/drivers/ao_sdcard.h b/src/drivers/ao_sdcard.h index b9f737c5..35e81ced 100644 --- a/src/drivers/ao_sdcard.h +++ b/src/drivers/ao_sdcard.h @@ -63,6 +63,7 @@ ao_sdcard_init(void); #define SDCARD_CMD_TIMEOUT 100 #define SDCARD_IDLE_WAIT 100 #define SDCARD_BLOCK_TIMEOUT 100 +#define SDCARD_IDLE_TIMEOUT 1000 enum ao_sdtype { ao_sdtype_unknown, -- cgit v1.2.3 From a0628541e1bfc3e4a122cc824188ed53fddf733e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 31 Mar 2013 12:21:03 -0700 Subject: altos: Disable CC115L debug commands now that it appears to work, leave these disabled by default Signed-off-by: Keith Packard --- src/drivers/ao_cc115l.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/drivers/ao_cc115l.c b/src/drivers/ao_cc115l.c index 0e019bc0..9a4908b5 100644 --- a/src/drivers/ao_cc115l.c +++ b/src/drivers/ao_cc115l.c @@ -33,7 +33,7 @@ static uint8_t ao_radio_mcu_wake; /* MARC status change */ static uint8_t ao_radio_marcstate; /* Last read MARC state value */ /* Debugging commands */ -#define CC115L_DEBUG 1 +#define CC115L_DEBUG 0 /* Runtime tracing */ #define CC115L_TRACE 0 -- cgit v1.2.3 From a0595d94c7deea29d9e3d4bcbc106b9bed5ee103 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 31 Mar 2013 12:22:28 -0700 Subject: altos: Move fat mount information to separate command. This makes the mount report precise error information and then prints that with the 'M' command. Signed-off-by: Keith Packard --- src/drivers/ao_fat.c | 326 +++++++++++++++++++++++++++++++++++++++------------ src/drivers/ao_fat.h | 12 ++ 2 files changed, 262 insertions(+), 76 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_fat.c b/src/drivers/ao_fat.c index 7d9bcd81..ea8cdf96 100644 --- a/src/drivers/ao_fat.c +++ b/src/drivers/ao_fat.c @@ -22,6 +22,18 @@ #include "ao_fat.h" #include "ao_bufio.h" +/* Include FAT commands */ +#define FAT_COMMANDS 1 + +/* Spew FAT tracing */ +#define FAT_TRACE 0 + +#if FAT_TRACE +#define DBG(...) printf(__VA_ARGS__) +#else +#define DBG(...) +#endif + /* * Basic file system types */ @@ -409,7 +421,7 @@ ao_fat_root_put(uint8_t *root, dirent_t e, uint8_t write) /* * ao_fat_root_extend * - * On FAT32, make the + * On FAT32, make the root directory at least 'ents' entries long */ static int8_t ao_fat_root_extend(dirent_t ents) @@ -440,14 +452,14 @@ ao_fat_setup_partition(void) mbr = ao_bufio_get(0); if (!mbr) - return 0; + return AO_FAT_FILESYSTEM_MBR_READ_FAILURE; /* Check the signature */ if (mbr[0x1fe] != 0x55 || mbr[0x1ff] != 0xaa) { - printf ("Invalid MBR signature %02x %02x\n", + DBG ("Invalid MBR signature %02x %02x\n", mbr[0x1fe], mbr[0x1ff]); ao_bufio_put(mbr, 0); - return 0; + return AO_FAT_FILESYSTEM_INVALID_MBR_SIGNATURE; } /* Check to see if it's actually a boot block, in which @@ -472,24 +484,22 @@ ao_fat_setup_partition(void) case 0x0c: /* FAT32 LBA */ break; default: - printf ("Invalid partition type %02x\n", partition_type); + DBG ("Invalid partition type %02x\n", partition_type); ao_bufio_put(mbr, 0); - return 0; + return AO_FAT_FILESYSTEM_INVALID_PARTITION_TYPE; } partition_start = get_u32(partition+8); partition_size = get_u32(partition+12); if (partition_size == 0) { - printf ("Zero-sized partition\n"); + DBG ("Zero-sized partition\n"); ao_bufio_put(mbr, 0); - return 0; + return AO_FAT_FILESYSTEM_ZERO_SIZED_PARTITION; } } partition_end = partition_start + partition_size; - printf ("Partition type %02x start %08x end %08x\n", - partition_type, partition_start, partition_end); ao_bufio_put(mbr, 0); - return 1; + return AO_FAT_FILESYSTEM_SUCCESS; } static uint8_t @@ -499,22 +509,22 @@ ao_fat_setup_fs(void) uint32_t data_sectors; if (!boot) - return 0; + return AO_FAT_FILESYSTEM_BOOT_READ_FAILURE; /* Check the signature */ if (boot[0x1fe] != 0x55 || boot[0x1ff] != 0xaa) { - printf ("Invalid BOOT signature %02x %02x\n", + DBG ("Invalid BOOT signature %02x %02x\n", boot[0x1fe], boot[0x1ff]); ao_fat_sector_put(boot, 0); - return 0; + return AO_FAT_FILESYSTEM_INVALID_BOOT_SIGNATURE; } /* Check the sector size */ if (get_u16(boot + 0xb) != SECTOR_SIZE) { - printf ("Invalid sector size %d\n", + DBG ("Invalid sector size %d\n", get_u16(boot + 0xb)); ao_fat_sector_put(boot, 0); - return 0; + return AO_FAT_FILESYSTEM_INVALID_SECTOR_SIZE; } sectors_per_cluster = boot[0xd]; @@ -552,18 +562,7 @@ ao_fat_setup_fs(void) number_cluster = data_sectors / sectors_per_cluster; - printf ("fat32: %d\n", fat32); - printf ("sectors per cluster %d\n", sectors_per_cluster); - printf ("reserved sectors %d\n", reserved_sector_count); - printf ("number of FATs %d\n", number_fat); - printf ("root entries %d\n", root_entries); - printf ("sectors per fat %d\n", sectors_per_fat); - - printf ("fat start %d\n", fat_start); - printf ("root start %d\n", root_start); - printf ("data start %d\n", data_start); - - return 1; + return AO_FAT_FILESYSTEM_SUCCESS; } /* @@ -576,6 +575,7 @@ static cluster_t ao_file_cluster; static uint8_t ao_file_opened; static uint8_t ao_filesystem_available; static uint8_t ao_filesystem_setup; +static uint8_t ao_filesystem_status; static uint8_t ao_fat_setup(void) @@ -597,13 +597,14 @@ ao_fat_setup(void) memset(&ao_file_dirent, '\0', sizeof (ao_file_dirent)); ao_file_offset = ao_file_cluster_offset = ao_file_cluster = ao_file_opened = 0; - if (!ao_fat_setup_partition()) - return 0; - if (!ao_fat_setup_fs()) - return 0; - ao_filesystem_available = 1; + ao_filesystem_status = ao_fat_setup_partition(); + if (ao_filesystem_status != AO_FAT_FILESYSTEM_SUCCESS) + return ao_filesystem_status; + ao_filesystem_status = ao_fat_setup_fs(); + if (ao_filesystem_status != AO_FAT_FILESYSTEM_SUCCESS) + return ao_filesystem_status; } - return ao_filesystem_available; + return ao_filesystem_status; } /* @@ -618,6 +619,9 @@ ao_fat_current_sector(void) uint16_t sector_index; cluster_t cluster; + DBG("current sector offset %d size %d\n", + ao_file_offset, ao_file_dirent.size); + if (ao_file_offset > ao_file_dirent.size) return 0xffffffff; @@ -626,6 +630,7 @@ ao_fat_current_sector(void) if (!ao_file_cluster || ao_file_offset < ao_file_cluster_offset) { ao_file_cluster = ao_file_dirent.cluster; ao_file_cluster_offset = 0; + DBG("\treset to start of file %08x\n", ao_file_cluster); } if (ao_file_cluster_offset + bytes_per_cluster <= ao_file_offset) { @@ -635,6 +640,7 @@ ao_fat_current_sector(void) cluster_distance = cluster_offset - ao_file_cluster_offset / bytes_per_cluster; + DBG("\tseek forward %d clusters\n", cluster_distance); cluster = ao_fat_cluster_seek(ao_file_cluster, cluster_distance); if (!ao_fat_cluster_valid(cluster)) @@ -644,12 +650,16 @@ ao_fat_current_sector(void) } sector_index = sector_offset % sectors_per_cluster; + DBG("current cluster %08x sector_index %d sector %d\n", + ao_file_cluster, sector_index, + data_start + (uint32_t) (ao_file_cluster-2) * sectors_per_cluster + sector_index); return data_start + (uint32_t) (ao_file_cluster-2) * sectors_per_cluster + sector_index; } static void ao_fat_set_offset(uint32_t offset) { + DBG("Set offset %d\n", offset); ao_file_offset = offset; } @@ -666,23 +676,30 @@ ao_fat_set_size(uint32_t size) cluster_t first_cluster; cluster_t have_clusters, need_clusters; - if (size == ao_file_dirent.size) + DBG ("Set size %d\n", size); + if (size == ao_file_dirent.size) { + DBG("\tsize match\n"); return AO_FAT_SUCCESS; + } first_cluster = ao_file_dirent.cluster; have_clusters = (ao_file_dirent.size + bytes_per_cluster - 1) / bytes_per_cluster; need_clusters = (size + bytes_per_cluster - 1) / bytes_per_cluster; + DBG ("\tfirst cluster %08x have %d need %d\n", first_cluster, have_clusters, need_clusters); if (have_clusters != need_clusters) { if (ao_file_cluster && size >= ao_file_cluster_offset) { cluster_t offset_clusters = (ao_file_cluster_offset + bytes_per_cluster) / bytes_per_cluster; cluster_t extra_clusters = need_clusters - offset_clusters; cluster_t next_cluster; + DBG ("\tset size relative offset_clusters %d extra_clusters %d\n", + offset_clusters, extra_clusters); next_cluster = ao_fat_cluster_set_size(ao_file_cluster, extra_clusters); if (next_cluster == AO_FAT_BAD_CLUSTER) return -AO_FAT_ENOSPC; } else { + DBG ("\tset size absolute need_clusters %d\n", need_clusters); first_cluster = ao_fat_cluster_set_size(first_cluster, need_clusters); if (first_cluster == AO_FAT_BAD_CLUSTER) @@ -690,6 +707,7 @@ ao_fat_set_size(uint32_t size) } } + DBG ("\tupdate directory size\n"); /* Update the directory entry */ dent = ao_fat_root_get(ao_file_dirent.entry); if (!dent) @@ -702,6 +720,7 @@ ao_fat_set_size(uint32_t size) ao_file_dirent.size = size; ao_file_dirent.cluster = first_cluster; + DBG ("set size done\n"); return AO_FAT_SUCCESS; } @@ -796,7 +815,7 @@ ao_fat_flush_fsinfo(void) void ao_fat_sync(void) { - if (!ao_fat_setup()) + if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) return; ao_fat_flush_fsinfo(); ao_bufio_flush(); @@ -812,8 +831,8 @@ ao_fat_sync(void) int8_t ao_fat_full(void) { - if (!ao_fat_setup()) - return -AO_FAT_EIO; + if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) + return 1; return filesystem_full; } @@ -828,7 +847,7 @@ ao_fat_open(char name[11], uint8_t mode) uint16_t entry = 0; struct ao_fat_dirent dirent; - if (!ao_fat_setup()) + if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) return -AO_FAT_EIO; if (ao_file_opened) @@ -864,7 +883,7 @@ ao_fat_creat(char name[11]) int8_t status; uint8_t *dent; - if (!ao_fat_setup()) + if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) return -AO_FAT_EIO; if (ao_file_opened) @@ -925,6 +944,32 @@ ao_fat_close(void) return AO_FAT_SUCCESS; } +/* + * ao_fat_map_current + * + * Map the sector pointed at by the current file offset + */ + +static void * +ao_fat_map_current(int len, cluster_offset_t *offsetp, cluster_offset_t *this_time) +{ + cluster_offset_t offset; + sector_t sector; + void *buf; + + offset = ao_file_offset & SECTOR_MASK; + sector = ao_fat_current_sector(); + if (sector == 0xffffffff) + return NULL; + buf = ao_fat_sector_get(sector); + if (offset + len < SECTOR_SIZE) + *this_time = len; + else + *this_time = SECTOR_SIZE - offset; + *offsetp = offset; + return buf; +} + /* * ao_fat_read * @@ -933,12 +978,11 @@ ao_fat_close(void) int ao_fat_read(void *dst, int len) { - uint8_t *dst_b = dst; - uint32_t sector; - uint16_t this_time; - uint16_t offset; - uint8_t *buf; - int ret = 0; + uint8_t *dst_b = dst; + cluster_offset_t this_time; + cluster_offset_t offset; + uint8_t *buf; + int ret = 0; if (!ao_file_opened) return -AO_FAT_EBADF; @@ -950,16 +994,7 @@ ao_fat_read(void *dst, int len) len = 0; while (len) { - offset = ao_file_offset & SECTOR_MASK; - if (offset + len < SECTOR_SIZE) - this_time = len; - else - this_time = SECTOR_SIZE - offset; - - sector = ao_fat_current_sector(); - if (sector == 0xffffffff) - break; - buf = ao_fat_sector_get(sector); + buf = ao_fat_map_current(len, &offset, &this_time); if (!buf) { ret = -AO_FAT_EIO; break; @@ -1000,16 +1035,7 @@ ao_fat_write(void *src, int len) } while (len) { - offset = ao_file_offset & SECTOR_MASK; - if (offset + len < SECTOR_SIZE) - this_time = len; - else - this_time = SECTOR_SIZE - offset; - - sector = ao_fat_current_sector(); - if (sector == 0xffffffff) - break; - buf = ao_fat_sector_get(sector); + buf = ao_fat_map_current(len, &offset, &this_time); if (!buf) { ret = -AO_FAT_EIO; break; @@ -1069,8 +1095,9 @@ ao_fat_unlink(char name[11]) uint16_t entry = 0; struct ao_fat_dirent dirent; - if (!ao_fat_setup()) + if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) return -AO_FAT_EIO; + while (ao_fat_readdir(&entry, &dirent)) { if (memcmp(name, dirent.name, 11) == 0) { uint8_t *next; @@ -1114,8 +1141,9 @@ ao_fat_readdir(uint16_t *entry, struct ao_fat_dirent *dirent) { uint8_t *dent; - if (!ao_fat_setup()) + if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) return -AO_FAT_EIO; + for (;;) { dent = ao_fat_root_get(*entry); if (!dent) @@ -1136,24 +1164,170 @@ ao_fat_readdir(uint16_t *entry, struct ao_fat_dirent *dirent) } } +static const char *filesystem_errors[] = { + [AO_FAT_FILESYSTEM_SUCCESS] = "FAT file system operating normally", + [AO_FAT_FILESYSTEM_MBR_READ_FAILURE] = "MBR media read error", + [AO_FAT_FILESYSTEM_INVALID_MBR_SIGNATURE] = "MBR signature invalid", + [AO_FAT_FILESYSTEM_INVALID_PARTITION_TYPE] = "Unsupported paritition type", + [AO_FAT_FILESYSTEM_ZERO_SIZED_PARTITION] = "Partition has zero sectors", + [AO_FAT_FILESYSTEM_BOOT_READ_FAILURE] = "Boot block media read error", + [AO_FAT_FILESYSTEM_INVALID_BOOT_SIGNATURE] = "Boot block signature invalid", + [AO_FAT_FILESYSTEM_INVALID_SECTOR_SIZE] = "Sector size not 512", +}; + static void -ao_fat_list(void) +ao_fat_mbr_cmd(void) +{ + uint8_t status; + + status = ao_fat_setup(); + if (status == AO_FAT_FILESYSTEM_SUCCESS) { + printf ("partition type: %02x\n", partition_type); + printf ("partition start: %08x\n", partition_start); + + printf ("partition end: %08x\n", partition_end); + + printf ("fat32: %d\n", fat32); + printf ("sectors per cluster %d\n", sectors_per_cluster); + printf ("reserved sectors %d\n", reserved_sector_count); + printf ("number of FATs %d\n", number_fat); + printf ("root entries %d\n", root_entries); + printf ("sectors per fat %d\n", sectors_per_fat); + + printf ("fat start %d\n", fat_start); + printf ("root start %d\n", root_start); + printf ("data start %d\n", data_start); + } else { + printf ("FAT filesystem not available: %s\n", filesystem_errors[status]); + } +} + +struct ao_fat_attr { + uint8_t bit; + char label; +}; + +static const struct ao_fat_attr ao_fat_attr[] = { + { .bit = AO_FAT_FILE_READ_ONLY, .label = 'R' }, + { .bit = AO_FAT_FILE_HIDDEN, .label = 'H' }, + { .bit = AO_FAT_FILE_SYSTEM, .label = 'S' }, + { .bit = AO_FAT_FILE_VOLUME_LABEL, .label = 'V' }, + { .bit = AO_FAT_FILE_DIRECTORY, .label = 'D' }, + { .bit = AO_FAT_FILE_ARCHIVE, .label = 'A' }, +}; + +#define NUM_FAT_ATTR (sizeof (ao_fat_attr) / sizeof (ao_fat_attr[0])) + +static void +ao_fat_list_cmd(void) { uint16_t entry = 0; struct ao_fat_dirent dirent; + int i; while (ao_fat_readdir(&entry, &dirent)) { - printf ("%-8.8s.%-3.3s %02x %04x %d\n", - dirent.name, - dirent.name + 8, - dirent.attr, - dirent.cluster, - dirent.size); + for (i = 0; i < 8; i++) + putchar(dirent.name[i]); + putchar('.'); + for (; i < 11; i++) + putchar(dirent.name[i]); + for (i = 0; i < NUM_FAT_ATTR; i++) + putchar (dirent.attr & ao_fat_attr[i].bit ? ao_fat_attr[i].label : ' '); + printf (" @%08x %d\n", dirent.cluster, dirent.size); + } +} + +static uint8_t +ao_fat_parse_name(char name[11]) +{ + uint8_t c; + + name[0] = '\0'; + ao_cmd_white(); + c = 0; + while (ao_cmd_lex_c != '\n') { + if (ao_cmd_lex_c == '.') { + for (; c < 8; c++) + name[c] = ' '; + } else { + if (c < 11) + name[c++] = ao_cmd_lex_c; + } + ao_cmd_lex(); + } +} + +static void +ao_fat_show_cmd(void) +{ + char name[11]; + int8_t status; + int cnt, i; + char buf[64]; + + ao_fat_parse_name(name); + if (name[0] == '\0') { + ao_cmd_status = ao_cmd_syntax_error; + return; + } + + status = ao_fat_open(name, AO_FAT_OPEN_READ); + if (status) { + printf ("Open failed: %d\n", status); + return; + } + while ((cnt = ao_fat_read(buf, sizeof(buf))) > 0) { + for (i = 0; i < cnt; i++) + putchar(buf[i]); + } + ao_fat_close(); +} + +static void +ao_fat_putchar(char c) +{ +} + +static void +ao_fat_write_cmd(void) +{ + char name[11]; + int8_t status; + int cnt, i; + char buf[64]; + char c; + + ao_fat_parse_name(name); + if (name[0] == '\0') { + ao_cmd_status = ao_cmd_syntax_error; + return; + } + + status = ao_fat_creat(name); + if (status) { + printf ("Open failed: %d\n", status); + return; + } + flush(); + while ((c = getchar()) != 4) { + if (c == '\r') c = '\n'; + if (ao_echo()) { + if (c == '\n') putchar ('\r'); + putchar(c); flush(); + } + if (ao_fat_write(&c, 1) != 1) { + printf ("Write failure\n"); + break; + } } + ao_fat_close(); } static const struct ao_cmds ao_fat_cmds[] = { - { ao_fat_list, "F\0List FAT" }, + { ao_fat_mbr_cmd, "M\0Show FAT MBR and other info" }, + { ao_fat_list_cmd, "F\0List FAT directory" }, + { ao_fat_show_cmd, "S \0Show FAT file" }, + { ao_fat_write_cmd, "W \0Write FAT file (end with ^D)" }, { 0, NULL }, }; diff --git a/src/drivers/ao_fat.h b/src/drivers/ao_fat.h index e460c22a..40786990 100644 --- a/src/drivers/ao_fat.h +++ b/src/drivers/ao_fat.h @@ -35,6 +35,7 @@ ao_fat_init(void); #define AO_FAT_IS_FILE(attr) (((attr) & (AO_FAT_FILE_VOLUME_LABEL|AO_FAT_FILE_DIRECTORY)) == 0) #define AO_FAT_IS_DIR(attr) (((attr) & (AO_FAT_FILE_DIRECTORY|AO_FAT_FILE_VOLUME_LABEL)) == AO_FAT_FILE_DIRECTORY) +/* API error codes */ #define AO_FAT_SUCCESS 0 #define AO_FAT_EPERM 1 #define AO_FAT_ENOENT 2 @@ -48,6 +49,17 @@ ao_fat_init(void); #define AO_FAT_EFBIG 27 #define AO_FAT_ENOSPC 28 +/* ao_fat_setup return values */ +#define AO_FAT_FILESYSTEM_SUCCESS 0 +#define AO_FAT_FILESYSTEM_MBR_READ_FAILURE 1 +#define AO_FAT_FILESYSTEM_INVALID_MBR_SIGNATURE 2 +#define AO_FAT_FILESYSTEM_INVALID_PARTITION_TYPE 3 +#define AO_FAT_FILESYSTEM_ZERO_SIZED_PARTITION 4 + +#define AO_FAT_FILESYSTEM_BOOT_READ_FAILURE 5 +#define AO_FAT_FILESYSTEM_INVALID_BOOT_SIGNATURE 6 +#define AO_FAT_FILESYSTEM_INVALID_SECTOR_SIZE 7 + void ao_fat_sync(void); -- cgit v1.2.3 From 7afcec1a1dce140dfa569469df4ef42ed407a742 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 31 Mar 2013 12:23:31 -0700 Subject: altos: Add sdcard read/write tracing This just dumps info in trace mode about read and write commands Signed-off-by: Keith Packard --- src/drivers/ao_sdcard.c | 10 +++++++++- src/drivers/ao_sdcard.h | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_sdcard.c b/src/drivers/ao_sdcard.c index 4eef6625..952000a7 100644 --- a/src/drivers/ao_sdcard.c +++ b/src/drivers/ao_sdcard.c @@ -27,8 +27,12 @@ #define ao_sdcard_select() ao_gpio_set(AO_SDCARD_SPI_CS_PORT,AO_SDCARD_SPI_CS_PIN,AO_SDCARD_SPI_CS,0) #define ao_sdcard_deselect() ao_gpio_set(AO_SDCARD_SPI_CS_PORT,AO_SDCARD_SPI_CS_PIN,AO_SDCARD_SPI_CS,1) +/* Include SD card commands */ #define SDCARD_DEBUG 0 +/* Spew SD tracing */ +#define SDCARD_TRACE 0 + static uint8_t initialized; static uint8_t present; static uint8_t mutex; @@ -37,7 +41,7 @@ static enum ao_sdtype sdtype; #define ao_sdcard_lock() ao_mutex_get(&mutex) #define ao_sdcard_unlock() ao_mutex_put(&mutex) -#if 0 +#if SDCARD_TRACE #define DBG(...) printf(__VA_ARGS__) #else #define DBG(...) @@ -369,6 +373,7 @@ ao_sdcard_read_block(uint32_t block, uint8_t *data) ao_sdcard_unlock(); return 0; } + DBG("read block %d\n", block); if (sdtype != ao_sdtype_sd2block) block <<= 9; ao_sdcard_get(); @@ -390,6 +395,7 @@ bail: ao_sdcard_deselect(); ao_sdcard_put(); ao_sdcard_unlock(); + DBG("read %s\n", ret == SDCARD_STATUS_READY_STATE ? "success" : "failure"); return ret == SDCARD_STATUS_READY_STATE; } @@ -415,6 +421,7 @@ ao_sdcard_write_block(uint32_t block, uint8_t *data) ao_sdcard_unlock(); return 0; } + DBG("write block %d\n", block); if (sdtype != ao_sdtype_sd2block) block <<= 9; ao_sdcard_get(); @@ -455,6 +462,7 @@ bail: ao_sdcard_deselect(); ao_sdcard_put(); ao_sdcard_unlock(); + DBG("write %s\n", ret == SDCARD_STATUS_READY_STATE ? "success" : "failure"); return ret == SDCARD_STATUS_READY_STATE; } diff --git a/src/drivers/ao_sdcard.h b/src/drivers/ao_sdcard.h index 35e81ced..be0ff1f3 100644 --- a/src/drivers/ao_sdcard.h +++ b/src/drivers/ao_sdcard.h @@ -63,7 +63,7 @@ ao_sdcard_init(void); #define SDCARD_CMD_TIMEOUT 100 #define SDCARD_IDLE_WAIT 100 #define SDCARD_BLOCK_TIMEOUT 100 -#define SDCARD_IDLE_TIMEOUT 1000 +#define SDCARD_IDLE_TIMEOUT 10000 enum ao_sdtype { ao_sdtype_unknown, -- cgit v1.2.3 From 4f1f3e836393304434130d362771a39f6f8f859a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 24 Mar 2013 15:00:20 -0700 Subject: altos: Do not release interrupts from any pollchar function getchar relies on interrupts being blocked across the pollchar calls and into the sleep call or it may go to sleep with data pending. This prefixes all pollchar functions with _ to indicate that they are to be called with interrupts blocked and eliminates all interrupt manipulation calls from within the pollchar functions. Signed-off-by: Keith Packard --- src/avr/ao_serial_avr.c | 43 +++++++++++++++++----------------- src/avr/ao_usb_avr.c | 42 ++++++++++++++-------------------- src/cc1111/ao_serial.c | 8 +++---- src/cc1111/ao_usb.c | 14 +++++++----- src/core/ao.h | 2 +- src/core/ao_packet.h | 2 +- src/core/ao_serial.h | 8 +++---- src/core/ao_stdio.c | 31 +++++++++++++------------ src/drivers/ao_btm.c | 52 +++++++++++++++++++++++++++--------------- src/drivers/ao_packet.c | 6 ++--- src/drivers/ao_packet_master.c | 7 +++++- src/drivers/ao_packet_slave.c | 2 +- src/stm/ao_serial_stm.c | 45 +++++++++++++++++------------------- src/stm/ao_usb_stm.c | 23 ++++++++----------- 14 files changed, 144 insertions(+), 141 deletions(-) (limited to 'src') diff --git a/src/avr/ao_serial_avr.c b/src/avr/ao_serial_avr.c index dcee246c..e0f813d5 100644 --- a/src/avr/ao_serial_avr.c +++ b/src/avr/ao_serial_avr.c @@ -59,52 +59,51 @@ ISR(USART1_UDRE_vect) ao_wakeup(&ao_serial1_tx_fifo); } -char -ao_serial1_getchar(void) __critical -{ - char c; - cli(); - while (ao_fifo_empty(ao_serial1_rx_fifo)) - ao_sleep(&ao_serial1_rx_fifo); - ao_fifo_remove(ao_serial1_rx_fifo, c); - sei(); - return c; -} - #if USE_SERIAL_1_STDIN -char -ao_serial1_pollchar(void) __critical +int +_ao_serial1_pollchar(void) { char c; - cli(); if (ao_fifo_empty(ao_serial1_rx_fifo)) { sei(); return AO_READ_AGAIN; } ao_fifo_remove(ao_serial1_rx_fifo,c); - sei(); return c; } #endif +char +ao_serial1_getchar(void) __critical +{ + char c; + + ao_arch_block_interrupts(); + while (ao_fifo_empty(ao_serial1_rx_fifo)) + ao_sleep(&ao_serial1_rx_fifo); + ao_fifo_remove(ao_serial1_rx_fifo, c); + ao_arch_release_interrupts(); + return c; +} + void -ao_serial1_putchar(char c) __critical +ao_serial1_putchar(char c) { - cli(); + ao_arch_block_interrupts(); while (ao_fifo_full(ao_serial1_tx_fifo)) ao_sleep(&ao_serial1_tx_fifo); ao_fifo_insert(ao_serial1_tx_fifo, c); ao_serial_tx1_start(); - sei(); + ao_arch_release_interrupts(); } void ao_serial1_drain(void) __critical { - cli(); + ao_arch_block_interrupts(); while (!ao_fifo_empty(ao_serial1_tx_fifo)) ao_sleep(&ao_serial1_tx_fifo); - sei(); + ao_arch_release_interrupts(); } static const struct { @@ -155,7 +154,7 @@ ao_serial_init(void) (1 << RXCIE1) | /* Enable receive interrupts */ (1 << UDRIE1)); /* Enable transmit empty interrupts */ #if USE_SERIAL_1_STDIN - ao_add_stdio(ao_serial1_pollchar, + ao_add_stdio(_ao_serial1_pollchar, ao_serial1_putchar, NULL); #endif diff --git a/src/avr/ao_usb_avr.c b/src/avr/ao_usb_avr.c index 2ef546c9..bd75b17d 100644 --- a/src/avr/ao_usb_avr.c +++ b/src/avr/ao_usb_avr.c @@ -411,7 +411,7 @@ ao_usb_ep0(void) /* Wait for a free IN buffer */ static void -ao_usb_in_wait(void) +_ao_usb_in_wait(void) { for (;;) { /* Check if the current buffer is writable */ @@ -419,7 +419,6 @@ ao_usb_in_wait(void) if (UEINTX & (1 << RWAL)) break; - cli(); /* Wait for an IN buffer to be ready */ for (;;) { UENUM = AO_USB_IN_EP; @@ -430,24 +429,24 @@ ao_usb_in_wait(void) } /* Ack the interrupt */ UEINTX &= ~(1 << TXINI); - sei(); } } /* Queue the current IN buffer for transmission */ static void -ao_usb_in_send(void) +_ao_usb_in_send(void) { UENUM = AO_USB_IN_EP; UEINTX &= ~(1 << FIFOCON); } void -ao_usb_flush(void) __critical +ao_usb_flush(void) { if (!ao_usb_running) return; + ao_arch_block_interrupts(); /* Anytime we've sent a character since * the last time we flushed, we'll need * to send a packet -- the only other time @@ -457,18 +456,20 @@ ao_usb_flush(void) __critical */ if (!ao_usb_in_flushed) { ao_usb_in_flushed = 1; - ao_usb_in_wait(); - ao_usb_in_send(); + _ao_usb_in_wait(); + _ao_usb_in_send(); } + ao_arch_release_interrupts(); } void -ao_usb_putchar(char c) __critical __reentrant +ao_usb_putchar(char c) { if (!ao_usb_running) return; - ao_usb_in_wait(); + ao_arch_block_interrupts(); + _ao_usb_in_wait(); /* Queue a byte */ UENUM = AO_USB_IN_EP; @@ -476,11 +477,12 @@ ao_usb_putchar(char c) __critical __reentrant /* Send the packet when full */ if ((UEINTX & (1 << RWAL)) == 0) - ao_usb_in_send(); + _ao_usb_in_send(); ao_usb_in_flushed = 0; + ao_arch_release_interrupts(); } -static int +int _ao_usb_pollchar(void) { uint8_t c; @@ -517,25 +519,15 @@ _ao_usb_pollchar(void) return c; } -int -ao_usb_pollchar(void) -{ - int c; - cli(); - c = _ao_usb_pollchar(); - sei(); - return c; -} - char -ao_usb_getchar(void) __critical +ao_usb_getchar(void) { int c; - cli(); + ao_arch_block_interrupts(); while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN) ao_sleep(&ao_stdin_ready); - sei(); + ao_arch_release_interrupts(); return c; } @@ -668,5 +660,5 @@ ao_usb_init(void) #if USB_DEBUG ao_add_task(&ao_usb_echo_task, ao_usb_echo, "usb echo"); #endif - ao_add_stdio(ao_usb_pollchar, ao_usb_putchar, ao_usb_flush); + ao_add_stdio(_ao_usb_pollchar, ao_usb_putchar, ao_usb_flush); } diff --git a/src/cc1111/ao_serial.c b/src/cc1111/ao_serial.c index 8913a9b0..81727836 100644 --- a/src/cc1111/ao_serial.c +++ b/src/cc1111/ao_serial.c @@ -92,7 +92,7 @@ ao_serial0_getchar(void) __critical #if USE_SERIAL_0_STDIN int -ao_serial0_pollchar(void) __critical +_ao_serial0_pollchar(void) { uint8_t c; if (ao_fifo_empty(ao_serial0_rx_fifo)) @@ -180,7 +180,7 @@ ao_serial1_getchar(void) __critical #if USE_SERIAL_1_STDIN int -ao_serial1_pollchar(void) __critical +_ao_serial1_pollchar(void) { uint8_t c; if (ao_fifo_empty(ao_serial1_rx_fifo)) @@ -271,7 +271,7 @@ ao_serial_init(void) IEN0 |= IEN0_URX0IE; IEN2 |= IEN2_UTX0IE; #if USE_SERIAL_0_STDIN && !DELAY_SERIAL_0_STDIN - ao_add_stdio(ao_serial0_pollchar, + ao_add_stdio(_ao_serial0_pollchar, ao_serial0_putchar, NULL); #endif @@ -327,7 +327,7 @@ ao_serial_init(void) IEN2 |= IEN2_UTX1IE; #if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN - ao_add_stdio(ao_serial1_pollchar, + ao_add_stdio(_ao_serial1_pollchar, ao_serial1_putchar, NULL); #endif diff --git a/src/cc1111/ao_usb.c b/src/cc1111/ao_usb.c index f66e807c..8bd2efdf 100644 --- a/src/cc1111/ao_usb.c +++ b/src/cc1111/ao_usb.c @@ -383,18 +383,18 @@ ao_usb_putchar(char c) __critical __reentrant } int -ao_usb_pollchar(void) __critical +_ao_usb_pollchar(void) { uint8_t c; if (ao_usb_out_bytes == 0) { USBINDEX = AO_USB_OUT_EP; if ((USBCSOL & USBCSOL_OUTPKT_RDY) == 0) - return -1; + return AO_READ_AGAIN; ao_usb_out_bytes = (USBCNTH << 8) | USBCNTL; if (ao_usb_out_bytes == 0) { USBINDEX = AO_USB_OUT_EP; USBCSOL &= ~USBCSOL_OUTPKT_RDY; - return -1; + return AO_READ_AGAIN; } } --ao_usb_out_bytes; @@ -407,12 +407,14 @@ ao_usb_pollchar(void) __critical } char -ao_usb_getchar(void) __critical +ao_usb_getchar(void) { int c; - while ((c = ao_usb_pollchar()) == AO_READ_AGAIN) + ao_arch_block_interrupts(); + while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN) ao_sleep(&ao_stdin_ready); + ao_arch_release_interrupts(); return c; } @@ -459,5 +461,5 @@ ao_usb_init(void) ao_usb_enable(); ao_add_task(&ao_usb_task, ao_usb_ep0, "usb"); - ao_add_stdio(ao_usb_pollchar, ao_usb_putchar, ao_usb_flush); + ao_add_stdio(_ao_usb_pollchar, ao_usb_putchar, ao_usb_flush); } diff --git a/src/core/ao.h b/src/core/ao.h index e3161b4c..6c790f69 100644 --- a/src/core/ao.h +++ b/src/core/ao.h @@ -638,7 +638,7 @@ ao_monitor_init(void) __reentrant; #define AO_READ_AGAIN (-1) struct ao_stdio { - int (*pollchar)(void); + int (*_pollchar)(void); /* Called with interrupts blocked */ void (*putchar)(char c) __reentrant; void (*flush)(void); uint8_t echo; diff --git a/src/core/ao_packet.h b/src/core/ao_packet.h index 08b184d6..6d121bb9 100644 --- a/src/core/ao_packet.h +++ b/src/core/ao_packet.h @@ -63,7 +63,7 @@ void ao_packet_putchar(char c) __reentrant; int -ao_packet_pollchar(void); +_ao_packet_pollchar(void); #if PACKET_HAS_MASTER /* ao_packet_master.c */ diff --git a/src/core/ao_serial.h b/src/core/ao_serial.h index a799bf2c..baf213c0 100644 --- a/src/core/ao_serial.h +++ b/src/core/ao_serial.h @@ -32,7 +32,7 @@ char ao_serial0_getchar(void); int -ao_serial0_pollchar(void); +_ao_serial0_pollchar(void); void ao_serial0_putchar(char c); @@ -52,7 +52,7 @@ char ao_serial1_getchar(void); int -ao_serial1_pollchar(void); +_ao_serial1_pollchar(void); void ao_serial1_putchar(char c); @@ -72,7 +72,7 @@ char ao_serial2_getchar(void); int -ao_serial2_pollchar(void); +_ao_serial2_pollchar(void); void ao_serial2_putchar(char c); @@ -92,7 +92,7 @@ char ao_serial3_getchar(void); int -ao_serial3_pollchar(void); +_ao_serial3_pollchar(void); void ao_serial3_putchar(char c); diff --git a/src/core/ao_stdio.c b/src/core/ao_stdio.c index 1748dfe8..977d74b1 100644 --- a/src/core/ao_stdio.c +++ b/src/core/ao_stdio.c @@ -99,20 +99,21 @@ char getchar(void) __reentrant { int c; - ao_arch_critical( - int8_t stdio = ao_cur_stdio; + int8_t stdio; - for (;;) { - c = ao_stdios[stdio].pollchar(); - if (c != AO_READ_AGAIN) - break; - if (++stdio == ao_num_stdios) - stdio = 0; - if (stdio == ao_cur_stdio) - ao_sleep(&ao_stdin_ready); - } - ao_cur_stdio = stdio; - ); + ao_arch_block_interrupts(); + stdio = ao_cur_stdio; + for (;;) { + c = ao_stdios[stdio]._pollchar(); + if (c != AO_READ_AGAIN) + break; + if (++stdio == ao_num_stdios) + stdio = 0; + if (stdio == ao_cur_stdio) + ao_sleep(&ao_stdin_ready); + } + ao_cur_stdio = stdio; + ao_arch_release_interrupts(); return c; } @@ -123,13 +124,13 @@ ao_echo(void) } int8_t -ao_add_stdio(int (*pollchar)(void), +ao_add_stdio(int (*_pollchar)(void), void (*putchar)(char), void (*flush)(void)) __reentrant { if (ao_num_stdios == AO_NUM_STDIOS) ao_panic(AO_PANIC_STDIO); - ao_stdios[ao_num_stdios].pollchar = pollchar; + ao_stdios[ao_num_stdios]._pollchar = _pollchar; ao_stdios[ao_num_stdios].putchar = putchar; ao_stdios[ao_num_stdios].flush = flush; ao_stdios[ao_num_stdios].echo = 1; diff --git a/src/drivers/ao_btm.c b/src/drivers/ao_btm.c index c862200a..de1f31a3 100644 --- a/src/drivers/ao_btm.c +++ b/src/drivers/ao_btm.c @@ -19,9 +19,10 @@ #ifndef ao_serial_btm_getchar #define ao_serial_btm_putchar ao_serial1_putchar -#define ao_serial_btm_pollchar ao_serial1_pollchar +#define _ao_serial_btm_pollchar _ao_serial1_pollchar #define ao_serial_btm_set_speed ao_serial1_set_speed #define ao_serial_btm_drain ao_serial1_drain +#define ao_serial_btm_rx_fifo ao_serial1_rx_fifo #endif int8_t ao_btm_stdio; @@ -111,6 +112,30 @@ __code struct ao_cmds ao_btm_cmds[] = { #define AO_BTM_MAX_REPLY 16 __xdata char ao_btm_reply[AO_BTM_MAX_REPLY]; +/* + * Read one bluetooth character. + * Returns AO_READ_AGAIN if no character arrives within 10ms + */ + +static int +ao_btm_getchar(void) +{ + int c; + + ao_arch_block_interrupts(); + while ((c = _ao_serial_btm_pollchar()) == AO_READ_AGAIN) { + ao_alarm(AO_MS_TO_TICKS(10)); + c = ao_sleep(&ao_serial_btm_rx_fifo); + ao_clear_alarm(); + if (c) { + c = AO_READ_AGAIN; + break; + } + } + ao_arch_release_interrupts(); + return c; +} + /* * Read a line of data from the serial port, truncating * it after a few characters. @@ -122,24 +147,13 @@ ao_btm_get_line(void) uint8_t ao_btm_reply_len = 0; int c; - for (;;) { - - while ((c = ao_serial_btm_pollchar()) != AO_READ_AGAIN) { - ao_btm_log_in_char(c); - if (ao_btm_reply_len < sizeof (ao_btm_reply)) - ao_btm_reply[ao_btm_reply_len++] = c; - if (c == '\r' || c == '\n') - goto done; - } - for (c = 0; c < 10; c++) { - ao_delay(AO_MS_TO_TICKS(10)); - if (!ao_fifo_empty(ao_serial1_rx_fifo)) - break; - } - if (c == 10) - goto done; + while ((c = ao_btm_getchar()) != AO_READ_AGAIN) { + ao_btm_log_in_char(c); + if (ao_btm_reply_len < sizeof (ao_btm_reply)) + ao_btm_reply[ao_btm_reply_len++] = c; + if (c == '\r' || c == '\n') + break; } -done: for (c = ao_btm_reply_len; c < sizeof (ao_btm_reply);) ao_btm_reply[c++] = '\0'; return ao_btm_reply_len; @@ -279,7 +293,7 @@ ao_btm(void) /* Turn off status reporting */ ao_btm_cmd("ATQ1\r"); - ao_btm_stdio = ao_add_stdio(ao_serial_btm_pollchar, + ao_btm_stdio = ao_add_stdio(_ao_serial_btm_pollchar, ao_serial_btm_putchar, NULL); ao_btm_echo(0); diff --git a/src/drivers/ao_packet.c b/src/drivers/ao_packet.c index 91319923..5a507478 100644 --- a/src/drivers/ao_packet.c +++ b/src/drivers/ao_packet.c @@ -169,12 +169,10 @@ ao_packet_putchar(char c) __reentrant tx_data[ao_packet_tx_used++] = c; } +/* May be called with interrupts blocked */ int -ao_packet_pollchar(void) +_ao_packet_pollchar(void) { - /* No need to block interrupts, all variables here - * are only manipulated in task context - */ if (!ao_packet_enable) return AO_READ_AGAIN; diff --git a/src/drivers/ao_packet_master.c b/src/drivers/ao_packet_master.c index 023c788b..4c0dc573 100644 --- a/src/drivers/ao_packet_master.c +++ b/src/drivers/ao_packet_master.c @@ -21,7 +21,12 @@ static char ao_packet_getchar(void) { int c; - while ((c = ao_packet_pollchar()) == AO_READ_AGAIN) { + + /* No need to block interrupts in this function as + * all packet variables are only modified from task + * context, not an interrupt handler + */ + while ((c = _ao_packet_pollchar()) == AO_READ_AGAIN) { if (!ao_packet_enable) break; if (ao_packet_master_sleeping) diff --git a/src/drivers/ao_packet_slave.c b/src/drivers/ao_packet_slave.c index e45775cb..e75df0d6 100644 --- a/src/drivers/ao_packet_slave.c +++ b/src/drivers/ao_packet_slave.c @@ -59,7 +59,7 @@ ao_packet_slave_stop(void) void ao_packet_slave_init(uint8_t enable) { - ao_add_stdio(ao_packet_pollchar, + ao_add_stdio(_ao_packet_pollchar, ao_packet_putchar, NULL); if (enable) diff --git a/src/stm/ao_serial_stm.c b/src/stm/ao_serial_stm.c index ce33f97e..2133c584 100644 --- a/src/stm/ao_serial_stm.c +++ b/src/stm/ao_serial_stm.c @@ -59,24 +59,11 @@ ao_usart_isr(struct ao_stm_usart *usart, int stdin) } } -char -ao_usart_getchar(struct ao_stm_usart *usart) -{ - char c; - ao_arch_block_interrupts(); - while (ao_fifo_empty(usart->rx_fifo)) - ao_sleep(&usart->rx_fifo); - ao_fifo_remove(usart->rx_fifo, c); - ao_arch_release_interrupts(); - return c; -} - int -ao_usart_pollchar(struct ao_stm_usart *usart) +_ao_usart_pollchar(struct ao_stm_usart *usart) { int c; - ao_arch_block_interrupts(); if (ao_fifo_empty(usart->rx_fifo)) c = AO_READ_AGAIN; else { @@ -84,10 +71,20 @@ ao_usart_pollchar(struct ao_stm_usart *usart) ao_fifo_remove(usart->rx_fifo,u); c = u; } - ao_arch_release_interrupts(); return c; } +char +ao_usart_getchar(struct ao_stm_usart *usart) +{ + int c; + ao_arch_block_interrupts(); + while ((c = _ao_usart_pollchar(usart)) == AO_READ_AGAIN) + ao_sleep(&usart->rx_fifo); + ao_arch_release_interrupts(); + return (char) c; +} + void ao_usart_putchar(struct ao_stm_usart *usart, char c) { @@ -201,9 +198,9 @@ ao_serial1_putchar(char c) } int -ao_serial1_pollchar(void) +_ao_serial1_pollchar(void) { - return ao_usart_pollchar(&ao_stm_usart1); + return _ao_usart_pollchar(&ao_stm_usart1); } void @@ -232,9 +229,9 @@ ao_serial2_putchar(char c) } int -ao_serial2_pollchar(void) +_ao_serial2_pollchar(void) { - return ao_usart_pollchar(&ao_stm_usart2); + return _ao_usart_pollchar(&ao_stm_usart2); } void @@ -263,9 +260,9 @@ ao_serial3_putchar(char c) } int -ao_serial3_pollchar(void) +_ao_serial3_pollchar(void) { - return ao_usart_pollchar(&ao_stm_usart3); + return _ao_usart_pollchar(&ao_stm_usart3); } void @@ -309,7 +306,7 @@ ao_serial_init(void) stm_nvic_set_enable(STM_ISR_USART1_POS); stm_nvic_set_priority(STM_ISR_USART1_POS, 4); #if USE_SERIAL_1_STDIN - ao_add_stdio(ao_serial1_pollchar, + ao_add_stdio(_ao_serial1_pollchar, ao_serial1_putchar, NULL); #endif @@ -346,7 +343,7 @@ ao_serial_init(void) stm_nvic_set_enable(STM_ISR_USART2_POS); stm_nvic_set_priority(STM_ISR_USART2_POS, 4); #if USE_SERIAL_2_STDIN - ao_add_stdio(ao_serial2_pollchar, + ao_add_stdio(_ao_serial2_pollchar, ao_serial2_putchar, NULL); #endif @@ -390,7 +387,7 @@ ao_serial_init(void) stm_nvic_set_enable(STM_ISR_USART3_POS); stm_nvic_set_priority(STM_ISR_USART3_POS, 4); #if USE_SERIAL_3_STDIN - ao_add_stdio(ao_serial3_pollchar, + ao_add_stdio(_ao_serial3_pollchar, ao_serial3_putchar, NULL); #endif diff --git a/src/stm/ao_usb_stm.c b/src/stm/ao_usb_stm.c index 9379e5cd..dfa58c42 100644 --- a/src/stm/ao_usb_stm.c +++ b/src/stm/ao_usb_stm.c @@ -229,10 +229,9 @@ ao_usb_set_stat_tx(int ep, uint32_t stat_tx) } static void -ao_usb_set_stat_rx(int ep, uint32_t stat_rx) { +_ao_usb_set_stat_rx(int ep, uint32_t stat_rx) { uint32_t epr_write, epr_old; - ao_arch_block_interrupts(); epr_write = epr_old = stm_usb.epr[ep]; epr_write &= STM_USB_EPR_PRESERVE_MASK; epr_write |= STM_USB_EPR_INVARIANT; @@ -240,6 +239,12 @@ ao_usb_set_stat_rx(int ep, uint32_t stat_rx) { STM_USB_EPR_STAT_RX_MASK << STM_USB_EPR_STAT_RX, stat_rx << STM_USB_EPR_STAT_RX); stm_usb.epr[ep] = epr_write; +} + +static void +ao_usb_set_stat_rx(int ep, uint32_t stat_rx) { + ao_arch_block_interrupts(); + _ao_usb_set_stat_rx(ep, stat_rx); ao_arch_release_interrupts(); } @@ -870,10 +875,10 @@ _ao_usb_out_recv(void) ao_usb_rx_pos = 0; /* ACK the packet */ - ao_usb_set_stat_rx(AO_USB_OUT_EPR, STM_USB_EPR_STAT_RX_VALID); + _ao_usb_set_stat_rx(AO_USB_OUT_EPR, STM_USB_EPR_STAT_RX_VALID); } -static int +int _ao_usb_pollchar(void) { uint8_t c; @@ -896,16 +901,6 @@ _ao_usb_pollchar(void) return c; } -int -ao_usb_pollchar(void) -{ - int c; - ao_arch_block_interrupts(); - c = _ao_usb_pollchar(); - ao_arch_release_interrupts(); - return c; -} - char ao_usb_getchar(void) { -- cgit v1.2.3 From de199601a177fc2d45ad9bd7357111111844d40a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 24 Mar 2013 15:03:59 -0700 Subject: altos/stm: Add debugging mechanism to STM USB driver This adds a pile of debugging hooks to the USB driver to try and isolate various lockup-related issues. It's all disabled by default, of course. Signed-off-by: Keith Packard --- src/stm/ao_usb_stm.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 101 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/stm/ao_usb_stm.c b/src/stm/ao_usb_stm.c index dfa58c42..44f49dfa 100644 --- a/src/stm/ao_usb_stm.c +++ b/src/stm/ao_usb_stm.c @@ -200,6 +200,29 @@ ao_usb_set_address(uint8_t address) (1 << STM_USB_EPR_EP_KIND) | \ (STM_USB_EPR_EA_MASK << STM_USB_EPR_EA)) +#define TX_DBG 0 +#define RX_DBG 0 + +#if TX_DBG +#define _tx_dbg0(msg) _dbg(__LINE__,msg,0) +#define _tx_dbg1(msg,value) _dbg(__LINE__,msg,value) +#else +#define _tx_dbg0(msg) +#define _tx_dbg1(msg,value) +#endif + +#if RX_DBG +#define _rx_dbg0(msg) _dbg(__LINE__,msg,0) +#define _rx_dbg1(msg,value) _dbg(__LINE__,msg,value) +#else +#define _rx_dbg0(msg) +#define _rx_dbg1(msg,value) +#endif + +#if TX_DBG || RX_DBG +static void _dbg(int line, char *msg, uint32_t value); +#endif + /* * Set the state of the specified endpoint register to a new * value. This is tricky because the bits toggle where the new @@ -211,6 +234,7 @@ _ao_usb_set_stat_tx(int ep, uint32_t stat_tx) { uint32_t epr_write, epr_old; + _tx_dbg1("set_stat_tx top", stat_tx); epr_old = epr_write = stm_usb.epr[ep]; epr_write &= STM_USB_EPR_PRESERVE_MASK; epr_write |= STM_USB_EPR_INVARIANT; @@ -218,6 +242,7 @@ _ao_usb_set_stat_tx(int ep, uint32_t stat_tx) STM_USB_EPR_STAT_TX_MASK << STM_USB_EPR_STAT_TX, stat_tx << STM_USB_EPR_STAT_TX); stm_usb.epr[ep] = epr_write; + _tx_dbg1("set_stat_tx bottom", epr_write); } static void @@ -338,7 +363,7 @@ ao_usb_set_configuration(void) STM_USB_EPR_EP_TYPE_INTERRUPT, STM_USB_EPR_STAT_RX_DISABLED, STM_USB_EPR_STAT_TX_NAK); - + /* Set up the OUT end point */ ao_usb_bdt[AO_USB_OUT_EPR].single.addr_rx = ao_usb_sram_addr; ao_usb_bdt[AO_USB_OUT_EPR].single.count_rx = ((1 << STM_USB_BDT_COUNT_RX_BL_SIZE) | @@ -351,7 +376,7 @@ ao_usb_set_configuration(void) STM_USB_EPR_EP_TYPE_BULK, STM_USB_EPR_STAT_RX_VALID, STM_USB_EPR_STAT_TX_DISABLED); - + /* Set up the IN end point */ ao_usb_bdt[AO_USB_IN_EPR].single.addr_tx = ao_usb_sram_addr; ao_usb_bdt[AO_USB_IN_EPR].single.count_tx = 0; @@ -409,12 +434,16 @@ stm_usb_lp_isr(void) case AO_USB_OUT_EPR: ++out_count; if (ao_usb_epr_ctr_rx(epr)) { + _rx_dbg1("RX ISR", epr); ao_usb_out_avail = 1; + _rx_dbg0("out avail set"); ao_wakeup(&ao_stdin_ready); + _rx_dbg0("stdin awoken"); } break; case AO_USB_IN_EPR: ++in_count; + _tx_dbg1("TX ISR", epr); if (ao_usb_epr_ctr_tx(epr)) { ao_usb_in_pending = 0; ao_wakeup(&ao_usb_in_pending); @@ -758,7 +787,7 @@ ao_usb_ep0(void) ao_sleep(&ao_usb_ep0_receive); ao_usb_ep0_receive = 0; ); - + if (receive & AO_USB_EP0_GOT_RESET) { debug ("\treset\n"); ao_usb_set_ep0(); @@ -796,6 +825,7 @@ ao_usb_ep0(void) static void ao_usb_in_send(void) { + _tx_dbg0("in_send start"); debug ("send %d\n", ao_usb_tx_count); ao_usb_in_pending = 1; ao_usb_write(ao_usb_tx_buffer, ao_usb_in_tx_buffer, 0, ao_usb_tx_count); @@ -813,9 +843,11 @@ _ao_usb_in_wait(void) if (ao_usb_tx_count < AO_USB_IN_SIZE) break; + _tx_dbg0("in_wait top"); /* Wait for an IN buffer to be ready */ while (ao_usb_in_pending) ao_sleep(&ao_usb_in_pending); + _tx_dbg0("in_wait bottom"); } } @@ -856,18 +888,23 @@ ao_usb_putchar(char c) ao_usb_tx_buffer[ao_usb_tx_count++] = (uint8_t) c; /* Send the packet when full */ - if (ao_usb_tx_count == AO_USB_IN_SIZE) - ao_usb_in_send(); + if (ao_usb_tx_count == AO_USB_IN_SIZE) { + _tx_dbg0("putchar full"); + _ao_usb_in_send(); + _tx_dbg0("putchar flushed"); + } ao_arch_release_interrupts(); } static void _ao_usb_out_recv(void) { + _rx_dbg0("out_recv top"); ao_usb_out_avail = 0; ao_usb_rx_count = ao_usb_bdt[AO_USB_OUT_EPR].single.count_rx & STM_USB_BDT_COUNT_RX_COUNT_RX_MASK; + _rx_dbg1("out_recv count", ao_usb_rx_count); debug ("recv %d\n", ao_usb_rx_count); debug_data("Fill OUT len %d:", ao_usb_rx_count); ao_usb_read(ao_usb_rx_buffer, ao_usb_out_rx_buffer, 0, ao_usb_rx_count); @@ -890,9 +927,12 @@ _ao_usb_pollchar(void) if (ao_usb_rx_pos != ao_usb_rx_count) break; + _rx_dbg0("poll check"); /* Check to see if a packet has arrived */ - if (!ao_usb_out_avail) + if (!ao_usb_out_avail) { + _rx_dbg0("poll none"); return AO_READ_AGAIN; + } _ao_usb_out_recv(); } @@ -966,7 +1006,7 @@ ao_usb_enable(void) /* Clear any spurious interrupts */ stm_usb.istr = 0; - + debug ("ao_usb_enable\n"); /* Enable interrupts */ @@ -1036,6 +1076,59 @@ ao_usb_init(void) ao_cmd_register(&ao_usb_cmds[0]); #endif #if !USB_ECHO - ao_add_stdio(ao_usb_pollchar, ao_usb_putchar, ao_usb_flush); + ao_add_stdio(_ao_usb_pollchar, ao_usb_putchar, ao_usb_flush); +#endif +} + +#if TX_DBG || RX_DBG + +struct ao_usb_dbg { + int line; + char *msg; + uint32_t value; + uint32_t primask; +#if TX_DBG + uint16_t in_count; + uint32_t in_epr; + uint32_t in_pending; + uint32_t tx_count; + uint32_t in_flushed; +#endif +#if RX_DBG + uint8_t rx_count; + uint8_t rx_pos; + uint8_t out_avail; + uint32_t out_epr; +#endif +}; + +#define NUM_USB_DBG 128 + +static struct ao_usb_dbg dbg[128]; +static int dbg_i; + +static void _dbg(int line, char *msg, uint32_t value) +{ + uint32_t primask; + dbg[dbg_i].line = line; + dbg[dbg_i].msg = msg; + dbg[dbg_i].value = value; + asm("mrs %0,primask" : "=&r" (primask)); + dbg[dbg_i].primask = primask; +#if TX_DBG + dbg[dbg_i].in_count = in_count; + dbg[dbg_i].in_epr = stm_usb.epr[AO_USB_IN_EPR]; + dbg[dbg_i].in_pending = ao_usb_in_pending; + dbg[dbg_i].tx_count = ao_usb_tx_count; + dbg[dbg_i].in_flushed = ao_usb_in_flushed; +#endif +#if RX_DBG + dbg[dbg_i].rx_count = ao_usb_rx_count; + dbg[dbg_i].rx_pos = ao_usb_rx_pos; + dbg[dbg_i].out_avail = ao_usb_out_avail; + dbg[dbg_i].out_epr = stm_usb.epr[AO_USB_OUT_EPR]; #endif + if (++dbg_i == NUM_USB_DBG) + dbg_i = 0; } +#endif -- cgit v1.2.3 From 8b2f211758dfa97230a730b8c4b31e0e711c19c9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 24 Mar 2013 15:04:57 -0700 Subject: altos/stm: Always check for idle IN buffer before sending Unlike the AVR and CC1111 USB drivers, the STM usb driver queues IN bytes in a local buffer instead of in the driver; this means that the driver is queuing bytes while the previous IN packet is queued for the host, which allows for overlapping execution. It also means that when the local buffer is full, we must check to see if the host has picked up the previous IN packet before trying to queue another IN packet for transmission. This is done by always waiting for the IN buffer to be ready before sending data. Signed-off-by: Keith Packard --- src/stm/ao_usb_stm.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/stm/ao_usb_stm.c b/src/stm/ao_usb_stm.c index 44f49dfa..e29abc87 100644 --- a/src/stm/ao_usb_stm.c +++ b/src/stm/ao_usb_stm.c @@ -823,15 +823,20 @@ ao_usb_ep0(void) /* Queue the current IN buffer for transmission */ static void -ao_usb_in_send(void) +_ao_usb_in_send(void) { _tx_dbg0("in_send start"); debug ("send %d\n", ao_usb_tx_count); + while (ao_usb_in_pending) + ao_sleep(&ao_usb_in_pending); ao_usb_in_pending = 1; + if (ao_usb_tx_count != AO_USB_IN_SIZE) + ao_usb_in_flushed = 1; ao_usb_write(ao_usb_tx_buffer, ao_usb_in_tx_buffer, 0, ao_usb_tx_count); ao_usb_bdt[AO_USB_IN_EPR].single.count_tx = ao_usb_tx_count; - ao_usb_set_stat_tx(AO_USB_IN_EPR, STM_USB_EPR_STAT_TX_VALID); ao_usb_tx_count = 0; + _ao_usb_set_stat_tx(AO_USB_IN_EPR, STM_USB_EPR_STAT_TX_VALID); + _tx_dbg0("in_send end"); } /* Wait for a free IN buffer. Interrupts are blocked */ @@ -865,12 +870,10 @@ ao_usb_flush(void) * want to send an empty packet */ ao_arch_block_interrupts(); - if (!ao_usb_in_flushed) { - ao_usb_in_flushed = 1; - /* Wait for an IN buffer to be ready */ - while (ao_usb_in_pending) - ao_sleep(&ao_usb_in_pending); - ao_usb_in_send(); + while (!ao_usb_in_flushed) { + _tx_dbg0("flush top"); + _ao_usb_in_send(); + _tx_dbg0("flush end"); } ao_arch_release_interrupts(); } -- cgit v1.2.3 From a70139c9a8a177df8f20f525703b13c0aec0fbc7 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 31 Mar 2013 12:29:37 -0700 Subject: altos: Don't add fat commands when building ao_fat_test Signed-off-by: Keith Packard --- src/drivers/ao_fat.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_fat.c b/src/drivers/ao_fat.c index ea8cdf96..bb0aa7a2 100644 --- a/src/drivers/ao_fat.c +++ b/src/drivers/ao_fat.c @@ -23,7 +23,9 @@ #include "ao_bufio.h" /* Include FAT commands */ +#ifndef AO_FAT_TEST #define FAT_COMMANDS 1 +#endif /* Spew FAT tracing */ #define FAT_TRACE 0 @@ -573,7 +575,6 @@ static uint32_t ao_file_offset; static uint32_t ao_file_cluster_offset; static cluster_t ao_file_cluster; static uint8_t ao_file_opened; -static uint8_t ao_filesystem_available; static uint8_t ao_filesystem_setup; static uint8_t ao_filesystem_status; @@ -1019,7 +1020,6 @@ int ao_fat_write(void *src, int len) { uint8_t *src_b = src; - uint32_t sector; uint16_t this_time; uint16_t offset; uint8_t *buf; @@ -1164,6 +1164,8 @@ ao_fat_readdir(uint16_t *entry, struct ao_fat_dirent *dirent) } } +#if FAT_COMMANDS + static const char *filesystem_errors[] = { [AO_FAT_FILESYSTEM_SUCCESS] = "FAT file system operating normally", [AO_FAT_FILESYSTEM_MBR_READ_FAILURE] = "MBR media read error", @@ -1331,6 +1333,8 @@ static const struct ao_cmds ao_fat_cmds[] = { { 0, NULL }, }; +#endif + void ao_fat_init(void) { -- cgit v1.2.3 From 144b44e13ce3361ff59cbb555e84d542455a4e17 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 31 Mar 2013 12:39:32 -0700 Subject: altos: Unmount file system after each testing pass in ao_fat_test Otherwise, we use stale data and 'bad things' happen. Signed-off-by: Keith Packard --- src/drivers/ao_fat.c | 6 ++++++ src/drivers/ao_fat.h | 3 +++ src/test/ao_fat_test.c | 10 ++++++---- 3 files changed, 15 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_fat.c b/src/drivers/ao_fat.c index bb0aa7a2..9cd3d34b 100644 --- a/src/drivers/ao_fat.c +++ b/src/drivers/ao_fat.c @@ -608,6 +608,12 @@ ao_fat_setup(void) return ao_filesystem_status; } +void +ao_fat_unmount(void) +{ + ao_filesystem_setup = 0; +} + /* * Basic file operations */ diff --git a/src/drivers/ao_fat.h b/src/drivers/ao_fat.h index 40786990..36aec7df 100644 --- a/src/drivers/ao_fat.h +++ b/src/drivers/ao_fat.h @@ -63,6 +63,9 @@ ao_fat_init(void); void ao_fat_sync(void); +void +ao_fat_unmount(void); + int8_t ao_fat_full(void); diff --git a/src/test/ao_fat_test.c b/src/test/ao_fat_test.c index 48d5d8a4..eb55d9c8 100644 --- a/src/test/ao_fat_test.c +++ b/src/test/ao_fat_test.c @@ -226,14 +226,15 @@ fatal(char *msg, ...) void check_fat(void) { - int e; - int f; + cluster_t e; + int f; for (e = 0; e < number_cluster; e++) { cluster_t v = ao_fat_entry_raw_read(e, 0); for (f = 1; f < number_fat; f++) { - if (ao_fat_entry_raw_read(e, f) != v) - fatal ("fats differ at %d\n", e); + cluster_t o = ao_fat_entry_raw_read(e, f); + if (o != v) + fatal ("fats differ at %08x (0 %08x %d %08x)\n", e, v, f, o); } } } @@ -490,6 +491,7 @@ main(int argc, char **argv) #else long_test_fs(); #endif + ao_fat_unmount(); } return 0; -- cgit v1.2.3 From d813566cdc4d43a43ed988dde4a3ceeccf24efe6 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 31 Mar 2013 12:46:41 -0700 Subject: altos: Fix command-line FAT filename parsing Pad extension with spaces Signed-off-by: Keith Packard --- src/drivers/ao_fat.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/drivers/ao_fat.c b/src/drivers/ao_fat.c index 9cd3d34b..3e9c00b5 100644 --- a/src/drivers/ao_fat.c +++ b/src/drivers/ao_fat.c @@ -1263,6 +1263,8 @@ ao_fat_parse_name(char name[11]) } ao_cmd_lex(); } + while (c < 11) + name[c++] = ' '; } static void -- cgit v1.2.3 From 182ceaac7d91dc6e9ebac6455d5de0c10687796b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 31 Mar 2013 13:55:16 -0700 Subject: altos: Increase SD card timeout at startup time Sometimes the SD card takes 'a while' to go into idle mode at first power up. Just hang around waiting for a long time. Signed-off-by: Keith Packard --- src/drivers/ao_sdcard.h | 4 ++-- src/telegps-v0.1/Makefile | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_sdcard.h b/src/drivers/ao_sdcard.h index be0ff1f3..512439b4 100644 --- a/src/drivers/ao_sdcard.h +++ b/src/drivers/ao_sdcard.h @@ -61,9 +61,9 @@ ao_sdcard_init(void); #define SDCARD_DATA_RES_ACCEPTED 0x05 #define SDCARD_CMD_TIMEOUT 100 -#define SDCARD_IDLE_WAIT 100 +#define SDCARD_IDLE_WAIT 1000 #define SDCARD_BLOCK_TIMEOUT 100 -#define SDCARD_IDLE_TIMEOUT 10000 +#define SDCARD_IDLE_TIMEOUT 1000 enum ao_sdtype { ao_sdtype_unknown, diff --git a/src/telegps-v0.1/Makefile b/src/telegps-v0.1/Makefile index 8e610db7..4458724d 100644 --- a/src/telegps-v0.1/Makefile +++ b/src/telegps-v0.1/Makefile @@ -16,8 +16,12 @@ INC = \ ao_cc115l.h \ ao_fec.h \ stm32l.h \ + ao_sdcard.h \ + ao_bufio.h \ + ao_fat.h \ Makefile + #PROFILE=ao_profile.c #PROFILE_DEF=-DAO_PROFILE=1 -- cgit v1.2.3 From 659a6915f5ba5129096e55ccc04c975d216546ae Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 31 Mar 2013 16:10:33 -0700 Subject: altos: Make ao_fat_readdir return real error values instead of 1/0 This way, we can distinguish between 'something bad happened' and 'you're at the end of the directory'. Signed-off-by: Keith Packard --- src/drivers/ao_fat.c | 11 +++++++---- src/drivers/ao_fat.h | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_fat.c b/src/drivers/ao_fat.c index 3e9c00b5..ddf560cc 100644 --- a/src/drivers/ao_fat.c +++ b/src/drivers/ao_fat.c @@ -1153,17 +1153,17 @@ ao_fat_readdir(uint16_t *entry, struct ao_fat_dirent *dirent) for (;;) { dent = ao_fat_root_get(*entry); if (!dent) - return 0; + return -AO_FAT_EDIREOF; if (dent[0] == AO_FAT_DENT_END) { ao_fat_root_put(dent, *entry, 0); - return 0; + return -AO_FAT_EDIREOF; } if (dent[0] != AO_FAT_DENT_EMPTY && (dent[0xb] & 0xf) != 0xf) { ao_fat_dirent_init(dent, *entry, dirent); ao_fat_root_put(dent, *entry, 0); (*entry)++; - return 1; + return AO_FAT_SUCCESS; } ao_fat_root_put(dent, *entry, 0); (*entry)++; @@ -1232,8 +1232,9 @@ ao_fat_list_cmd(void) uint16_t entry = 0; struct ao_fat_dirent dirent; int i; + int8_t status; - while (ao_fat_readdir(&entry, &dirent)) { + while ((status = ao_fat_readdir(&entry, &dirent)) == AO_FAT_SUCCESS) { for (i = 0; i < 8; i++) putchar(dirent.name[i]); putchar('.'); @@ -1243,6 +1244,8 @@ ao_fat_list_cmd(void) putchar (dirent.attr & ao_fat_attr[i].bit ? ao_fat_attr[i].label : ' '); printf (" @%08x %d\n", dirent.cluster, dirent.size); } + if (status != -AO_FAT_EDIREOF) + printf ("readdir failed: %d\n", status); } static uint8_t diff --git a/src/drivers/ao_fat.h b/src/drivers/ao_fat.h index 36aec7df..fe154cdf 100644 --- a/src/drivers/ao_fat.h +++ b/src/drivers/ao_fat.h @@ -48,6 +48,7 @@ ao_fat_init(void); #define AO_FAT_EMFILE 24 #define AO_FAT_EFBIG 27 #define AO_FAT_ENOSPC 28 +#define AO_FAT_EDIREOF 29 /* ao_fat_setup return values */ #define AO_FAT_FILESYSTEM_SUCCESS 0 -- cgit v1.2.3 From c2de64b10894b366398a8b37ebd2305d9be46d46 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 31 Mar 2013 16:11:27 -0700 Subject: altos: Create the log file if it doesn't already exist open will return failure unless the file already exists. Signed-off-by: Keith Packard --- src/drivers/ao_log_fat.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_log_fat.c b/src/drivers/ao_log_fat.c index 684148b7..2741555f 100644 --- a/src/drivers/ao_log_fat.c +++ b/src/drivers/ao_log_fat.c @@ -20,23 +20,34 @@ #include "ao_fat.h" static uint8_t log_year, log_month, log_day; -static uint8_t log_running; +static uint8_t log_open; static uint8_t log_mutex; static void ao_log_open(void) { char name[12]; + int8_t status; sprintf(name,"%04d%02d%02dLOG", 2000 + log_year, log_month, log_day); - if (ao_fat_open(name, AO_FAT_OPEN_WRITE) == AO_FAT_SUCCESS) - log_running = 1; + status = ao_fat_open(name, AO_FAT_OPEN_WRITE); + switch (status) { + case AO_FAT_SUCCESS: + ao_fat_seek(0, AO_FAT_SEEK_END); + log_open = 1; + break; + case -AO_FAT_ENOENT: + status = ao_fat_creat(name); + if (status == AO_FAT_SUCCESS) + log_open = 1; + break; + } } static void ao_log_close(void) { - log_running = 0; + log_open = 0; ao_fat_close(); } @@ -52,20 +63,20 @@ ao_log_mega(struct ao_log_mega *log) uint8_t wrote = 0; ao_mutex_get(&log_mutex); if (log->type == AO_LOG_GPS_TIME) { - if (log_running && + if (log_open && (log_year != log->u.gps.year || log_month != log->u.gps.month || log_day != log->u.gps.day)) { ao_log_close(); } - if (!log_running) { + if (!log_open) { log_year = log->u.gps.year; log_month = log->u.gps.month; log_day = log->u.gps.day; ao_log_open(); } } - if (log_running) { + if (log_open) { wrote = ao_fat_write(log, sizeof (*log)) == AO_FAT_SUCCESS; ao_fat_sync(); } -- cgit v1.2.3 From a764bf06d0975cbf1620b079351c7437053ea1a8 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 1 Apr 2013 01:58:37 -0700 Subject: altos: Flush the on-board mega log after every sample interval. SPI flash parts don't need flushing, but the SD card does. Make sure the SD card contents are sane after every logging interval has passed by flushing all dirty blocks to the device. Signed-off-by: Keith Packard --- src/core/ao_log.h | 3 +++ src/core/ao_log_mega.c | 2 ++ src/drivers/ao_log_fat.c | 6 ++++++ 3 files changed, 11 insertions(+) (limited to 'src') diff --git a/src/core/ao_log.h b/src/core/ao_log.h index 036d6f2d..cac78771 100644 --- a/src/core/ao_log.h +++ b/src/core/ao_log.h @@ -268,4 +268,7 @@ ao_log_data(__xdata struct ao_log_record *log) __reentrant; uint8_t ao_log_mega(__xdata struct ao_log_mega *log) __reentrant; +void +ao_log_flush(void); + #endif /* _AO_LOG_H_ */ diff --git a/src/core/ao_log_mega.c b/src/core/ao_log_mega.c index e03687ad..ba3f7bfc 100644 --- a/src/core/ao_log_mega.c +++ b/src/core/ao_log_mega.c @@ -171,6 +171,8 @@ ao_log(void) } #endif + ao_log_flush(); + /* Wait for a while */ ao_delay(AO_MS_TO_TICKS(100)); diff --git a/src/drivers/ao_log_fat.c b/src/drivers/ao_log_fat.c index 2741555f..6b433b99 100644 --- a/src/drivers/ao_log_fat.c +++ b/src/drivers/ao_log_fat.c @@ -83,3 +83,9 @@ ao_log_mega(struct ao_log_mega *log) ao_mutex_put(&log_mutex); return wrote; } + +void +ao_log_flush(void) +{ + ao_fat_sync(); +} -- cgit v1.2.3 From 76bd204de744c34e5cbf6efa93adb89bc2cb08b3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 1 Apr 2013 02:00:21 -0700 Subject: altos: let FAT tracing work in ao_fat_test as needed This allows the FAT DBG hooks to be enabled even if some other module turned DBG off. Signed-off-by: Keith Packard --- src/drivers/ao_fat.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/drivers/ao_fat.c b/src/drivers/ao_fat.c index ddf560cc..6aae1410 100644 --- a/src/drivers/ao_fat.c +++ b/src/drivers/ao_fat.c @@ -30,6 +30,10 @@ /* Spew FAT tracing */ #define FAT_TRACE 0 +#ifdef DBG +#undef DBG +#endif + #if FAT_TRACE #define DBG(...) printf(__VA_ARGS__) #else -- cgit v1.2.3 From 0838b6c8797b84cf8df8f92ee20fb6ae79e434d7 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 1 Apr 2013 02:02:14 -0700 Subject: altos: Make sure FAT cluster allocation works for size zero files There were some rounding errors mis-computing the number of clusters needed, and the logic to figure out how to re-connect a chain was broken. Signed-off-by: Keith Packard --- src/drivers/ao_fat.c | 195 +++++++++++++++++++++++++++++---------------------- 1 file changed, 112 insertions(+), 83 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_fat.c b/src/drivers/ao_fat.c index 6aae1410..3c72c397 100644 --- a/src/drivers/ao_fat.c +++ b/src/drivers/ao_fat.c @@ -286,101 +286,130 @@ ao_fat_cluster_seek(cluster_t cluster, cluster_t distance) static cluster_t ao_fat_cluster_set_size(cluster_t first_cluster, cluster_t size) { - cluster_t clear_cluster = 0; + cluster_t have; + cluster_t last_cluster; + cluster_t next_cluster; + + /* Walk the cluster chain to the + * spot where it needs to change. That + * will either be the end of the chain (in case it needs to grow), + * or after the desired number of clusters, in which case it needs to shrink + */ + next_cluster = first_cluster; + last_cluster = 0; + DBG("\tclusters:"); + for (have = 0; have < size; have++) { + DBG(" %08x", next_cluster); + if (!ao_fat_cluster_valid(next_cluster)) + break; + last_cluster = next_cluster; + next_cluster = ao_fat_entry_read(next_cluster); + } + DBG("\n"); + + /* At this point, last_cluster points to the last valid + * cluster in the file, if any. That's the spot in the FAT + * that needs to be rewritten, either to truncate the file by + * writing an END marker, or to extend the file by writing + * more clusters. next_cluster will contain the value of the + * FAT at last_cluster. + * + * If this is at the head of the cluster chain, then + * last_cluster will be zero and next_cluster will + * be the first cluster in the chain. + */ + if (have == size) { + /* The file is large enough, truncate as needed */ + if (ao_fat_cluster_valid(next_cluster)) { + DBG("truncate between %08x and %08x\n", last_cluster, next_cluster); + if (last_cluster) + /* + * Otherwise, rewrite the last cluster + * in the chain with a LAST marker + */ + (void) ao_fat_entry_replace(last_cluster, + AO_FAT_LAST_CLUSTER); + else + /* + * If the file is getting erased, then + * rewrite the directory entry cluster + * value + */ + first_cluster = 0; - if (size == 0) { - clear_cluster = first_cluster; - first_cluster = 0; - } else { - cluster_t have; - cluster_t last_cluster = 0; - cluster_t next_cluster; - - /* Walk the cluster chain to the - * spot where it needs to change. That - * will either be the end of the chain (in case it needs to grow), - * or after the desired number of clusters, in which case it needs to shrink - */ - next_cluster = first_cluster; - for (have = 0; have < size; have++) { - last_cluster = next_cluster; - next_cluster = ao_fat_entry_read(last_cluster); - if (!ao_fat_cluster_valid(next_cluster)) - break; - } + /* Clear the remaining clusters in the chain */ + ao_fat_free_cluster_chain(next_cluster); - if (have == size) { - /* The file is large enough, truncate as needed */ - if (ao_fat_cluster_valid(next_cluster)) { - /* Rewrite that cluster entry with 0xffff to mark the end of the chain */ - clear_cluster = ao_fat_entry_replace(last_cluster, AO_FAT_LAST_CLUSTER); - filesystem_full = 0; - } else { - /* The chain is already the right length, don't mess with it */ - ; - } + /* The file system is no longer full (if it was) */ + filesystem_full = 0; } else { - cluster_t need; - cluster_t free; + DBG("unchanged FAT chain\n"); + /* The chain is already the right length, don't mess with it */ + ; + } + } else { + cluster_t need; + cluster_t free; - if (filesystem_full) - return AO_FAT_BAD_CLUSTER; + if (filesystem_full) + return AO_FAT_BAD_CLUSTER; - if (next_free < 2 || number_cluster <= next_free) { - next_free = 2; - fsinfo_dirty = 1; - } + /* Set next_free if it has wrapped or wasn't set before */ + if (next_free < 2 || number_cluster <= next_free) { + next_free = 2; + fsinfo_dirty = 1; + } - /* See if there are enough free clusters in the file system */ - need = size - have; + /* See if there are enough free clusters in the file system */ + need = size - have; #define loop_cluster for (free = next_free; need > 0;) -#define next_cluster \ - if (++free == number_cluster) \ - free = 2; \ - if (free == next_free) \ - break; \ - - loop_cluster { - if (!ao_fat_entry_read(free)) - need--; - next_cluster; - } - /* Still need some, tell the user that we've failed */ - if (need) { - filesystem_full = 1; - return AO_FAT_BAD_CLUSTER; - } +#define next_cluster \ + if (++free == number_cluster) \ + free = 2; \ + if (free == next_free) \ + break; \ + + loop_cluster { + if (!ao_fat_entry_read(free)) + need--; + next_cluster; + } - /* Now go allocate those clusters and - * thread them onto the chain - */ - need = size - have; - loop_cluster { - if (!ao_fat_entry_read(free)) { - next_free = free + 1; - if (next_free >= number_cluster) - next_free = 2; - fsinfo_dirty = 1; - if (last_cluster) - ao_fat_entry_replace(last_cluster, free); - else - first_cluster = free; - last_cluster = free; - need--; - } - next_cluster; + /* Still need some, tell the user that we've failed */ + if (need) { + filesystem_full = 1; + return AO_FAT_BAD_CLUSTER; + } + + /* Now go allocate those clusters and + * thread them onto the chain + */ + need = size - have; + loop_cluster { + if (ao_fat_entry_read(free) == 0) { + next_free = free + 1; + if (next_free >= number_cluster) + next_free = 2; + fsinfo_dirty = 1; + DBG("\tadd cluster. old %08x new %08x\n", last_cluster, free); + if (last_cluster) + ao_fat_entry_replace(last_cluster, free); + else + first_cluster = free; + last_cluster = free; + need--; } + next_cluster; + } #undef loop_cluster #undef next_cluster - /* Mark the new end of the chain */ - ao_fat_entry_replace(last_cluster, AO_FAT_LAST_CLUSTER); - } + DBG("\tlast cluster %08x\n", last_cluster); + /* Mark the new end of the chain */ + ao_fat_entry_replace(last_cluster, AO_FAT_LAST_CLUSTER); } - /* Deallocate clusters off the end of the file */ - if (ao_fat_cluster_valid(clear_cluster)) - ao_fat_free_cluster_chain(clear_cluster); + DBG("\tfirst cluster %08x\n", first_cluster); return first_cluster; } @@ -437,8 +466,8 @@ ao_fat_root_extend(dirent_t ents) if (!fat32) return 0; - byte_size = ents * 0x20; - cluster_size = byte_size / bytes_per_cluster; + byte_size = (ents + 1) * 0x20; + cluster_size = (byte_size + bytes_per_cluster - 1) / bytes_per_cluster; if (ao_fat_cluster_set_size(root_cluster, cluster_size) != AO_FAT_BAD_CLUSTER) return 1; return 0; -- cgit v1.2.3 From 79d01a571935138b24b86a7181307ee014d248ed Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 1 Apr 2013 02:03:57 -0700 Subject: altos: Support open on multiple simultaneous FAT files Need to be able to see the contents of a log file, even if the logger is running. Signed-off-by: Keith Packard --- src/drivers/ao_fat.c | 453 ++++++++++++++++++++++++++++++++--------------- src/drivers/ao_fat.h | 8 +- src/drivers/ao_log_fat.c | 24 +-- 3 files changed, 329 insertions(+), 156 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_fat.c b/src/drivers/ao_fat.c index 3c72c397..87c4158b 100644 --- a/src/drivers/ao_fat.c +++ b/src/drivers/ao_fat.c @@ -601,13 +601,94 @@ ao_fat_setup_fs(void) } /* - * State for the current opened file + * State for an open file */ -static struct ao_fat_dirent ao_file_dirent; -static uint32_t ao_file_offset; -static uint32_t ao_file_cluster_offset; -static cluster_t ao_file_cluster; -static uint8_t ao_file_opened; + +struct ao_file { + struct ao_fat_dirent *dirent; + offset_t offset; + offset_t cluster_offset; + cluster_t cluster; + uint8_t busy; +}; + +#define AO_FAT_NFILE 8 + +static struct ao_fat_dirent ao_file_dirent[AO_FAT_NFILE]; + +static struct ao_fat_dirent * +ao_fat_file_dirent_alloc(struct ao_fat_dirent *want) +{ + int8_t d; + struct ao_fat_dirent *free = NULL, *dirent; + + for (d = 0; d < AO_FAT_NFILE; d++) { + + dirent = &ao_file_dirent[d]; + /* See if there's another user of this file already */ + if (want && dirent->name[0] != 0) { + if (dirent->entry == want->entry) + return dirent; + } else { + if (!free) { + free = dirent; + if (!want) + break; + } + } + } + if (free && want) + *free = *want; + return free; +} + +static struct ao_file ao_file_table[AO_FAT_NFILE]; + +static int8_t +ao_fat_fd_alloc(struct ao_fat_dirent *dirent) +{ + int8_t fd; + + for (fd = 0; fd < AO_FAT_NFILE; fd++) + if (!ao_file_table[fd].busy) { + ao_file_table[fd].dirent = ao_fat_file_dirent_alloc(dirent); + ao_file_table[fd].busy = 1; + ao_file_table[fd].offset = 0; + ao_file_table[fd].cluster_offset = 0; + ao_file_table[fd].cluster = ao_file_table[fd].dirent->cluster; + + return fd; + } + return -AO_FAT_EMFILE; +} + +static void +ao_fat_fd_free(int8_t fd) +{ + struct ao_file *file = &ao_file_table[fd]; + struct ao_fat_dirent *dirent = file->dirent; + memset(&ao_file_table[fd], '\0', sizeof (struct ao_file)); + + /* Check and see if another ao_file references the same dirent */ + for (fd = 0; fd < AO_FAT_NFILE; fd++) + if (ao_file_table[fd].dirent == dirent) + return; + memset(dirent, '\0', sizeof (struct ao_fat_dirent)); +} + +static struct ao_file * +ao_fat_fd_to_file(int8_t fd) +{ + struct ao_file *file; + if (fd < 0 || AO_FAT_NFILE <= fd) + return NULL; + + file = &ao_file_table[fd]; + if (!file->busy) + return NULL; + return file; +} + static uint8_t ao_filesystem_setup; static uint8_t ao_filesystem_status; @@ -628,9 +709,10 @@ ao_fat_setup(void) number_cluster = fat_start = root_start = data_start = 0; next_free = filesystem_full = 0; fat32 = fsinfo_dirty = root_cluster = fsinfo_sector = free_count = 0; - memset(&ao_file_dirent, '\0', sizeof (ao_file_dirent)); - ao_file_offset = ao_file_cluster_offset = ao_file_cluster = ao_file_opened = 0; + /* Reset open file table */ + memset(&ao_file_table, '\0', sizeof (ao_file_table)); + ao_filesystem_status = ao_fat_setup_partition(); if (ao_filesystem_status != AO_FAT_FILESYSTEM_SUCCESS) return ao_filesystem_status; @@ -652,7 +734,7 @@ ao_fat_unmount(void) */ static uint32_t -ao_fat_current_sector(void) +ao_fat_current_sector(struct ao_file *file) { cluster_t cluster_offset; uint32_t sector_offset; @@ -660,49 +742,74 @@ ao_fat_current_sector(void) cluster_t cluster; DBG("current sector offset %d size %d\n", - ao_file_offset, ao_file_dirent.size); + file->offset, file->dirent->size); - if (ao_file_offset > ao_file_dirent.size) + if (file->offset > file->dirent->size) { + printf ("file offset %d larger than size %d\n", + file->offset, file->dirent->size); return 0xffffffff; + } - sector_offset = ao_file_offset >> SECTOR_SHIFT; + sector_offset = file->offset >> SECTOR_SHIFT; - if (!ao_file_cluster || ao_file_offset < ao_file_cluster_offset) { - ao_file_cluster = ao_file_dirent.cluster; - ao_file_cluster_offset = 0; - DBG("\treset to start of file %08x\n", ao_file_cluster); + if (!file->cluster || file->offset < file->cluster_offset) { + file->cluster = file->dirent->cluster; + file->cluster_offset = 0; + DBG("\treset to start of file %08x\n", file->cluster); } - if (ao_file_cluster_offset + bytes_per_cluster <= ao_file_offset) { + if (file->cluster_offset + bytes_per_cluster <= file->offset) { cluster_t cluster_distance; cluster_offset = sector_offset / sectors_per_cluster; - cluster_distance = cluster_offset - ao_file_cluster_offset / bytes_per_cluster; + cluster_distance = cluster_offset - file->cluster_offset / bytes_per_cluster; DBG("\tseek forward %d clusters\n", cluster_distance); - cluster = ao_fat_cluster_seek(ao_file_cluster, cluster_distance); + cluster = ao_fat_cluster_seek(file->cluster, cluster_distance); - if (!ao_fat_cluster_valid(cluster)) + if (!ao_fat_cluster_valid(cluster)) { + printf ("invalid cluster %08x\n", cluster); return 0xffffffff; - ao_file_cluster = cluster; - ao_file_cluster_offset = cluster_offset * bytes_per_cluster; + } + file->cluster = cluster; + file->cluster_offset = cluster_offset * bytes_per_cluster; } sector_index = sector_offset % sectors_per_cluster; DBG("current cluster %08x sector_index %d sector %d\n", - ao_file_cluster, sector_index, - data_start + (uint32_t) (ao_file_cluster-2) * sectors_per_cluster + sector_index); - return data_start + (uint32_t) (ao_file_cluster-2) * sectors_per_cluster + sector_index; + file->cluster, sector_index, + data_start + (uint32_t) (file->cluster-2) * sectors_per_cluster + sector_index); + return data_start + (uint32_t) (file->cluster-2) * sectors_per_cluster + sector_index; } +/* + * ao_fat_invaldate_cluster_offset + * + * When the file size gets shrunk, invalidate + * any file structures referencing clusters beyond that point + */ + static void -ao_fat_set_offset(uint32_t offset) +ao_fat_invalidate_cluster_offset(struct ao_fat_dirent *dirent) { - DBG("Set offset %d\n", offset); - ao_file_offset = offset; + int8_t fd; + struct ao_file *file; + + for (fd = 0; fd < AO_FAT_NFILE; fd++) { + file = &ao_file_table[fd]; + if (!file->busy) + continue; + if (file->dirent == dirent) { + if (file->cluster_offset >= dirent->size) { + file->cluster_offset = 0; + file->cluster = dirent->cluster; + } + } + } } + /* * ao_fat_set_size * @@ -710,32 +817,34 @@ ao_fat_set_offset(uint32_t offset) * the cluster chain as needed */ static int8_t -ao_fat_set_size(uint32_t size) +ao_fat_set_size(struct ao_file *file, uint32_t size) { uint8_t *dent; cluster_t first_cluster; cluster_t have_clusters, need_clusters; DBG ("Set size %d\n", size); - if (size == ao_file_dirent.size) { + if (size == file->dirent->size) { DBG("\tsize match\n"); return AO_FAT_SUCCESS; } - first_cluster = ao_file_dirent.cluster; - have_clusters = (ao_file_dirent.size + bytes_per_cluster - 1) / bytes_per_cluster; + first_cluster = file->dirent->cluster; + have_clusters = (file->dirent->size + bytes_per_cluster - 1) / bytes_per_cluster; need_clusters = (size + bytes_per_cluster - 1) / bytes_per_cluster; DBG ("\tfirst cluster %08x have %d need %d\n", first_cluster, have_clusters, need_clusters); if (have_clusters != need_clusters) { - if (ao_file_cluster && size >= ao_file_cluster_offset) { - cluster_t offset_clusters = (ao_file_cluster_offset + bytes_per_cluster) / bytes_per_cluster; + if (file->cluster && size > file->cluster_offset) { + cluster_t offset_clusters = (file->cluster_offset + bytes_per_cluster) / bytes_per_cluster; cluster_t extra_clusters = need_clusters - offset_clusters; cluster_t next_cluster; DBG ("\tset size relative offset_clusters %d extra_clusters %d\n", offset_clusters, extra_clusters); - next_cluster = ao_fat_cluster_set_size(ao_file_cluster, extra_clusters); + + /* Need one more to account for file->cluster, which we already have */ + next_cluster = ao_fat_cluster_set_size(file->cluster, extra_clusters + 1); if (next_cluster == AO_FAT_BAD_CLUSTER) return -AO_FAT_ENOSPC; } else { @@ -749,17 +858,21 @@ ao_fat_set_size(uint32_t size) DBG ("\tupdate directory size\n"); /* Update the directory entry */ - dent = ao_fat_root_get(ao_file_dirent.entry); - if (!dent) + dent = ao_fat_root_get(file->dirent->entry); + if (!dent) { + printf ("dent update failed\n"); return -AO_FAT_EIO; + } put_u32(dent + 0x1c, size); put_u16(dent + 0x1a, first_cluster); if (fat32) put_u16(dent + 0x14, first_cluster >> 16); - ao_fat_root_put(dent, ao_file_dirent.entry, 1); + ao_fat_root_put(dent, file->dirent->entry, 1); - ao_file_dirent.size = size; - ao_file_dirent.cluster = first_cluster; + file->dirent->size = size; + file->dirent->cluster = first_cluster; + if (have_clusters > need_clusters) + ao_fat_invalidate_cluster_offset(file->dirent); DBG ("set size done\n"); return AO_FAT_SUCCESS; } @@ -803,7 +916,7 @@ ao_fat_root_init(uint8_t *dent, char name[11], uint8_t attr) static void -ao_fat_dirent_init(uint8_t *dent, uint16_t entry, struct ao_fat_dirent *dirent) +ao_fat_dirent_init(struct ao_fat_dirent *dirent, uint8_t *dent, uint16_t entry) { memcpy(dirent->name, dent + 0x00, 11); dirent->attr = dent[0x0b]; @@ -886,14 +999,18 @@ ao_fat_open(char name[11], uint8_t mode) { uint16_t entry = 0; struct ao_fat_dirent dirent; + int8_t status; if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) return -AO_FAT_EIO; - if (ao_file_opened) - return -AO_FAT_EMFILE; - - while (ao_fat_readdir(&entry, &dirent)) { + for (;;) { + status = ao_fat_readdir(&entry, &dirent); + if (status < 0) { + if (status == -AO_FAT_EDIREOF) + return -AO_FAT_ENOENT; + return status; + } if (!memcmp(name, dirent.name, 11)) { if (AO_FAT_IS_DIR(dirent.attr)) return -AO_FAT_EISDIR; @@ -901,10 +1018,7 @@ ao_fat_open(char name[11], uint8_t mode) return -AO_FAT_EPERM; if (mode > AO_FAT_OPEN_READ && (dirent.attr & AO_FAT_FILE_READ_ONLY)) return -AO_FAT_EACCESS; - ao_file_dirent = dirent; - ao_fat_set_offset(0); - ao_file_opened = 1; - return AO_FAT_SUCCESS; + return ao_fat_fd_alloc(&dirent); } } return -AO_FAT_ENOENT; @@ -919,49 +1033,62 @@ ao_fat_open(char name[11], uint8_t mode) int8_t ao_fat_creat(char name[11]) { - uint16_t entry; - int8_t status; - uint8_t *dent; + uint16_t entry; + int8_t fd; + int8_t status; + uint8_t *dent; + struct ao_file *file; if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) return -AO_FAT_EIO; - if (ao_file_opened) - return -AO_FAT_EMFILE; + fd = ao_fat_open(name, AO_FAT_OPEN_WRITE); + if (fd >= 0) { + file = &ao_file_table[fd]; + status = ao_fat_set_size(file, 0); + if (status < 0) { + ao_fat_close(fd); + fd = status; + } + } else { + if (fd == -AO_FAT_ENOENT) { + entry = 0; + for (;;) { + dent = ao_fat_root_get(entry); + if (!dent) { + + if (ao_fat_root_extend(entry)) + continue; + fd = -AO_FAT_ENOSPC; + break; + } + if (dent[0] == AO_FAT_DENT_EMPTY || dent[0] == AO_FAT_DENT_END) { + fd = ao_fat_fd_alloc(NULL); + if (fd < 0) { + ao_fat_root_put(dent, entry, 0); + break; + } - status = ao_fat_open(name, AO_FAT_OPEN_WRITE); + file = &ao_file_table[fd]; + /* Initialize the dent */ + ao_fat_root_init(dent, name, AO_FAT_FILE_REGULAR); - switch (status) { - case -AO_FAT_SUCCESS: - status = ao_fat_set_size(0); - break; - case -AO_FAT_ENOENT: - entry = 0; - for (;;) { - dent = ao_fat_root_get(entry); - if (!dent) { - - if (ao_fat_root_extend(entry)) - continue; - status = -AO_FAT_ENOSPC; - break; - } - - if (dent[0] == AO_FAT_DENT_EMPTY || dent[0] == AO_FAT_DENT_END) { - ao_fat_root_init(dent, name, AO_FAT_FILE_REGULAR); - ao_fat_dirent_init(dent, entry, &ao_file_dirent); - ao_fat_root_put(dent, entry, 1); - ao_file_opened = 1; - ao_fat_set_offset(0); - status = -AO_FAT_SUCCESS; - break; - } else { - ao_fat_root_put(dent, entry, 0); + /* Now initialize the dirent from the dent */ + ao_fat_dirent_init(file->dirent, dent, entry); + + /* And write the dent to storage */ + ao_fat_root_put(dent, entry, 1); + + status = -AO_FAT_SUCCESS; + break; + } else { + ao_fat_root_put(dent, entry, 0); + } + entry++; } - entry++; } } - return status; + return fd; } /* @@ -970,16 +1097,13 @@ ao_fat_creat(char name[11]) * Close the currently open file */ int8_t -ao_fat_close(void) +ao_fat_close(int8_t fd) { - if (!ao_file_opened) + struct ao_file *file = ao_fat_fd_to_file(fd); + if (!file) return -AO_FAT_EBADF; - memset(&ao_file_dirent, '\0', sizeof (struct ao_fat_dirent)); - ao_file_offset = 0; - ao_file_cluster = 0; - ao_file_opened = 0; - + ao_fat_fd_free(fd); ao_fat_sync(); return AO_FAT_SUCCESS; } @@ -991,17 +1115,21 @@ ao_fat_close(void) */ static void * -ao_fat_map_current(int len, cluster_offset_t *offsetp, cluster_offset_t *this_time) +ao_fat_map_current(struct ao_file *file, int len, cluster_offset_t *offsetp, cluster_offset_t *this_time) { cluster_offset_t offset; sector_t sector; void *buf; - offset = ao_file_offset & SECTOR_MASK; - sector = ao_fat_current_sector(); - if (sector == 0xffffffff) + offset = file->offset & SECTOR_MASK; + sector = ao_fat_current_sector(file); + if (sector == 0xffffffff) { + printf ("invalid sector at offset %d\n", file->offset); return NULL; + } buf = ao_fat_sector_get(sector); + if (!buf) + printf ("sector get failed. Sector %d. Partition end %d\n", sector, partition_end); if (offset + len < SECTOR_SIZE) *this_time = len; else @@ -1016,26 +1144,27 @@ ao_fat_map_current(int len, cluster_offset_t *offsetp, cluster_offset_t *this_ti * Read from the file */ int -ao_fat_read(void *dst, int len) +ao_fat_read(int8_t fd, void *dst, int len) { uint8_t *dst_b = dst; cluster_offset_t this_time; cluster_offset_t offset; uint8_t *buf; int ret = 0; - - if (!ao_file_opened) + struct ao_file *file = ao_fat_fd_to_file(fd); + if (!file) return -AO_FAT_EBADF; - if (ao_file_offset + len > ao_file_dirent.size) - len = ao_file_dirent.size - ao_file_offset; + if (file->offset + len > file->dirent->size) + len = file->dirent->size - file->offset; if (len < 0) len = 0; while (len) { - buf = ao_fat_map_current(len, &offset, &this_time); + buf = ao_fat_map_current(file, len, &offset, &this_time); if (!buf) { + printf ("map_current failed\n"); ret = -AO_FAT_EIO; break; } @@ -1045,7 +1174,7 @@ ao_fat_read(void *dst, int len) ret += this_time; len -= this_time; dst_b += this_time; - ao_fat_set_offset(ao_file_offset + this_time); + file->offset = file->offset + this_time; } return ret; } @@ -1056,26 +1185,27 @@ ao_fat_read(void *dst, int len) * Write to the file, extended as necessary */ int -ao_fat_write(void *src, int len) +ao_fat_write(int8_t fd, void *src, int len) { - uint8_t *src_b = src; - uint16_t this_time; - uint16_t offset; - uint8_t *buf; - int ret = 0; - - if (!ao_file_opened) + uint8_t *src_b = src; + cluster_offset_t this_time; + cluster_offset_t offset; + uint8_t *buf; + int ret = 0; + struct ao_file *file = ao_fat_fd_to_file(fd); + if (!file) return -AO_FAT_EBADF; - if (ao_file_offset + len > ao_file_dirent.size) { - ret = ao_fat_set_size(ao_file_offset + len); + if (file->offset + len > file->dirent->size) { + ret = ao_fat_set_size(file, file->offset + len); if (ret < 0) return ret; } while (len) { - buf = ao_fat_map_current(len, &offset, &this_time); + buf = ao_fat_map_current(file, len, &offset, &this_time); if (!buf) { + printf ("map_current failed\n"); ret = -AO_FAT_EIO; break; } @@ -1085,7 +1215,7 @@ ao_fat_write(void *src, int len) ret += this_time; len -= this_time; src_b += this_time; - ao_fat_set_offset(ao_file_offset + this_time); + file->offset = file->offset + this_time; } return ret; } @@ -1100,13 +1230,14 @@ ao_fat_write(void *src, int len) * write */ int32_t -ao_fat_seek(int32_t pos, uint8_t whence) +ao_fat_seek(int8_t fd, int32_t pos, uint8_t whence) { - uint32_t new_offset = ao_file_offset; - - if (!ao_file_opened) + offset_t new_offset; + struct ao_file *file = ao_fat_fd_to_file(fd); + if (!file) return -AO_FAT_EBADF; + new_offset = file->offset; switch (whence) { case AO_FAT_SEEK_SET: new_offset = pos; @@ -1115,11 +1246,11 @@ ao_fat_seek(int32_t pos, uint8_t whence) new_offset += pos; break; case AO_FAT_SEEK_END: - new_offset = ao_file_dirent.size + pos; + new_offset = file->dirent->size + pos; break; } - ao_fat_set_offset(new_offset); - return ao_file_offset; + file->offset = new_offset; + return file->offset; } /* @@ -1193,7 +1324,7 @@ ao_fat_readdir(uint16_t *entry, struct ao_fat_dirent *dirent) return -AO_FAT_EDIREOF; } if (dent[0] != AO_FAT_DENT_EMPTY && (dent[0xb] & 0xf) != 0xf) { - ao_fat_dirent_init(dent, *entry, dirent); + ao_fat_dirent_init(dirent, dent, *entry); ao_fat_root_put(dent, *entry, 0); (*entry)++; return AO_FAT_SUCCESS; @@ -1304,12 +1435,12 @@ ao_fat_parse_name(char name[11]) } static void -ao_fat_show_cmd(void) +ao_fat_dump_cmd(void) { char name[11]; - int8_t status; + int8_t fd; int cnt, i; - char buf[64]; + char buf[32]; ao_fat_parse_name(name); if (name[0] == '\0') { @@ -1317,31 +1448,27 @@ ao_fat_show_cmd(void) return; } - status = ao_fat_open(name, AO_FAT_OPEN_READ); - if (status) { - printf ("Open failed: %d\n", status); + fd = ao_fat_open(name, AO_FAT_OPEN_READ); + if (fd < 0) { + printf ("Open failed: %d\n", fd); return; } - while ((cnt = ao_fat_read(buf, sizeof(buf))) > 0) { + while ((cnt = ao_fat_read(fd, buf, sizeof(buf))) > 0) { for (i = 0; i < cnt; i++) putchar(buf[i]); } - ao_fat_close(); -} - -static void -ao_fat_putchar(char c) -{ + ao_fat_close(fd); } static void ao_fat_write_cmd(void) { char name[11]; - int8_t status; + int8_t fd; int cnt, i; char buf[64]; char c; + int status; ao_fat_parse_name(name); if (name[0] == '\0') { @@ -1349,9 +1476,9 @@ ao_fat_write_cmd(void) return; } - status = ao_fat_creat(name); - if (status) { - printf ("Open failed: %d\n", status); + fd = ao_fat_creat(name); + if (fd < 0) { + printf ("Open failed: %d\n", fd); return; } flush(); @@ -1361,19 +1488,61 @@ ao_fat_write_cmd(void) if (c == '\n') putchar ('\r'); putchar(c); flush(); } - if (ao_fat_write(&c, 1) != 1) { - printf ("Write failure\n"); + status = ao_fat_write(fd, &c, 1); + if (status != 1) { + printf ("Write failure %d\n", status); break; } } - ao_fat_close(); + ao_fat_close(fd); +} + +static void +put32(uint32_t a) +{ + ao_cmd_put16(a >> 16); + ao_cmd_put16(a); +} + +static void +ao_fat_hexdump_cmd(void) +{ + char name[11]; + int8_t fd; + int cnt, i; + char buf[8]; + uint32_t addr; + + ao_fat_parse_name(name); + if (name[0] == '\0') { + ao_cmd_status = ao_cmd_syntax_error; + return; + } + + fd = ao_fat_open(name, AO_FAT_OPEN_READ); + if (fd < 0) { + printf ("Open failed: %d\n", fd); + return; + } + addr = 0; + while ((cnt = ao_fat_read(fd, buf, sizeof(buf))) > 0) { + put32(addr); + for (i = 0; i < cnt; i++) { + putchar(' '); + ao_cmd_put8(buf[i]); + } + putchar('\n'); + addr += cnt; + } + ao_fat_close(fd); } static const struct ao_cmds ao_fat_cmds[] = { { ao_fat_mbr_cmd, "M\0Show FAT MBR and other info" }, { ao_fat_list_cmd, "F\0List FAT directory" }, - { ao_fat_show_cmd, "S \0Show FAT file" }, + { ao_fat_dump_cmd, "D \0Dump FAT file" }, { ao_fat_write_cmd, "W \0Write FAT file (end with ^D)" }, + { ao_fat_hexdump_cmd, "H \0HEX dump FAT file" }, { 0, NULL }, }; diff --git a/src/drivers/ao_fat.h b/src/drivers/ao_fat.h index fe154cdf..01435363 100644 --- a/src/drivers/ao_fat.h +++ b/src/drivers/ao_fat.h @@ -81,20 +81,20 @@ int8_t ao_fat_creat(char name[11]); int8_t -ao_fat_close(void); +ao_fat_close(int8_t fd); int -ao_fat_read(void *dest, int len); +ao_fat_read(int8_t fd, void *dest, int len); int -ao_fat_write(void *src, int len); +ao_fat_write(int8_t fd, void *src, int len); #define AO_FAT_SEEK_SET 0 #define AO_FAT_SEEK_CUR 1 #define AO_FAT_SEEK_END 2 int32_t -ao_fat_seek(int32_t pos, uint8_t whence); +ao_fat_seek(int8_t fd, int32_t pos, uint8_t whence); int8_t ao_fat_unlink(char name[11]); diff --git a/src/drivers/ao_log_fat.c b/src/drivers/ao_log_fat.c index 6b433b99..af77401c 100644 --- a/src/drivers/ao_log_fat.c +++ b/src/drivers/ao_log_fat.c @@ -21,6 +21,7 @@ static uint8_t log_year, log_month, log_day; static uint8_t log_open; +static int8_t log_fd; static uint8_t log_mutex; static void @@ -31,24 +32,27 @@ ao_log_open(void) sprintf(name,"%04d%02d%02dLOG", 2000 + log_year, log_month, log_day); status = ao_fat_open(name, AO_FAT_OPEN_WRITE); - switch (status) { - case AO_FAT_SUCCESS: - ao_fat_seek(0, AO_FAT_SEEK_END); + if (status >= 0) { + log_fd = status; + ao_fat_seek(log_fd, 0, AO_FAT_SEEK_END); log_open = 1; - break; - case -AO_FAT_ENOENT: + } else if (status == -AO_FAT_ENOENT) { status = ao_fat_creat(name); - if (status == AO_FAT_SUCCESS) + if (status == AO_FAT_SUCCESS) { + log_fd = status; log_open = 1; - break; + } } } static void ao_log_close(void) { - log_open = 0; - ao_fat_close(); + if (log_open) { + log_open = 0; + ao_fat_close(log_fd); + log_fd = -1; + } } uint8_t @@ -77,7 +81,7 @@ ao_log_mega(struct ao_log_mega *log) } } if (log_open) { - wrote = ao_fat_write(log, sizeof (*log)) == AO_FAT_SUCCESS; + wrote = ao_fat_write(log_fd, log, sizeof (*log)) == AO_FAT_SUCCESS; ao_fat_sync(); } ao_mutex_put(&log_mutex); -- cgit v1.2.3 From fae116fbebb9658fe15690ff43dfe8568a58c2a9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 1 Apr 2013 02:06:03 -0700 Subject: altos: Add a FAT test that re-writes the same file multiple times This caught a bunch of FAT cluster chain allocation bugs. Signed-off-by: Keith Packard --- src/test/ao_fat_test.c | 125 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 96 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/test/ao_fat_test.c b/src/test/ao_fat_test.c index eb55d9c8..a1bd5fbf 100644 --- a/src/test/ao_fat_test.c +++ b/src/test/ao_fat_test.c @@ -350,28 +350,89 @@ uint32_t sizes[NUM_FILES]; unsigned char md5[NUM_FILES][MD5_DIGEST_LENGTH]; +void +micro_test_fs(void) +{ + int8_t fd; + char name[] = "FOO "; + char buf[512]; + int len; + + printf ("write once\n"); + if ((fd = ao_fat_creat(name)) >= 0) { + ao_fat_write(fd, "hello world\n", 12); + ao_fat_close(fd); + } + + printf ("read first\n"); + if ((fd = ao_fat_open(name, AO_FAT_OPEN_READ)) >= 0) { + len = ao_fat_read(fd, buf, sizeof(buf)); + write (1, buf, len); + ao_fat_close(fd); + } + + printf ("write again\n"); + if ((fd = ao_fat_creat(name)) >= 0) { + ao_fat_write(fd, "hi\n", 3); + ao_fat_close(fd); + } + + printf ("read again\n"); + if ((fd = ao_fat_open(name, AO_FAT_OPEN_READ)) >= 0) { + len = ao_fat_read(fd, buf, sizeof(buf)); + write (1, buf, len); + ao_fat_close(fd); + } + + printf ("write 3\n"); + if ((fd = ao_fat_creat(name)) >= 0) { + int l; + char c; + + for (l = 0; l < 10; l++) { + for (c = ' '; c < '~'; c++) + ao_fat_write(fd, &c, 1); + c = '\n'; + ao_fat_write(fd, &c, 1); + } + ao_fat_close(fd); + } + + printf ("read 3\n"); + if ((fd = ao_fat_open(name, AO_FAT_OPEN_READ)) >= 0) { + while ((len = ao_fat_read(fd, buf, sizeof(buf))) > 0) + write (1, buf, len); + ao_fat_close(fd); + } + + check_fs(); + printf ("all done\n"); +} + + void short_test_fs(void) { int len; + int8_t fd; char buf[345]; - if (ao_fat_open("HELLO TXT",AO_FAT_OPEN_READ) == AO_FAT_SUCCESS) { + if ((fd = ao_fat_open("HELLO TXT",AO_FAT_OPEN_READ)) >= 0) { printf ("File contents for HELLO.TXT\n"); - while ((len = ao_fat_read(buf, sizeof(buf)))) + while ((len = ao_fat_read(fd, buf, sizeof(buf)))) write(1, buf, len); - ao_fat_close(); + ao_fat_close(fd); } - if (ao_fat_creat("NEWFILE TXT") == AO_FAT_SUCCESS) { + if ((fd = ao_fat_creat("NEWFILE TXT")) >= 0) { printf ("Create new file\n"); for (len = 0; len < 2; len++) - ao_fat_write("hello, world!\n", 14); - ao_fat_seek(0, AO_FAT_SEEK_SET); + ao_fat_write(fd, "hello, world!\n", 14); + ao_fat_seek(fd, 0, AO_FAT_SEEK_SET); printf ("read new file\n"); - while ((len = ao_fat_read(buf, sizeof (buf)))) + while ((len = ao_fat_read(fd, buf, sizeof (buf)))) write (1, buf, len); - ao_fat_close(); + ao_fat_close(fd); } check_fs(); @@ -386,6 +447,7 @@ long_test_fs(void) unsigned char md5_check[MD5_DIGEST_LENGTH]; char buf[337]; int len; + int8_t fd; uint64_t total_file_size = 0; total_reads = total_writes = 0; @@ -395,10 +457,10 @@ long_test_fs(void) memset(sizes, '\0', sizeof (sizes)); for (id = 0; id < NUM_FILES; id++) { sprintf(name, "D%07dTXT", id); - if ((id % (NUM_FILES/50)) == 0) { + if ((id % ((NUM_FILES+49)/50)) == 0) { printf ("."); fflush(stdout); } - if (ao_fat_creat(name) == AO_FAT_SUCCESS) { + if ((fd = ao_fat_creat(name)) >= 0) { int j; char line[64]; check_bufio("file created"); @@ -407,7 +469,7 @@ long_test_fs(void) int len, ret; sprintf (line, "Hello, world %d %d\r\n", id, j); len = strlen(line); - ret = ao_fat_write((uint8_t *) line, len); + ret = ao_fat_write(fd, line, len); if (ret <= 0) break; total_file_size += ret; @@ -416,7 +478,7 @@ long_test_fs(void) if (ret != len) printf ("write failed %d\n", ret); } - ao_fat_close(); + ao_fat_close(fd); MD5_Final(&md5[id][0], &ctx); check_bufio("file written"); } @@ -436,16 +498,16 @@ long_test_fs(void) uint32_t size; sprintf(name, "D%07dTXT", id); size = 0; - if ((id % (NUM_FILES/50)) == 0) { + if ((id % ((NUM_FILES+49)/50)) == 0) { printf ("."); fflush(stdout); } - if (ao_fat_open(name, AO_FAT_OPEN_READ) == AO_FAT_SUCCESS) { + if ((fd = ao_fat_open(name, AO_FAT_OPEN_READ)) >= 0) { MD5_Init(&ctx); - while ((len = ao_fat_read((uint8_t *) buf, sizeof(buf))) > 0) { + while ((len = ao_fat_read(fd, buf, sizeof(buf))) > 0) { MD5_Update(&ctx, buf, len); size += len; } - ao_fat_close(); + ao_fat_close(fd); MD5_Final(md5_check, &ctx); if (size != sizes[id]) fatal("file %d: size differs %d written %d read\n", @@ -468,6 +530,20 @@ char *params[] = { NULL }; +void +do_test(void (*test)(void)) +{ + ao_fat_init(); + + check_bufio("top"); + ao_fat_setup(); + + check_fs(); + check_bufio("after setup"); + (*test)(); + ao_fat_unmount(); +} + int main(int argc, char **argv) { @@ -478,21 +554,12 @@ main(int argc, char **argv) for (p = 0; fs_params[p].fat; p++) { param = &fs_params[p]; - ao_fat_init(); - - check_bufio("top"); - ao_fat_setup(); - - check_fs(); - check_bufio("after setup"); -#ifdef SIMPLE_TEST - short_test_fs(); -#else - long_test_fs(); -#endif - ao_fat_unmount(); + do_test(micro_test_fs); + do_test(short_test_fs); + do_test(long_test_fs); } + unlink (fs); return 0; } -- cgit v1.2.3 From b3a41bed39ec1abfc3ab74e9be7dd393e975542b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 1 Apr 2013 02:07:06 -0700 Subject: altos: Provide build hooks for sampling profiler in telegps Might prove useful if the CPU is ever doing anything? Signed-off-by: Keith Packard --- src/telegps-v0.1/Makefile | 3 ++- src/telegps-v0.1/ao_telegps.c | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/telegps-v0.1/Makefile b/src/telegps-v0.1/Makefile index 4458724d..1e551e15 100644 --- a/src/telegps-v0.1/Makefile +++ b/src/telegps-v0.1/Makefile @@ -62,7 +62,8 @@ ALTOS_SRC = \ ao_fat.c \ ao_log_fat.c \ ao_gps_report_mega.c \ - ao_telemetry.c + ao_telemetry.c \ + $(SAMPLE_PROFILE) PRODUCT=TeleGPS-v0.1 PRODUCT_DEF=-DTELEGPS diff --git a/src/telegps-v0.1/ao_telegps.c b/src/telegps-v0.1/ao_telegps.c index 91796c21..4620de3b 100644 --- a/src/telegps-v0.1/ao_telegps.c +++ b/src/telegps-v0.1/ao_telegps.c @@ -52,12 +52,15 @@ main(void) ao_fat_init(); ao_gps_init(); - ao_gps_report_mega_init(); +// ao_gps_report_mega_init(); ao_telemetry_init(); ao_telemetry_set_interval(AO_SEC_TO_TICKS(1)); ao_rdf_set(1); +#if HAS_SAMPLE_PROFILE + ao_sample_profile_init(); +#endif ao_config_init(); ao_start_scheduler(); -- cgit v1.2.3 From b34370cea662eb245e43aca20a6650b84b55ef6f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 1 Apr 2013 02:08:18 -0700 Subject: altos: Retry SD card I/O. Use time for timeouts instead of counts Sometimes I/O operations may fail; give the card a chance and retry the operation in case it works the next time. Replace the loop counts with loops that check the clock so that they'll have consistent timeouts even if the CPU or SPI speed changes. Signed-off-by: Keith Packard --- src/drivers/ao_sdcard.c | 361 ++++++++++++++++++++++++++++++++++++------------ src/drivers/ao_sdcard.h | 19 ++- 2 files changed, 281 insertions(+), 99 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_sdcard.c b/src/drivers/ao_sdcard.c index 952000a7..6073677a 100644 --- a/src/drivers/ao_sdcard.c +++ b/src/drivers/ao_sdcard.c @@ -28,11 +28,14 @@ #define ao_sdcard_deselect() ao_gpio_set(AO_SDCARD_SPI_CS_PORT,AO_SDCARD_SPI_CS_PIN,AO_SDCARD_SPI_CS,1) /* Include SD card commands */ -#define SDCARD_DEBUG 0 +#define SDCARD_DEBUG 1 /* Spew SD tracing */ #define SDCARD_TRACE 0 +/* Emit error and warning messages */ +#define SDCARD_WARN 0 + static uint8_t initialized; static uint8_t present; static uint8_t mutex; @@ -47,6 +50,38 @@ static enum ao_sdtype sdtype; #define DBG(...) #endif +#if SDCARD_WARN +#define WARN(...) printf(__VA_ARGS__) +#else +#define WARN(...) +#endif + +#define later(x,y) ((int16_t) ((x) - (y)) >= 0) + +/* + * Wait while the card is busy. The card will return a stream of 0xff + * when it is ready to accept a command + */ + +static uint8_t +ao_sdcard_wait_busy(void) +{ + uint16_t timeout = ao_time() + SDCARD_BUSY_TIMEOUT; + uint8_t reply; + for (;;) { + ao_sdcard_recv(&reply, 1); + DBG("\t\twait busy %02x\n", reply); + if (reply == 0xff) + break; + if (later(ao_time(), timeout)) { + WARN("wait busy timeout\n"); + return 0; + } + } + return 1; +} + + /* * Send an SD command and await the status reply */ @@ -57,15 +92,13 @@ ao_sdcard_send_cmd(uint8_t cmd, uint32_t arg) uint8_t data[6]; uint8_t reply; int i; + uint16_t timeout; DBG ("\tsend_cmd %d arg %08x\n", cmd, arg); + + /* Wait for the card to not be busy */ if (cmd != SDCARD_GO_IDLE_STATE) { - for (i = 0; i < SDCARD_CMD_TIMEOUT; i++) { - ao_sdcard_recv(&reply, 1); - if (reply == 0xff) - break; - } - if (i == SDCARD_CMD_TIMEOUT) + if (!ao_sdcard_wait_busy()) return SDCARD_STATUS_TIMEOUT; } @@ -85,13 +118,22 @@ ao_sdcard_send_cmd(uint8_t cmd, uint32_t arg) /* The first reply byte will be the status, * which must have the high bit clear */ - for (i = 0; i < SDCARD_CMD_TIMEOUT; i++) { + timeout = ao_time() + SDCARD_CMD_TIMEOUT; + for (;;) { ao_sdcard_recv(&reply, 1); DBG ("\t\tgot byte %02x\n", reply); if ((reply & 0x80) == 0) - return reply; + break; + if (later(ao_time(), timeout)) { + WARN("send_cmd %02x timeout\n", cmd); + return SDCARD_STATUS_TIMEOUT; + } } - return SDCARD_STATUS_TIMEOUT; +#if SDCARD_WARN + if (reply != SDCARD_STATUS_READY_STATE && reply != SDCARD_STATUS_IDLE_STATE) + WARN("send_cmd %d failed %02x\n", cmd, reply); +#endif + return reply; } /* @@ -109,21 +151,8 @@ ao_sdcard_recv_reply(uint8_t *reply, int len) } /* - * Wait while the card is busy. The - * card will return a stream of 0xff - * until it isn't busy anymore + * Switch to 'idle' state. This is used to get the card into SPI mode */ -static void -ao_sdcard_wait_busy(void) -{ - uint8_t v; - - do { - ao_sdcard_recv(&v, 1); - } while (v != 0xff); - ao_sdcard_send_fixed(0xff, 1); -} - static uint8_t ao_sdcard_go_idle_state(void) { @@ -175,20 +204,33 @@ ao_sdcard_send_if_cond(uint32_t arg, uint8_t send_if_cond_response[4]) return ret; } -static uint8_t -ao_sdcard_send_status(void) +/* + * _ao_sdcard_send_status + * + * Get the 2-byte status value. + * + * Called from other functions with CS held low already, + * hence prefixing the name with '_' + */ +static uint16_t +_ao_sdcard_send_status(void) { uint8_t ret; + uint8_t extra; DBG ("send_status\n"); - ao_sdcard_select(); ret = ao_sdcard_send_cmd(SDCARD_SEND_STATUS, 0); - ao_sdcard_recv_reply(NULL, 0); + ao_sdcard_recv_reply(&extra, 1); if (ret != SDCARD_STATUS_READY_STATE) DBG ("\tsend_if_cond failed %02x\n", ret); - return ret; + return ret | (extra << 8); } +/* + * ao_sdcard_set_blocklen + * + * Set the block length for future read and write commands + */ static uint8_t ao_sdcard_set_blocklen(uint32_t blocklen) { @@ -198,21 +240,28 @@ ao_sdcard_set_blocklen(uint32_t blocklen) ao_sdcard_select(); ret = ao_sdcard_send_cmd(SDCARD_SET_BLOCKLEN, blocklen); ao_sdcard_recv_reply(NULL, 0); + ao_sdcard_deselect(); if (ret != SDCARD_STATUS_READY_STATE) DBG ("\tsend_if_cond failed %02x\n", ret); return ret; } +/* + * _ao_sdcard_app_cmd + * + * Send the app command prefix + * + * Called with the CS held low, hence + * the '_' prefix + */ static uint8_t -ao_sdcard_app_cmd(void) +_ao_sdcard_app_cmd(void) { uint8_t ret; DBG ("app_cmd\n"); - ao_sdcard_select(); ret = ao_sdcard_send_cmd(SDCARD_APP_CMD, 0); ao_sdcard_recv_reply(NULL, 0); - ao_sdcard_deselect(); DBG ("\tapp_cmd status %02x\n"); return ret; } @@ -222,13 +271,14 @@ ao_sdcard_app_send_op_cond(uint32_t arg) { uint8_t ret; - ret = ao_sdcard_app_cmd(); - if (ret != SDCARD_STATUS_IDLE_STATE) - return ret; DBG("send_op_comd\n"); ao_sdcard_select(); + ret = _ao_sdcard_app_cmd(); + if (ret != SDCARD_STATUS_IDLE_STATE) + goto bail; ret = ao_sdcard_send_cmd(SDCARD_APP_SEND_OP_COMD, arg); ao_sdcard_recv_reply(NULL, 0); +bail: ao_sdcard_deselect(); DBG ("\tapp_send_op_cond status %02x\n", ret); return ret; @@ -254,6 +304,10 @@ ao_sdcard_read_ocr(uint8_t read_ocr_response[4]) return ret; } +/* + * Follow the flow-chart defined by the SD group to + * initialize the card and figure out what kind it is + */ static void ao_sdcard_setup(void) { @@ -269,10 +323,7 @@ ao_sdcard_setup(void) */ ao_sdcard_send_fixed(0xff, 10); - ao_delay(AO_MS_TO_TICKS(10)); - /* Reset the card and get it into SPI mode */ - for (i = 0; i < SDCARD_IDLE_WAIT; i++) { if (ao_sdcard_go_idle_state() == SDCARD_STATUS_IDLE_STATE) break; @@ -281,7 +332,6 @@ ao_sdcard_setup(void) goto bail; /* Figure out what kind of card we have */ - sdtype = ao_sdtype_unknown; if (ao_sdcard_send_if_cond(0x1aa, response) == SDCARD_STATUS_IDLE_STATE) { @@ -337,18 +387,85 @@ bail: ao_sdcard_put(); } +static uint8_t +_ao_sdcard_reset(void) +{ + int i; + uint8_t ret; + uint8_t response[10]; + + for (i = 0; i < SDCARD_IDLE_WAIT; i++) { + if (ao_sdcard_go_idle_state() == SDCARD_STATUS_IDLE_STATE) + break; + } + if (i == SDCARD_IDLE_WAIT) { + ret = 0x3f; + goto bail; + } + + /* Follow the setup path to get the card out of idle state and + * up and running again + */ + if (ao_sdcard_send_if_cond(0x1aa, response) == SDCARD_STATUS_IDLE_STATE) { + uint32_t arg = 0; + uint8_t sdver2 = 0; + + /* Check for SD version 2 */ + if ((response[2] & 0xf) == 1 && response[3] == 0xaa) { + arg = 0x40000000; + sdver2 = 1; + } + + for (i = 0; i < SDCARD_IDLE_WAIT; i++) { + ret = ao_sdcard_app_send_op_cond(arg); + if (ret != SDCARD_STATUS_IDLE_STATE) + break; + } + + if (ret != SDCARD_STATUS_READY_STATE) { + /* MMC */ + for (i = 0; i < SDCARD_IDLE_WAIT; i++) { + ret = ao_sdcard_send_op_cond(); + if (ret != SDCARD_STATUS_IDLE_STATE) + break; + } + if (ret != SDCARD_STATUS_READY_STATE) + goto bail; + } + + /* For everything but SDHC cards, set the block length */ + if (sdtype != ao_sdtype_sd2block) { + ret = ao_sdcard_set_blocklen(512); + if (ret != SDCARD_STATUS_READY_STATE) + DBG ("set_blocklen failed, ignoring\n"); + } + } +bail: + return ret; +} + +/* + * The card will send 0xff until it is ready to send + * the data block at which point it will send the START_BLOCK + * marker followed by the data. This function waits while + * the card is sending 0xff + */ static uint8_t ao_sdcard_wait_block_start(void) { - int i; - uint8_t v; + uint8_t v; + uint16_t timeout = ao_time() + SDCARD_BLOCK_TIMEOUT; DBG ("\twait_block_start\n"); - for (i = 0; i < SDCARD_BLOCK_TIMEOUT; i++) { + for (;;) { ao_sdcard_recv(&v, 1); DBG("\t\trecv %02x\n", v); if (v != 0xff) break; + if (later(ao_time(), timeout)) { + printf ("wait block start timeout\n"); + return 0xff; + } } return v; } @@ -360,7 +477,9 @@ uint8_t ao_sdcard_read_block(uint32_t block, uint8_t *data) { uint8_t ret; + uint8_t start_block; uint8_t crc[2]; + int tries; ao_sdcard_lock(); if (!initialized) { @@ -376,25 +495,53 @@ ao_sdcard_read_block(uint32_t block, uint8_t *data) DBG("read block %d\n", block); if (sdtype != ao_sdtype_sd2block) block <<= 9; + ao_sdcard_get(); - ao_sdcard_select(); - ret = ao_sdcard_send_cmd(SDCARD_READ_BLOCK, block); - ao_sdcard_recv_reply(NULL, 0); - if (ret != SDCARD_STATUS_READY_STATE) - goto bail; + for (tries = 0; tries < 10; tries++) { + ao_sdcard_select(); - /* Wait for the data start block marker */ - if (ao_sdcard_wait_block_start() != SDCARD_DATA_START_BLOCK) { - ret = 0x3f; - goto bail; - } + ret = ao_sdcard_send_cmd(SDCARD_READ_BLOCK, block); + ao_sdcard_recv_reply(NULL, 0); + if (ret != SDCARD_STATUS_READY_STATE) { + uint16_t status; + WARN ("read block command failed %d status %02x\n", block, ret); + status = _ao_sdcard_send_status(); + WARN ("\tstatus now %04x\n", status); + goto bail; + } - ao_sdcard_recv(data, 512); - ao_sdcard_recv(crc, 2); -bail: - ao_sdcard_deselect(); + ao_sdcard_send_fixed(0xff, 1); + + /* Wait for the data start block marker */ + start_block = ao_sdcard_wait_block_start(); + if (start_block != SDCARD_DATA_START_BLOCK) { + WARN ("wait block start failed %02x\n", start_block); + ret = 0x3f; + goto bail; + } + + ao_sdcard_recv(data, 512); + ao_sdcard_recv(crc, 2); + bail: + ao_sdcard_deselect(); + if (ret == SDCARD_STATUS_READY_STATE) + break; + if (ret == SDCARD_STATUS_IDLE_STATE) { + ret = _ao_sdcard_reset(); + if (ret != SDCARD_STATUS_READY_STATE) + break; + } + } ao_sdcard_put(); ao_sdcard_unlock(); + +#if SDCARD_WARN + if (ret != SDCARD_STATUS_READY_STATE) + WARN("read failed\n"); + else if (tries) + WARN("took %d tries to read %d\n", tries + 1, block); +#endif + DBG("read %s\n", ret == SDCARD_STATUS_READY_STATE ? "success" : "failure"); return ret == SDCARD_STATUS_READY_STATE; } @@ -406,9 +553,12 @@ uint8_t ao_sdcard_write_block(uint32_t block, uint8_t *data) { uint8_t ret; - uint8_t response; - uint8_t start_block[2]; + uint8_t response[1]; + uint8_t start_block[8]; + uint16_t status; + static uint8_t check_data[512]; int i; + int tries; ao_sdcard_lock(); if (!initialized) { @@ -424,45 +574,64 @@ ao_sdcard_write_block(uint32_t block, uint8_t *data) DBG("write block %d\n", block); if (sdtype != ao_sdtype_sd2block) block <<= 9; - ao_sdcard_get(); - ao_sdcard_select(); - ret = ao_sdcard_send_cmd(SDCARD_WRITE_BLOCK, block); - ao_sdcard_recv_reply(NULL, 0); - if (ret != SDCARD_STATUS_READY_STATE) - goto bail; - - /* Write a pad byte followed by the data start block marker */ - start_block[0] = 0xff; - start_block[1] = SDCARD_DATA_START_BLOCK; - ao_sdcard_send(start_block, 2); - - /* Send the data */ - ao_sdcard_send(data, 512); - - /* Fake the CRC */ - ao_sdcard_send_fixed(0xff, 2); + ao_sdcard_get(); - /* See if the card liked the data */ - ao_sdcard_recv(&response, 1); - if ((response & SDCARD_DATA_RES_MASK) != SDCARD_DATA_RES_ACCEPTED) { - ret = 0x3f; - goto bail; - } + for (tries = 0; tries < 10; tries++) { + ao_sdcard_select(); + + ret = ao_sdcard_send_cmd(SDCARD_WRITE_BLOCK, block); + ao_sdcard_recv_reply(NULL, 0); + if (ret != SDCARD_STATUS_READY_STATE) + goto bail; + + /* Write a pad byte followed by the data start block marker */ + start_block[0] = 0xff; + start_block[1] = SDCARD_DATA_START_BLOCK; + ao_sdcard_send(start_block, 2); + + /* Send the data */ + ao_sdcard_send(data, 512); + + /* Fake the CRC */ + ao_sdcard_send_fixed(0xff, 2); + + /* See if the card liked the data */ + ao_sdcard_recv(response, sizeof (response)); + if ((response[0] & SDCARD_DATA_RES_MASK) != SDCARD_DATA_RES_ACCEPTED) { + int i; + WARN("Data not accepted, response"); + for (i = 0; i < sizeof (response); i++) + WARN(" %02x", response[i]); + WARN("\n"); + ret = 0x3f; + goto bail; + } - /* Wait for the bus to go idle (should be done with an interrupt) */ - for (i = 0; i < SDCARD_IDLE_TIMEOUT; i++) { - ao_sdcard_recv(&response, 1); - if (response == 0xff) + /* Wait for the bus to go idle (should be done with an interrupt?) */ + if (!ao_sdcard_wait_busy()) { + ret = 0x3f; + goto bail; + } + + /* Check the current status after the write completes */ + status = _ao_sdcard_send_status(); + if ((status & 0xff) != SDCARD_STATUS_READY_STATE) { + WARN ("send status after write %04x\n", status); + ret = status & 0xff; + goto bail; + } + bail: + ao_sdcard_deselect(); + DBG("write %s\n", ret == SDCARD_STATUS_READY_STATE ? "success" : "failure"); + if (ret == SDCARD_STATUS_READY_STATE) break; } - if (i == SDCARD_IDLE_TIMEOUT) - ret = 0x3f; -bail: - ao_sdcard_deselect(); ao_sdcard_put(); ao_sdcard_unlock(); - DBG("write %s\n", ret == SDCARD_STATUS_READY_STATE ? "success" : "failure"); + if (tries) + WARN("took %d tries to write %d\n", tries + 1, block); + return ret == SDCARD_STATUS_READY_STATE; } @@ -473,9 +642,17 @@ static void ao_sdcard_test_read(void) { int i; - if (!ao_sdcard_read_block(1, test_data)) { - printf ("read error\n"); + + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) return; + + for (i = 0; i < 100; i++) { + printf ("."); flush(); + if (!ao_sdcard_read_block(ao_cmd_lex_u32+i, test_data)) { + printf ("read error %d\n", i); + return; + } } printf ("data:"); for (i = 0; i < 18; i++) diff --git a/src/drivers/ao_sdcard.h b/src/drivers/ao_sdcard.h index 512439b4..e55a3dec 100644 --- a/src/drivers/ao_sdcard.h +++ b/src/drivers/ao_sdcard.h @@ -49,9 +49,14 @@ ao_sdcard_init(void); #define SDCARD_APP_SEND_OP_COMD 41 /* Status */ -#define SDCARD_STATUS_READY_STATE 0 -#define SDCARD_STATUS_IDLE_STATE 1 -#define SDCARD_STATUS_ILLEGAL_COMMAND 4 +#define SDCARD_STATUS_READY_STATE 0x00 +#define SDCARD_STATUS_IDLE_STATE 0x01 +#define SDCARD_STATUS_ERASE_RESET 0x02 +#define SDCARD_STATUS_ILLEGAL_COMMAND 0x04 +#define SDCARD_STATUS_COM_CRC_ERROR 0x08 +#define SDCARD_STATUS_ERASE_SEQ_ERROR 0x10 +#define SDCARD_STATUS_ADDRESS_ERROR 0x20 +#define SDCARD_STATUS_PARAMETER_ERROR 0x40 #define SDCARD_STATUS_TIMEOUT 0xff #define SDCARD_DATA_START_BLOCK 0xfe @@ -60,10 +65,10 @@ ao_sdcard_init(void); #define SDCARD_DATA_RES_MASK 0x1f #define SDCARD_DATA_RES_ACCEPTED 0x05 -#define SDCARD_CMD_TIMEOUT 100 -#define SDCARD_IDLE_WAIT 1000 -#define SDCARD_BLOCK_TIMEOUT 100 -#define SDCARD_IDLE_TIMEOUT 1000 +#define SDCARD_CMD_TIMEOUT AO_MS_TO_TICKS(100) +#define SDCARD_BUSY_TIMEOUT AO_MS_TO_TICKS(100) +#define SDCARD_IDLE_WAIT 10000 +#define SDCARD_BLOCK_TIMEOUT AO_MS_TO_TICKS(1000) enum ao_sdtype { ao_sdtype_unknown, -- cgit v1.2.3 From 14c63f94f36a95272d91695039abf54efb423a91 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 1 Apr 2013 02:10:14 -0700 Subject: altos: Add defines for the specific pins used for telegps SPI These aren't needed at this point, but who knows? Signed-off-by: Keith Packard --- src/telegps-v0.1/ao_pins.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/telegps-v0.1/ao_pins.h b/src/telegps-v0.1/ao_pins.h index eea050c9..5bea2681 100644 --- a/src/telegps-v0.1/ao_pins.h +++ b/src/telegps-v0.1/ao_pins.h @@ -79,6 +79,11 @@ #define SPI_1_PE13_PE14_PE15 0 #define SPI_1_OSPEEDR STM_OSPEEDR_10MHz +#define SPI_1_PORT (&stm_gpioa) +#define SPI_1_SCK_PIN 5 +#define SPI_1_MISO_PIN 6 +#define SPI_1_MOSI_PIN 7 + #define HAS_SPI_2 1 #define SPI_2_PB13_PB14_PB15 1 /* CC115L */ #define SPI_2_PD1_PD3_PD4 0 @@ -166,6 +171,10 @@ */ #define AO_SDCARD_SPI_BUS AO_SPI_1_PA5_PA6_PA7 +#define AO_SDCARD_SPI_PORT SPI_1_PORT +#define AO_SDCARD_SPI_SCK_PIN SPI_1_SCK_PIN +#define AO_SDCARD_SPI_MISO_PIN SPI_1_MISO_PIN +#define AO_SDCARD_SPI_MOSI_PIN SPI_1_MOSI_PIN #define AO_SDCARD_SPI_CS_PORT (&stm_gpioa) #define AO_SDCARD_SPI_CS_PIN 4 #define AO_SDCARD_SPI stm_spi1 -- cgit v1.2.3 From 985df526ec142258ef990d0b55b0a14e13c099b4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 1 Apr 2013 02:39:35 -0700 Subject: altos: Horrible kludge -- disable radio while talking with SD card The SD card really doesn't like the RFI generated by our enormous radio, so just lock the radio out while working with the card. Signed-off-by: Keith Packard --- src/drivers/ao_cc115l.c | 2 +- src/drivers/ao_sdcard.c | 11 ++++++++--- src/telegps-v0.1/ao_telegps.c | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_cc115l.c b/src/drivers/ao_cc115l.c index 9a4908b5..d6a938ac 100644 --- a/src/drivers/ao_cc115l.c +++ b/src/drivers/ao_cc115l.c @@ -23,7 +23,7 @@ #define AO_RADIO_MAX_SEND sizeof (struct ao_telemetry_generic) -static uint8_t ao_radio_mutex; +uint8_t ao_radio_mutex; static uint8_t ao_radio_fifo; /* fifo drained interrupt received */ static uint8_t ao_radio_done; /* tx done interrupt received */ diff --git a/src/drivers/ao_sdcard.c b/src/drivers/ao_sdcard.c index 6073677a..59ac9400 100644 --- a/src/drivers/ao_sdcard.c +++ b/src/drivers/ao_sdcard.c @@ -18,9 +18,11 @@ #include "ao.h" #include "ao_sdcard.h" -#define ao_sdcard_get_slow() ao_spi_get(AO_SDCARD_SPI_BUS, AO_SPI_SPEED_250kHz) -#define ao_sdcard_get() ao_spi_get(AO_SDCARD_SPI_BUS, AO_SPI_SPEED_FAST) -#define ao_sdcard_put() ao_spi_put(AO_SDCARD_SPI_BUS) +extern uint8_t ao_radio_mutex; + +#define ao_sdcard_get_slow() do { ao_mutex_get(&ao_radio_mutex); ao_spi_get(AO_SDCARD_SPI_BUS, AO_SPI_SPEED_250kHz); } while (0) +#define ao_sdcard_get() do { ao_mutex_get(&ao_radio_mutex); ao_spi_get(AO_SDCARD_SPI_BUS, AO_SPI_SPEED_FAST); } while (0) +#define ao_sdcard_put() do { ao_spi_put(AO_SDCARD_SPI_BUS); ao_mutex_put(&ao_radio_mutex); } while (0) #define ao_sdcard_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_SDCARD_SPI_BUS) #define ao_sdcard_send(d,l) ao_spi_send((d), (l), AO_SDCARD_SPI_BUS) #define ao_sdcard_recv(d,l) ao_spi_recv((d), (l), AO_SDCARD_SPI_BUS) @@ -686,6 +688,9 @@ static const struct ao_cmds ao_sdcard_cmds[] = { void ao_sdcard_init(void) { + stm_pupdr_set(AO_SDCARD_SPI_PORT, AO_SDCARD_SPI_SCK_PIN, STM_PUPDR_PULL_UP); + stm_pupdr_set(AO_SDCARD_SPI_PORT, AO_SDCARD_SPI_MISO_PIN, STM_PUPDR_PULL_UP); + stm_pupdr_set(AO_SDCARD_SPI_PORT, AO_SDCARD_SPI_MOSI_PIN, STM_PUPDR_PULL_UP); ao_spi_init_cs(AO_SDCARD_SPI_CS_PORT, (1 << AO_SDCARD_SPI_CS_PIN)); #if SDCARD_DEBUG ao_cmd_register(&ao_sdcard_cmds[0]); diff --git a/src/telegps-v0.1/ao_telegps.c b/src/telegps-v0.1/ao_telegps.c index 4620de3b..68116bfb 100644 --- a/src/telegps-v0.1/ao_telegps.c +++ b/src/telegps-v0.1/ao_telegps.c @@ -52,7 +52,7 @@ main(void) ao_fat_init(); ao_gps_init(); -// ao_gps_report_mega_init(); + ao_gps_report_mega_init(); ao_telemetry_init(); ao_telemetry_set_interval(AO_SEC_TO_TICKS(1)); -- cgit v1.2.3 From 96c32125a780ad6b39c015f4abbae07fead68582 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 2 Apr 2013 16:41:29 -0700 Subject: altos: Shorten SD initialization timeouts. This makes failure when no card is present much quicker. Signed-off-by: Keith Packard --- src/drivers/ao_sdcard.c | 18 +++++++++--------- src/drivers/ao_sdcard.h | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_sdcard.c b/src/drivers/ao_sdcard.c index 59ac9400..6314a30c 100644 --- a/src/drivers/ao_sdcard.c +++ b/src/drivers/ao_sdcard.c @@ -30,7 +30,7 @@ extern uint8_t ao_radio_mutex; #define ao_sdcard_deselect() ao_gpio_set(AO_SDCARD_SPI_CS_PORT,AO_SDCARD_SPI_CS_PIN,AO_SDCARD_SPI_CS,1) /* Include SD card commands */ -#define SDCARD_DEBUG 1 +#define SDCARD_DEBUG 0 /* Spew SD tracing */ #define SDCARD_TRACE 0 @@ -326,11 +326,11 @@ ao_sdcard_setup(void) ao_sdcard_send_fixed(0xff, 10); /* Reset the card and get it into SPI mode */ - for (i = 0; i < SDCARD_IDLE_WAIT; i++) { + for (i = 0; i < SDCARD_IDLE_RETRY; i++) { if (ao_sdcard_go_idle_state() == SDCARD_STATUS_IDLE_STATE) break; } - if (i == SDCARD_IDLE_WAIT) + if (i == SDCARD_IDLE_RETRY) goto bail; /* Figure out what kind of card we have */ @@ -346,14 +346,14 @@ ao_sdcard_setup(void) sdver2 = 1; } - for (i = 0; i < SDCARD_IDLE_WAIT; i++) { + for (i = 0; i < SDCARD_IDLE_RETRY; i++) { ret = ao_sdcard_app_send_op_cond(arg); if (ret != SDCARD_STATUS_IDLE_STATE) break; } if (ret != SDCARD_STATUS_READY_STATE) { /* MMC */ - for (i = 0; i < SDCARD_IDLE_WAIT; i++) { + for (i = 0; i < SDCARD_IDLE_RETRY; i++) { ret = ao_sdcard_send_op_cond(); if (ret != SDCARD_STATUS_IDLE_STATE) break; @@ -396,11 +396,11 @@ _ao_sdcard_reset(void) uint8_t ret; uint8_t response[10]; - for (i = 0; i < SDCARD_IDLE_WAIT; i++) { + for (i = 0; i < SDCARD_IDLE_RETRY; i++) { if (ao_sdcard_go_idle_state() == SDCARD_STATUS_IDLE_STATE) break; } - if (i == SDCARD_IDLE_WAIT) { + if (i == SDCARD_IDLE_RETRY) { ret = 0x3f; goto bail; } @@ -418,7 +418,7 @@ _ao_sdcard_reset(void) sdver2 = 1; } - for (i = 0; i < SDCARD_IDLE_WAIT; i++) { + for (i = 0; i < SDCARD_IDLE_RETRY; i++) { ret = ao_sdcard_app_send_op_cond(arg); if (ret != SDCARD_STATUS_IDLE_STATE) break; @@ -426,7 +426,7 @@ _ao_sdcard_reset(void) if (ret != SDCARD_STATUS_READY_STATE) { /* MMC */ - for (i = 0; i < SDCARD_IDLE_WAIT; i++) { + for (i = 0; i < SDCARD_IDLE_RETRY; i++) { ret = ao_sdcard_send_op_cond(); if (ret != SDCARD_STATUS_IDLE_STATE) break; diff --git a/src/drivers/ao_sdcard.h b/src/drivers/ao_sdcard.h index e55a3dec..0d1464b3 100644 --- a/src/drivers/ao_sdcard.h +++ b/src/drivers/ao_sdcard.h @@ -65,10 +65,10 @@ ao_sdcard_init(void); #define SDCARD_DATA_RES_MASK 0x1f #define SDCARD_DATA_RES_ACCEPTED 0x05 -#define SDCARD_CMD_TIMEOUT AO_MS_TO_TICKS(100) -#define SDCARD_BUSY_TIMEOUT AO_MS_TO_TICKS(100) -#define SDCARD_IDLE_WAIT 10000 -#define SDCARD_BLOCK_TIMEOUT AO_MS_TO_TICKS(1000) +#define SDCARD_CMD_TIMEOUT AO_MS_TO_TICKS(20) +#define SDCARD_BUSY_TIMEOUT AO_MS_TO_TICKS(20) +#define SDCARD_BLOCK_TIMEOUT AO_MS_TO_TICKS(200) +#define SDCARD_IDLE_RETRY 10 enum ao_sdtype { ao_sdtype_unknown, -- cgit v1.2.3 From 0cd203e418e73a1f11460425985b7575c2f0a76c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 2 Apr 2013 16:43:53 -0700 Subject: Set telegps USB id to 0025 It was accidentally using the same ID as megadongle... Signed-off-by: Keith Packard --- altoslib/AltosLib.java | 3 ++- altosuilib/AltosUSBDevice.java | 3 ++- src/telegps-v0.1/Makefile | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index 192da0a9..0b5475f7 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -91,8 +91,9 @@ public class AltosLib { public final static int product_telepyro =0x0012; public final static int product_megametrum = 0x0023; public final static int product_megadongle = 0x0024; + public final static int product_telegps = 0x0025; public final static int product_altusmetrum_min = 0x000a; - public final static int product_altusmetrum_max = 0x0024; + public final static int product_altusmetrum_max = 0x0025; public final static int product_any = 0x10000; public final static int product_basestation = 0x10000 + 1; diff --git a/altosuilib/AltosUSBDevice.java b/altosuilib/AltosUSBDevice.java index a5496597..5268927c 100644 --- a/altosuilib/AltosUSBDevice.java +++ b/altosuilib/AltosUSBDevice.java @@ -76,7 +76,8 @@ public class AltosUSBDevice extends altos_device implements AltosDevice { if (want_product == AltosUILib.product_altimeter) return matchProduct(AltosUILib.product_telemetrum) || - matchProduct(AltosUILib.product_megametrum); + matchProduct(AltosUILib.product_megametrum) || + matchProduct(AltosUILib.product_telegps); int have_product = getProduct(); diff --git a/src/telegps-v0.1/Makefile b/src/telegps-v0.1/Makefile index 1e551e15..aae37660 100644 --- a/src/telegps-v0.1/Makefile +++ b/src/telegps-v0.1/Makefile @@ -67,7 +67,7 @@ ALTOS_SRC = \ PRODUCT=TeleGPS-v0.1 PRODUCT_DEF=-DTELEGPS -IDPRODUCT=0x0024 +IDPRODUCT=0x0025 CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g -- cgit v1.2.3 From 0c0dc761095a5a77c87c3b4dcd1d42a4e79f6604 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 6 Apr 2013 23:48:36 -0700 Subject: altos: Try RDF mode for TX calibration Trying to get the radio to stop modulating the carrier when calibrating the radio, we'll try RDF mode which says no preamble or sync data. This might shift the frequency though? Signed-off-by: Keith Packard --- src/drivers/ao_cc115l.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/drivers/ao_cc115l.c b/src/drivers/ao_cc115l.c index d6a938ac..216432bd 100644 --- a/src/drivers/ao_cc115l.c +++ b/src/drivers/ao_cc115l.c @@ -638,7 +638,7 @@ ao_radio_test_cmd(void) #endif ao_radio_get(); ao_radio_set_len(0xff); - ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX | AO_RADIO_MODE_BITS_FIXED); + ao_radio_set_mode(AO_RADIO_MODE_RDF); ao_radio_strobe(CC115L_SFTX); ao_radio_pa_on(); ao_radio_strobe(CC115L_STX); -- cgit v1.2.3 From 28adf5541354715b185dbb45b28c97c7d9cf8bcd Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 8 Apr 2013 16:48:40 -0700 Subject: altos: Create telebt-v1.0 product. Remove old telebt products Signed-off-by: Keith Packard --- src/Makefile | 2 +- src/drivers/ao_btm.c | 2 +- src/product/Makefile.telebt | 97 ------------------------------------------- src/product/ao_telebt.c | 61 --------------------------- src/telebt-v0.0/.gitignore | 2 - src/telebt-v0.0/.sdcdbrc | 1 - src/telebt-v0.0/Makefile | 9 ---- src/telebt-v0.1/.gitignore | 2 - src/telebt-v0.1/.sdcdbrc | 2 - src/telebt-v0.1/Makefile | 21 ---------- src/telebt-v1.0/.gitignore | 2 + src/telebt-v1.0/.sdcdbrc | 2 + src/telebt-v1.0/Makefile | 96 ++++++++++++++++++++++++++++++++++++++++++ src/telebt-v1.0/ao_pins.h | 89 +++++++++++++++++++++++++++++++++++++++ src/telebt-v1.0/ao_telebt.c | 40 ++++++++++++++++++ src/teleshield-v0.1/ao_pins.h | 1 + 16 files changed, 232 insertions(+), 197 deletions(-) delete mode 100644 src/product/Makefile.telebt delete mode 100644 src/product/ao_telebt.c delete mode 100644 src/telebt-v0.0/.gitignore delete mode 100644 src/telebt-v0.0/.sdcdbrc delete mode 100644 src/telebt-v0.0/Makefile delete mode 100644 src/telebt-v0.1/.gitignore delete mode 100644 src/telebt-v0.1/.sdcdbrc delete mode 100644 src/telebt-v0.1/Makefile create mode 100644 src/telebt-v1.0/.gitignore create mode 100644 src/telebt-v1.0/.sdcdbrc create mode 100644 src/telebt-v1.0/Makefile create mode 100644 src/telebt-v1.0/ao_pins.h create mode 100644 src/telebt-v1.0/ao_telebt.c (limited to 'src') diff --git a/src/Makefile b/src/Makefile index 9e31e3ea..d91a235a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -18,7 +18,7 @@ SDCCDIRS=\ telemetrum-v1.2 telemetrum-v1.1 telemetrum-v1.0 \ teledongle-v0.2 teledongle-v0.1 \ telemini-v1.0 telenano-v0.1 \ - telebt-v0.0 telebt-v0.1 \ + telebt-v1.0 \ telemetrum-v0.1-sky telemetrum-v0.1-sirf \ telelaunch-v0.1 tidongle test \ teleterra-v0.2 teleshield-v0.1 \ diff --git a/src/drivers/ao_btm.c b/src/drivers/ao_btm.c index de1f31a3..3b6028a0 100644 --- a/src/drivers/ao_btm.c +++ b/src/drivers/ao_btm.c @@ -302,7 +302,7 @@ ao_btm(void) while (!ao_btm_connected) ao_sleep(&ao_btm_connected); while (ao_btm_connected) { - ao_led_for(AO_LED_GREEN, AO_MS_TO_TICKS(20)); + ao_led_for(AO_BT_LED, AO_MS_TO_TICKS(20)); ao_delay(AO_SEC_TO_TICKS(3)); } } diff --git a/src/product/Makefile.telebt b/src/product/Makefile.telebt deleted file mode 100644 index fd52cec4..00000000 --- a/src/product/Makefile.telebt +++ /dev/null @@ -1,97 +0,0 @@ -# -# TeleBT build file -# -# Define TELEBT_VER, TELEBT_DEF, TELEBT_INC and TELEBT_SRC -# and include this file - -vpath %.c ..:../core:../cc1111:../drivers:../product -vpath %.h ..:../core:../cc1111:../drivers:../product -vpath ao-make-product.5c ../util - -ifndef VERSION -include ../Version -endif - -INC = \ - ao.h \ - ao_pins.h \ - ao_arch.h \ - ao_arch_funcs.h \ - cc1111.h \ - ao_product.h \ - $(TELEBT_INC) - -CORE_SRC = \ - ao_cmd.c \ - ao_config.c \ - ao_gps_print.c \ - ao_monitor.c \ - ao_mutex.c \ - ao_panic.c \ - ao_state.c \ - ao_stdio.c \ - ao_task.c \ - ao_freq.c - -CC1111_SRC = \ - ao_dbg.c \ - ao_dma.c \ - ao_led.c \ - ao_packet.c \ - ao_packet_master.c \ - ao_radio.c \ - ao_romconfig.c \ - ao_serial.c \ - ao_string.c \ - ao_timer.c \ - ao_usb.c \ - _bp.c - -DRIVER_SRC = \ - ao_btm.c - -PRODUCT_SRC = \ - ao_telebt.c - -SRC = \ - $(CORE_SRC) \ - $(CC1111_SRC) \ - $(DRIVER_SRC) \ - $(PRODUCT_SRC) \ - $(TELEBT_SRC) - -PROGNAME = telebt-v$(TELEBT_VER) -PROG = $(PROGNAME)-$(VERSION).ihx -PRODUCT=TeleBT-v$(TELEBT_VER) -PRODUCT_DEF=-DTELEBT_V_$(TELEBT_DEF) -IDPRODUCT=0x000e - -include ../cc1111/Makefile.cc1111 - -NICKLE=nickle -CHECK_STACK=sh ../util/check-stack - -V=0 -# The user has explicitly enabled quiet compilation. -ifeq ($(V),0) -quiet = @printf " $1 $2 $@\n"; $($1) -endif -# Otherwise, print the full command line. -quiet ?= $($1) - -all: $(PROG) - -$(PROG): $(REL) Makefile - $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. - $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@ - -ao_product.h: ao-make-product.5c ../Version - $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ - -distclean: clean - -clean: clean-cc1111 - -install: - -uninstall: diff --git a/src/product/ao_telebt.c b/src/product/ao_telebt.c deleted file mode 100644 index 46c63418..00000000 --- a/src/product/ao_telebt.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include "ao.h" - -#if HAS_LOG -__code uint8_t ao_log_format = AO_LOG_FORMAT_NONE; /* until we actually log stuff */ -#endif - -void -main(void) -{ - ao_clock_init(); - - /* Turn on the LED until the system is stable */ - ao_led_init(LEDS_AVAILABLE); - ao_led_on(AO_LED_RED); - ao_timer_init(); -#if HAS_BEEP - ao_beep_init(); -#endif - ao_cmd_init(); -#if HAS_EEPROM - ao_spi_init(); - ao_storage_init(); -#endif - ao_usb_init(); - ao_monitor_init(); -#if HAS_LOG - ao_report_init(); -#endif - ao_radio_init(); - ao_packet_master_init(); - ao_btm_init(); -#if HAS_LOG - ao_log_single_init(); -#endif -#if HAS_DBG - ao_dbg_init(); -#endif -#if HAS_AES - ao_aes_init(); - ao_radio_cmac_init(); -#endif - ao_config_init(); - ao_start_scheduler(); -} diff --git a/src/telebt-v0.0/.gitignore b/src/telebt-v0.0/.gitignore deleted file mode 100644 index 1acfbfcc..00000000 --- a/src/telebt-v0.0/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -telebt-* -ao_product.h diff --git a/src/telebt-v0.0/.sdcdbrc b/src/telebt-v0.0/.sdcdbrc deleted file mode 100644 index 710b4a2f..00000000 --- a/src/telebt-v0.0/.sdcdbrc +++ /dev/null @@ -1 +0,0 @@ ---directory=.. diff --git a/src/telebt-v0.0/Makefile b/src/telebt-v0.0/Makefile deleted file mode 100644 index e89639ab..00000000 --- a/src/telebt-v0.0/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# TeleBT v0.0 build -# - -TELEBT_VER=0.0 -TELEBT_DEF=0_0 - -include ../product/Makefile.telebt - diff --git a/src/telebt-v0.1/.gitignore b/src/telebt-v0.1/.gitignore deleted file mode 100644 index 1acfbfcc..00000000 --- a/src/telebt-v0.1/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -telebt-* -ao_product.h diff --git a/src/telebt-v0.1/.sdcdbrc b/src/telebt-v0.1/.sdcdbrc deleted file mode 100644 index b9f6129c..00000000 --- a/src/telebt-v0.1/.sdcdbrc +++ /dev/null @@ -1,2 +0,0 @@ ---directory=../cc1111:../product:../core:../drivers:. - diff --git a/src/telebt-v0.1/Makefile b/src/telebt-v0.1/Makefile deleted file mode 100644 index 90cd3cac..00000000 --- a/src/telebt-v0.1/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# -# TeleBT v0.1 build -# - -TELEBT_VER=0.1 -TELEBT_DEF=0_1 - -TELEBT_INC = \ - ao_25lc1024.h - -TELEBT_SRC = \ - ao_beep.c \ - ao_log_single.c \ - ao_log_telem.c \ - ao_report.c \ - ao_spi.c \ - ao_storage.c \ - ao_m25.c - -include ../product/Makefile.telebt - diff --git a/src/telebt-v1.0/.gitignore b/src/telebt-v1.0/.gitignore new file mode 100644 index 00000000..1acfbfcc --- /dev/null +++ b/src/telebt-v1.0/.gitignore @@ -0,0 +1,2 @@ +telebt-* +ao_product.h diff --git a/src/telebt-v1.0/.sdcdbrc b/src/telebt-v1.0/.sdcdbrc new file mode 100644 index 00000000..b9f6129c --- /dev/null +++ b/src/telebt-v1.0/.sdcdbrc @@ -0,0 +1,2 @@ +--directory=../cc1111:../product:../core:../drivers:. + diff --git a/src/telebt-v1.0/Makefile b/src/telebt-v1.0/Makefile new file mode 100644 index 00000000..1a3f1c80 --- /dev/null +++ b/src/telebt-v1.0/Makefile @@ -0,0 +1,96 @@ +# +# TeleBT build file +# + +TELEBT_VER=1.0 +TELEBT_DEF=1_0 + +vpath %.c ..:../core:../cc1111:../drivers:../product +vpath %.h ..:../core:../cc1111:../drivers:../product +vpath ao-make-product.5c ../util + +ifndef VERSION +include ../Version +endif + +INC = \ + ao.h \ + ao_pins.h \ + ao_arch.h \ + ao_arch_funcs.h \ + cc1111.h \ + ao_product.h + +CORE_SRC = \ + ao_cmd.c \ + ao_config.c \ + ao_gps_print.c \ + ao_monitor.c \ + ao_mutex.c \ + ao_panic.c \ + ao_state.c \ + ao_stdio.c \ + ao_task.c \ + ao_freq.c + +CC1111_SRC = \ + ao_dbg.c \ + ao_dma.c \ + ao_led.c \ + ao_packet.c \ + ao_packet_master.c \ + ao_radio.c \ + ao_romconfig.c \ + ao_serial.c \ + ao_string.c \ + ao_timer.c \ + ao_usb.c \ + _bp.c + +DRIVER_SRC = \ + ao_btm.c + +PRODUCT_SRC = \ + ao_telebt.c + +SRC = \ + $(CORE_SRC) \ + $(CC1111_SRC) \ + $(DRIVER_SRC) \ + $(PRODUCT_SRC) + +PROGNAME = telebt-v$(TELEBT_VER) +PROG = $(PROGNAME)-$(VERSION).ihx +PRODUCT=TeleBT-v$(TELEBT_VER) +PRODUCT_DEF=-DTELEBT_V_$(TELEBT_DEF) +IDPRODUCT=0x000e + +include ../cc1111/Makefile.cc1111 + +NICKLE=nickle +CHECK_STACK=sh ../util/check-stack + +V=0 +# The user has explicitly enabled quiet compilation. +ifeq ($(V),0) +quiet = @printf " $1 $2 $@\n"; $($1) +endif +# Otherwise, print the full command line. +quiet ?= $($1) + +all: $(PROG) + +$(PROG): $(REL) Makefile + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. + $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@ + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean: clean + +clean: clean-cc1111 + +install: + +uninstall: diff --git a/src/telebt-v1.0/ao_pins.h b/src/telebt-v1.0/ao_pins.h new file mode 100644 index 00000000..b248521d --- /dev/null +++ b/src/telebt-v1.0/ao_pins.h @@ -0,0 +1,89 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define HAS_RADIO 1 +#define HAS_FLIGHT 0 +#define HAS_USB 1 +#define HAS_BEEP 0 +#define HAS_SERIAL_1 1 +#define HAS_SERIAL_1_ALT_1 1 +#define HAS_SERIAL_1_ALT_2 0 +#define HAS_SERIAL_1_HW_FLOW 1 +#define USE_SERIAL_1_STDIN 1 +#define DELAY_SERIAL_1_STDIN 1 +#define HAS_ADC 0 +#define HAS_DBG 1 +#define HAS_EEPROM 0 +#define HAS_LOG 0 +#define USE_INTERNAL_FLASH 0 +#define HAS_BTM 1 +#define DBG_ON_P1 1 +#define DBG_ON_P0 0 +#define PACKET_HAS_MASTER 1 +#define PACKET_HAS_SLAVE 0 +#define AO_LED_RED 1 +#define AO_LED_BLUE 2 +#define LEDS_AVAILABLE (AO_LED_RED|AO_LED_BLUE) +#define AO_MONITOR_LED AO_LED_RED +#define AO_BT_LED AO_LED_BLUE +#define BT_LINK_ON_P2 0 +#define BT_LINK_ON_P1 1 +#define BT_LINK_PIN_INDEX 7 +#define BT_LINK_PIN P1_7 +#define HAS_MONITOR 1 +#define LEGACY_MONITOR 0 + +#if DBG_ON_P1 + + #define DBG_CLOCK (1 << 4) /* mi0 */ + #define DBG_DATA (1 << 5) /* mo0 */ + #define DBG_RESET_N (1 << 3) /* c0 */ + + #define DBG_CLOCK_PIN (P1_4) + #define DBG_DATA_PIN (P1_5) + #define DBG_RESET_N_PIN (P1_3) + + #define DBG_PORT_NUM 1 + #define DBG_PORT P1 + #define DBG_PORT_SEL P1SEL + #define DBG_PORT_INP P1INP + #define DBG_PORT_DIR P1DIR + +#endif /* DBG_ON_P1 */ + +#if DBG_ON_P0 + + #define DBG_CLOCK (1 << 3) + #define DBG_DATA (1 << 4) + #define DBG_RESET_N (1 << 5) + + #define DBG_CLOCK_PIN (P0_3) + #define DBG_DATA_PIN (P0_4) + #define DBG_RESET_N_PIN (P0_5) + + #define DBG_PORT_NUM 0 + #define DBG_PORT P0 + #define DBG_PORT_SEL P0SEL + #define DBG_PORT_INP P0INP + #define DBG_PORT_DIR P0DIR + +#endif /* DBG_ON_P0 */ + +#endif /* _AO_PINS_H_ */ diff --git a/src/telebt-v1.0/ao_telebt.c b/src/telebt-v1.0/ao_telebt.c new file mode 100644 index 00000000..89434e7e --- /dev/null +++ b/src/telebt-v1.0/ao_telebt.c @@ -0,0 +1,40 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +void +main(void) +{ + ao_clock_init(); + + /* Turn on the LED until the system is stable */ + ao_led_init(LEDS_AVAILABLE); + ao_led_on(AO_LED_RED); + ao_timer_init(); + ao_cmd_init(); + ao_usb_init(); + ao_monitor_init(); + ao_radio_init(); + ao_packet_master_init(); + ao_btm_init(); +#if HAS_DBG + ao_dbg_init(); +#endif + ao_config_init(); + ao_start_scheduler(); +} diff --git a/src/teleshield-v0.1/ao_pins.h b/src/teleshield-v0.1/ao_pins.h index 888512b1..30239afc 100644 --- a/src/teleshield-v0.1/ao_pins.h +++ b/src/teleshield-v0.1/ao_pins.h @@ -46,6 +46,7 @@ #define AO_LED_RED 1 #define AO_LED_GREEN 2 #define AO_MONITOR_LED AO_LED_RED + #define AO_BT_LED AO_LED_GREEN #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) #define SPI_CS_ON_P1 1 #define SPI_CS_ON_P0 0 -- cgit v1.2.3 From 08eb1e3e1abb1aa4f5ea92b781a2ff8f480006c5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 8 Apr 2013 17:42:18 -0700 Subject: altos: Monitor battery voltage on telebt Signed-off-by: Keith Packard --- src/cc1111/ao_adc.c | 9 +++++++++ src/telebt-v1.0/Makefile | 1 + src/telebt-v1.0/ao_pins.h | 14 +++++++++++++- src/telebt-v1.0/ao_telebt.c | 1 + 4 files changed, 24 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/cc1111/ao_adc.c b/src/cc1111/ao_adc.c index bfdc418a..ed76179b 100644 --- a/src/cc1111/ao_adc.c +++ b/src/cc1111/ao_adc.c @@ -153,6 +153,15 @@ ao_adc_isr(void) __interrupt 1 #define GOT_ADC #endif /* TELEFIRE_V_0_1 */ +#ifdef TELEBT_V_1_0 + a = (uint8_t __xdata *) (&ao_data_ring[ao_data_head].adc.batt); + a[0] = ADCL; + a[1] = ADCH; + if (0) + ; +#define GOT_ADC +#endif + #ifndef GOT_ADC #error No known ADC configuration set #endif diff --git a/src/telebt-v1.0/Makefile b/src/telebt-v1.0/Makefile index 1a3f1c80..911a8b09 100644 --- a/src/telebt-v1.0/Makefile +++ b/src/telebt-v1.0/Makefile @@ -35,6 +35,7 @@ CORE_SRC = \ CC1111_SRC = \ ao_dbg.c \ + ao_adc.c \ ao_dma.c \ ao_led.c \ ao_packet.c \ diff --git a/src/telebt-v1.0/ao_pins.h b/src/telebt-v1.0/ao_pins.h index b248521d..9e47f3b8 100644 --- a/src/telebt-v1.0/ao_pins.h +++ b/src/telebt-v1.0/ao_pins.h @@ -28,7 +28,6 @@ #define HAS_SERIAL_1_HW_FLOW 1 #define USE_SERIAL_1_STDIN 1 #define DELAY_SERIAL_1_STDIN 1 -#define HAS_ADC 0 #define HAS_DBG 1 #define HAS_EEPROM 0 #define HAS_LOG 0 @@ -50,6 +49,19 @@ #define HAS_MONITOR 1 #define LEGACY_MONITOR 0 +#define HAS_ADC 1 +#define AO_PAD_ADC_BATT 0 +#define AO_ADC_PINS (1 << AO_PAD_ADC_BATT) + +struct ao_adc { + int16_t batt; +}; + +#define AO_ADC_DUMP(p) \ + printf ("tick: %5u batt %5d\n", \ + (p)->tick, \ + (p)->adc.batt) + #if DBG_ON_P1 #define DBG_CLOCK (1 << 4) /* mi0 */ diff --git a/src/telebt-v1.0/ao_telebt.c b/src/telebt-v1.0/ao_telebt.c index 89434e7e..4a50a9d4 100644 --- a/src/telebt-v1.0/ao_telebt.c +++ b/src/telebt-v1.0/ao_telebt.c @@ -31,6 +31,7 @@ main(void) ao_monitor_init(); ao_radio_init(); ao_packet_master_init(); + ao_adc_init(); ao_btm_init(); #if HAS_DBG ao_dbg_init(); -- cgit v1.2.3 From 398c02b945a58634c8932f07df2c2be8438da7d1 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 9 Apr 2013 00:28:05 -0700 Subject: altoslib/altosui: Carry receiver status around in AltosListenerState This moves the crc_errors into the new structure and adds a receiver battery voltage value there as well. Now the receiver status can be monitored separately from the flight status. That also means that code receiving state updates should be prepared to accept missing listener or flight state values. Signed-off-by: Keith Packard --- altoslib/AltosConfigData.java | 6 + altoslib/AltosFlightReader.java | 4 + altoslib/AltosGPS.java | 57 +++++----- altoslib/AltosIdleMonitor.java | 6 +- altoslib/AltosLink.java | 57 ++++++++++ altoslib/AltosListenerState.java | 28 +++++ altoslib/AltosRecord.java | 24 ++-- altoslib/AltosSensorMM.java | 122 +++++++++----------- altoslib/AltosSensorTM.java | 80 ++++++------- altoslib/AltosState.java | 21 +++- altoslib/AltosTelemetryReader.java | 8 ++ altoslib/Makefile.am | 1 + altosui/AltosAscent.java | 36 +++--- altosui/AltosCompanionInfo.java | 2 +- altosui/AltosDescent.java | 48 ++++---- altosui/AltosDisplayThread.java | 55 ++++----- altosui/AltosFlightDisplay.java | 2 +- altosui/AltosFlightStatus.java | 38 ++++--- altosui/AltosFlightStatusUpdate.java | 12 +- altosui/AltosFlightUI.java | 31 ++--- altosui/AltosGraphUI.java | 2 +- altosui/AltosIdleMonitorUI.java | 10 +- altosui/AltosInfoTable.java | 213 ++++++++++++++++++----------------- altosui/AltosLanded.java | 32 +++--- altosui/AltosPad.java | 199 +++++++++++++++++++------------- altosui/AltosSiteMap.java | 6 +- altosui/AltosSiteMapTile.java | 2 +- src/core/ao.h | 2 +- src/stm/ao_timer.c | 11 +- 29 files changed, 632 insertions(+), 483 deletions(-) create mode 100644 altoslib/AltosListenerState.java (limited to 'src') diff --git a/altoslib/AltosConfigData.java b/altoslib/AltosConfigData.java index 45b95646..57605607 100644 --- a/altoslib/AltosConfigData.java +++ b/altoslib/AltosConfigData.java @@ -135,6 +135,12 @@ public class AltosConfigData implements Iterable { } } + public boolean has_monitor_battery() { + if (product.startsWith("TeleBT")) + return true; + return false; + } + int[] parse_version(String v) { String[] parts = v.split("\\."); int r[] = new int[parts.length]; diff --git a/altoslib/AltosFlightReader.java b/altoslib/AltosFlightReader.java index 3039b4dc..34526658 100644 --- a/altoslib/AltosFlightReader.java +++ b/altoslib/AltosFlightReader.java @@ -45,4 +45,8 @@ public class AltosFlightReader { public boolean supports_telemetry(int telemetry) { return false; } public File backing_file() { return null; } + + public boolean has_monitor_battery() { return false; } + + public double monitor_battery() { return AltosRecord.MISSING; } } diff --git a/altoslib/AltosGPS.java b/altoslib/AltosGPS.java index 068d8c9c..f23842f3 100644 --- a/altoslib/AltosGPS.java +++ b/altoslib/AltosGPS.java @@ -217,33 +217,38 @@ public class AltosGPS { } public AltosGPS(AltosGPS old) { - nsat = old.nsat; - locked = old.locked; - connected = old.connected; - lat = old.lat; /* degrees (+N -S) */ - lon = old.lon; /* degrees (+E -W) */ - alt = old.alt; /* m */ - year = old.year; - month = old.month; - day = old.day; - hour = old.hour; - minute = old.minute; - second = old.second; - - ground_speed = old.ground_speed; /* m/s */ - course = old.course; /* degrees */ - climb_rate = old.climb_rate; /* m/s */ - hdop = old.hdop; /* unitless? */ - h_error = old.h_error; /* m */ - v_error = old.v_error; /* m */ - - if (old.cc_gps_sat != null) { - cc_gps_sat = new AltosGPSSat[old.cc_gps_sat.length]; - for (int i = 0; i < old.cc_gps_sat.length; i++) { - cc_gps_sat[i] = new AltosGPSSat(); - cc_gps_sat[i].svid = old.cc_gps_sat[i].svid; - cc_gps_sat[i].c_n0 = old.cc_gps_sat[i].c_n0; + if (old != null) { + nsat = old.nsat; + locked = old.locked; + connected = old.connected; + lat = old.lat; /* degrees (+N -S) */ + lon = old.lon; /* degrees (+E -W) */ + alt = old.alt; /* m */ + year = old.year; + month = old.month; + day = old.day; + hour = old.hour; + minute = old.minute; + second = old.second; + + ground_speed = old.ground_speed; /* m/s */ + course = old.course; /* degrees */ + climb_rate = old.climb_rate; /* m/s */ + hdop = old.hdop; /* unitless? */ + h_error = old.h_error; /* m */ + v_error = old.v_error; /* m */ + + if (old.cc_gps_sat != null) { + cc_gps_sat = new AltosGPSSat[old.cc_gps_sat.length]; + for (int i = 0; i < old.cc_gps_sat.length; i++) { + cc_gps_sat[i] = new AltosGPSSat(); + cc_gps_sat[i].svid = old.cc_gps_sat[i].svid; + cc_gps_sat[i].c_n0 = old.cc_gps_sat[i].c_n0; + } } + } else { + ClearGPSTime(); + cc_gps_sat = null; } } } diff --git a/altoslib/AltosIdleMonitor.java b/altoslib/AltosIdleMonitor.java index f2f75bbb..ec51b9c1 100644 --- a/altoslib/AltosIdleMonitor.java +++ b/altoslib/AltosIdleMonitor.java @@ -116,8 +116,10 @@ public class AltosIdleMonitor extends Thread { } finally { if (remote) { link.stop_remote(); - if (record != null) - record.rssi = AltosRSSI(); + if (record != null) { + record.rssi = link.rssi(); + record.monitor_battery = link.monitor_battery(); + } } else { if (record != null) record.rssi = 0; diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index 9eb25ce0..159ebfe1 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -364,6 +364,63 @@ public abstract class AltosLink implements Runnable { remote = false; } + public int rssi() throws TimeoutException, InterruptedException { + if (remote) + return 0; + printf("s\n"); + String line = get_reply_no_dialog(5000); + if (line == null) + throw new TimeoutException(); + String[] items = line.split("\\s+"); + if (items.length < 2) + return 0; + if (!items[0].equals("RSSI:")) + return 0; + int rssi = Integer.parseInt(items[1]); + return rssi; + } + + public String[] adc() throws TimeoutException, InterruptedException { + printf("a\n"); + for (;;) { + String line = get_reply_no_dialog(5000); + if (line == null) { + throw new TimeoutException(); + } + if (!line.startsWith("tick:")) + continue; + String[] items = line.split("\\s+"); + return items; + } + } + + public boolean has_monitor_battery() { + return config_data.has_monitor_battery(); + } + + public double monitor_battery() { + int monitor_batt = AltosRecord.MISSING; + + if (config_data.has_monitor_battery()) { + try { + String[] items = adc(); + for (int i = 0; i < items.length;) { + if (items[i].equals("batt")) { + monitor_batt = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + i++; + } + } catch (InterruptedException ie) { + } catch (TimeoutException te) { + } + } + if (monitor_batt == AltosRecord.MISSING) + return AltosRecord.MISSING; + return AltosConvert.cc_battery_to_voltage(monitor_batt); + } + public AltosLink() { callsign = ""; } diff --git a/altoslib/AltosListenerState.java b/altoslib/AltosListenerState.java new file mode 100644 index 00000000..2fb4673e --- /dev/null +++ b/altoslib/AltosListenerState.java @@ -0,0 +1,28 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + +public class AltosListenerState { + public int crc_errors; + public double battery; + + public AltosListenerState() { + crc_errors = 0; + battery = AltosRecord.MISSING; + } +} diff --git a/altoslib/AltosRecord.java b/altoslib/AltosRecord.java index f8c44cc5..7046b9f1 100644 --- a/altoslib/AltosRecord.java +++ b/altoslib/AltosRecord.java @@ -17,7 +17,7 @@ package org.altusmetrum.altoslib_1; -public abstract class AltosRecord implements Comparable , Cloneable { +public class AltosRecord implements Comparable , Cloneable { public static final int seen_flight = 1; public static final int seen_sensor = 2; @@ -75,15 +75,17 @@ public abstract class AltosRecord implements Comparable , Cloneable * temperature: °C */ - abstract public double pressure(); - abstract public double ground_pressure(); - abstract public double acceleration(); + public double pressure() { return MISSING; } + public double ground_pressure() { return MISSING; } + public double acceleration() { return MISSING; } public double altitude() { double p = pressure(); - if (p == MISSING) + if (p == MISSING) { + System.out.printf ("altitude missing\n"); return MISSING; + } return AltosConvert.pressure_to_altitude(p); } @@ -126,7 +128,11 @@ public abstract class AltosRecord implements Comparable , Cloneable return tick - o.tick; } - abstract public AltosRecord clone(); + public AltosRecord clone() { + AltosRecord n = new AltosRecord(); + n.copy(this); + return n; + } public void copy(AltosRecord old) { seen = old.seen; @@ -150,13 +156,13 @@ public abstract class AltosRecord implements Comparable , Cloneable seen = 0; version = 0; callsign = "N0CALL"; - serial = 0; - flight = 0; + serial = MISSING; + flight = MISSING; rssi = 0; status = 0; state = AltosLib.ao_flight_startup; tick = 0; - gps = new AltosGPS(); + gps = null; new_gps = false; companion = null; diff --git a/altoslib/AltosSensorMM.java b/altoslib/AltosSensorMM.java index 8372d047..6d1b61c0 100644 --- a/altoslib/AltosSensorMM.java +++ b/altoslib/AltosSensorMM.java @@ -28,75 +28,65 @@ class AltosSensorMM { int accel_ref; public AltosSensorMM(AltosLink link) throws InterruptedException, TimeoutException { - link.printf("a\n"); - for (;;) { - String line = link.get_reply_no_dialog(5000); - if (line == null) { - throw new TimeoutException(); + String[] items = link.adc(); + sense = new int[6]; + for (int i = 0; i < items.length;) { + if (items[i].equals("tick:")) { + tick = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("0:")) { + sense[0] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("1:")) { + sense[1] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("2:")) { + sense[2] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("3:")) { + sense[3] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("4:")) { + sense[4] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("5:")) { + sense[5] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("6:")) { + v_batt = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("7:")) { + v_pyro = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("8:")) { + accel = Integer.parseInt(items[i+1]); + i += 2; + continue; } - if (!line.startsWith("tick:")) + if (items[i].equals("9:")) { + accel_ref = Integer.parseInt(items[i+1]); + i += 2; continue; - String[] items = line.split("\\s+"); - sense = new int[6]; - for (int i = 0; i < items.length;) { - if (items[i].equals("tick:")) { - tick = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("0:")) { - sense[0] = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("1:")) { - sense[1] = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("2:")) { - sense[2] = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("3:")) { - sense[3] = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("4:")) { - sense[4] = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("5:")) { - sense[5] = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("6:")) { - v_batt = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("7:")) { - v_pyro = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("8:")) { - accel = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("9:")) { - accel_ref = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - i++; } - break; + i++; } } } diff --git a/altoslib/AltosSensorTM.java b/altoslib/AltosSensorTM.java index f5fa83a5..754dc5bb 100644 --- a/altoslib/AltosSensorTM.java +++ b/altoslib/AltosSensorTM.java @@ -23,54 +23,44 @@ class AltosSensorTM extends AltosRecordTM { public AltosSensorTM(AltosLink link, AltosConfigData config_data) throws InterruptedException, TimeoutException { super(); - link.printf("a\n"); - for (;;) { - String line = link.get_reply_no_dialog(5000); - if (line == null) { - throw new TimeoutException(); + String[] items = link.adc(); + for (int i = 0; i < items.length;) { + if (items[i].equals("tick:")) { + tick = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("accel:")) { + accel = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("pres:")) { + pres = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("temp:")) { + temp = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("batt:")) { + batt = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("drogue:")) { + drogue = Integer.parseInt(items[i+1]); + i += 2; + continue; } - if (!line.startsWith("tick:")) + if (items[i].equals("main:")) { + main = Integer.parseInt(items[i+1]); + i += 2; continue; - String[] items = line.split("\\s+"); - for (int i = 0; i < items.length;) { - if (items[i].equals("tick:")) { - tick = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("accel:")) { - accel = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("pres:")) { - pres = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("temp:")) { - temp = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("batt:")) { - batt = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("drogue:")) { - drogue = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("main:")) { - main = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - i++; } - break; + i++; } ground_accel = config_data.accel_cal_plus; ground_pres = pres; diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index 8a3bbd4c..f1bcb1c1 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -155,30 +155,41 @@ public class AltosState { /* compute barometric speed */ double height_change = height - prev_state.height; + + double prev_baro_speed = prev_state.baro_speed; + if (prev_baro_speed == AltosRecord.MISSING) + prev_baro_speed = 0; + if (time_change > 0) - baro_speed = (prev_state.baro_speed * 3 + (height_change / time_change)) / 4.0; + baro_speed = (prev_baro_speed * 3 + (height_change / time_change)) / 4.0; else baro_speed = prev_state.baro_speed; + double prev_accel_speed = prev_state.accel_speed; + + if (prev_accel_speed == AltosRecord.MISSING) + prev_accel_speed = 0; + if (acceleration == AltosRecord.MISSING) { /* Fill in mising acceleration value */ accel_speed = baro_speed; - if (time_change > 0) - acceleration = (accel_speed - prev_state.accel_speed) / time_change; + + if (time_change > 0 && accel_speed != AltosRecord.MISSING) + acceleration = (accel_speed - prev_accel_speed) / time_change; else acceleration = prev_state.acceleration; } else { /* compute accelerometer speed */ - accel_speed = prev_state.accel_speed + acceleration * time_change; + accel_speed = prev_accel_speed + acceleration * time_change; } } - } else { npad = 0; ngps = 0; gps = null; baro_speed = AltosRecord.MISSING; accel_speed = AltosRecord.MISSING; + pad_alt = AltosRecord.MISSING; max_baro_speed = 0; max_accel_speed = 0; max_height = 0; diff --git a/altoslib/AltosTelemetryReader.java b/altoslib/AltosTelemetryReader.java index f365b821..b4293c73 100644 --- a/altoslib/AltosTelemetryReader.java +++ b/altoslib/AltosTelemetryReader.java @@ -107,6 +107,14 @@ public class AltosTelemetryReader extends AltosFlightReader { return log.file(); } + public boolean has_monitor_battery() { + return link.has_monitor_battery(); + } + + public double monitor_battery() { + return link.monitor_battery(); + } + public AltosTelemetryReader (AltosLink in_link) throws IOException, InterruptedException, TimeoutException { link = in_link; diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 8e5701ad..30a9d954 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -37,6 +37,7 @@ altoslib_JAVA = \ AltosIMUQuery.java \ AltosLine.java \ AltosLink.java \ + AltosListenerState.java \ AltosLog.java \ AltosMs5607.java \ AltosMs5607Query.java \ diff --git a/altosui/AltosAscent.java b/altosui/AltosAscent.java index 80a5b759..4da4d591 100644 --- a/altosui/AltosAscent.java +++ b/altosui/AltosAscent.java @@ -42,7 +42,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { label.setVisible(false); } - void show(AltosState state, int crc_errors) {} + void show(AltosState state, AltosListenerState listener_state) {} void show(String s) { show(); @@ -107,7 +107,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { public class AscentValue { JLabel label; JTextField value; - void show(AltosState state, int crc_errors) {} + void show(AltosState state, AltosListenerState listener_state) {} void reset() { value.setText(""); @@ -174,7 +174,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { JTextField max_value; double max; - void show(AltosState state, int crc_errors) {} + void show(AltosState state, AltosListenerState listener_state) {} void reset() { value.setText(""); @@ -239,7 +239,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { class Height extends AscentValueHold { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { show(AltosConvert.height, state.height); } public Height (GridBagLayout layout, int y) { @@ -250,7 +250,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { Height height; class Speed extends AscentValueHold { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { double speed = state.accel_speed; if (!state.ascent) speed = state.baro_speed; @@ -264,7 +264,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { Speed speed; class Accel extends AscentValueHold { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { show(AltosConvert.accel, state.acceleration); } public Accel (GridBagLayout layout, int y) { @@ -286,7 +286,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { } class Apogee extends AscentStatus { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { show("%4.2f V", state.drogue_sense); lights.set(state.drogue_sense > 3.2); } @@ -298,7 +298,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { Apogee apogee; class Main extends AscentStatus { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { show("%4.2f V", state.main_sense); lights.set(state.main_sense > 3.2); } @@ -310,7 +310,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { Main main; class Lat extends AscentValue { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { if (state.gps != null) show(pos(state.gps.lat,"N", "S")); else @@ -324,7 +324,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { Lat lat; class Lon extends AscentValue { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { if (state.gps != null) show(pos(state.gps.lon,"E", "W")); else @@ -359,25 +359,25 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { accel.set_font(); } - public void show(AltosState state, int crc_errors) { + public void show(AltosState state, AltosListenerState listener_state) { if (state.gps != null && state.gps.connected) { - lat.show(state, crc_errors); - lon.show(state, crc_errors); + lat.show(state, listener_state); + lon.show(state, listener_state); } else { lat.hide(); lon.hide(); } - height.show(state, crc_errors); + height.show(state, listener_state); if (state.main_sense != AltosRecord.MISSING) - main.show(state, crc_errors); + main.show(state, listener_state); else main.hide(); if (state.drogue_sense != AltosRecord.MISSING) - apogee.show(state, crc_errors); + apogee.show(state, listener_state); else apogee.hide(); - speed.show(state, crc_errors); - accel.show(state, crc_errors); + speed.show(state, listener_state); + accel.show(state, listener_state); } public void labels(GridBagLayout layout, int y) { diff --git a/altosui/AltosCompanionInfo.java b/altosui/AltosCompanionInfo.java index 7dd36aec..ebe1d1f9 100644 --- a/altosui/AltosCompanionInfo.java +++ b/altosui/AltosCompanionInfo.java @@ -83,7 +83,7 @@ public class AltosCompanionInfo extends JTable { } } - public void show(AltosState state, int crc_errors) { + public void show(AltosState state, AltosListenerState listener_state) { if (state == null) return; if (state.data.companion != null) diff --git a/altosui/AltosDescent.java b/altosui/AltosDescent.java index 9838f46b..29d33ddc 100644 --- a/altosui/AltosDescent.java +++ b/altosui/AltosDescent.java @@ -29,7 +29,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { JTextField value; AltosLights lights; - abstract void show(AltosState state, int crc_errors); + abstract void show(AltosState state, AltosListenerState listener_state); void show() { label.setVisible(true); @@ -108,7 +108,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { value.setText(""); } - abstract void show(AltosState state, int crc_errors); + abstract void show(AltosState state, AltosListenerState listener_state); void show() { label.setVisible(true); @@ -192,7 +192,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { value2.setFont(Altos.value_font); } - abstract void show(AltosState state, int crc_errors); + abstract void show(AltosState state, AltosListenerState listener_state); void show(String v1, String v2) { show(); @@ -244,7 +244,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { } class Height extends DescentValue { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { show(AltosConvert.height, state.height); } public Height (GridBagLayout layout, int x, int y) { @@ -255,7 +255,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { Height height; class Speed extends DescentValue { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { double speed = state.accel_speed; if (!state.ascent) speed = state.baro_speed; @@ -280,7 +280,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { } class Lat extends DescentValue { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { if (state.gps != null && state.gps.connected) show(pos(state.gps.lat,"N", "S")); else @@ -294,7 +294,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { Lat lat; class Lon extends DescentValue { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { if (state.gps != null && state.gps.connected) show(pos(state.gps.lon,"W", "E")); else @@ -308,7 +308,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { Lon lon; class Distance extends DescentValue { - void show(AltosState state, int crc_errors) { + void show(AltosState state, AltosListenerState listener_state) { if (state.from_pad != null) show(AltosConvert.distance, state.from_pad.distance); else @@ -324,7 +324,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { class Apogee extends DescentStatus { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { show("%4.2f V", state.drogue_sense); lights.set(state.drogue_sense > 3.2); } @@ -336,7 +336,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { Apogee apogee; class Main extends DescentStatus { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { show("%4.2f V", state.main_sense); lights.set(state.main_sense > 3.2); } @@ -348,7 +348,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { Main main; class Bearing extends DescentDualValue { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { if (state.from_pad != null) { show( String.format("%3.0f°", state.from_pad.bearing), state.from_pad.bearing_words( @@ -365,7 +365,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { Bearing bearing; class Range extends DescentValue { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { show(AltosConvert.distance, state.range); } public Range (GridBagLayout layout, int x, int y) { @@ -376,7 +376,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { Range range; class Elevation extends DescentValue { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { show("%3.0f°", state.elevation); } public Elevation (GridBagLayout layout, int x, int y) { @@ -412,16 +412,16 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { apogee.set_font(); } - public void show(AltosState state, int crc_errors) { - height.show(state, crc_errors); - speed.show(state, crc_errors); + public void show(AltosState state, AltosListenerState listener_state) { + height.show(state, listener_state); + speed.show(state, listener_state); if (state.gps != null && state.gps.connected) { - bearing.show(state, crc_errors); - range.show(state, crc_errors); - distance.show(state, crc_errors); - elevation.show(state, crc_errors); - lat.show(state, crc_errors); - lon.show(state, crc_errors); + bearing.show(state, listener_state); + range.show(state, listener_state); + distance.show(state, listener_state); + elevation.show(state, listener_state); + lat.show(state, listener_state); + lon.show(state, listener_state); } else { bearing.hide(); range.hide(); @@ -431,11 +431,11 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { lon.hide(); } if (state.main_sense != AltosRecord.MISSING) - main.show(state, crc_errors); + main.show(state, listener_state); else main.hide(); if (state.drogue_sense != AltosRecord.MISSING) - apogee.show(state, crc_errors); + apogee.show(state, listener_state); else apogee.hide(); } diff --git a/altosui/AltosDisplayThread.java b/altosui/AltosDisplayThread.java index 6f8aa9ee..095bed99 100644 --- a/altosui/AltosDisplayThread.java +++ b/altosui/AltosDisplayThread.java @@ -29,21 +29,17 @@ public class AltosDisplayThread extends Thread { IdleThread idle_thread; AltosVoice voice; AltosFlightReader reader; - int crc_errors; + AltosState old_state, state; + AltosListenerState listener_state; AltosFlightDisplay display; - void show_internal(AltosState state, int crc_errors) { - if (state != null) - display.show(state, crc_errors); - } - - void show_safely(AltosState in_state, int in_crc_errors) { - final AltosState state = in_state; - final int crc_errors = in_crc_errors; + synchronized void show_safely() { + final AltosState my_state = state; + final AltosListenerState my_listener_state = listener_state; Runnable r = new Runnable() { public void run() { try { - show_internal(state, crc_errors); + display.show(my_state, my_listener_state); } catch (Exception ex) { } } @@ -73,7 +69,6 @@ public class AltosDisplayThread extends Thread { class IdleThread extends Thread { boolean started; - private AltosState state; int reported_landing; int report_interval; long report_time; @@ -129,7 +124,7 @@ public class AltosDisplayThread extends Thread { ++reported_landing; if (state.state != Altos.ao_flight_landed) { state.state = Altos.ao_flight_landed; - show_safely(state, 0); + show_safely(); } } } @@ -145,6 +140,10 @@ public class AltosDisplayThread extends Thread { public void run () { try { for (;;) { + if (reader.has_monitor_battery()) { + listener_state.battery = reader.monitor_battery(); + show_safely(); + } set_report_time(); for (;;) { voice.drain(); @@ -155,6 +154,7 @@ public class AltosDisplayThread extends Thread { wait(sleep_time); } } + report(false); } } catch (InterruptedException ie) { @@ -164,18 +164,7 @@ public class AltosDisplayThread extends Thread { } } - public synchronized void notice(AltosState new_state, boolean spoken) { - AltosState old_state = state; - state = new_state; - if (!started && state.state > Altos.ao_flight_pad) { - started = true; - start(); - } - - if (state.state < Altos.ao_flight_drogue) - report_interval = 10000; - else - report_interval = 20000; + public synchronized void notice(boolean spoken) { if (old_state != null && old_state.state != state.state) { report_time = now(); this.notify(); @@ -184,13 +173,12 @@ public class AltosDisplayThread extends Thread { } public IdleThread() { - state = null; reported_landing = 0; report_interval = 10000; } } - boolean tell(AltosState state, AltosState old_state) { + synchronized boolean tell() { boolean ret = false; if (old_state == null || old_state.state != state.state) { voice.speak(state.data.state()); @@ -222,12 +210,10 @@ public class AltosDisplayThread extends Thread { public void run() { boolean interrupted = false; - //String line; - AltosState state = null; - AltosState old_state = null; boolean told; idle_thread = new IdleThread(); + idle_thread.start(); try { for (;;) { @@ -238,14 +224,14 @@ public class AltosDisplayThread extends Thread { old_state = state; state = new AltosState(record, state); reader.update(state); - show_safely(state, crc_errors); - told = tell(state, old_state); - idle_thread.notice(state, told); + show_safely(); + told = tell(); + idle_thread.notice(told); } catch (ParseException pp) { System.out.printf("Parse error: %d \"%s\"\n", pp.getErrorOffset(), pp.getMessage()); } catch (AltosCRCException ce) { - ++crc_errors; - show_safely(state, crc_errors); + ++listener_state.crc_errors; + show_safely(); } } } catch (InterruptedException ee) { @@ -264,6 +250,7 @@ public class AltosDisplayThread extends Thread { } public AltosDisplayThread(Frame in_parent, AltosVoice in_voice, AltosFlightDisplay in_display, AltosFlightReader in_reader) { + listener_state = new AltosListenerState(); parent = in_parent; voice = in_voice; display = in_display; diff --git a/altosui/AltosFlightDisplay.java b/altosui/AltosFlightDisplay.java index d1ed7d2f..4f4c158e 100644 --- a/altosui/AltosFlightDisplay.java +++ b/altosui/AltosFlightDisplay.java @@ -22,7 +22,7 @@ import org.altusmetrum.altoslib_1.*; public interface AltosFlightDisplay { void reset(); - void show(AltosState state, int crc_errors); + void show(AltosState state, AltosListenerState listener_state); void set_font(); } diff --git a/altosui/AltosFlightStatus.java b/altosui/AltosFlightStatus.java index 20539a9f..d2910414 100644 --- a/altosui/AltosFlightStatus.java +++ b/altosui/AltosFlightStatus.java @@ -28,7 +28,7 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay JLabel label; JTextField value; - void show(AltosState state, int crc_errors) {} + void show(AltosState state, AltosListenerState listener_state) {} void reset() { value.setText(""); @@ -64,7 +64,7 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay } class Call extends FlightValue { - void show(AltosState state, int crc_errors) { + void show(AltosState state, AltosListenerState listener_state) { value.setText(state.data.callsign); } public Call (GridBagLayout layout, int x) { @@ -75,8 +75,11 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay Call call; class Serial extends FlightValue { - void show(AltosState state, int crc_errors) { - value.setText(String.format("%d", state.data.serial)); + void show(AltosState state, AltosListenerState listener_state) { + if (state.data.serial == AltosRecord.MISSING) + value.setText("none"); + else + value.setText(String.format("%d", state.data.serial)); } public Serial (GridBagLayout layout, int x) { super (layout, x, "Serial"); @@ -86,8 +89,11 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay Serial serial; class Flight extends FlightValue { - void show(AltosState state, int crc_errors) { - value.setText(String.format("%d", state.data.flight)); + void show(AltosState state, AltosListenerState listener_state) { + if (state.data.flight == AltosRecord.MISSING) + value.setText("none"); + else + value.setText(String.format("%d", state.data.flight)); } public Flight (GridBagLayout layout, int x) { super (layout, x, "Flight"); @@ -97,7 +103,7 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay Flight flight; class FlightState extends FlightValue { - void show(AltosState state, int crc_errors) { + void show(AltosState state, AltosListenerState listener_state) { value.setText(state.data.state()); } public FlightState (GridBagLayout layout, int x) { @@ -108,7 +114,7 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay FlightState flight_state; class RSSI extends FlightValue { - void show(AltosState state, int crc_errors) { + void show(AltosState state, AltosListenerState listener_state) { value.setText(String.format("%d", state.data.rssi)); } public RSSI (GridBagLayout layout, int x) { @@ -119,7 +125,7 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay RSSI rssi; class LastPacket extends FlightValue { - void show(AltosState state, int crc_errors) { + void show(AltosState state, AltosListenerState listener_state) { long secs = (System.currentTimeMillis() - state.report_time + 500) / 1000; value.setText(String.format("%d", secs)); } @@ -148,13 +154,13 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay last_packet.set_font(); } - public void show (AltosState state, int crc_errors) { - call.show(state, crc_errors); - serial.show(state, crc_errors); - flight.show(state, crc_errors); - flight_state.show(state, crc_errors); - rssi.show(state, crc_errors); - last_packet.show(state, crc_errors); + public void show (AltosState state, AltosListenerState listener_state) { + call.show(state, listener_state); + serial.show(state, listener_state); + flight.show(state, listener_state); + flight_state.show(state, listener_state); + rssi.show(state, listener_state); + last_packet.show(state, listener_state); } public int height() { diff --git a/altosui/AltosFlightStatusUpdate.java b/altosui/AltosFlightStatusUpdate.java index bf679b85..962a08f7 100644 --- a/altosui/AltosFlightStatusUpdate.java +++ b/altosui/AltosFlightStatusUpdate.java @@ -22,12 +22,16 @@ import org.altusmetrum.altoslib_1.*; public class AltosFlightStatusUpdate implements ActionListener { - public AltosState saved_state; - AltosFlightStatus flightStatus; + public AltosState saved_state; + public AltosListenerState saved_listener_state; + AltosFlightStatus flightStatus; public void actionPerformed (ActionEvent e) { - if (saved_state != null) - flightStatus.show(saved_state, 0); + if (saved_state != null) { + if (saved_listener_state == null) + saved_listener_state = new AltosListenerState(); + flightStatus.show(saved_state, saved_listener_state); + } } public AltosFlightStatusUpdate (AltosFlightStatus in_flightStatus) { diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index c04a4357..6b258f2e 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -98,11 +98,15 @@ public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, A AltosFlightStatusUpdate status_update; - public void show(AltosState state, int crc_errors) { + public void show(AltosState state, AltosListenerState listener_state) { status_update.saved_state = state; - JComponent tab = which_tab(state); - try { - pad.show(state, crc_errors); + + if (state == null) { + System.out.printf ("no state provided\n"); + state = new AltosState(new AltosRecord()); + } + + pad.show(state, listener_state); if (state.state != Altos.ao_flight_startup) { if (!has_state) { @@ -114,25 +118,26 @@ public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, A } } - ascent.show(state, crc_errors); - descent.show(state, crc_errors); - landed.show(state, crc_errors); + ascent.show(state, listener_state); + descent.show(state, listener_state); + landed.show(state, listener_state); + JComponent tab = which_tab(state); if (tab != cur_tab) { if (cur_tab == pane.getSelectedComponent()) { pane.setSelectedComponent(tab); } cur_tab = tab; } - flightStatus.show(state, crc_errors); - flightInfo.show(state, crc_errors); + flightStatus.show(state, listener_state); + flightInfo.show(state, listener_state); if (state.data.companion != null) { if (!has_companion) { pane.add("Companion", companion); has_companion= true; } - companion.show(state, crc_errors); + companion.show(state, listener_state); } else { if (has_companion) { pane.remove(companion); @@ -144,17 +149,13 @@ public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, A pane.add("Site Map", sitemap); has_map = true; } - sitemap.show(state, crc_errors); + sitemap.show(state, listener_state); } else { if (has_map) { pane.remove(sitemap); has_map = false; } } - } catch (Exception e) { - System.out.print("Show exception " + e + "\n"); - e.printStackTrace(); - } } public void set_exit_on_close() { diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index f6e57e7e..d8b8f6dd 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -35,7 +35,7 @@ public class AltosGraphUI extends AltosUIFrame if (state.gps != null && state.gps.locked && state.gps.nsat >= 4) { if (map == null) map = new AltosSiteMap(); - map.show(state, 0); + map.show(state, null); has_gps = true; } } diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index 8c883eeb..1ef30f0a 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -63,12 +63,12 @@ public class AltosIdleMonitorUI extends AltosUIFrame implements AltosFlightDispl AltosFlightStatusUpdate status_update; - public void show(AltosState state, int crc_errors) { + public void show(AltosState state, AltosListenerState listener_state) { status_update.saved_state = state; try { - pad.show(state, crc_errors); - flightStatus.show(state, crc_errors); - flightInfo.show(state, crc_errors); + pad.show(state, listener_state); + flightStatus.show(state, listener_state); + flightInfo.show(state, listener_state); } catch (Exception e) { System.out.print("Show exception" + e); } @@ -77,7 +77,7 @@ public class AltosIdleMonitorUI extends AltosUIFrame implements AltosFlightDispl public void update(final AltosState state) { Runnable r = new Runnable() { public void run() { - show(state, 0); + show(state, null); } }; SwingUtilities.invokeLater(r); diff --git a/altosui/AltosInfoTable.java b/altosui/AltosInfoTable.java index 1dce6daf..3d16faf2 100644 --- a/altosui/AltosInfoTable.java +++ b/altosui/AltosInfoTable.java @@ -104,111 +104,118 @@ public class AltosInfoTable extends JTable { model.clear(); } - public void show(AltosState state, int crc_errors) { - if (state == null) - return; + public void show(AltosState state, AltosListenerState listener_state) { info_reset(); - if (state.altitude != AltosRecord.MISSING) - info_add_row(0, "Altitude", "%6.0f m", state.altitude); - if (state.ground_altitude != AltosRecord.MISSING) - info_add_row(0, "Pad altitude", "%6.0f m", state.ground_altitude); - if (state.height != AltosRecord.MISSING) - info_add_row(0, "Height", "%6.0f m", state.height); - if (state.max_height != AltosRecord.MISSING) - info_add_row(0, "Max height", "%6.0f m", state.max_height); - if (state.acceleration != AltosRecord.MISSING) - info_add_row(0, "Acceleration", "%8.1f m/s²", state.acceleration); - if (state.max_acceleration != AltosRecord.MISSING) - info_add_row(0, "Max acceleration", "%8.1f m/s²", state.max_acceleration); - if (state.speed() != AltosRecord.MISSING) - info_add_row(0, "Speed", "%8.1f m/s", state.speed()); - if (state.max_speed() != AltosRecord.MISSING) - info_add_row(0, "Max Speed", "%8.1f m/s", state.max_accel_speed); - if (state.temperature != AltosRecord.MISSING) - info_add_row(0, "Temperature", "%9.2f °C", state.temperature); - if (state.battery != AltosRecord.MISSING) - info_add_row(0, "Battery", "%9.2f V", state.battery); - if (state.drogue_sense != AltosRecord.MISSING) - info_add_row(0, "Drogue", "%9.2f V", state.drogue_sense); - if (state.main_sense != AltosRecord.MISSING) - info_add_row(0, "Main", "%9.2f V", state.main_sense); - info_add_row(0, "CRC Errors", "%6d", crc_errors); - - if (state.gps == null || !state.gps.connected) { - info_add_row(1, "GPS", "not available"); - } else { - if (state.gps_ready) - info_add_row(1, "GPS state", "%s", "ready"); - else - info_add_row(1, "GPS state", "wait (%d)", - state.gps_waiting); - if (state.data.gps.locked) - info_add_row(1, "GPS", " locked"); - else if (state.data.gps.connected) - info_add_row(1, "GPS", " unlocked"); - else - info_add_row(1, "GPS", " missing"); - info_add_row(1, "Satellites", "%6d", state.data.gps.nsat); - info_add_deg(1, "Latitude", state.gps.lat, 'N', 'S'); - info_add_deg(1, "Longitude", state.gps.lon, 'E', 'W'); - info_add_row(1, "GPS altitude", "%6d", state.gps.alt); - info_add_row(1, "GPS height", "%6.0f", state.gps_height); - - /* The SkyTraq GPS doesn't report these values */ - /* - if (false) { - info_add_row(1, "GPS ground speed", "%8.1f m/s %3d°", - state.gps.ground_speed, - state.gps.course); - info_add_row(1, "GPS climb rate", "%8.1f m/s", - state.gps.climb_rate); - info_add_row(1, "GPS error", "%6d m(h)%3d m(v)", - state.gps.h_error, state.gps.v_error); - } - */ - - info_add_row(1, "GPS hdop", "%8.1f", state.gps.hdop); - - if (state.npad > 0) { - if (state.from_pad != null) { - info_add_row(1, "Distance from pad", "%6d m", - (int) (state.from_pad.distance + 0.5)); - info_add_row(1, "Direction from pad", "%6d°", - (int) (state.from_pad.bearing + 0.5)); - info_add_row(1, "Elevation from pad", "%6d°", - (int) (state.elevation + 0.5)); - info_add_row(1, "Range from pad", "%6d m", - (int) (state.range + 0.5)); - } else { - info_add_row(1, "Distance from pad", "unknown"); - info_add_row(1, "Direction from pad", "unknown"); - info_add_row(1, "Elevation from pad", "unknown"); - info_add_row(1, "Range from pad", "unknown"); + if (state != null) { + if (state.altitude != AltosRecord.MISSING) + info_add_row(0, "Altitude", "%6.0f m", state.altitude); + if (state.ground_altitude != AltosRecord.MISSING) + info_add_row(0, "Pad altitude", "%6.0f m", state.ground_altitude); + if (state.height != AltosRecord.MISSING) + info_add_row(0, "Height", "%6.0f m", state.height); + if (state.height != AltosRecord.MISSING) + info_add_row(0, "Max height", "%6.0f m", state.max_height); + if (state.acceleration != AltosRecord.MISSING) + info_add_row(0, "Acceleration", "%8.1f m/s²", state.acceleration); + if (state.acceleration != AltosRecord.MISSING) + info_add_row(0, "Max acceleration", "%8.1f m/s²", state.max_acceleration); + if (state.speed() != AltosRecord.MISSING) + info_add_row(0, "Speed", "%8.1f m/s", state.speed()); + if (state.speed() != AltosRecord.MISSING) + info_add_row(0, "Max Speed", "%8.1f m/s", state.max_accel_speed); + if (state.temperature != AltosRecord.MISSING) + info_add_row(0, "Temperature", "%9.2f °C", state.temperature); + if (state.battery != AltosRecord.MISSING) + info_add_row(0, "Battery", "%9.2f V", state.battery); + if (state.drogue_sense != AltosRecord.MISSING) + info_add_row(0, "Drogue", "%9.2f V", state.drogue_sense); + if (state.main_sense != AltosRecord.MISSING) + info_add_row(0, "Main", "%9.2f V", state.main_sense); + } + if (listener_state != null) { + info_add_row(0, "CRC Errors", "%6d", listener_state.crc_errors); + + if (listener_state.battery != AltosRecord.MISSING) + info_add_row(0, "Receiver Battery", "%9.2f", listener_state.battery); + } + + if (state != null) { + if (state.gps == null || !state.gps.connected) { + info_add_row(1, "GPS", "not available"); + } else { + if (state.gps_ready) + info_add_row(1, "GPS state", "%s", "ready"); + else + info_add_row(1, "GPS state", "wait (%d)", + state.gps_waiting); + if (state.data.gps.locked) + info_add_row(1, "GPS", " locked"); + else if (state.data.gps.connected) + info_add_row(1, "GPS", " unlocked"); + else + info_add_row(1, "GPS", " missing"); + info_add_row(1, "Satellites", "%6d", state.data.gps.nsat); + info_add_deg(1, "Latitude", state.gps.lat, 'N', 'S'); + info_add_deg(1, "Longitude", state.gps.lon, 'E', 'W'); + info_add_row(1, "GPS altitude", "%6d", state.gps.alt); + info_add_row(1, "GPS height", "%6.0f", state.gps_height); + + /* The SkyTraq GPS doesn't report these values */ + /* + if (false) { + info_add_row(1, "GPS ground speed", "%8.1f m/s %3d°", + state.gps.ground_speed, + state.gps.course); + info_add_row(1, "GPS climb rate", "%8.1f m/s", + state.gps.climb_rate); + info_add_row(1, "GPS error", "%6d m(h)%3d m(v)", + state.gps.h_error, state.gps.v_error); + } + */ + + info_add_row(1, "GPS hdop", "%8.1f", state.gps.hdop); + + if (state.npad > 0) { + if (state.from_pad != null) { + info_add_row(1, "Distance from pad", "%6d m", + (int) (state.from_pad.distance + 0.5)); + info_add_row(1, "Direction from pad", "%6d°", + (int) (state.from_pad.bearing + 0.5)); + info_add_row(1, "Elevation from pad", "%6d°", + (int) (state.elevation + 0.5)); + info_add_row(1, "Range from pad", "%6d m", + (int) (state.range + 0.5)); + } else { + info_add_row(1, "Distance from pad", "unknown"); + info_add_row(1, "Direction from pad", "unknown"); + info_add_row(1, "Elevation from pad", "unknown"); + info_add_row(1, "Range from pad", "unknown"); + } + info_add_deg(1, "Pad latitude", state.pad_lat, 'N', 'S'); + info_add_deg(1, "Pad longitude", state.pad_lon, 'E', 'W'); + info_add_row(1, "Pad GPS alt", "%6.0f m", state.pad_alt); } - info_add_deg(1, "Pad latitude", state.pad_lat, 'N', 'S'); - info_add_deg(1, "Pad longitude", state.pad_lon, 'E', 'W'); - info_add_row(1, "Pad GPS alt", "%6.0f m", state.pad_alt); - } - info_add_row(1, "GPS date", "%04d-%02d-%02d", - state.gps.year, - state.gps.month, - state.gps.day); - info_add_row(1, "GPS time", " %02d:%02d:%02d", - state.gps.hour, - state.gps.minute, - state.gps.second); - //int nsat_vis = 0; - int c; - - if (state.gps.cc_gps_sat == null) - info_add_row(2, "Satellites Visible", "%4d", 0); - else { - info_add_row(2, "Satellites Visible", "%4d", state.gps.cc_gps_sat.length); - for (c = 0; c < state.gps.cc_gps_sat.length; c++) { - info_add_row(2, "Satellite id,C/N0", - "%4d, %4d", - state.gps.cc_gps_sat[c].svid, - state.gps.cc_gps_sat[c].c_n0); + info_add_row(1, "GPS date", "%04d-%02d-%02d", + state.gps.year, + state.gps.month, + state.gps.day); + info_add_row(1, "GPS time", " %02d:%02d:%02d", + state.gps.hour, + state.gps.minute, + state.gps.second); + //int nsat_vis = 0; + int c; + + if (state.gps.cc_gps_sat == null) + info_add_row(2, "Satellites Visible", "%4d", 0); + else { + info_add_row(2, "Satellites Visible", "%4d", state.gps.cc_gps_sat.length); + for (c = 0; c < state.gps.cc_gps_sat.length; c++) { + info_add_row(2, "Satellite id,C/N0", + "%4d, %4d", + state.gps.cc_gps_sat[c].svid, + state.gps.cc_gps_sat[c].c_n0); + } } } } diff --git a/altosui/AltosLanded.java b/altosui/AltosLanded.java index a245dde3..1d209bda 100644 --- a/altosui/AltosLanded.java +++ b/altosui/AltosLanded.java @@ -29,7 +29,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio public class LandedValue { JLabel label; JTextField value; - void show(AltosState state, int crc_errors) {} + void show(AltosState state, AltosListenerState listener_state) {} void reset() { value.setText(""); @@ -102,7 +102,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio } class Lat extends LandedValue { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { if (state.gps != null && state.gps.connected) show(pos(state.gps.lat,"N", "S")); else @@ -116,7 +116,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio Lat lat; class Lon extends LandedValue { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { show(); if (state.gps != null && state.gps.connected) show(pos(state.gps.lon,"E", "W")); @@ -131,7 +131,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio Lon lon; class Bearing extends LandedValue { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { show(); if (state.from_pad != null) show("%3.0f°", state.from_pad.bearing); @@ -146,7 +146,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio Bearing bearing; class Distance extends LandedValue { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { show(); if (state.from_pad != null) show(AltosConvert.distance, state.from_pad.distance); @@ -161,7 +161,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio Distance distance; class Height extends LandedValue { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { show(AltosConvert.height, state.max_height); } public Height (GridBagLayout layout, int y) { @@ -172,7 +172,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio Height height; class Speed extends LandedValue { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { show(AltosConvert.speed, state.max_speed()); } public Speed (GridBagLayout layout, int y) { @@ -183,7 +183,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio Speed speed; class Accel extends LandedValue { - void show (AltosState state, int crc_errors) { + void show (AltosState state, AltosListenerState listener_state) { show(AltosConvert.accel, state.max_acceleration); } public Accel (GridBagLayout layout, int y) { @@ -213,21 +213,21 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio accel.set_font(); } - public void show(AltosState state, int crc_errors) { + public void show(AltosState state, AltosListenerState listener_state) { if (state.gps != null && state.gps.connected) { - bearing.show(state, crc_errors); - distance.show(state, crc_errors); - lat.show(state, crc_errors); - lon.show(state, crc_errors); + bearing.show(state, listener_state); + distance.show(state, listener_state); + lat.show(state, listener_state); + lon.show(state, listener_state); } else { bearing.hide(); distance.hide(); lat.hide(); lon.hide(); } - height.show(state, crc_errors); - speed.show(state, crc_errors); - accel.show(state, crc_errors); + height.show(state, listener_state); + speed.show(state, listener_state); + accel.show(state, listener_state); if (reader.backing_file() != null) graph.setEnabled(true); } diff --git a/altosui/AltosPad.java b/altosui/AltosPad.java index eb08525c..e2316a13 100644 --- a/altosui/AltosPad.java +++ b/altosui/AltosPad.java @@ -29,7 +29,7 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { JTextField value; AltosLights lights; - void show(AltosState state, int crc_errors) {} + void show(AltosState state, AltosListenerState listener_state) {} void reset() { value.setText(""); @@ -109,7 +109,7 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { public class LaunchValue { JLabel label; JTextField value; - void show(AltosState state, int crc_errors) {} + void show(AltosState state, AltosListenerState listener_state) {} void show() { label.setVisible(true); @@ -175,8 +175,8 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { } class Battery extends LaunchStatus { - void show (AltosState state, int crc_errors) { - if (state.battery == AltosRecord.MISSING) + void show (AltosState state, AltosListenerState listener_state) { + if (state == null || state.battery == AltosRecord.MISSING) hide(); else { show("%4.2f V", state.battery); @@ -191,9 +191,13 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { Battery battery; class Apogee extends LaunchStatus { - void show (AltosState state, int crc_errors) { - show("%4.2f V", state.drogue_sense); - lights.set(state.drogue_sense > 3.2); + void show (AltosState state, AltosListenerState listener_state) { + if (state == null || state.drogue_sense == AltosRecord.MISSING) + hide(); + else { + show("%4.2f V", state.drogue_sense); + lights.set(state.drogue_sense > 3.2); + } } public Apogee (GridBagLayout layout, int y) { super(layout, y, "Apogee Igniter Voltage"); @@ -203,9 +207,13 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { Apogee apogee; class Main extends LaunchStatus { - void show (AltosState state, int crc_errors) { - show("%4.2f V", state.main_sense); - lights.set(state.main_sense > 3.2); + void show (AltosState state, AltosListenerState listener_state) { + if (state == null || state.main_sense == AltosRecord.MISSING) + hide(); + else { + show("%4.2f V", state.main_sense); + lights.set(state.main_sense > 3.2); + } } public Main (GridBagLayout layout, int y) { super(layout, y, "Main Igniter Voltage"); @@ -215,18 +223,21 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { Main main; class LoggingReady extends LaunchStatus { - void show (AltosState state, int crc_errors) { - if (state.data.flight != 0) { - if (state.data.state <= Altos.ao_flight_pad) - show("Ready to record"); - else if (state.data.state < Altos.ao_flight_landed) - show("Recording data"); - else - show("Recorded data"); + void show (AltosState state, AltosListenerState listener_state) { + if (state == null || state.data.flight == AltosRecord.MISSING) { + hide(); + } else { + if (state.data.flight != 0) { + if (state.data.state <= Altos.ao_flight_pad) + show("Ready to record"); + else if (state.data.state < Altos.ao_flight_landed) + show("Recording data"); + else + show("Recorded data"); + } else + show("Storage full"); + lights.set(state.data.flight != 0); } - else - show("Storage full"); - lights.set(state.data.flight != 0); } public LoggingReady (GridBagLayout layout, int y) { super(layout, y, "On-board Data Logging"); @@ -236,9 +247,13 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { LoggingReady logging_ready; class GPSLocked extends LaunchStatus { - void show (AltosState state, int crc_errors) { - show("%4d sats", state.gps.nsat); - lights.set(state.gps.locked && state.gps.nsat >= 4); + void show (AltosState state, AltosListenerState listener_state) { + if (state == null || state.gps == null) + hide(); + else { + show("%4d sats", state.gps.nsat); + lights.set(state.gps.locked && state.gps.nsat >= 4); + } } public GPSLocked (GridBagLayout layout, int y) { super (layout, y, "GPS Locked"); @@ -248,12 +263,16 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { GPSLocked gps_locked; class GPSReady extends LaunchStatus { - void show (AltosState state, int crc_errors) { - if (state.gps_ready) - show("Ready"); - else - show("Waiting %d", state.gps_waiting); - lights.set(state.gps_ready); + void show (AltosState state, AltosListenerState listener_state) { + if (state == null || state.gps == null) + hide(); + else { + if (state.gps_ready) + show("Ready"); + else + show("Waiting %d", state.gps_waiting); + lights.set(state.gps_ready); + } } public GPSReady (GridBagLayout layout, int y) { super (layout, y, "GPS Ready"); @@ -262,6 +281,22 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { GPSReady gps_ready; + class ReceiverBattery extends LaunchStatus { + void show (AltosState state, AltosListenerState listener_state) { + if (listener_state == null || listener_state.battery == AltosRecord.MISSING) + hide(); + else { + show("%4.2f V", listener_state.battery); + lights.set(listener_state.battery > 3.7); + } + } + public ReceiverBattery (GridBagLayout layout, int y) { + super(layout, y, "Receiver Battery"); + } + } + + ReceiverBattery receiver_battery; + String pos(double p, String pos, String neg) { String h = pos; if (p < 0) { @@ -274,13 +309,17 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { } class PadLat extends LaunchValue { - void show (AltosState state, int crc_errors) { - if (state.state < AltosLib.ao_flight_pad && state.gps != null) { - show(pos(state.gps.lat,"N", "S")); - set_label("Latitude"); - } else { - show(pos(state.pad_lat,"N", "S")); - set_label("Pad Latitude"); + void show (AltosState state, AltosListenerState listener_state) { + if (state == null || state.gps == null) { + hide(); + } else { + if (state.state < AltosLib.ao_flight_pad) { + show(pos(state.gps.lat,"N", "S")); + set_label("Latitude"); + } else { + show(pos(state.pad_lat,"N", "S")); + set_label("Pad Latitude"); + } } } public PadLat (GridBagLayout layout, int y) { @@ -291,13 +330,17 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { PadLat pad_lat; class PadLon extends LaunchValue { - void show (AltosState state, int crc_errors) { - if (state.state < AltosLib.ao_flight_pad && state.gps != null) { - show(pos(state.gps.lon,"E", "W")); - set_label("Longitude"); - } else { - show(pos(state.pad_lon,"E", "W")); - set_label("Pad Longitude"); + void show (AltosState state, AltosListenerState listener_state) { + if (state == null || state.gps == null) { + hide(); + } else { + if (state.state < AltosLib.ao_flight_pad) { + show(pos(state.gps.lon,"E", "W")); + set_label("Longitude"); + } else { + show(pos(state.pad_lon,"E", "W")); + set_label("Pad Longitude"); + } } } public PadLon (GridBagLayout layout, int y) { @@ -308,16 +351,20 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { PadLon pad_lon; class PadAlt extends LaunchValue { - void show (AltosState state, int crc_errors) { - if (state.state < AltosLib.ao_flight_pad && state.gps != null) { - show("%4.0f m", state.gps.alt); - set_label("Altitude"); - } else { - if (state.pad_alt == AltosRecord.MISSING) - hide(); - else { - show("%4.0f m", state.pad_alt); - set_label("Pad Altitude"); + void show (AltosState state, AltosListenerState listener_state) { + if (state == null) + hide(); + else { + if (state.state < AltosLib.ao_flight_pad && state.gps != null) { + show("%4.0f m", state.gps.alt); + set_label("Altitude"); + } else { + if (state.pad_alt == AltosRecord.MISSING) + hide(); + else { + show("%4.0f m", state.pad_alt); + set_label("Pad Altitude"); + } } } } @@ -335,6 +382,7 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { logging_ready.reset(); gps_locked.reset(); gps_ready.reset(); + receiver_battery.reset(); pad_lat.reset(); pad_lon.reset(); pad_alt.reset(); @@ -347,34 +395,23 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { logging_ready.set_font(); gps_locked.set_font(); gps_ready.set_font(); + receiver_battery.set_font(); pad_lat.set_font(); pad_lon.set_font(); pad_alt.set_font(); } - public void show(AltosState state, int crc_errors) { - battery.show(state, crc_errors); - if (state.drogue_sense == AltosRecord.MISSING) - apogee.hide(); - else - apogee.show(state, crc_errors); - if (state.main_sense == AltosRecord.MISSING) - main.hide(); - else - main.show(state, crc_errors); - logging_ready.show(state, crc_errors); - pad_alt.show(state, crc_errors); - if (state.gps != null && state.gps.connected) { - gps_locked.show(state, crc_errors); - gps_ready.show(state, crc_errors); - pad_lat.show(state, crc_errors); - pad_lon.show(state, crc_errors); - } else { - gps_locked.hide(); - gps_ready.hide(); - pad_lat.hide(); - pad_lon.hide(); - } + public void show(AltosState state, AltosListenerState listener_state) { + battery.show(state, listener_state); + apogee.show(state, listener_state); + main.show(state, listener_state); + logging_ready.show(state, listener_state); + pad_alt.show(state, listener_state); + receiver_battery.show(state, listener_state); + gps_locked.show(state, listener_state); + gps_ready.show(state, listener_state); + pad_lat.show(state, listener_state); + pad_lon.show(state, listener_state); } public AltosPad() { @@ -398,8 +435,10 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { logging_ready = new LoggingReady(layout, 3); gps_locked = new GPSLocked(layout, 4); gps_ready = new GPSReady(layout, 5); - pad_lat = new PadLat(layout, 6); - pad_lon = new PadLon(layout, 7); - pad_alt = new PadAlt(layout, 8); + receiver_battery = new ReceiverBattery(layout, 6); + pad_lat = new PadLat(layout, 7); + pad_lon = new PadLon(layout, 8); + pad_alt = new PadAlt(layout, 9); + show(null, null); } } diff --git a/altosui/AltosSiteMap.java b/altosui/AltosSiteMap.java index f614eae6..5bf02e54 100644 --- a/altosui/AltosSiteMap.java +++ b/altosui/AltosSiteMap.java @@ -264,7 +264,7 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { initMaps(lat, lon); scrollRocketToVisible(pt(lat, lon)); } - public void show(final AltosState state, final int crc_errors) { + public void show(final AltosState state, final AltosListenerState listener_state) { // if insufficient gps data, nothing to update if (!state.gps.locked && state.gps.nsat < 4) return; @@ -294,7 +294,7 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { Point2D.Double ref, lref; ref = translatePoint(pt, tileCoordOffset(offset)); lref = translatePoint(last_pt, tileCoordOffset(offset)); - tile.show(state, crc_errors, lref, ref); + tile.show(state, listener_state, lref, ref); if (0 <= ref.x && ref.x < px_size) if (0 <= ref.y && ref.y < px_size) in_any = true; @@ -307,7 +307,7 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { lref = translatePoint(last_pt, tileCoordOffset(offset)); AltosSiteMapTile tile = createTile(offset); - tile.show(state, crc_errors, lref, ref); + tile.show(state, listener_state, lref, ref); initMap(offset); finishTileLater(tile, offset); } diff --git a/altosui/AltosSiteMapTile.java b/altosui/AltosSiteMapTile.java index 10e65bcd..365e4b6c 100644 --- a/altosui/AltosSiteMapTile.java +++ b/altosui/AltosSiteMapTile.java @@ -56,7 +56,7 @@ public class AltosSiteMapTile extends JLayeredPane { private boolean drawn_landed_circle = false; private boolean drawn_boost_circle = false; - public synchronized void show(AltosState state, int crc_errors, + public synchronized void show(AltosState state, AltosListenerState listener_state, Point2D.Double last_pt, Point2D.Double pt) { if (0 <= state.state && state.state < stateColors.length) { diff --git a/src/core/ao.h b/src/core/ao.h index 6c790f69..977e10b8 100644 --- a/src/core/ao.h +++ b/src/core/ao.h @@ -94,7 +94,7 @@ extern volatile __data AO_TICK_TYPE ao_tick_count; #define AO_SEC_TO_TICKS(s) ((s) * AO_HERTZ) /* Returns the current time in ticks */ -uint16_t +AO_TICK_TYPE ao_time(void); /* Suspend the current task until ticks time has passed */ diff --git a/src/stm/ao_timer.c b/src/stm/ao_timer.c index e07625d8..8b7c2327 100644 --- a/src/stm/ao_timer.c +++ b/src/stm/ao_timer.c @@ -18,15 +18,12 @@ #include "ao.h" #include -volatile __data AO_TICK_TYPE ao_tick_count; +volatile AO_TICK_TYPE ao_tick_count; -uint16_t ao_time(void) +AO_TICK_TYPE +ao_time(void) { - uint16_t v; - ao_arch_critical( - v = ao_tick_count; - ); - return v; + return ao_tick_count; } #if AO_DATA_ALL -- cgit v1.2.3 From 7e6e2ca60c65a4fe2bee0bd8b9b89d45a7dbcfb3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 12 Apr 2013 01:55:33 -0700 Subject: altos: Delay while waking up SD card a bit This seems to make bringing the card from idle to ready mode more reliable. If you spam the card with requests, it will eventually whinge and shut down communications. Signed-off-by: Keith Packard --- src/drivers/ao_sdcard.c | 6 ++++-- src/drivers/ao_sdcard.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_sdcard.c b/src/drivers/ao_sdcard.c index 6314a30c..c13017f0 100644 --- a/src/drivers/ao_sdcard.c +++ b/src/drivers/ao_sdcard.c @@ -346,14 +346,16 @@ ao_sdcard_setup(void) sdver2 = 1; } - for (i = 0; i < SDCARD_IDLE_RETRY; i++) { + for (i = 0; i < SDCARD_OP_COND_RETRY; i++) { + ao_delay(AO_MS_TO_TICKS(10)); ret = ao_sdcard_app_send_op_cond(arg); if (ret != SDCARD_STATUS_IDLE_STATE) break; } if (ret != SDCARD_STATUS_READY_STATE) { /* MMC */ - for (i = 0; i < SDCARD_IDLE_RETRY; i++) { + for (i = 0; i < SDCARD_OP_COND_RETRY; i++) { + ao_delay(AO_MS_TO_TICKS(10)); ret = ao_sdcard_send_op_cond(); if (ret != SDCARD_STATUS_IDLE_STATE) break; diff --git a/src/drivers/ao_sdcard.h b/src/drivers/ao_sdcard.h index 0d1464b3..50b70c73 100644 --- a/src/drivers/ao_sdcard.h +++ b/src/drivers/ao_sdcard.h @@ -69,6 +69,7 @@ ao_sdcard_init(void); #define SDCARD_BUSY_TIMEOUT AO_MS_TO_TICKS(20) #define SDCARD_BLOCK_TIMEOUT AO_MS_TO_TICKS(200) #define SDCARD_IDLE_RETRY 10 +#define SDCARD_OP_COND_RETRY 10 enum ao_sdtype { ao_sdtype_unknown, -- cgit v1.2.3 From c54bd59780275ece87eafb8143cf0637b35e794c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 12 Apr 2013 02:35:15 -0700 Subject: altos: Stick a mutex around FAT operations This allows the command line and logging operations to occur safely in parallel Signed-off-by: Keith Packard --- src/drivers/ao_fat.c | 436 ++++++++++++++++++++++++++++++------------------- src/test/ao_fat_test.c | 16 +- 2 files changed, 275 insertions(+), 177 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_fat.c b/src/drivers/ao_fat.c index 87c4158b..afd645cd 100644 --- a/src/drivers/ao_fat.c +++ b/src/drivers/ao_fat.c @@ -50,6 +50,9 @@ typedef ao_fat_cluster_t cluster_t; typedef ao_fat_dirent_t dirent_t; typedef ao_fat_cluster_offset_t cluster_offset_t; +/* Global FAT lock */ +static uint8_t ao_fat_mutex; + /* Partition information, sector numbers */ static uint8_t partition_type; @@ -123,14 +126,14 @@ put_u16(uint8_t *base, uint16_t value) } static uint8_t -ao_fat_cluster_valid(cluster_t cluster) +_ao_fat_cluster_valid(cluster_t cluster) { return (2 <= cluster && cluster < number_cluster); } /* Start using a sector */ static uint8_t * -ao_fat_sector_get(sector_t sector) +_ao_fat_sector_get(sector_t sector) { sector += partition_start; if (sector >= partition_end) @@ -139,18 +142,18 @@ ao_fat_sector_get(sector_t sector) } /* Finish using a sector, 'w' is 1 if modified */ -#define ao_fat_sector_put(b,w) ao_bufio_put(b,w) +#define _ao_fat_sector_put(b,w) ao_bufio_put(b,w) /* Get the next cluster entry in the chain */ static cluster_t -ao_fat_entry_read(cluster_t cluster) +_ao_fat_entry_read(cluster_t cluster) { sector_t sector; cluster_t offset; uint8_t *buf; cluster_t ret; - if (!ao_fat_cluster_valid(cluster)) + if (!_ao_fat_cluster_valid(cluster)) return 0xfffffff7; if (fat32) @@ -159,7 +162,7 @@ ao_fat_entry_read(cluster_t cluster) cluster <<= 1; sector = cluster >> (SECTOR_SHIFT); offset = cluster & SECTOR_MASK; - buf = ao_fat_sector_get(fat_start + sector); + buf = _ao_fat_sector_get(fat_start + sector); if (!buf) return 0; @@ -171,7 +174,7 @@ ao_fat_entry_read(cluster_t cluster) if (AO_FAT_IS_LAST_CLUSTER16(ret)) ret |= 0xfff0000; } - ao_fat_sector_put(buf, 0); + _ao_fat_sector_put(buf, 0); return ret; } @@ -179,7 +182,7 @@ ao_fat_entry_read(cluster_t cluster) * 'new_value'. Return the previous value. */ static cluster_t -ao_fat_entry_replace(cluster_t cluster, cluster_t new_value) +_ao_fat_entry_replace(cluster_t cluster, cluster_t new_value) { sector_t sector; cluster_offset_t offset; @@ -188,7 +191,7 @@ ao_fat_entry_replace(cluster_t cluster, cluster_t new_value) cluster_t old_value; uint8_t fat; - if (!ao_fat_cluster_valid(cluster)) + if (!_ao_fat_cluster_valid(cluster)) return 0xfffffff7; /* Convert from cluster index to byte index */ @@ -201,7 +204,7 @@ ao_fat_entry_replace(cluster_t cluster, cluster_t new_value) new_value &= 0xfffffff; for (fat = 0; fat < number_fat; fat++) { - buf = ao_fat_sector_get(fat_start + fat * sectors_per_fat + sector); + buf = _ao_fat_sector_get(fat_start + fat * sectors_per_fat + sector); if (!buf) return 0; if (fat32) { @@ -231,7 +234,7 @@ ao_fat_entry_replace(cluster_t cluster, cluster_t new_value) } put_u16(buf + offset, new_value); } - ao_fat_sector_put(buf, 1); + _ao_fat_sector_put(buf, 1); } return ret; @@ -242,19 +245,19 @@ ao_fat_entry_replace(cluster_t cluster, cluster_t new_value) * all of them as free */ static void -ao_fat_free_cluster_chain(cluster_t cluster) +_ao_fat_free_cluster_chain(cluster_t cluster) { - while (ao_fat_cluster_valid(cluster)) { + while (_ao_fat_cluster_valid(cluster)) { if (cluster < next_free) { next_free = cluster; fsinfo_dirty = 1; } - cluster = ao_fat_entry_replace(cluster, 0x00000000); + cluster = _ao_fat_entry_replace(cluster, 0x00000000); } } /* - * ao_fat_cluster_seek + * _ao_fat_cluster_seek * * The basic file system operation -- map a file cluster index to a * partition cluster number. Done by computing the cluster number and @@ -263,11 +266,11 @@ ao_fat_free_cluster_chain(cluster_t cluster) * is damaged somehow */ static cluster_t -ao_fat_cluster_seek(cluster_t cluster, cluster_t distance) +_ao_fat_cluster_seek(cluster_t cluster, cluster_t distance) { while (distance) { - cluster = ao_fat_entry_read(cluster); - if (!ao_fat_cluster_valid(cluster)) + cluster = _ao_fat_entry_read(cluster); + if (!_ao_fat_cluster_valid(cluster)) break; distance--; } @@ -275,7 +278,7 @@ ao_fat_cluster_seek(cluster_t cluster, cluster_t distance) } /* - * ao_fat_cluster_set_size + * _ao_fat_cluster_set_size * * Set the number of clusters in the specified chain, * freeing extra ones or alocating new ones as needed @@ -284,7 +287,7 @@ ao_fat_cluster_seek(cluster_t cluster, cluster_t distance) */ static cluster_t -ao_fat_cluster_set_size(cluster_t first_cluster, cluster_t size) +_ao_fat_cluster_set_size(cluster_t first_cluster, cluster_t size) { cluster_t have; cluster_t last_cluster; @@ -300,10 +303,10 @@ ao_fat_cluster_set_size(cluster_t first_cluster, cluster_t size) DBG("\tclusters:"); for (have = 0; have < size; have++) { DBG(" %08x", next_cluster); - if (!ao_fat_cluster_valid(next_cluster)) + if (!_ao_fat_cluster_valid(next_cluster)) break; last_cluster = next_cluster; - next_cluster = ao_fat_entry_read(next_cluster); + next_cluster = _ao_fat_entry_read(next_cluster); } DBG("\n"); @@ -320,14 +323,14 @@ ao_fat_cluster_set_size(cluster_t first_cluster, cluster_t size) */ if (have == size) { /* The file is large enough, truncate as needed */ - if (ao_fat_cluster_valid(next_cluster)) { + if (_ao_fat_cluster_valid(next_cluster)) { DBG("truncate between %08x and %08x\n", last_cluster, next_cluster); if (last_cluster) /* * Otherwise, rewrite the last cluster * in the chain with a LAST marker */ - (void) ao_fat_entry_replace(last_cluster, + (void) _ao_fat_entry_replace(last_cluster, AO_FAT_LAST_CLUSTER); else /* @@ -338,7 +341,7 @@ ao_fat_cluster_set_size(cluster_t first_cluster, cluster_t size) first_cluster = 0; /* Clear the remaining clusters in the chain */ - ao_fat_free_cluster_chain(next_cluster); + _ao_fat_free_cluster_chain(next_cluster); /* The file system is no longer full (if it was) */ filesystem_full = 0; @@ -371,7 +374,7 @@ ao_fat_cluster_set_size(cluster_t first_cluster, cluster_t size) break; \ loop_cluster { - if (!ao_fat_entry_read(free)) + if (!_ao_fat_entry_read(free)) need--; next_cluster; } @@ -387,14 +390,14 @@ ao_fat_cluster_set_size(cluster_t first_cluster, cluster_t size) */ need = size - have; loop_cluster { - if (ao_fat_entry_read(free) == 0) { + if (_ao_fat_entry_read(free) == 0) { next_free = free + 1; if (next_free >= number_cluster) next_free = 2; fsinfo_dirty = 1; DBG("\tadd cluster. old %08x new %08x\n", last_cluster, free); if (last_cluster) - ao_fat_entry_replace(last_cluster, free); + _ao_fat_entry_replace(last_cluster, free); else first_cluster = free; last_cluster = free; @@ -406,7 +409,7 @@ ao_fat_cluster_set_size(cluster_t first_cluster, cluster_t size) #undef next_cluster DBG("\tlast cluster %08x\n", last_cluster); /* Mark the new end of the chain */ - ao_fat_entry_replace(last_cluster, AO_FAT_LAST_CLUSTER); + _ao_fat_entry_replace(last_cluster, AO_FAT_LAST_CLUSTER); } DBG("\tfirst cluster %08x\n", first_cluster); @@ -415,7 +418,7 @@ ao_fat_cluster_set_size(cluster_t first_cluster, cluster_t size) /* Start using a root directory entry */ static uint8_t * -ao_fat_root_get(dirent_t e) +_ao_fat_root_get(dirent_t e) { offset_t byte = e * DIRENT_SIZE; sector_t sector = byte >> SECTOR_SHIFT; @@ -425,9 +428,9 @@ ao_fat_root_get(dirent_t e) if (fat32) { cluster_t cluster_distance = sector / sectors_per_cluster; sector_t sector_index = sector % sectors_per_cluster; - cluster_t cluster = ao_fat_cluster_seek(root_cluster, cluster_distance); + cluster_t cluster = _ao_fat_cluster_seek(root_cluster, cluster_distance); - if (ao_fat_cluster_valid(cluster)) + if (_ao_fat_cluster_valid(cluster)) sector = data_start + (cluster-2) * sectors_per_cluster + sector_index; else return NULL; @@ -437,7 +440,7 @@ ao_fat_root_get(dirent_t e) sector = root_start + sector; } - buf = ao_fat_sector_get(sector); + buf = _ao_fat_sector_get(sector); if (!buf) return NULL; return buf + offset; @@ -445,21 +448,21 @@ ao_fat_root_get(dirent_t e) /* Finish using a root directory entry, 'w' is 1 if modified */ static void -ao_fat_root_put(uint8_t *root, dirent_t e, uint8_t write) +_ao_fat_root_put(uint8_t *root, dirent_t e, uint8_t write) { cluster_offset_t offset = ((e * DIRENT_SIZE) & SECTOR_MASK); uint8_t *buf = root - offset; - ao_fat_sector_put(buf, write); + _ao_fat_sector_put(buf, write); } /* - * ao_fat_root_extend + * _ao_fat_root_extend * * On FAT32, make the root directory at least 'ents' entries long */ static int8_t -ao_fat_root_extend(dirent_t ents) +_ao_fat_root_extend(dirent_t ents) { offset_t byte_size; cluster_t cluster_size; @@ -468,18 +471,18 @@ ao_fat_root_extend(dirent_t ents) byte_size = (ents + 1) * 0x20; cluster_size = (byte_size + bytes_per_cluster - 1) / bytes_per_cluster; - if (ao_fat_cluster_set_size(root_cluster, cluster_size) != AO_FAT_BAD_CLUSTER) + if (_ao_fat_cluster_set_size(root_cluster, cluster_size) != AO_FAT_BAD_CLUSTER) return 1; return 0; } /* - * ao_fat_setup_partition + * _ao_fat_setup_partition * * Load the boot block and find the first partition */ static uint8_t -ao_fat_setup_partition(void) +_ao_fat_setup_partition(void) { uint8_t *mbr; uint8_t *partition; @@ -538,9 +541,9 @@ ao_fat_setup_partition(void) } static uint8_t -ao_fat_setup_fs(void) +_ao_fat_setup_fs(void) { - uint8_t *boot = ao_fat_sector_get(0); + uint8_t *boot = _ao_fat_sector_get(0); uint32_t data_sectors; if (!boot) @@ -550,7 +553,7 @@ ao_fat_setup_fs(void) if (boot[0x1fe] != 0x55 || boot[0x1ff] != 0xaa) { DBG ("Invalid BOOT signature %02x %02x\n", boot[0x1fe], boot[0x1ff]); - ao_fat_sector_put(boot, 0); + _ao_fat_sector_put(boot, 0); return AO_FAT_FILESYSTEM_INVALID_BOOT_SIGNATURE; } @@ -558,7 +561,7 @@ ao_fat_setup_fs(void) if (get_u16(boot + 0xb) != SECTOR_SIZE) { DBG ("Invalid sector size %d\n", get_u16(boot + 0xb)); - ao_fat_sector_put(boot, 0); + _ao_fat_sector_put(boot, 0); return AO_FAT_FILESYSTEM_INVALID_SECTOR_SIZE; } @@ -575,17 +578,17 @@ ao_fat_setup_fs(void) root_cluster = get_u32(boot+0x2c); fsinfo_sector = get_u16(boot + 0x30); } - ao_fat_sector_put(boot, 0); + _ao_fat_sector_put(boot, 0); free_count = 0xffffffff; next_free = 0; if (fat32 && fsinfo_sector) { - uint8_t *fsinfo = ao_fat_sector_get(fsinfo_sector); + uint8_t *fsinfo = _ao_fat_sector_get(fsinfo_sector); if (fsinfo) { free_count = get_u32(fsinfo + 0x1e8); next_free = get_u32(fsinfo + 0x1ec); - ao_fat_sector_put(fsinfo, 0); + _ao_fat_sector_put(fsinfo, 0); } } @@ -617,7 +620,7 @@ struct ao_file { static struct ao_fat_dirent ao_file_dirent[AO_FAT_NFILE]; static struct ao_fat_dirent * -ao_fat_file_dirent_alloc(struct ao_fat_dirent *want) +_ao_fat_file_dirent_alloc(struct ao_fat_dirent *want) { int8_t d; struct ao_fat_dirent *free = NULL, *dirent; @@ -645,13 +648,13 @@ ao_fat_file_dirent_alloc(struct ao_fat_dirent *want) static struct ao_file ao_file_table[AO_FAT_NFILE]; static int8_t -ao_fat_fd_alloc(struct ao_fat_dirent *dirent) +_ao_fat_fd_alloc(struct ao_fat_dirent *dirent) { int8_t fd; for (fd = 0; fd < AO_FAT_NFILE; fd++) if (!ao_file_table[fd].busy) { - ao_file_table[fd].dirent = ao_fat_file_dirent_alloc(dirent); + ao_file_table[fd].dirent = _ao_fat_file_dirent_alloc(dirent); ao_file_table[fd].busy = 1; ao_file_table[fd].offset = 0; ao_file_table[fd].cluster_offset = 0; @@ -663,7 +666,7 @@ ao_fat_fd_alloc(struct ao_fat_dirent *dirent) } static void -ao_fat_fd_free(int8_t fd) +_ao_fat_fd_free(int8_t fd) { struct ao_file *file = &ao_file_table[fd]; struct ao_fat_dirent *dirent = file->dirent; @@ -677,7 +680,7 @@ ao_fat_fd_free(int8_t fd) } static struct ao_file * -ao_fat_fd_to_file(int8_t fd) +_ao_fat_fd_to_file(int8_t fd) { struct ao_file *file; if (fd < 0 || AO_FAT_NFILE <= fd) @@ -693,7 +696,7 @@ static uint8_t ao_filesystem_setup; static uint8_t ao_filesystem_status; static uint8_t -ao_fat_setup(void) +_ao_fat_setup(void) { if (!ao_filesystem_setup) { @@ -713,10 +716,10 @@ ao_fat_setup(void) /* Reset open file table */ memset(&ao_file_table, '\0', sizeof (ao_file_table)); - ao_filesystem_status = ao_fat_setup_partition(); + ao_filesystem_status = _ao_fat_setup_partition(); if (ao_filesystem_status != AO_FAT_FILESYSTEM_SUCCESS) return ao_filesystem_status; - ao_filesystem_status = ao_fat_setup_fs(); + ao_filesystem_status = _ao_fat_setup_fs(); if (ao_filesystem_status != AO_FAT_FILESYSTEM_SUCCESS) return ao_filesystem_status; } @@ -734,7 +737,7 @@ ao_fat_unmount(void) */ static uint32_t -ao_fat_current_sector(struct ao_file *file) +_ao_fat_current_sector(struct ao_file *file) { cluster_t cluster_offset; uint32_t sector_offset; @@ -766,9 +769,9 @@ ao_fat_current_sector(struct ao_file *file) cluster_distance = cluster_offset - file->cluster_offset / bytes_per_cluster; DBG("\tseek forward %d clusters\n", cluster_distance); - cluster = ao_fat_cluster_seek(file->cluster, cluster_distance); + cluster = _ao_fat_cluster_seek(file->cluster, cluster_distance); - if (!ao_fat_cluster_valid(cluster)) { + if (!_ao_fat_cluster_valid(cluster)) { printf ("invalid cluster %08x\n", cluster); return 0xffffffff; } @@ -784,14 +787,14 @@ ao_fat_current_sector(struct ao_file *file) } /* - * ao_fat_invaldate_cluster_offset + * _ao_fat_invaldate_cluster_offset * * When the file size gets shrunk, invalidate * any file structures referencing clusters beyond that point */ static void -ao_fat_invalidate_cluster_offset(struct ao_fat_dirent *dirent) +_ao_fat_invalidate_cluster_offset(struct ao_fat_dirent *dirent) { int8_t fd; struct ao_file *file; @@ -811,13 +814,13 @@ ao_fat_invalidate_cluster_offset(struct ao_fat_dirent *dirent) /* - * ao_fat_set_size + * _ao_fat_set_size * * Set the size of the current file, truncating or extending * the cluster chain as needed */ static int8_t -ao_fat_set_size(struct ao_file *file, uint32_t size) +_ao_fat_set_size(struct ao_file *file, uint32_t size) { uint8_t *dent; cluster_t first_cluster; @@ -844,12 +847,12 @@ ao_fat_set_size(struct ao_file *file, uint32_t size) offset_clusters, extra_clusters); /* Need one more to account for file->cluster, which we already have */ - next_cluster = ao_fat_cluster_set_size(file->cluster, extra_clusters + 1); + next_cluster = _ao_fat_cluster_set_size(file->cluster, extra_clusters + 1); if (next_cluster == AO_FAT_BAD_CLUSTER) return -AO_FAT_ENOSPC; } else { DBG ("\tset size absolute need_clusters %d\n", need_clusters); - first_cluster = ao_fat_cluster_set_size(first_cluster, need_clusters); + first_cluster = _ao_fat_cluster_set_size(first_cluster, need_clusters); if (first_cluster == AO_FAT_BAD_CLUSTER) return -AO_FAT_ENOSPC; @@ -858,7 +861,7 @@ ao_fat_set_size(struct ao_file *file, uint32_t size) DBG ("\tupdate directory size\n"); /* Update the directory entry */ - dent = ao_fat_root_get(file->dirent->entry); + dent = _ao_fat_root_get(file->dirent->entry); if (!dent) { printf ("dent update failed\n"); return -AO_FAT_EIO; @@ -867,23 +870,23 @@ ao_fat_set_size(struct ao_file *file, uint32_t size) put_u16(dent + 0x1a, first_cluster); if (fat32) put_u16(dent + 0x14, first_cluster >> 16); - ao_fat_root_put(dent, file->dirent->entry, 1); + _ao_fat_root_put(dent, file->dirent->entry, 1); file->dirent->size = size; file->dirent->cluster = first_cluster; if (have_clusters > need_clusters) - ao_fat_invalidate_cluster_offset(file->dirent); + _ao_fat_invalidate_cluster_offset(file->dirent); DBG ("set size done\n"); return AO_FAT_SUCCESS; } /* - * ao_fat_root_init + * _ao_fat_root_init * * Initialize a root directory entry */ static void -ao_fat_root_init(uint8_t *dent, char name[11], uint8_t attr) +_ao_fat_root_init(uint8_t *dent, char name[11], uint8_t attr) { memset(dent, '\0', 0x20); memmove(dent, name, 11); @@ -916,7 +919,7 @@ ao_fat_root_init(uint8_t *dent, char name[11], uint8_t attr) static void -ao_fat_dirent_init(struct ao_fat_dirent *dirent, uint8_t *dent, uint16_t entry) +_ao_fat_dirent_init(struct ao_fat_dirent *dirent, uint8_t *dent, uint16_t entry) { memcpy(dirent->name, dent + 0x00, 11); dirent->attr = dent[0x0b]; @@ -928,13 +931,13 @@ ao_fat_dirent_init(struct ao_fat_dirent *dirent, uint8_t *dent, uint16_t entry) } /* - * ao_fat_flush_fsinfo + * _ao_fat_flush_fsinfo * * Write out any fsinfo changes to disk */ static void -ao_fat_flush_fsinfo(void) +_ao_fat_flush_fsinfo(void) { uint8_t *fsinfo; @@ -947,11 +950,11 @@ ao_fat_flush_fsinfo(void) if (!fsinfo_sector) return; - fsinfo = ao_fat_sector_get(fsinfo_sector); + fsinfo = _ao_fat_sector_get(fsinfo_sector); if (fsinfo) { put_u32(fsinfo + 0x1e8, free_count); put_u32(fsinfo + 0x1ec, next_free); - ao_fat_sector_put(fsinfo, 1); + _ao_fat_sector_put(fsinfo, 1); } } @@ -965,15 +968,23 @@ ao_fat_flush_fsinfo(void) * Flush any pending I/O to storage */ -void -ao_fat_sync(void) +static void +_ao_fat_sync(void) { - if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) + if (_ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) return; - ao_fat_flush_fsinfo(); + _ao_fat_flush_fsinfo(); ao_bufio_flush(); } +void +ao_fat_sync(void) +{ + ao_mutex_get(&ao_fat_mutex); + _ao_fat_sync(); + ao_mutex_put(&ao_fat_mutex); +} + /* * ao_fat_full * @@ -984,28 +995,71 @@ ao_fat_sync(void) int8_t ao_fat_full(void) { - if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) + ao_mutex_get(&ao_fat_mutex); + if (_ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) { + ao_mutex_put(&ao_fat_mutex); return 1; + } + ao_mutex_put(&ao_fat_mutex); return filesystem_full; } +static int8_t +_ao_fat_readdir(uint16_t *entry, struct ao_fat_dirent *dirent) +{ + uint8_t *dent; + + if (_ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) + return -AO_FAT_EIO; + + for (;;) { + dent = _ao_fat_root_get(*entry); + if (!dent) + return -AO_FAT_EDIREOF; + + if (dent[0] == AO_FAT_DENT_END) { + _ao_fat_root_put(dent, *entry, 0); + return -AO_FAT_EDIREOF; + } + if (dent[0] != AO_FAT_DENT_EMPTY && (dent[0xb] & 0xf) != 0xf) { + _ao_fat_dirent_init(dirent, dent, *entry); + _ao_fat_root_put(dent, *entry, 0); + (*entry)++; + return AO_FAT_SUCCESS; + } + _ao_fat_root_put(dent, *entry, 0); + (*entry)++; + } +} + +int8_t +ao_fat_readdir(uint16_t *entry, struct ao_fat_dirent *dirent) +{ + int8_t status; + + ao_mutex_get(&ao_fat_mutex); + status = _ao_fat_readdir(entry, dirent); + ao_mutex_put(&ao_fat_mutex); + return status; +} + /* * ao_fat_open * * Open an existing file. */ -int8_t -ao_fat_open(char name[11], uint8_t mode) +static int8_t +_ao_fat_open(char name[11], uint8_t mode) { uint16_t entry = 0; struct ao_fat_dirent dirent; int8_t status; - if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) + if (_ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) return -AO_FAT_EIO; for (;;) { - status = ao_fat_readdir(&entry, &dirent); + status = _ao_fat_readdir(&entry, &dirent); if (status < 0) { if (status == -AO_FAT_EDIREOF) return -AO_FAT_ENOENT; @@ -1018,20 +1072,62 @@ ao_fat_open(char name[11], uint8_t mode) return -AO_FAT_EPERM; if (mode > AO_FAT_OPEN_READ && (dirent.attr & AO_FAT_FILE_READ_ONLY)) return -AO_FAT_EACCESS; - return ao_fat_fd_alloc(&dirent); + return _ao_fat_fd_alloc(&dirent); } } return -AO_FAT_ENOENT; } +int8_t +ao_fat_open(char name[11], uint8_t mode) +{ + int8_t status; + + ao_mutex_get(&ao_fat_mutex); + status = _ao_fat_open(name, mode); + ao_mutex_put(&ao_fat_mutex); + return status; +} + +/* + * ao_fat_close + * + * Close the currently open file + */ +static int8_t +_ao_fat_close(int8_t fd) +{ + struct ao_file *file; + + file = _ao_fat_fd_to_file(fd); + if (!file) + return -AO_FAT_EBADF; + + _ao_fat_fd_free(fd); + _ao_fat_sync(); + return AO_FAT_SUCCESS; +} + +int8_t +ao_fat_close(int8_t fd) +{ + int8_t status; + + ao_mutex_get(&ao_fat_mutex); + status = _ao_fat_close(fd); + ao_mutex_put(&ao_fat_mutex); + return status; +} + /* * ao_fat_creat * * Open and truncate an existing file or * create a new file */ -int8_t -ao_fat_creat(char name[11]) + +static int8_t +_ao_fat_creat(char name[11]) { uint16_t entry; int8_t fd; @@ -1039,50 +1135,50 @@ ao_fat_creat(char name[11]) uint8_t *dent; struct ao_file *file; - if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) + if (_ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) return -AO_FAT_EIO; - fd = ao_fat_open(name, AO_FAT_OPEN_WRITE); + fd = _ao_fat_open(name, AO_FAT_OPEN_WRITE); if (fd >= 0) { file = &ao_file_table[fd]; - status = ao_fat_set_size(file, 0); + status = _ao_fat_set_size(file, 0); if (status < 0) { - ao_fat_close(fd); + _ao_fat_close(fd); fd = status; } } else { if (fd == -AO_FAT_ENOENT) { entry = 0; for (;;) { - dent = ao_fat_root_get(entry); + dent = _ao_fat_root_get(entry); if (!dent) { - if (ao_fat_root_extend(entry)) + if (_ao_fat_root_extend(entry)) continue; fd = -AO_FAT_ENOSPC; break; } if (dent[0] == AO_FAT_DENT_EMPTY || dent[0] == AO_FAT_DENT_END) { - fd = ao_fat_fd_alloc(NULL); + fd = _ao_fat_fd_alloc(NULL); if (fd < 0) { - ao_fat_root_put(dent, entry, 0); + _ao_fat_root_put(dent, entry, 0); break; } file = &ao_file_table[fd]; /* Initialize the dent */ - ao_fat_root_init(dent, name, AO_FAT_FILE_REGULAR); + _ao_fat_root_init(dent, name, AO_FAT_FILE_REGULAR); /* Now initialize the dirent from the dent */ - ao_fat_dirent_init(file->dirent, dent, entry); + _ao_fat_dirent_init(file->dirent, dent, entry); /* And write the dent to storage */ - ao_fat_root_put(dent, entry, 1); + _ao_fat_root_put(dent, entry, 1); status = -AO_FAT_SUCCESS; break; } else { - ao_fat_root_put(dent, entry, 0); + _ao_fat_root_put(dent, entry, 0); } entry++; } @@ -1091,21 +1187,15 @@ ao_fat_creat(char name[11]) return fd; } -/* - * ao_fat_close - * - * Close the currently open file - */ int8_t -ao_fat_close(int8_t fd) +ao_fat_creat(char name[11]) { - struct ao_file *file = ao_fat_fd_to_file(fd); - if (!file) - return -AO_FAT_EBADF; + int8_t status; - ao_fat_fd_free(fd); - ao_fat_sync(); - return AO_FAT_SUCCESS; + ao_mutex_get(&ao_fat_mutex); + status = _ao_fat_creat(name); + ao_mutex_put(&ao_fat_mutex); + return status; } /* @@ -1122,12 +1212,12 @@ ao_fat_map_current(struct ao_file *file, int len, cluster_offset_t *offsetp, clu void *buf; offset = file->offset & SECTOR_MASK; - sector = ao_fat_current_sector(file); + sector = _ao_fat_current_sector(file); if (sector == 0xffffffff) { printf ("invalid sector at offset %d\n", file->offset); return NULL; } - buf = ao_fat_sector_get(sector); + buf = _ao_fat_sector_get(sector); if (!buf) printf ("sector get failed. Sector %d. Partition end %d\n", sector, partition_end); if (offset + len < SECTOR_SIZE) @@ -1151,9 +1241,14 @@ ao_fat_read(int8_t fd, void *dst, int len) cluster_offset_t offset; uint8_t *buf; int ret = 0; - struct ao_file *file = ao_fat_fd_to_file(fd); - if (!file) - return -AO_FAT_EBADF; + struct ao_file *file; + + ao_mutex_get(&ao_fat_mutex); + file = _ao_fat_fd_to_file(fd); + if (!file) { + ret = -AO_FAT_EBADF; + goto done; + } if (file->offset + len > file->dirent->size) len = file->dirent->size - file->offset; @@ -1169,13 +1264,15 @@ ao_fat_read(int8_t fd, void *dst, int len) break; } memcpy(dst_b, buf + offset, this_time); - ao_fat_sector_put(buf, 0); + _ao_fat_sector_put(buf, 0); ret += this_time; len -= this_time; dst_b += this_time; file->offset = file->offset + this_time; } +done: + ao_mutex_put(&ao_fat_mutex); return ret; } @@ -1192,14 +1289,19 @@ ao_fat_write(int8_t fd, void *src, int len) cluster_offset_t offset; uint8_t *buf; int ret = 0; - struct ao_file *file = ao_fat_fd_to_file(fd); - if (!file) - return -AO_FAT_EBADF; + struct ao_file *file; + + ao_mutex_get(&ao_fat_mutex); + file = _ao_fat_fd_to_file(fd); + if (!file) { + ret = -AO_FAT_EBADF; + goto done; + } if (file->offset + len > file->dirent->size) { - ret = ao_fat_set_size(file, file->offset + len); + ret = _ao_fat_set_size(file, file->offset + len); if (ret < 0) - return ret; + goto done; } while (len) { @@ -1210,13 +1312,15 @@ ao_fat_write(int8_t fd, void *src, int len) break; } memcpy(buf + offset, src_b, this_time); - ao_fat_sector_put(buf, 1); + _ao_fat_sector_put(buf, 1); ret += this_time; len -= this_time; src_b += this_time; file->offset = file->offset + this_time; } +done: + ao_mutex_put(&ao_fat_mutex); return ret; } @@ -1233,9 +1337,15 @@ int32_t ao_fat_seek(int8_t fd, int32_t pos, uint8_t whence) { offset_t new_offset; - struct ao_file *file = ao_fat_fd_to_file(fd); - if (!file) - return -AO_FAT_EBADF; + struct ao_file *file; + int32_t ret; + + ao_mutex_get(&ao_fat_mutex); + file = _ao_fat_fd_to_file(fd); + if (!file) { + ret = -AO_FAT_EBADF; + goto done; + } new_offset = file->offset; switch (whence) { @@ -1249,8 +1359,10 @@ ao_fat_seek(int8_t fd, int32_t pos, uint8_t whence) new_offset = file->dirent->size + pos; break; } - file->offset = new_offset; - return file->offset; + ret = file->offset = new_offset; +done: + ao_mutex_put(&ao_fat_mutex); + return ret; } /* @@ -1264,9 +1376,13 @@ ao_fat_unlink(char name[11]) { uint16_t entry = 0; struct ao_fat_dirent dirent; + int8_t ret; - if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) - return -AO_FAT_EIO; + ao_mutex_get(&ao_fat_mutex); + if (_ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) { + ret = -AO_FAT_EIO; + goto done; + } while (ao_fat_readdir(&entry, &dirent)) { if (memcmp(name, dirent.name, 11) == 0) { @@ -1274,30 +1390,38 @@ ao_fat_unlink(char name[11]) uint8_t *ent; uint8_t delete; - if (AO_FAT_IS_DIR(dirent.attr)) - return -AO_FAT_EISDIR; - if (!AO_FAT_IS_FILE(dirent.attr)) - return -AO_FAT_EPERM; + if (AO_FAT_IS_DIR(dirent.attr)) { + ret = -AO_FAT_EISDIR; + goto done; + } + if (!AO_FAT_IS_FILE(dirent.attr)) { + ret = -AO_FAT_EPERM; + goto done; + } - ao_fat_free_cluster_chain(dirent.cluster); - next = ao_fat_root_get(dirent.entry + 1); + _ao_fat_free_cluster_chain(dirent.cluster); + next = _ao_fat_root_get(dirent.entry + 1); if (next && next[0] != AO_FAT_DENT_END) delete = AO_FAT_DENT_EMPTY; else delete = AO_FAT_DENT_END; if (next) - ao_fat_root_put(next, dirent.entry + 1, 0); - ent = ao_fat_root_get(dirent.entry); + _ao_fat_root_put(next, dirent.entry + 1, 0); + ent = _ao_fat_root_get(dirent.entry); if (ent) { memset(ent, '\0', DIRENT_SIZE); *ent = delete; - ao_fat_root_put(ent, dirent.entry, 1); + _ao_fat_root_put(ent, dirent.entry, 1); } ao_bufio_flush(); - return AO_FAT_SUCCESS; + ret = AO_FAT_SUCCESS; + goto done; } } - return -AO_FAT_ENOENT; + ret = -AO_FAT_ENOENT; +done: + ao_mutex_put(&ao_fat_mutex); + return ret; } int8_t @@ -1306,34 +1430,6 @@ ao_fat_rename(char old[11], char new[11]) return -AO_FAT_EIO; } -int8_t -ao_fat_readdir(uint16_t *entry, struct ao_fat_dirent *dirent) -{ - uint8_t *dent; - - if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) - return -AO_FAT_EIO; - - for (;;) { - dent = ao_fat_root_get(*entry); - if (!dent) - return -AO_FAT_EDIREOF; - - if (dent[0] == AO_FAT_DENT_END) { - ao_fat_root_put(dent, *entry, 0); - return -AO_FAT_EDIREOF; - } - if (dent[0] != AO_FAT_DENT_EMPTY && (dent[0xb] & 0xf) != 0xf) { - ao_fat_dirent_init(dirent, dent, *entry); - ao_fat_root_put(dent, *entry, 0); - (*entry)++; - return AO_FAT_SUCCESS; - } - ao_fat_root_put(dent, *entry, 0); - (*entry)++; - } -} - #if FAT_COMMANDS static const char *filesystem_errors[] = { @@ -1352,7 +1448,8 @@ ao_fat_mbr_cmd(void) { uint8_t status; - status = ao_fat_setup(); + ao_mutex_get(&ao_fat_mutex); + status = _ao_fat_setup(); if (status == AO_FAT_FILESYSTEM_SUCCESS) { printf ("partition type: %02x\n", partition_type); printf ("partition start: %08x\n", partition_start); @@ -1372,6 +1469,7 @@ ao_fat_mbr_cmd(void) } else { printf ("FAT filesystem not available: %s\n", filesystem_errors[status]); } + ao_mutex_put(&ao_fat_mutex); } struct ao_fat_attr { diff --git a/src/test/ao_fat_test.c b/src/test/ao_fat_test.c index a1bd5fbf..d1309024 100644 --- a/src/test/ao_fat_test.c +++ b/src/test/ao_fat_test.c @@ -158,14 +158,14 @@ ao_fat_entry_raw_read(cluster_t cluster, uint8_t fat) cluster <<= 1; sector = cluster >> SECTOR_SHIFT; offset = cluster & SECTOR_MASK; - buf = ao_fat_sector_get(fat_start + fat * sectors_per_fat + sector); + buf = _ao_fat_sector_get(fat_start + fat * sectors_per_fat + sector); if (!buf) return 0; if (fat32) ret = get_u32(buf + offset); else ret = get_u16(buf + offset); - ao_fat_sector_put(buf, 0); + _ao_fat_sector_put(buf, 0); return ret; } @@ -252,7 +252,7 @@ check_file(dirent_t dent, cluster_t first_cluster, dirent_t *used) fat32 ? !AO_FAT_IS_LAST_CLUSTER(cluster) : !AO_FAT_IS_LAST_CLUSTER16(cluster); cluster = ao_fat_entry_raw_read(cluster, 0)) { - if (!ao_fat_cluster_valid(cluster)) + if (!_ao_fat_cluster_valid(cluster)) fatal("file %d: invalid cluster %08x\n", dent, cluster); if (used[cluster]) fatal("file %d: duplicate cluster %08x also in file %d\n", dent, cluster, used[cluster]-1); @@ -274,7 +274,7 @@ check_fs(void) used = calloc(sizeof (dirent_t), number_cluster); - for (r = 0; (dent = ao_fat_root_get(r)); r++) { + for (r = 0; (dent = _ao_fat_root_get(r)); r++) { cluster_t clusters; offset_t size; cluster_t first_cluster; @@ -287,7 +287,7 @@ check_fs(void) if (fat32) first_cluster |= (cluster_t) get_u16(dent + 0x14) << 16; size = get_u32(dent + 0x1c); - ao_fat_root_put(dent, r, 0); + _ao_fat_root_put(dent, r, 0); if (name[0] == AO_FAT_DENT_END) { break; @@ -308,12 +308,12 @@ check_fs(void) } if (!fat32) { for (; r < root_entries; r++) { - uint8_t *dent = ao_fat_root_get(r); + uint8_t *dent = _ao_fat_root_get(r); if (!dent) fatal("cannot map dent %d\n", r); if (dent[0] != AO_FAT_DENT_END) fatal("found non-zero dent past end %d\n", r); - ao_fat_root_put(dent, r, 0); + _ao_fat_root_put(dent, r, 0); } } else { check_file((dirent_t) -1, root_cluster, used); @@ -536,7 +536,7 @@ do_test(void (*test)(void)) ao_fat_init(); check_bufio("top"); - ao_fat_setup(); + _ao_fat_setup(); check_fs(); check_bufio("after setup"); -- cgit v1.2.3 From cdbf8053658c71a657005af68202023d0b4af1fe Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 12 Apr 2013 02:42:37 -0700 Subject: altos: Don't include bufio debug commands by default We shouldn't need these Signed-off-by: Keith Packard --- src/drivers/ao_bufio.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/drivers/ao_bufio.c b/src/drivers/ao_bufio.c index 87de457f..c0fe604a 100644 --- a/src/drivers/ao_bufio.c +++ b/src/drivers/ao_bufio.c @@ -19,6 +19,11 @@ #include "ao.h" #endif +/* Include bufio commands */ +#ifndef AO_FAT_TEST +#define BUFIO_COMMANDS 0 +#endif + #include "ao_sdcard.h" #include "ao_bufio.h" @@ -268,6 +273,7 @@ ao_bufio_flush(void) ao_bufio_unlock(); } +#if BUFIO_COMMANDS static void ao_bufio_test_read(void) { @@ -290,6 +296,7 @@ static const struct ao_cmds ao_bufio_cmds[] = { { ao_bufio_test_read, "q\0Test bufio read" }, { 0, NULL }, }; +#endif void ao_bufio_setup(void) @@ -308,5 +315,7 @@ ao_bufio_init(void) { ao_bufio_setup(); ao_sdcard_init(); +#if BUFIO_COMMANDS ao_cmd_register(&ao_bufio_cmds[0]); +#endif } -- cgit v1.2.3 From 679401fff981b675dd5a188c64e8940254588800 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 12 Apr 2013 03:09:16 -0700 Subject: altos: Make sure the packet format is set reasonably for radio test Dunno if this matters, but it might as well be set reasonably Signed-off-by: Keith Packard --- src/drivers/ao_cc115l.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_cc115l.c b/src/drivers/ao_cc115l.c index 216432bd..30c56442 100644 --- a/src/drivers/ao_cc115l.c +++ b/src/drivers/ao_cc115l.c @@ -442,15 +442,10 @@ static const uint16_t radio_setup[] = { AO_CC115L_DONE_INT_GPIO_IOCFG, CC115L_IOCFG_GPIO_CFG_PA_PD | (1 << CC115L_IOCFG_GPIO_INV), CC115L_FIFOTHR, 0x47, /* TX FIFO Thresholds */ - CC115L_FREQ2, 0x10, /* Frequency Control Word, High Byte */ - CC115L_FREQ1, 0xb6, /* Frequency Control Word, Middle Byte */ - CC115L_FREQ0, 0xa5, /* Frequency Control Word, Low Byte */ - CC115L_MDMCFG2, 0x13, /* Modem Configuration */ CC115L_MDMCFG1, (0x00 | (CC115L_MDMCFG1_NUM_PREAMBLE_4 << CC115L_MDMCFG1_NUM_PREAMBLE) | (1 << CC115L_MDMCFG1_CHANSPC_E)), CC115L_MDMCFG0, 248, /* Channel spacing M value (100kHz channels) */ - CC115L_DEVIATN, 0x35, /* Modem Deviation Setting */ CC115L_MCSM0, 0x38, /* Main Radio Control State Machine Configuration */ CC115L_RESERVED_0X20, 0xfb, /* Use setting from SmartRF Studio */ CC115L_FSCAL3, 0xe9, /* Frequency Synthesizer Calibration */ @@ -460,7 +455,6 @@ static const uint16_t radio_setup[] = { CC115L_TEST2, 0x81, /* Various Test Settings */ CC115L_TEST1, 0x35, /* Various Test Settings */ CC115L_TEST0, 0x09, /* Various Test Settings */ - CC115L_PA, 0x00, /* Power setting (as low as possible) */ }; static uint8_t ao_radio_configured = 0; @@ -638,7 +632,7 @@ ao_radio_test_cmd(void) #endif ao_radio_get(); ao_radio_set_len(0xff); - ao_radio_set_mode(AO_RADIO_MODE_RDF); + ao_radio_set_mode(AO_RADIO_MODE_RDF|AO_RADIO_MODE_BITS_FIXED); ao_radio_strobe(CC115L_SFTX); ao_radio_pa_on(); ao_radio_strobe(CC115L_STX); -- cgit v1.2.3 From b4ffb3ed36fc8696603616bf5f31b07fb3829614 Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Sat, 20 Apr 2013 23:55:06 -0600 Subject: document my snazzy new 4-pin to MM v0.1 debug cable --- src/megametrum-v0.1/stlink-pins | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/megametrum-v0.1/stlink-pins b/src/megametrum-v0.1/stlink-pins index 3bd16d0b..390f8e5d 100644 --- a/src/megametrum-v0.1/stlink-pins +++ b/src/megametrum-v0.1/stlink-pins @@ -42,6 +42,14 @@ NRST 2 5 SWDIO 3 4 SWCLK 4 2 +Altus Metrum standard 4-pin connector to MegaMetrum v0.1 misc connector: + + AMstd MM v0.1 +gnd 1 1 +nrst 2 2 +swdio 3 8 +swclk 4 9 + MegaAccel: Jumpers -- cgit v1.2.3 From 759376cd0aac61c5afce31aed27ef98aba791173 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Mon, 22 Apr 2013 13:50:13 +1200 Subject: altos: update .gitignore files Signed-off-by: Mike Beattie --- .gitignore | 1 + src/test/.gitignore | 1 + 2 files changed, 2 insertions(+) (limited to 'src') diff --git a/.gitignore b/.gitignore index 6ae2b864..5dec09a5 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ ao-tidongle.h ao-tools/ao-bitbang/ao-bitbang ao-tools/ao-dbg/ao-dbg ao-tools/ao-dumplog/ao-dumplog +ao-tools/ao-dump-up/ao-dump-up ao-tools/ao-eeprom/ao-eeprom ao-tools/ao-edit-telem/ao-edit-telem ao-tools/ao-list/ao-list diff --git a/src/test/.gitignore b/src/test/.gitignore index 8d79d168..8f74c348 100644 --- a/src/test/.gitignore +++ b/src/test/.gitignore @@ -7,6 +7,7 @@ ao_gps_test ao_gps_test_skytraq ao_convert_test ao_convert_pa_test +ao_fat_test ao_fec_test ao_flight_test_mm ao_flight_test_noisy_accel -- cgit v1.2.3 From 8c05f608c8f103649c1e5ec0d5742621e233af78 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 22 Apr 2013 11:06:36 -0500 Subject: Move cortex toolchain to /opt/cortex Signed-off-by: Keith Packard --- src/stm-bringup/Makefile | 4 ++-- src/stm/Makefile.defs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/stm-bringup/Makefile b/src/stm-bringup/Makefile index 5cc94bd9..1bc5aaad 100644 --- a/src/stm-bringup/Makefile +++ b/src/stm-bringup/Makefile @@ -8,8 +8,8 @@ endif CC=arm-none-eabi-gcc OBJCOPY=arm-none-eabi-objcopy -PDCLIB=/home/keithp/sat -C_LIB=$(PDCLIB)/lib/pdclib.a +PDCLIB=/opt/cortex +C_LIB=$(PDCLIB)/lib/pdclib-cortex-m3.a C_INC=-I$(PDCLIB)/include DEF_CFLAGS=-g -std=gnu99 -Os -mlittle-endian -mthumb -ffreestanding -nostdlib -I. -I../../src/stm $(C_INC) diff --git a/src/stm/Makefile.defs b/src/stm/Makefile.defs index 04404cdc..1480f0b3 100644 --- a/src/stm/Makefile.defs +++ b/src/stm/Makefile.defs @@ -8,8 +8,8 @@ vpath matrix.5c ../kalman vpath ao-make-product.5c ../util CC=arm-none-eabi-gcc -SAT=/home/keithp/sat -SAT_CLIB=$(SAT)/lib/pdclib.a +SAT=/opt/cortex +SAT_CLIB=$(SAT)/lib/pdclib-cortex-m3.a SAT_CFLAGS=-I$(SAT)/include ifndef VERSION -- cgit v1.2.3 From aa7eac32adf4c2cdf441991d02411758f2682d1e Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Mon, 22 Apr 2013 13:00:26 -0600 Subject: name change from MegaMetrum to TeleMega --- altoslib/AltosConfigData.java | 2 +- altoslib/AltosIdleMonitor.java | 4 +- altoslib/AltosLib.java | 6 +- altosui/AltosDataChooser.java | 2 +- altosui/AltosEepromDownload.java | 2 +- altosui/Makefile.am | 2 +- altosui/altos-windows.nsi.in | 2 +- altosuilib/AltosUSBDevice.java | 6 +- ao-bringup/megametrum.cfg | 4 - ao-bringup/megametrum.gdb | 2 - ao-bringup/telemega.cfg | 4 + ao-bringup/telemega.gdb | 2 + debian/docs | 2 +- doc/altos.xsl | 2 +- doc/megametrum-outline.pdf | Bin 4349 -> 0 bytes doc/megametrum-outline.svg | 244 ------------------------ doc/release-notes-1.2.xsl | 2 +- src/Makefile | 2 +- src/core/ao_fec_rx.c | 2 +- src/core/ao_log.h | 2 +- src/core/ao_log_mega.c | 2 +- src/core/ao_telemetry.c | 2 +- src/drivers/ao_companion.c | 2 +- src/megametrum-v0.1/.gitignore | 2 - src/megametrum-v0.1/Makefile | 131 ------------- src/megametrum-v0.1/ao_megametrum.c | 100 ---------- src/megametrum-v0.1/ao_pins.h | 359 ------------------------------------ src/megametrum-v0.1/stlink-pins | 57 ------ src/stm/ao_i2c_stm.c | 2 +- src/telelco-v0.1/Makefile | 2 +- src/test/Makefile | 2 +- src/test/ao_flight_test.c | 22 +-- telemetrum.inf | 8 +- 33 files changed, 46 insertions(+), 939 deletions(-) delete mode 100644 ao-bringup/megametrum.cfg delete mode 100644 ao-bringup/megametrum.gdb create mode 100644 ao-bringup/telemega.cfg create mode 100644 ao-bringup/telemega.gdb delete mode 100644 doc/megametrum-outline.pdf delete mode 100644 doc/megametrum-outline.svg delete mode 100644 src/megametrum-v0.1/.gitignore delete mode 100644 src/megametrum-v0.1/Makefile delete mode 100644 src/megametrum-v0.1/ao_megametrum.c delete mode 100644 src/megametrum-v0.1/ao_pins.h delete mode 100644 src/megametrum-v0.1/stlink-pins (limited to 'src') diff --git a/altoslib/AltosConfigData.java b/altoslib/AltosConfigData.java index 57605607..2ca5a7a5 100644 --- a/altoslib/AltosConfigData.java +++ b/altoslib/AltosConfigData.java @@ -504,7 +504,7 @@ public class AltosConfigData implements Iterable { switch (log_format) { case AltosLib.AO_LOG_FORMAT_FULL: case AltosLib.AO_LOG_FORMAT_TINY: - case AltosLib.AO_LOG_FORMAT_MEGAMETRUM: + case AltosLib.AO_LOG_FORMAT_TELEMEGA: link.printf("l\n"); read_link(link, "done"); default: diff --git a/altoslib/AltosIdleMonitor.java b/altoslib/AltosIdleMonitor.java index c379547f..2e4ddef2 100644 --- a/altoslib/AltosIdleMonitor.java +++ b/altoslib/AltosIdleMonitor.java @@ -52,11 +52,11 @@ public class AltosIdleMonitor extends Thread { } boolean has_sensor_mm(AltosConfigData config_data) { - return config_data.product.startsWith("MegaMetrum"); + return config_data.product.startsWith("TeleMega"); } boolean has_gps(AltosConfigData config_data) { - return config_data.product.startsWith("TeleMetrum") || config_data.product.startsWith("MegaMetrum"); + return config_data.product.startsWith("TeleMetrum") || config_data.product.startsWith("TeleMega"); } AltosRecord sensor_mm(AltosConfigData config_data) throws InterruptedException, TimeoutException { diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index 0b5475f7..25d17e72 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -50,7 +50,7 @@ public class AltosLib { public static final int AO_LOG_SERIAL_NUMBER = 2002; public static final int AO_LOG_LOG_FORMAT = 2003; - /* Added for header fields in megametrum files */ + /* Added for header fields in telemega files */ public static final int AO_LOG_BARO_RESERVED = 3000; public static final int AO_LOG_BARO_SENS = 3001; public static final int AO_LOG_BARO_OFF = 3002; @@ -89,7 +89,7 @@ public class AltosLib { public final static int product_telelco = 0x0010; public final static int product_telescience = 0x0011; public final static int product_telepyro =0x0012; - public final static int product_megametrum = 0x0023; + public final static int product_telemega = 0x0023; public final static int product_megadongle = 0x0024; public final static int product_telegps = 0x0025; public final static int product_altusmetrum_min = 0x000a; @@ -215,7 +215,7 @@ public class AltosLib { public static final int AO_LOG_FORMAT_TINY = 2; public static final int AO_LOG_FORMAT_TELEMETRY = 3; public static final int AO_LOG_FORMAT_TELESCIENCE = 4; - public static final int AO_LOG_FORMAT_MEGAMETRUM = 5; + public static final int AO_LOG_FORMAT_TELEMEGA = 5; public static final int AO_LOG_FORMAT_NONE = 127; public static boolean isspace(int c) { diff --git a/altosui/AltosDataChooser.java b/altosui/AltosDataChooser.java index 7de18afb..f914f138 100644 --- a/altosui/AltosDataChooser.java +++ b/altosui/AltosDataChooser.java @@ -75,7 +75,7 @@ public class AltosDataChooser extends JFileChooser { "eeprom")); setFileFilter(new FileNameExtensionFilter("Telemetry file", "telem")); - setFileFilter(new FileNameExtensionFilter("MegaMetrum eeprom file", + setFileFilter(new FileNameExtensionFilter("TeleMega eeprom file", "mega")); setFileFilter(new FileNameExtensionFilter("Flight data file", "telem", "eeprom", "mega")); diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index 801d4ec0..a0523b58 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -366,7 +366,7 @@ public class AltosEepromDownload implements Runnable { extension = "science"; CaptureTeleScience(eechunk); break; - case AltosLib.AO_LOG_FORMAT_MEGAMETRUM: + case AltosLib.AO_LOG_FORMAT_TELEMEGA: extension = "mega"; CaptureMega(eechunk); } diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 96cf77f2..4bfef47c 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -157,7 +157,7 @@ FIRMWARE=$(FIRMWARE_TM) $(FIRMWARE_TELEMINI) $(FIRMWARE_TD) ALTUSMETRUM_DOC=$(top_srcdir)/doc/altusmetrum.pdf ALTOS_DOC=$(top_srcdir)/doc/altos.pdf TELEMETRY_DOC=$(top_srcdir)/doc/telemetry.pdf -TEMPLATE_DOC=$(top_srcdir)/doc/telemetrum-outline.pdf $(top_srcdir)/doc/megametrum-outline.pdf +TEMPLATE_DOC=$(top_srcdir)/doc/telemetrum-outline.pdf $(top_srcdir)/doc/telemega-outline.pdf DOC=$(ALTUSMETRUM_DOC) $(ALTOS_DOC) $(TELEMETRY_DOC) $(TEMPLATE_DOC) diff --git a/altosui/altos-windows.nsi.in b/altosui/altos-windows.nsi.in index cde54b41..9886e4a2 100644 --- a/altosui/altos-windows.nsi.in +++ b/altosui/altos-windows.nsi.in @@ -131,7 +131,7 @@ Section "Documentation" File "../doc/altos.pdf" File "../doc/telemetry.pdf" File "../doc/telemetrum-outline.pdf" - File "../doc/megametrum-outline.pdf" + File "../doc/telemega-outline.pdf" SectionEnd Section "Uninstaller" diff --git a/altosuilib/AltosUSBDevice.java b/altosuilib/AltosUSBDevice.java index 5268927c..0f6cbd10 100644 --- a/altosuilib/AltosUSBDevice.java +++ b/altosuilib/AltosUSBDevice.java @@ -72,11 +72,11 @@ public class AltosUSBDevice extends altos_device implements AltosDevice { return matchProduct(AltosUILib.product_teledongle) || matchProduct(AltosUILib.product_teleterra) || matchProduct(AltosUILib.product_telebt) || - matchProduct(AltosUILib.product_megadongle); + matchProduct(AltosUILib.product_telemega); if (want_product == AltosUILib.product_altimeter) return matchProduct(AltosUILib.product_telemetrum) || - matchProduct(AltosUILib.product_megametrum) || + matchProduct(AltosUILib.product_telemega) || matchProduct(AltosUILib.product_telegps); int have_product = getProduct(); @@ -110,4 +110,4 @@ public class AltosUSBDevice extends altos_device implements AltosDevice { return device_list; } -} \ No newline at end of file +} diff --git a/ao-bringup/megametrum.cfg b/ao-bringup/megametrum.cfg deleted file mode 100644 index e95c6f2b..00000000 --- a/ao-bringup/megametrum.cfg +++ /dev/null @@ -1,4 +0,0 @@ -# openocd config for MegaMetrum using the Olimex ARM-USB-OCD dongle - -source /opt/stm32/share/openocd/scripts/interface/olimex-arm-usb-ocd.cfg -source /opt/stm32/share/openocd/scripts/target/stm32l.cfg diff --git a/ao-bringup/megametrum.gdb b/ao-bringup/megametrum.gdb deleted file mode 100644 index 964ae1f3..00000000 --- a/ao-bringup/megametrum.gdb +++ /dev/null @@ -1,2 +0,0 @@ -target remote localhost:3333 -monitor poll diff --git a/ao-bringup/telemega.cfg b/ao-bringup/telemega.cfg new file mode 100644 index 00000000..f6b96c13 --- /dev/null +++ b/ao-bringup/telemega.cfg @@ -0,0 +1,4 @@ +# openocd config for TeleMega using the Olimex ARM-USB-OCD dongle + +source /opt/stm32/share/openocd/scripts/interface/olimex-arm-usb-ocd.cfg +source /opt/stm32/share/openocd/scripts/target/stm32l.cfg diff --git a/ao-bringup/telemega.gdb b/ao-bringup/telemega.gdb new file mode 100644 index 00000000..964ae1f3 --- /dev/null +++ b/ao-bringup/telemega.gdb @@ -0,0 +1,2 @@ +target remote localhost:3333 +monitor poll diff --git a/debian/docs b/debian/docs index 3ac75ad4..dcdb7763 100644 --- a/debian/docs +++ b/debian/docs @@ -7,4 +7,4 @@ doc/telemetry.pdf doc/altos.html doc/altos.pdf doc/telemetrum-outline.pdf -doc/megametrum-outline.pdf +doc/telemega-outline.pdf diff --git a/doc/altos.xsl b/doc/altos.xsl index c301adde..5af94725 100644 --- a/doc/altos.xsl +++ b/doc/altos.xsl @@ -50,7 +50,7 @@ STM32L series from ST Microelectronics. This ARM Cortex-M3 based microcontroller offers low power consumption and a wide variety of built-in peripherals. Altus Metrum uses - this in the MegaMetrum, MegaDongle and TeleLCO projects. + this in the TeleMega, MegaDongle and TeleLCO projects. diff --git a/doc/megametrum-outline.pdf b/doc/megametrum-outline.pdf deleted file mode 100644 index f8fc26e2..00000000 Binary files a/doc/megametrum-outline.pdf and /dev/null differ diff --git a/doc/megametrum-outline.svg b/doc/megametrum-outline.svg deleted file mode 100644 index e8d74d38..00000000 --- a/doc/megametrum-outline.svg +++ /dev/null @@ -1,244 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - UP - - diff --git a/doc/release-notes-1.2.xsl b/doc/release-notes-1.2.xsl index 610fa1a2..b254c7b5 100644 --- a/doc/release-notes-1.2.xsl +++ b/doc/release-notes-1.2.xsl @@ -41,7 +41,7 @@ raised, breaking the Descent tab contents. - Add preliminary MegaMetrum support, including configuration, + Add preliminary TeleMega support, including configuration, data download and analysis. diff --git a/src/Makefile b/src/Makefile index d91a235a..e271ddf3 100644 --- a/src/Makefile +++ b/src/Makefile @@ -29,7 +29,7 @@ AVRDIRS=\ telescience-v0.1 telescience-pwm telepyro-v0.1 micropeak ARMDIRS=\ - megametrum-v0.1 megadongle-v0.1 stm-bringup stm-demo telelco-v0.1 \ + telemega-v0.1 megadongle-v0.1 stm-bringup stm-demo telelco-v0.1 \ telescience-v0.2 ifneq ($(shell which sdcc),) diff --git a/src/core/ao_fec_rx.c b/src/core/ao_fec_rx.c index 072a9e90..c4f5559a 100644 --- a/src/core/ao_fec_rx.c +++ b/src/core/ao_fec_rx.c @@ -18,7 +18,7 @@ #include #include -#ifdef MEGAMETRUM +#ifdef TELEMEGA #include #endif diff --git a/src/core/ao_log.h b/src/core/ao_log.h index cac78771..a68a40dd 100644 --- a/src/core/ao_log.h +++ b/src/core/ao_log.h @@ -43,7 +43,7 @@ extern __pdata enum ao_flight_state ao_log_state; #define AO_LOG_FORMAT_TINY 2 /* two byte state/baro records */ #define AO_LOG_FORMAT_TELEMETRY 3 /* 32 byte ao_telemetry records */ #define AO_LOG_FORMAT_TELESCIENCE 4 /* 32 byte typed telescience records */ -#define AO_LOG_FORMAT_MEGAMETRUM 5 /* 32 byte typed megametrum records */ +#define AO_LOG_FORMAT_TELEMEGA 5 /* 32 byte typed telemega records */ #define AO_LOG_FORMAT_NONE 127 /* No log at all */ extern __code uint8_t ao_log_format; diff --git a/src/core/ao_log_mega.c b/src/core/ao_log_mega.c index ba3f7bfc..abf953a6 100644 --- a/src/core/ao_log_mega.c +++ b/src/core/ao_log_mega.c @@ -23,7 +23,7 @@ static __xdata uint8_t ao_log_mutex; static __xdata struct ao_log_mega log; -__code uint8_t ao_log_format = AO_LOG_FORMAT_MEGAMETRUM; +__code uint8_t ao_log_format = AO_LOG_FORMAT_TELEMEGA; static uint8_t ao_log_csum(__xdata uint8_t *b) __reentrant diff --git a/src/core/ao_telemetry.c b/src/core/ao_telemetry.c index 3aa315c7..03aa48d8 100644 --- a/src/core/ao_telemetry.c +++ b/src/core/ao_telemetry.c @@ -29,7 +29,7 @@ static __pdata uint16_t ao_aprs_time; #include #endif -#if defined(MEGAMETRUM) +#if defined(TELEMEGA) #define AO_SEND_MEGA 1 #endif diff --git a/src/drivers/ao_companion.c b/src/drivers/ao_companion.c index 0ebe8429..0f405253 100644 --- a/src/drivers/ao_companion.c +++ b/src/drivers/ao_companion.c @@ -18,7 +18,7 @@ #include #include -#ifdef MEGAMETRUM +#ifdef TELEMEGA #define ao_spi_slow(b) #define ao_spi_fast(b) #endif diff --git a/src/megametrum-v0.1/.gitignore b/src/megametrum-v0.1/.gitignore deleted file mode 100644 index b04d3950..00000000 --- a/src/megametrum-v0.1/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -ao_product.h -megametrum-*.elf diff --git a/src/megametrum-v0.1/Makefile b/src/megametrum-v0.1/Makefile deleted file mode 100644 index a5fdcbb2..00000000 --- a/src/megametrum-v0.1/Makefile +++ /dev/null @@ -1,131 +0,0 @@ -# -# AltOS build -# -# - -include ../stm/Makefile.defs - -INC = \ - ao.h \ - ao_arch.h \ - ao_arch_funcs.h \ - ao_companion.h \ - ao_data.h \ - ao_sample.h \ - ao_pins.h \ - altitude-pa.h \ - ao_kalman.h \ - ao_product.h \ - ao_ms5607.h \ - ao_hmc5883.h \ - ao_mpu6000.h \ - ao_mma655x.h \ - ao_cc1120_CC1120.h \ - ao_profile.h \ - ao_task.h \ - ao_whiten.h \ - ao_sample_profile.h \ - ao_mpu.h \ - stm32l.h \ - Makefile - -# -# Common AltOS sources -# -# ao_hmc5883.c - -#PROFILE=ao_profile.c -#PROFILE_DEF=-DAO_PROFILE=1 - -#SAMPLE_PROFILE=ao_sample_profile.c \ -# ao_sample_profile_timer.c -#SAMPLE_PROFILE_DEF=-DHAS_SAMPLE_PROFILE=1 - -#STACK_GUARD=ao_mpu_stm.c -#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1 - -ALTOS_SRC = \ - ao_interrupt.c \ - ao_product.c \ - ao_romconfig.c \ - ao_cmd.c \ - ao_config.c \ - ao_task.c \ - ao_led.c \ - ao_stdio.c \ - ao_panic.c \ - ao_timer.c \ - ao_mutex.c \ - ao_serial_stm.c \ - ao_gps_skytraq.c \ - ao_gps_report_mega.c \ - ao_ignite.c \ - ao_freq.c \ - ao_dma_stm.c \ - ao_spi_stm.c \ - ao_cc1120.c \ - ao_fec_tx.c \ - ao_fec_rx.c \ - ao_data.c \ - ao_ms5607.c \ - ao_mma655x.c \ - ao_hmc5883.c \ - ao_adc_stm.c \ - ao_beep_stm.c \ - ao_storage.c \ - ao_m25.c \ - ao_usb_stm.c \ - ao_exti_stm.c \ - ao_report.c \ - ao_i2c_stm.c \ - ao_mpu6000.c \ - ao_convert_pa.c \ - ao_log.c \ - ao_log_mega.c \ - ao_sample.c \ - ao_kalman.c \ - ao_flight.c \ - ao_telemetry.c \ - ao_packet_slave.c \ - ao_packet.c \ - ao_companion.c \ - ao_pyro.c \ - ao_aprs.c \ - $(PROFILE) \ - $(SAMPLE_PROFILE) \ - $(STACK_GUARD) - -PRODUCT=MegaMetrum-v0.1 -PRODUCT_DEF=-DMEGAMETRUM -IDPRODUCT=0x0023 - -CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g - -PROGNAME=megametrum-v0.1 -PROG=$(PROGNAME)-$(VERSION).elf - -SRC=$(ALTOS_SRC) ao_megametrum.c -OBJ=$(SRC:.c=.o) - -all: $(PROG) - -$(PROG): Makefile $(OBJ) altos.ld - $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc - -../altitude-pa.h: make-altitude-pa - nickle $< > $@ - -$(OBJ): $(INC) - -ao_product.h: ao-make-product.5c ../Version - $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ - -distclean: clean - -clean: - rm -f *.o $(PROGNAME)-*.elf - rm -f ao_product.h - -install: - -uninstall: diff --git a/src/megametrum-v0.1/ao_megametrum.c b/src/megametrum-v0.1/ao_megametrum.c deleted file mode 100644 index fbdab64a..00000000 --- a/src/megametrum-v0.1/ao_megametrum.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if HAS_SAMPLE_PROFILE -#include -#endif -#include -#if HAS_STACK_GUARD -#include -#endif - -int -main(void) -{ - ao_clock_init(); - -#if HAS_STACK_GUARD - ao_mpu_init(); -#endif - - ao_task_init(); - ao_serial_init(); - ao_led_init(LEDS_AVAILABLE); - ao_led_on(AO_LED_GREEN); - ao_timer_init(); - - ao_i2c_init(); - ao_spi_init(); - ao_dma_init(); - ao_exti_init(); - - ao_adc_init(); -#if HAS_BEEP - ao_beep_init(); -#endif - ao_cmd_init(); - -#if HAS_MS5607 - ao_ms5607_init(); -#endif -#if HAS_HMC5883 - ao_hmc5883_init(); -#endif -#if HAS_MPU6000 - ao_mpu6000_init(); -#endif -#if HAS_MMA655X - ao_mma655x_init(); -#endif - - ao_storage_init(); - - ao_flight_init(); - ao_log_init(); - ao_report_init(); - - ao_usb_init(); - ao_gps_init(); - ao_gps_report_mega_init(); - ao_telemetry_init(); - ao_radio_init(); - ao_packet_slave_init(FALSE); - ao_igniter_init(); - ao_companion_init(); - ao_pyro_init(); - - ao_config_init(); -#if AO_PROFILE - ao_profile_init(); -#endif -#if HAS_SAMPLE_PROFILE - ao_sample_profile_init(); -#endif - - ao_start_scheduler(); - return 0; -} diff --git a/src/megametrum-v0.1/ao_pins.h b/src/megametrum-v0.1/ao_pins.h deleted file mode 100644 index 4c645871..00000000 --- a/src/megametrum-v0.1/ao_pins.h +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Copyright © 2012 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#ifndef _AO_PINS_H_ -#define _AO_PINS_H_ - -#define HAS_TASK_QUEUE 1 - -/* 8MHz High speed external crystal */ -#define AO_HSE 8000000 - -/* PLLVCO = 96MHz (so that USB will work) */ -#define AO_PLLMUL 12 -#define AO_RCC_CFGR_PLLMUL (STM_RCC_CFGR_PLLMUL_12) - -/* SYSCLK = 32MHz (no need to go faster than CPU) */ -#define AO_PLLDIV 3 -#define AO_RCC_CFGR_PLLDIV (STM_RCC_CFGR_PLLDIV_3) - -/* HCLK = 32MHz (CPU clock) */ -#define AO_AHB_PRESCALER 1 -#define AO_RCC_CFGR_HPRE_DIV STM_RCC_CFGR_HPRE_DIV_1 - -/* Run APB1 at 16MHz (HCLK/2) */ -#define AO_APB1_PRESCALER 2 -#define AO_RCC_CFGR_PPRE1_DIV STM_RCC_CFGR_PPRE2_DIV_2 - -/* Run APB2 at 16MHz (HCLK/2) */ -#define AO_APB2_PRESCALER 2 -#define AO_RCC_CFGR_PPRE2_DIV STM_RCC_CFGR_PPRE2_DIV_2 - -#define HAS_SERIAL_1 1 -#define USE_SERIAL_1_STDIN 0 -#define SERIAL_1_PB6_PB7 0 -#define SERIAL_1_PA9_PA10 1 - -#define HAS_SERIAL_2 0 -#define USE_SERIAL_2_STDIN 0 -#define SERIAL_2_PA2_PA3 0 -#define SERIAL_2_PD5_PD6 0 - -#define HAS_SERIAL_3 1 -#define USE_SERIAL_3_STDIN 0 -#define SERIAL_3_PB10_PB11 0 -#define SERIAL_3_PC10_PC11 1 -#define SERIAL_3_PD8_PD9 0 - -#define ao_gps_getchar ao_serial3_getchar -#define ao_gps_putchar ao_serial3_putchar -#define ao_gps_set_speed ao_serial3_set_speed -#define ao_gps_fifo (ao_stm_usart3.rx_fifo) - -#define HAS_EEPROM 1 -#define USE_INTERNAL_FLASH 0 -#define HAS_USB 1 -#define HAS_BEEP 1 -#define HAS_RADIO 1 -#define HAS_TELEMETRY 1 -#define HAS_APRS 1 - -#define HAS_SPI_1 1 -#define SPI_1_PA5_PA6_PA7 1 /* Barometer */ -#define SPI_1_PB3_PB4_PB5 0 -#define SPI_1_PE13_PE14_PE15 1 /* Accelerometer */ -#define SPI_1_OSPEEDR STM_OSPEEDR_10MHz - -#define HAS_SPI_2 1 -#define SPI_2_PB13_PB14_PB15 1 /* Flash, Companion */ -#define SPI_2_PD1_PD3_PD4 0 -#define SPI_2_OSPEEDR STM_OSPEEDR_10MHz - -#define SPI_2_PORT (&stm_gpiob) -#define SPI_2_SCK_PIN 13 -#define SPI_2_MISO_PIN 14 -#define SPI_2_MOSI_PIN 15 - -#define HAS_I2C_1 1 -#define I2C_1_PB8_PB9 1 - -#define HAS_I2C_2 1 -#define I2C_2_PB10_PB11 1 - -#define PACKET_HAS_SLAVE 1 -#define PACKET_HAS_MASTER 0 - -#define LOW_LEVEL_DEBUG 0 - -#define LED_PORT_ENABLE STM_RCC_AHBENR_GPIOCEN -#define LED_PORT (&stm_gpioc) -#define LED_PIN_RED 8 -#define LED_PIN_GREEN 9 -#define AO_LED_RED (1 << LED_PIN_RED) -#define AO_LED_GREEN (1 << LED_PIN_GREEN) - -#define LEDS_AVAILABLE (AO_LED_RED | AO_LED_GREEN) - -#define HAS_GPS 1 -#define HAS_FLIGHT 1 -#define HAS_ADC 1 -#define HAS_LOG 1 - -/* - * Igniter - */ - -#define HAS_IGNITE 1 -#define HAS_IGNITE_REPORT 1 - -#define AO_SENSE_DROGUE(p) ((p)->adc.sense[0]) -#define AO_SENSE_MAIN(p) ((p)->adc.sense[1]) -#define AO_IGNITER_CLOSED 400 -#define AO_IGNITER_OPEN 60 - -#define AO_IGNITER_DROGUE_PORT (&stm_gpiod) -#define AO_IGNITER_DROGUE_PIN 6 - -#define AO_IGNITER_MAIN_PORT (&stm_gpiod) -#define AO_IGNITER_MAIN_PIN 7 - -#define AO_PYRO_PORT_0 (&stm_gpiob) -#define AO_PYRO_PIN_0 5 - -#define AO_PYRO_PORT_1 (&stm_gpioe) -#define AO_PYRO_PIN_1 4 - -#define AO_PYRO_PORT_2 (&stm_gpioe) -#define AO_PYRO_PIN_2 6 - -#define AO_PYRO_PORT_3 (&stm_gpioe) -#define AO_PYRO_PIN_3 5 - -/* Number of general purpose pyro channels available */ -#define AO_PYRO_NUM 4 - -#define AO_IGNITER_SET_DROGUE(v) stm_gpio_set(AO_IGNITER_DROGUE_PORT, AO_IGNITER_DROGUE_PIN, v) -#define AO_IGNITER_SET_MAIN(v) stm_gpio_set(AO_IGNITER_MAIN_PORT, AO_IGNITER_MAIN_PIN, v) - -/* - * ADC - */ -#define AO_DATA_RING 32 -#define AO_ADC_NUM_SENSE 6 - -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; -}; - -#define AO_ADC_SENSE_A 0 -#define AO_ADC_SENSE_A_PORT (&stm_gpioa) -#define AO_ADC_SENSE_A_PIN 0 - -#define AO_ADC_SENSE_B 1 -#define AO_ADC_SENSE_B_PORT (&stm_gpioa) -#define AO_ADC_SENSE_B_PIN 1 - -#define AO_ADC_SENSE_C 2 -#define AO_ADC_SENSE_C_PORT (&stm_gpioa) -#define AO_ADC_SENSE_C_PIN 2 - -#define AO_ADC_SENSE_D 3 -#define AO_ADC_SENSE_D_PORT (&stm_gpioa) -#define AO_ADC_SENSE_D_PIN 3 - -#define AO_ADC_SENSE_E 4 -#define AO_ADC_SENSE_E_PORT (&stm_gpioa) -#define AO_ADC_SENSE_E_PIN 4 - -#define AO_ADC_SENSE_F 22 -#define AO_ADC_SENSE_F_PORT (&stm_gpioe) -#define AO_ADC_SENSE_F_PIN 7 - -#define AO_ADC_V_BATT 8 -#define AO_ADC_V_BATT_PORT (&stm_gpiob) -#define AO_ADC_V_BATT_PIN 0 - -#define AO_ADC_V_PBATT 9 -#define AO_ADC_V_PBATT_PORT (&stm_gpiob) -#define AO_ADC_V_PBATT_PIN 1 - -#define AO_ADC_ACCEL_REF 10 -#define AO_ADC_ACCEL_REF_PORT (&stm_gpioc) -#define AO_ADC_ACCEL_REF_PIN 0 - -#define AO_ADC_ACCEL 11 -#define AO_ADC_ACCEL_PORT (&stm_gpioc) -#define AO_ADC_ACCEL_PIN 1 - -#define AO_ADC_TEMP 16 - -#define AO_ADC_RCC_AHBENR ((1 << STM_RCC_AHBENR_GPIOAEN) | \ - (1 << STM_RCC_AHBENR_GPIOEEN) | \ - (1 << STM_RCC_AHBENR_GPIOBEN) | \ - (1 << STM_RCC_AHBENR_GPIOCEN)) - -#define AO_NUM_ADC_PIN (AO_ADC_NUM_SENSE + 4) - -#define AO_ADC_PIN0_PORT AO_ADC_SENSE_A_PORT -#define AO_ADC_PIN0_PIN AO_ADC_SENSE_A_PIN -#define AO_ADC_PIN1_PORT AO_ADC_SENSE_B_PORT -#define AO_ADC_PIN1_PIN AO_ADC_SENSE_B_PIN -#define AO_ADC_PIN2_PORT AO_ADC_SENSE_C_PORT -#define AO_ADC_PIN2_PIN AO_ADC_SENSE_C_PIN -#define AO_ADC_PIN3_PORT AO_ADC_SENSE_D_PORT -#define AO_ADC_PIN3_PIN AO_ADC_SENSE_D_PIN -#define AO_ADC_PIN4_PORT AO_ADC_SENSE_E_PORT -#define AO_ADC_PIN4_PIN AO_ADC_SENSE_E_PIN -#define AO_ADC_PIN5_PORT AO_ADC_SENSE_F_PORT -#define AO_ADC_PIN5_PIN AO_ADC_SENSE_F_PIN -#define AO_ADC_PIN6_PORT AO_ADC_V_BATT_PORT -#define AO_ADC_PIN6_PIN AO_ADC_V_BATT_PIN -#define AO_ADC_PIN7_PORT AO_ADC_V_PBATT_PORT -#define AO_ADC_PIN7_PIN AO_ADC_V_PBATT_PIN -#define AO_ADC_PIN8_PORT AO_ADC_ACCEL_REF_PORT -#define AO_ADC_PIN8_PIN AO_ADC_ACCEL_REF_PIN -#define AO_ADC_PIN9_PORT AO_ADC_ACCEL_PORT -#define AO_ADC_PIN9_PIN AO_ADC_ACCEL_PIN - -#define AO_NUM_ADC (AO_ADC_NUM_SENSE + 5) - -#define AO_ADC_SQ1 AO_ADC_SENSE_A -#define AO_ADC_SQ2 AO_ADC_SENSE_B -#define AO_ADC_SQ3 AO_ADC_SENSE_C -#define AO_ADC_SQ4 AO_ADC_SENSE_D -#define AO_ADC_SQ5 AO_ADC_SENSE_E -#define AO_ADC_SQ6 AO_ADC_SENSE_F -#define AO_ADC_SQ7 AO_ADC_V_BATT -#define AO_ADC_SQ8 AO_ADC_V_PBATT -#define AO_ADC_SQ9 AO_ADC_ACCEL_REF -#define AO_ADC_SQ10 AO_ADC_ACCEL -#define AO_ADC_SQ11 AO_ADC_TEMP - -/* - * Pressure sensor settings - */ -#define HAS_MS5607 1 -#define HAS_MS5611 0 -#define AO_MS5607_PRIVATE_PINS 1 -#define AO_MS5607_CS_PORT (&stm_gpioc) -#define AO_MS5607_CS_PIN 4 -#define AO_MS5607_CS_MASK (1 << AO_MS5607_CS) -#define AO_MS5607_MISO_PORT (&stm_gpioa) -#define AO_MS5607_MISO_PIN 6 -#define AO_MS5607_MISO_MASK (1 << AO_MS5607_MISO) -#define AO_MS5607_SPI_INDEX AO_SPI_1_PA5_PA6_PA7 - -/* - * SPI Flash memory - */ - -#define M25_MAX_CHIPS 1 -#define AO_M25_SPI_CS_PORT (&stm_gpiod) -#define AO_M25_SPI_CS_MASK (1 << 3) -#define AO_M25_SPI_BUS AO_SPI_2_PB13_PB14_PB15 - -/* - * Radio (cc1120) - */ - -/* gets pretty close to 434.550 */ - -#define AO_RADIO_CAL_DEFAULT 0x6ca333 - -#define AO_FEC_DEBUG 0 -#define AO_CC1120_SPI_CS_PORT (&stm_gpioc) -#define AO_CC1120_SPI_CS_PIN 5 -#define AO_CC1120_SPI_BUS AO_SPI_2_PB13_PB14_PB15 -#define AO_CC1120_SPI stm_spi2 - -#define AO_CC1120_INT_PORT (&stm_gpioc) -#define AO_CC1120_INT_PIN 14 -#define AO_CC1120_MCU_WAKEUP_PORT (&stm_gpioc) -#define AO_CC1120_MCU_WAKEUP_PIN (0) - -#define AO_CC1120_INT_GPIO 2 -#define AO_CC1120_INT_GPIO_IOCFG CC1120_IOCFG2 - -#define AO_CC1120_MARC_GPIO 3 -#define AO_CC1120_MARC_GPIO_IOCFG CC1120_IOCFG3 - - -#define HAS_BOOT_RADIO 0 - -/* - * Mag sensor (hmc5883) - */ - -#define HAS_HMC5883 0 -#define AO_HMC5883_INT_PORT (&stm_gpioc) -#define AO_HMC5883_INT_PIN 12 -#define AO_HMC5883_I2C_INDEX STM_I2C_INDEX(1) - -/* - * mpu6000 - */ - -#define HAS_MPU6000 1 -#define AO_MPU6000_INT_PORT (&stm_gpioc) -#define AO_MPU6000_INT_PIN 13 -#define AO_MPU6000_I2C_INDEX STM_I2C_INDEX(1) - -#define HAS_HIGHG_ACCEL 0 - -/* - * mma655x - */ - -#define HAS_MMA655X 1 -#define AO_MMA655X_SPI_INDEX AO_SPI_1_PE13_PE14_PE15 -#define AO_MMA655X_CS_PORT (&stm_gpiod) -#define AO_MMA655X_CS_PIN 4 - -#define NUM_CMDS 16 - -/* - * Companion - */ - -#define AO_COMPANION_CS_PORT (&stm_gpiod) -#define AO_COMPANION_CS_PIN (0) -#define AO_COMPANION_SPI_BUS AO_SPI_2_PB13_PB14_PB15 - -/* - * Monitor - */ - -#define HAS_MONITOR 0 -#define LEGACY_MONITOR 0 -#define HAS_MONITOR_PUT 1 -#define AO_MONITOR_LED 0 -#define HAS_RSSI 0 - -/* - * Profiling Viterbi decoding - */ - -#ifndef AO_PROFILE -#define AO_PROFILE 0 -#endif - -#endif /* _AO_PINS_H_ */ diff --git a/src/megametrum-v0.1/stlink-pins b/src/megametrum-v0.1/stlink-pins deleted file mode 100644 index 390f8e5d..00000000 --- a/src/megametrum-v0.1/stlink-pins +++ /dev/null @@ -1,57 +0,0 @@ -ST discovery card pins - -1 AIN-1 -2 JTCK -3 GND -4 JTMS -5 NRST -6 SWO - -MegaMetrum v0.1 misc connector - -1 GND -2 reset_n -3 boot0 -4 tx1 -5 rx1 -6 +3.3V -7 GND -8 jtms -9 jtck -10 jtdi -11 jtdo -12 jntrst -13 sda2 -14 scl2 -15 pe1 -16 pe0 - -For debugging: - - ST MM v0.1 -JTCK 2 9 -GND 3 7 -JTMS 4 8 -NRST 5 2 - -Altus Metrum STM32L standard debug connector (4 pin MicoMaTch): - - TL ST -GND 1 3 -NRST 2 5 -SWDIO 3 4 -SWCLK 4 2 - -Altus Metrum standard 4-pin connector to MegaMetrum v0.1 misc connector: - - AMstd MM v0.1 -gnd 1 1 -nrst 2 2 -swdio 3 8 -swclk 4 9 - -MegaAccel: - -Jumpers -PC0 (pin15) (blue) PE0 (pin97) accel_ref (debug 16) -PC1 (pin16) (green) PE1 (pin98) accel (debug 15) diff --git a/src/stm/ao_i2c_stm.c b/src/stm/ao_i2c_stm.c index 779e2275..809b5c6f 100644 --- a/src/stm/ao_i2c_stm.c +++ b/src/stm/ao_i2c_stm.c @@ -36,7 +36,7 @@ static uint16_t ao_i2c_addr[STM_NUM_I2C]; uint8_t ao_i2c_mutex[STM_NUM_I2C]; # define I2C_HIGH_SLOW 5000 /* ns, 100kHz clock */ -#ifdef MEGAMETRUM +#ifdef TELEMEGA # define I2C_HIGH_FAST 2000 /* ns, 167kHz clock */ #else # define I2C_HIGH_FAST 1000 /* ns, 333kHz clock */ diff --git a/src/telelco-v0.1/Makefile b/src/telelco-v0.1/Makefile index d2702dd6..a4a83d02 100644 --- a/src/telelco-v0.1/Makefile +++ b/src/telelco-v0.1/Makefile @@ -61,7 +61,7 @@ ALTOS_SRC = \ ao_radio_cmac_cmd.c PRODUCT=TeleLCO-v0.1 -PRODUCT_DEF=-DMEGAMETRUM +PRODUCT_DEF=-DTELEMEGA IDPRODUCT=0x0023 CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g diff --git a/src/test/Makefile b/src/test/Makefile index 991bdbfc..a62b59c5 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -30,7 +30,7 @@ ao_flight_test_accel: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kal 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 $@ $< -lm + cc -DTELEMEGA=1 $(CFLAGS) -o $@ $< -lm 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 cdd1f236..99bed7ee 100644 --- a/src/test/ao_flight_test.c +++ b/src/test/ao_flight_test.c @@ -35,7 +35,7 @@ #define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16)) #define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16)) -#if MEGAMETRUM +#if TELEMEGA #define AO_ADC_NUM_SENSE 6 #define HAS_MS5607 1 #define HAS_MPU6000 1 @@ -195,7 +195,7 @@ struct ao_cmds { #define ao_xmemcmp(d,s,c) memcmp(d,s,c) #define AO_NEED_ALTITUDE_TO_PRES 1 -#if MEGAMETRUM +#if TELEMEGA #include "ao_convert_pa.c" #include struct ao_ms5607_prom ms5607_prom; @@ -333,7 +333,7 @@ ao_insert(void) #else double accel = 0.0; #endif -#if MEGAMETRUM +#if TELEMEGA double height; ao_ms5607_convert(&ao_data_static.ms5607_raw, &ao_data_static.ms5607_cooked); @@ -373,7 +373,7 @@ ao_insert(void) if (!ao_summary) { printf("%7.2f height %8.2f accel %8.3f " -#if MEGAMETRUM +#if TELEMEGA "roll %8.3f angle %8.3f qangle %8.3f " "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 @@ -381,7 +381,7 @@ ao_insert(void) time, height, accel, -#if MEGAMETRUM +#if TELEMEGA ao_mpu6000_gyro(ao_sample_roll_angle) / 100.0, ao_mpu6000_gyro(ao_sample_angle) / 100.0, ao_sample_qangle, @@ -555,7 +555,7 @@ int32(uint8_t *bytes, int off) static int log_format; -#if MEGAMETRUM +#if TELEMEGA static double ao_vec_norm(double x, double y, double z) @@ -774,7 +774,7 @@ ao_sleep(void *wchan) for (;;) { if (ao_records_read > 2 && ao_flight_state == ao_flight_startup) { -#if MEGAMETRUM +#if TELEMEGA ao_data_static.mpu6000 = ao_ground_mpu6000; #else ao_data_static.adc.accel = ao_flight_ground_accel; @@ -800,8 +800,8 @@ ao_sleep(void *wchan) if (words[nword] == NULL) break; } -#if MEGAMETRUM - if (log_format == AO_LOG_FORMAT_MEGAMETRUM && nword == 30 && strlen(words[0]) == 1) { +#if TELEMEGA + if (log_format == AO_LOG_FORMAT_TELEMEGA && nword == 30 && strlen(words[0]) == 1) { int i; struct ao_ms5607_value value; @@ -885,7 +885,7 @@ ao_sleep(void *wchan) continue; } #else - if (nword == 4 && log_format != AO_LOG_FORMAT_MEGAMETRUM) { + if (nword == 4 && log_format != AO_LOG_FORMAT_TELEMEGA) { type = words[0][0]; tick = strtoul(words[1], NULL, 16); a = strtoul(words[2], NULL, 16); @@ -1002,7 +1002,7 @@ ao_sleep(void *wchan) if (type != 'F' && !ao_flight_started) continue; -#if MEGAMETRUM +#if TELEMEGA (void) a; (void) b; #else diff --git a/telemetrum.inf b/telemetrum.inf index 91416bca..386dd286 100755 --- a/telemetrum.inf +++ b/telemetrum.inf @@ -30,7 +30,7 @@ DefaultDestDir = 12 %TeleScience% = AltusMetrum.Install, USB\VID_FFFE&PID_0011, AltusMetrumSerial %TelePyro% = AltusMetrum.Install, USB\VID_FFFE&PID_0012, AltusMetrumSerial %TeleShield% = AltusMetrum.Install, USB\VID_FFFE&PID_0013, AltusMetrumSerial -%MegaMetrum% = AltusMetrum.Install, USB\VID_FFFE&PID_0023, AltusMetrumSerial +%TeleMega% = AltusMetrum.Install, USB\VID_FFFE&PID_0023, AltusMetrumSerial %MegaDongle = AltusMetrum.Install, USB\VID_FFFE&PID_0024, AltusMetrumSerial %TeleGPS% = AltusMetrum.Install, USB\VID_FFFE&PID_0025, AltusMetrumSerial %AltusMetrum26% = AltusMetrum.Install, USB\VID_FFFE&PID_0026, AltusMetrumSerial @@ -52,7 +52,7 @@ DefaultDestDir = 12 %TeleScience% = AltusMetrum.Install, USB\VID_FFFE&PID_0011, AltusMetrumSerial %TelePyro% = AltusMetrum.Install, USB\VID_FFFE&PID_0012, AltusMetrumSerial %TeleShield% = AltusMetrum.Install, USB\VID_FFFE&PID_0013, AltusMetrumSerial -%MegaMetrum% = AltusMetrum.Install, USB\VID_FFFE&PID_0023, AltusMetrumSerial +%TeleMega% = AltusMetrum.Install, USB\VID_FFFE&PID_0023, AltusMetrumSerial %MegaDongle = AltusMetrum.Install, USB\VID_FFFE&PID_0024, AltusMetrumSerial %TeleGPS% = AltusMetrum.Install, USB\VID_FFFE&PID_0025, AltusMetrumSerial %AltusMetrum26% = AltusMetrum.Install, USB\VID_FFFE&PID_0026, AltusMetrumSerial @@ -74,7 +74,7 @@ DefaultDestDir = 12 %TeleScience% = AltusMetrum.Install, USB\VID_FFFE&PID_0011, AltusMetrumSerial %TelePyro% = AltusMetrum.Install, USB\VID_FFFE&PID_0012, AltusMetrumSerial %TeleShield% = AltusMetrum.Install, USB\VID_FFFE&PID_0013, AltusMetrumSerial -%MegaMetrum% = AltusMetrum.Install, USB\VID_FFFE&PID_0023, AltusMetrumSerial +%TeleMega% = AltusMetrum.Install, USB\VID_FFFE&PID_0023, AltusMetrumSerial %MegaDongle = AltusMetrum.Install, USB\VID_FFFE&PID_0024, AltusMetrumSerial %TeleGPS% = AltusMetrum.Install, USB\VID_FFFE&PID_0025, AltusMetrumSerial %AltusMetrum26% = AltusMetrum.Install, USB\VID_FFFE&PID_0026, AltusMetrumSerial @@ -96,7 +96,7 @@ DefaultDestDir = 12 %TeleScience% = AltusMetrum.Install, USB\VID_FFFE&PID_0011, AltusMetrumSerial %TelePyro% = AltusMetrum.Install, USB\VID_FFFE&PID_0012, AltusMetrumSerial %TeleShield% = AltusMetrum.Install, USB\VID_FFFE&PID_0013, AltusMetrumSerial -%MegaMetrum% = AltusMetrum.Install, USB\VID_FFFE&PID_0023, AltusMetrumSerial +%TeleMega% = AltusMetrum.Install, USB\VID_FFFE&PID_0023, AltusMetrumSerial %MegaDongle = AltusMetrum.Install, USB\VID_FFFE&PID_0024, AltusMetrumSerial %TeleGPS% = AltusMetrum.Install, USB\VID_FFFE&PID_0025, AltusMetrumSerial %AltusMetrum26% = AltusMetrum.Install, USB\VID_FFFE&PID_0026, AltusMetrumSerial -- cgit v1.2.3 From e9a6c4f71e02bb0073dcd030de735904494da81f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 22 Apr 2013 15:15:03 -0500 Subject: altos: Re-generate TeleMega bits Lost in the great megametrum rename Signed-off-by: Keith Packard --- src/telemega-v0.1/.gitignore | 2 + src/telemega-v0.1/Makefile | 131 +++++++++++++++ src/telemega-v0.1/ao_pins.h | 359 ++++++++++++++++++++++++++++++++++++++++ src/telemega-v0.1/ao_telemega.c | 100 +++++++++++ src/telemega-v0.1/stlink-pins | 57 +++++++ 5 files changed, 649 insertions(+) create mode 100644 src/telemega-v0.1/.gitignore create mode 100644 src/telemega-v0.1/Makefile create mode 100644 src/telemega-v0.1/ao_pins.h create mode 100644 src/telemega-v0.1/ao_telemega.c create mode 100644 src/telemega-v0.1/stlink-pins (limited to 'src') diff --git a/src/telemega-v0.1/.gitignore b/src/telemega-v0.1/.gitignore new file mode 100644 index 00000000..e67759a2 --- /dev/null +++ b/src/telemega-v0.1/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +telemega-*.elf diff --git a/src/telemega-v0.1/Makefile b/src/telemega-v0.1/Makefile new file mode 100644 index 00000000..16393ea0 --- /dev/null +++ b/src/telemega-v0.1/Makefile @@ -0,0 +1,131 @@ +# +# AltOS build +# +# + +include ../stm/Makefile.defs + +INC = \ + ao.h \ + ao_arch.h \ + ao_arch_funcs.h \ + ao_companion.h \ + ao_data.h \ + ao_sample.h \ + ao_pins.h \ + altitude-pa.h \ + ao_kalman.h \ + ao_product.h \ + ao_ms5607.h \ + ao_hmc5883.h \ + ao_mpu6000.h \ + ao_mma655x.h \ + ao_cc1120_CC1120.h \ + ao_profile.h \ + ao_task.h \ + ao_whiten.h \ + ao_sample_profile.h \ + ao_mpu.h \ + stm32l.h \ + Makefile + +# +# Common AltOS sources +# +# ao_hmc5883.c + +#PROFILE=ao_profile.c +#PROFILE_DEF=-DAO_PROFILE=1 + +#SAMPLE_PROFILE=ao_sample_profile.c \ +# ao_sample_profile_timer.c +#SAMPLE_PROFILE_DEF=-DHAS_SAMPLE_PROFILE=1 + +#STACK_GUARD=ao_mpu_stm.c +#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1 + +ALTOS_SRC = \ + ao_interrupt.c \ + ao_product.c \ + ao_romconfig.c \ + ao_cmd.c \ + ao_config.c \ + ao_task.c \ + ao_led.c \ + ao_stdio.c \ + ao_panic.c \ + ao_timer.c \ + ao_mutex.c \ + ao_serial_stm.c \ + ao_gps_skytraq.c \ + ao_gps_report_mega.c \ + ao_ignite.c \ + ao_freq.c \ + ao_dma_stm.c \ + ao_spi_stm.c \ + ao_cc1120.c \ + ao_fec_tx.c \ + ao_fec_rx.c \ + ao_data.c \ + ao_ms5607.c \ + ao_mma655x.c \ + ao_hmc5883.c \ + ao_adc_stm.c \ + ao_beep_stm.c \ + ao_storage.c \ + ao_m25.c \ + ao_usb_stm.c \ + ao_exti_stm.c \ + ao_report.c \ + ao_i2c_stm.c \ + ao_mpu6000.c \ + ao_convert_pa.c \ + ao_log.c \ + ao_log_mega.c \ + ao_sample.c \ + ao_kalman.c \ + ao_flight.c \ + ao_telemetry.c \ + ao_packet_slave.c \ + ao_packet.c \ + ao_companion.c \ + ao_pyro.c \ + ao_aprs.c \ + $(PROFILE) \ + $(SAMPLE_PROFILE) \ + $(STACK_GUARD) + +PRODUCT=TeleMega-v0.1 +PRODUCT_DEF=-DTELEMEGA +IDPRODUCT=0x0023 + +CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g + +PROGNAME=telemega-v0.1 +PROG=$(PROGNAME)-$(VERSION).elf + +SRC=$(ALTOS_SRC) ao_telemega.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) + +$(PROG): Makefile $(OBJ) altos.ld + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc + +../altitude-pa.h: make-altitude-pa + nickle $< > $@ + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean: clean + +clean: + rm -f *.o $(PROGNAME)-*.elf + rm -f ao_product.h + +install: + +uninstall: diff --git a/src/telemega-v0.1/ao_pins.h b/src/telemega-v0.1/ao_pins.h new file mode 100644 index 00000000..4c645871 --- /dev/null +++ b/src/telemega-v0.1/ao_pins.h @@ -0,0 +1,359 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define HAS_TASK_QUEUE 1 + +/* 8MHz High speed external crystal */ +#define AO_HSE 8000000 + +/* PLLVCO = 96MHz (so that USB will work) */ +#define AO_PLLMUL 12 +#define AO_RCC_CFGR_PLLMUL (STM_RCC_CFGR_PLLMUL_12) + +/* SYSCLK = 32MHz (no need to go faster than CPU) */ +#define AO_PLLDIV 3 +#define AO_RCC_CFGR_PLLDIV (STM_RCC_CFGR_PLLDIV_3) + +/* HCLK = 32MHz (CPU clock) */ +#define AO_AHB_PRESCALER 1 +#define AO_RCC_CFGR_HPRE_DIV STM_RCC_CFGR_HPRE_DIV_1 + +/* Run APB1 at 16MHz (HCLK/2) */ +#define AO_APB1_PRESCALER 2 +#define AO_RCC_CFGR_PPRE1_DIV STM_RCC_CFGR_PPRE2_DIV_2 + +/* Run APB2 at 16MHz (HCLK/2) */ +#define AO_APB2_PRESCALER 2 +#define AO_RCC_CFGR_PPRE2_DIV STM_RCC_CFGR_PPRE2_DIV_2 + +#define HAS_SERIAL_1 1 +#define USE_SERIAL_1_STDIN 0 +#define SERIAL_1_PB6_PB7 0 +#define SERIAL_1_PA9_PA10 1 + +#define HAS_SERIAL_2 0 +#define USE_SERIAL_2_STDIN 0 +#define SERIAL_2_PA2_PA3 0 +#define SERIAL_2_PD5_PD6 0 + +#define HAS_SERIAL_3 1 +#define USE_SERIAL_3_STDIN 0 +#define SERIAL_3_PB10_PB11 0 +#define SERIAL_3_PC10_PC11 1 +#define SERIAL_3_PD8_PD9 0 + +#define ao_gps_getchar ao_serial3_getchar +#define ao_gps_putchar ao_serial3_putchar +#define ao_gps_set_speed ao_serial3_set_speed +#define ao_gps_fifo (ao_stm_usart3.rx_fifo) + +#define HAS_EEPROM 1 +#define USE_INTERNAL_FLASH 0 +#define HAS_USB 1 +#define HAS_BEEP 1 +#define HAS_RADIO 1 +#define HAS_TELEMETRY 1 +#define HAS_APRS 1 + +#define HAS_SPI_1 1 +#define SPI_1_PA5_PA6_PA7 1 /* Barometer */ +#define SPI_1_PB3_PB4_PB5 0 +#define SPI_1_PE13_PE14_PE15 1 /* Accelerometer */ +#define SPI_1_OSPEEDR STM_OSPEEDR_10MHz + +#define HAS_SPI_2 1 +#define SPI_2_PB13_PB14_PB15 1 /* Flash, Companion */ +#define SPI_2_PD1_PD3_PD4 0 +#define SPI_2_OSPEEDR STM_OSPEEDR_10MHz + +#define SPI_2_PORT (&stm_gpiob) +#define SPI_2_SCK_PIN 13 +#define SPI_2_MISO_PIN 14 +#define SPI_2_MOSI_PIN 15 + +#define HAS_I2C_1 1 +#define I2C_1_PB8_PB9 1 + +#define HAS_I2C_2 1 +#define I2C_2_PB10_PB11 1 + +#define PACKET_HAS_SLAVE 1 +#define PACKET_HAS_MASTER 0 + +#define LOW_LEVEL_DEBUG 0 + +#define LED_PORT_ENABLE STM_RCC_AHBENR_GPIOCEN +#define LED_PORT (&stm_gpioc) +#define LED_PIN_RED 8 +#define LED_PIN_GREEN 9 +#define AO_LED_RED (1 << LED_PIN_RED) +#define AO_LED_GREEN (1 << LED_PIN_GREEN) + +#define LEDS_AVAILABLE (AO_LED_RED | AO_LED_GREEN) + +#define HAS_GPS 1 +#define HAS_FLIGHT 1 +#define HAS_ADC 1 +#define HAS_LOG 1 + +/* + * Igniter + */ + +#define HAS_IGNITE 1 +#define HAS_IGNITE_REPORT 1 + +#define AO_SENSE_DROGUE(p) ((p)->adc.sense[0]) +#define AO_SENSE_MAIN(p) ((p)->adc.sense[1]) +#define AO_IGNITER_CLOSED 400 +#define AO_IGNITER_OPEN 60 + +#define AO_IGNITER_DROGUE_PORT (&stm_gpiod) +#define AO_IGNITER_DROGUE_PIN 6 + +#define AO_IGNITER_MAIN_PORT (&stm_gpiod) +#define AO_IGNITER_MAIN_PIN 7 + +#define AO_PYRO_PORT_0 (&stm_gpiob) +#define AO_PYRO_PIN_0 5 + +#define AO_PYRO_PORT_1 (&stm_gpioe) +#define AO_PYRO_PIN_1 4 + +#define AO_PYRO_PORT_2 (&stm_gpioe) +#define AO_PYRO_PIN_2 6 + +#define AO_PYRO_PORT_3 (&stm_gpioe) +#define AO_PYRO_PIN_3 5 + +/* Number of general purpose pyro channels available */ +#define AO_PYRO_NUM 4 + +#define AO_IGNITER_SET_DROGUE(v) stm_gpio_set(AO_IGNITER_DROGUE_PORT, AO_IGNITER_DROGUE_PIN, v) +#define AO_IGNITER_SET_MAIN(v) stm_gpio_set(AO_IGNITER_MAIN_PORT, AO_IGNITER_MAIN_PIN, v) + +/* + * ADC + */ +#define AO_DATA_RING 32 +#define AO_ADC_NUM_SENSE 6 + +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; +}; + +#define AO_ADC_SENSE_A 0 +#define AO_ADC_SENSE_A_PORT (&stm_gpioa) +#define AO_ADC_SENSE_A_PIN 0 + +#define AO_ADC_SENSE_B 1 +#define AO_ADC_SENSE_B_PORT (&stm_gpioa) +#define AO_ADC_SENSE_B_PIN 1 + +#define AO_ADC_SENSE_C 2 +#define AO_ADC_SENSE_C_PORT (&stm_gpioa) +#define AO_ADC_SENSE_C_PIN 2 + +#define AO_ADC_SENSE_D 3 +#define AO_ADC_SENSE_D_PORT (&stm_gpioa) +#define AO_ADC_SENSE_D_PIN 3 + +#define AO_ADC_SENSE_E 4 +#define AO_ADC_SENSE_E_PORT (&stm_gpioa) +#define AO_ADC_SENSE_E_PIN 4 + +#define AO_ADC_SENSE_F 22 +#define AO_ADC_SENSE_F_PORT (&stm_gpioe) +#define AO_ADC_SENSE_F_PIN 7 + +#define AO_ADC_V_BATT 8 +#define AO_ADC_V_BATT_PORT (&stm_gpiob) +#define AO_ADC_V_BATT_PIN 0 + +#define AO_ADC_V_PBATT 9 +#define AO_ADC_V_PBATT_PORT (&stm_gpiob) +#define AO_ADC_V_PBATT_PIN 1 + +#define AO_ADC_ACCEL_REF 10 +#define AO_ADC_ACCEL_REF_PORT (&stm_gpioc) +#define AO_ADC_ACCEL_REF_PIN 0 + +#define AO_ADC_ACCEL 11 +#define AO_ADC_ACCEL_PORT (&stm_gpioc) +#define AO_ADC_ACCEL_PIN 1 + +#define AO_ADC_TEMP 16 + +#define AO_ADC_RCC_AHBENR ((1 << STM_RCC_AHBENR_GPIOAEN) | \ + (1 << STM_RCC_AHBENR_GPIOEEN) | \ + (1 << STM_RCC_AHBENR_GPIOBEN) | \ + (1 << STM_RCC_AHBENR_GPIOCEN)) + +#define AO_NUM_ADC_PIN (AO_ADC_NUM_SENSE + 4) + +#define AO_ADC_PIN0_PORT AO_ADC_SENSE_A_PORT +#define AO_ADC_PIN0_PIN AO_ADC_SENSE_A_PIN +#define AO_ADC_PIN1_PORT AO_ADC_SENSE_B_PORT +#define AO_ADC_PIN1_PIN AO_ADC_SENSE_B_PIN +#define AO_ADC_PIN2_PORT AO_ADC_SENSE_C_PORT +#define AO_ADC_PIN2_PIN AO_ADC_SENSE_C_PIN +#define AO_ADC_PIN3_PORT AO_ADC_SENSE_D_PORT +#define AO_ADC_PIN3_PIN AO_ADC_SENSE_D_PIN +#define AO_ADC_PIN4_PORT AO_ADC_SENSE_E_PORT +#define AO_ADC_PIN4_PIN AO_ADC_SENSE_E_PIN +#define AO_ADC_PIN5_PORT AO_ADC_SENSE_F_PORT +#define AO_ADC_PIN5_PIN AO_ADC_SENSE_F_PIN +#define AO_ADC_PIN6_PORT AO_ADC_V_BATT_PORT +#define AO_ADC_PIN6_PIN AO_ADC_V_BATT_PIN +#define AO_ADC_PIN7_PORT AO_ADC_V_PBATT_PORT +#define AO_ADC_PIN7_PIN AO_ADC_V_PBATT_PIN +#define AO_ADC_PIN8_PORT AO_ADC_ACCEL_REF_PORT +#define AO_ADC_PIN8_PIN AO_ADC_ACCEL_REF_PIN +#define AO_ADC_PIN9_PORT AO_ADC_ACCEL_PORT +#define AO_ADC_PIN9_PIN AO_ADC_ACCEL_PIN + +#define AO_NUM_ADC (AO_ADC_NUM_SENSE + 5) + +#define AO_ADC_SQ1 AO_ADC_SENSE_A +#define AO_ADC_SQ2 AO_ADC_SENSE_B +#define AO_ADC_SQ3 AO_ADC_SENSE_C +#define AO_ADC_SQ4 AO_ADC_SENSE_D +#define AO_ADC_SQ5 AO_ADC_SENSE_E +#define AO_ADC_SQ6 AO_ADC_SENSE_F +#define AO_ADC_SQ7 AO_ADC_V_BATT +#define AO_ADC_SQ8 AO_ADC_V_PBATT +#define AO_ADC_SQ9 AO_ADC_ACCEL_REF +#define AO_ADC_SQ10 AO_ADC_ACCEL +#define AO_ADC_SQ11 AO_ADC_TEMP + +/* + * Pressure sensor settings + */ +#define HAS_MS5607 1 +#define HAS_MS5611 0 +#define AO_MS5607_PRIVATE_PINS 1 +#define AO_MS5607_CS_PORT (&stm_gpioc) +#define AO_MS5607_CS_PIN 4 +#define AO_MS5607_CS_MASK (1 << AO_MS5607_CS) +#define AO_MS5607_MISO_PORT (&stm_gpioa) +#define AO_MS5607_MISO_PIN 6 +#define AO_MS5607_MISO_MASK (1 << AO_MS5607_MISO) +#define AO_MS5607_SPI_INDEX AO_SPI_1_PA5_PA6_PA7 + +/* + * SPI Flash memory + */ + +#define M25_MAX_CHIPS 1 +#define AO_M25_SPI_CS_PORT (&stm_gpiod) +#define AO_M25_SPI_CS_MASK (1 << 3) +#define AO_M25_SPI_BUS AO_SPI_2_PB13_PB14_PB15 + +/* + * Radio (cc1120) + */ + +/* gets pretty close to 434.550 */ + +#define AO_RADIO_CAL_DEFAULT 0x6ca333 + +#define AO_FEC_DEBUG 0 +#define AO_CC1120_SPI_CS_PORT (&stm_gpioc) +#define AO_CC1120_SPI_CS_PIN 5 +#define AO_CC1120_SPI_BUS AO_SPI_2_PB13_PB14_PB15 +#define AO_CC1120_SPI stm_spi2 + +#define AO_CC1120_INT_PORT (&stm_gpioc) +#define AO_CC1120_INT_PIN 14 +#define AO_CC1120_MCU_WAKEUP_PORT (&stm_gpioc) +#define AO_CC1120_MCU_WAKEUP_PIN (0) + +#define AO_CC1120_INT_GPIO 2 +#define AO_CC1120_INT_GPIO_IOCFG CC1120_IOCFG2 + +#define AO_CC1120_MARC_GPIO 3 +#define AO_CC1120_MARC_GPIO_IOCFG CC1120_IOCFG3 + + +#define HAS_BOOT_RADIO 0 + +/* + * Mag sensor (hmc5883) + */ + +#define HAS_HMC5883 0 +#define AO_HMC5883_INT_PORT (&stm_gpioc) +#define AO_HMC5883_INT_PIN 12 +#define AO_HMC5883_I2C_INDEX STM_I2C_INDEX(1) + +/* + * mpu6000 + */ + +#define HAS_MPU6000 1 +#define AO_MPU6000_INT_PORT (&stm_gpioc) +#define AO_MPU6000_INT_PIN 13 +#define AO_MPU6000_I2C_INDEX STM_I2C_INDEX(1) + +#define HAS_HIGHG_ACCEL 0 + +/* + * mma655x + */ + +#define HAS_MMA655X 1 +#define AO_MMA655X_SPI_INDEX AO_SPI_1_PE13_PE14_PE15 +#define AO_MMA655X_CS_PORT (&stm_gpiod) +#define AO_MMA655X_CS_PIN 4 + +#define NUM_CMDS 16 + +/* + * Companion + */ + +#define AO_COMPANION_CS_PORT (&stm_gpiod) +#define AO_COMPANION_CS_PIN (0) +#define AO_COMPANION_SPI_BUS AO_SPI_2_PB13_PB14_PB15 + +/* + * Monitor + */ + +#define HAS_MONITOR 0 +#define LEGACY_MONITOR 0 +#define HAS_MONITOR_PUT 1 +#define AO_MONITOR_LED 0 +#define HAS_RSSI 0 + +/* + * Profiling Viterbi decoding + */ + +#ifndef AO_PROFILE +#define AO_PROFILE 0 +#endif + +#endif /* _AO_PINS_H_ */ diff --git a/src/telemega-v0.1/ao_telemega.c b/src/telemega-v0.1/ao_telemega.c new file mode 100644 index 00000000..fbdab64a --- /dev/null +++ b/src/telemega-v0.1/ao_telemega.c @@ -0,0 +1,100 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if HAS_SAMPLE_PROFILE +#include +#endif +#include +#if HAS_STACK_GUARD +#include +#endif + +int +main(void) +{ + ao_clock_init(); + +#if HAS_STACK_GUARD + ao_mpu_init(); +#endif + + ao_task_init(); + ao_serial_init(); + ao_led_init(LEDS_AVAILABLE); + ao_led_on(AO_LED_GREEN); + ao_timer_init(); + + ao_i2c_init(); + ao_spi_init(); + ao_dma_init(); + ao_exti_init(); + + ao_adc_init(); +#if HAS_BEEP + ao_beep_init(); +#endif + ao_cmd_init(); + +#if HAS_MS5607 + ao_ms5607_init(); +#endif +#if HAS_HMC5883 + ao_hmc5883_init(); +#endif +#if HAS_MPU6000 + ao_mpu6000_init(); +#endif +#if HAS_MMA655X + ao_mma655x_init(); +#endif + + ao_storage_init(); + + ao_flight_init(); + ao_log_init(); + ao_report_init(); + + ao_usb_init(); + ao_gps_init(); + ao_gps_report_mega_init(); + ao_telemetry_init(); + ao_radio_init(); + ao_packet_slave_init(FALSE); + ao_igniter_init(); + ao_companion_init(); + ao_pyro_init(); + + ao_config_init(); +#if AO_PROFILE + ao_profile_init(); +#endif +#if HAS_SAMPLE_PROFILE + ao_sample_profile_init(); +#endif + + ao_start_scheduler(); + return 0; +} diff --git a/src/telemega-v0.1/stlink-pins b/src/telemega-v0.1/stlink-pins new file mode 100644 index 00000000..390f8e5d --- /dev/null +++ b/src/telemega-v0.1/stlink-pins @@ -0,0 +1,57 @@ +ST discovery card pins + +1 AIN-1 +2 JTCK +3 GND +4 JTMS +5 NRST +6 SWO + +MegaMetrum v0.1 misc connector + +1 GND +2 reset_n +3 boot0 +4 tx1 +5 rx1 +6 +3.3V +7 GND +8 jtms +9 jtck +10 jtdi +11 jtdo +12 jntrst +13 sda2 +14 scl2 +15 pe1 +16 pe0 + +For debugging: + + ST MM v0.1 +JTCK 2 9 +GND 3 7 +JTMS 4 8 +NRST 5 2 + +Altus Metrum STM32L standard debug connector (4 pin MicoMaTch): + + TL ST +GND 1 3 +NRST 2 5 +SWDIO 3 4 +SWCLK 4 2 + +Altus Metrum standard 4-pin connector to MegaMetrum v0.1 misc connector: + + AMstd MM v0.1 +gnd 1 1 +nrst 2 2 +swdio 3 8 +swclk 4 9 + +MegaAccel: + +Jumpers +PC0 (pin15) (blue) PE0 (pin97) accel_ref (debug 16) +PC1 (pin16) (green) PE1 (pin98) accel (debug 15) -- cgit v1.2.3