telemini-v1.0 telenano-v0.1 \
telebt-v0.0 telebt-v0.1 \
telemetrum-v0.1-sky telemetrum-v0.1-sirf \
- tidongle test
+ tidongle test telescience-v0.1
all: all-local all-recursive
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING];
+volatile __data uint8_t ao_adc_head;
+
+const uint8_t adc_channels[AO_LOG_TELESCIENCE_NUM_ADC] = {
+ 0x00,
+ 0x01,
+ 0x04,
+ 0x05,
+ 0x06,
+ 0x07,
+ 0x20,
+ 0x21,
+ 0x22,
+ 0x23,
+ 0x24,
+ 0x25,
+};
+
+static uint8_t ao_adc_channel;
+
+#define ADC_CHANNEL_LOW(c) (((c) & 0x1f) << MUX0)
+#define ADC_CHANNEL_HIGH(c) ((((c) & 0x20) >> 5) << MUX5)
+
+#define ADCSRA_INIT ((1 << ADEN) | /* Enable ADC */ \
+ (0 << ADATE) | /* No auto ADC trigger */ \
+ (1 << ADIF) | /* Clear interrupt */ \
+ (0 << ADIE) | /* Enable interrupt */ \
+ (6 << ADPS0)) /* Prescale clock by 64 */
+
+#define ADCSRB_INIT ((0 << ADHSM) | /* No high-speed mode */ \
+ (0 << ACME) | /* Some comparitor thing */ \
+ (2 << ADTS0)) /* Free running mode (don't care) */
+
+static void
+ao_adc_start(void)
+{
+ uint8_t channel = adc_channels[ao_adc_channel];
+ ADMUX = ((0 << REFS1) | /* AVcc reference */
+ (1 << REFS0) | /* AVcc reference */
+ (1 << ADLAR) | /* Left-shift results */
+ (ADC_CHANNEL_LOW(channel))); /* Select channel */
+
+ ADCSRB = (ADCSRB_INIT |
+ ADC_CHANNEL_HIGH(channel)); /* High channel bit */
+
+ ADCSRA = (ADCSRA_INIT |
+ (1 << ADSC) |
+ (1 << ADIE)); /* Start conversion */
+}
+
+ISR(ADC_vect)
+{
+ uint16_t value;
+
+ /* Must read ADCL first or the value there will be lost */
+ value = ADCL;
+ value |= (ADCH << 8);
+ ao_adc_ring[ao_adc_head].adc[ao_adc_channel] = value;
+ if (++ao_adc_channel < AO_TELESCIENCE_NUM_ADC)
+ ao_adc_start();
+ else {
+ ADCSRA = ADCSRA_INIT;
+ ao_adc_ring[ao_adc_head].tick = ao_time();
+ ao_adc_head = ao_adc_ring_next(ao_adc_head);
+ ao_wakeup((void *) &ao_adc_head);
+ ao_cpu_sleep_disable = 0;
+ }
+}
+
+void
+ao_adc_poll(void)
+{
+ ao_cpu_sleep_disable = 1;
+ ao_adc_channel = 0;
+ ao_adc_start();
+}
+
+void
+ao_adc_get(__xdata struct ao_adc *packet)
+{
+ uint8_t i = ao_adc_ring_prev(ao_adc_head);
+ memcpy(packet, (void *) &ao_adc_ring[i], sizeof (struct ao_adc));
+}
+
+static void
+ao_adc_dump(void) __reentrant
+{
+ static __xdata struct ao_adc packet;
+ uint8_t i;
+ ao_adc_get(&packet);
+ printf("tick: %5u", packet.tick);
+ for (i = 0; i < AO_TELESCIENCE_NUM_ADC; i++)
+ printf (" %2d: %5u", i, packet.adc[i]);
+ printf ("\n");
+}
+
+__code struct ao_cmds ao_adc_cmds[] = {
+ { ao_adc_dump, "a\0Display current ADC values" },
+ { 0, NULL },
+};
+
+void
+ao_adc_init(void)
+{
+ DIDR0 = 0xf3;
+ DIDR2 = 0x3f;
+ ADCSRB = ADCSRB_INIT;
+ ADCSRA = ADCSRA_INIT;
+ ao_cmd_register(&ao_adc_cmds[0]);
+}
#define ao_arch_critical(b) do { cli(); b; sei(); } while (0)
+#define AO_TELESCIENCE_NUM_ADC 12
+
+struct ao_adc {
+ uint16_t tick; /* tick when the sample was read */
+ uint16_t adc[AO_TELESCIENCE_NUM_ADC]; /* samples */
+};
+
+#define AO_ADC_RING 16
+
#endif /* _AO_ARCH_H_ */
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+#include "ao_product.h"
+
+struct ao_companion_command ao_companion_command;
+
+static const struct ao_companion_setup ao_telescience_setup = {
+ .board_id = AO_idProduct_NUMBER,
+ .board_id_inverse = ~AO_idProduct_NUMBER,
+ .update_period = 50,
+ .channels = AO_LOG_TELESCIENCE_NUM_ADC,
+};
+
+static uint8_t
+ao_spi_read(uint8_t *buf, uint8_t len)
+{
+ while (len--) {
+ while (!(SPSR & (1 << SPIF)))
+ if ((PINB & (1 << PINB0)))
+ return 0;
+ *buf++ = SPDR;
+ }
+ return 1;
+}
+
+static void
+ao_spi_write(uint8_t *buf, uint8_t len)
+{
+ while (len--) {
+ SPDR = *buf++;
+ while (!(SPSR & (1 << SPIF)))
+ if ((PINB & (1 << PINB0)))
+ return;
+ }
+ /* Clear pending SPIF bit by reading */
+ (void) SPDR;
+}
+
+static uint8_t ao_spi_slave_recv(void)
+{
+ if (!ao_spi_read((uint8_t *) &ao_companion_command,
+ sizeof (ao_companion_command)))
+ return 0;
+
+ /* Figure out the outbound data */
+ switch (ao_companion_command.command) {
+ case AO_COMPANION_SETUP:
+ ao_spi_write((uint8_t *) &ao_telescience_setup,
+ sizeof (ao_telescience_setup));
+ break;
+ case AO_COMPANION_FETCH:
+ ao_spi_write((uint8_t *) &ao_adc_ring[ao_adc_ring_prev(ao_adc_head)].adc,
+ AO_LOG_TELESCIENCE_NUM_ADC * sizeof (uint16_t));
+ break;
+ case AO_COMPANION_NOTIFY:
+ break;
+ default:
+ return 0;
+ }
+
+ ao_log_store.tm_tick = ao_companion_command.tick;
+ if (ao_log_store.tm_state != ao_companion_command.flight_state) {
+ ao_log_store.tm_state = ao_companion_command.flight_state;
+ return 1;
+ }
+ return 0;
+}
+
+static uint8_t ao_spi_slave_running;
+
+ISR(PCINT0_vect)
+{
+ if ((PINB & (1 << PINB0)) == 0) {
+ if (!ao_spi_slave_running) {
+ uint8_t changed;
+ ao_spi_slave_running = 1;
+ cli();
+ changed = ao_spi_slave_recv();
+ sei();
+ if (changed && ao_flight_boost <= ao_log_store.tm_state) {
+ if (ao_log_store.tm_state < ao_flight_landed)
+ ao_log_start();
+ else
+ ao_log_stop();
+ }
+ }
+ } else {
+ ao_spi_slave_running = 0;
+ }
+}
+
+void ao_spi_slave_debug(void) {
+ printf ("slave running %d\n", ao_spi_slave_running);
+}
+
+void
+ao_spi_slave_init(void)
+{
+ PCMSK0 |= (1 << PCINT0); /* Enable PCINT0 pin change */
+ PCICR |= (1 << PCIE0); /* Enable pin change interrupt */
+
+ DDRB = ((DDRB & 0xf0) |
+ (1 << 3) | /* MISO, output */
+ (0 << 2) | /* MOSI, input */
+ (0 << 1) | /* SCK, input */
+ (0 << 0)); /* SS, input */
+
+ /* We'd like to have a pull-up on SS so that disconnecting the
+ * TM would cause any SPI transaction to abort. However, when
+ * I tried that, SPI transactions would spontaneously abort,
+ * making me assume that we needed a less aggressive pull-up
+ * than is offered inside the AVR
+ */
+ PORTB = ((PORTB & 0xf0) |
+ (1 << 3) | /* MISO, output */
+ (0 << 2) | /* MOSI, no pull-up */
+ (0 << 1) | /* SCK, no pull-up */
+ (0 << 0)); /* SS, no pull-up */
+
+ SPCR = (0 << SPIE) | /* Disable SPI interrupts */
+ (1 << SPE) | /* Enable SPI */
+ (0 << DORD) | /* MSB first */
+ (0 << MSTR) | /* Slave mode */
+ (0 << CPOL) | /* Clock low when idle */
+ (0 << CPHA); /* Sample at leading clock edge */
+}
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+/*
+ * Atmega32u4 USART in MSPIM (master SPI mode)
+ */
+
+__xdata uint8_t ao_spi_mutex;
+
+/* Send bytes over SPI.
+ *
+ * This just polls; the SPI is set to go as fast as possible,
+ * so using interrupts would take way too long
+ */
+void
+ao_spi_send(void __xdata *block, uint16_t len) __reentrant
+{
+ uint8_t *d = block;
+
+ ao_mutex_get(&ao_spi_mutex);
+ while (len--) {
+ while (!(UCSR1A & (1 << UDRE1)));
+ UDR1 = *d++;
+ while (!(UCSR1A & (1 << RXC1)));
+ (void) UDR1;
+ }
+ ao_mutex_put(&ao_spi_mutex);
+}
+
+/* Receive bytes over SPI.
+ *
+ * This sets up tow DMA engines, one reading the data and another
+ * writing constant values to the SPI transmitter as that is what
+ * clocks the data coming in.
+ */
+void
+ao_spi_recv(void __xdata *block, uint16_t len) __reentrant
+{
+ uint8_t *d = block;
+
+ ao_mutex_get(&ao_spi_mutex);
+ while (len--) {
+ while (!(UCSR1A & (1 << UDRE1)));
+ UDR1 = 0;
+ while (!(UCSR1A & (1 << RXC1)));
+ *d++ = UDR1;
+ }
+ ao_mutex_put(&ao_spi_mutex);
+}
+
+/*
+ * Initialize USART0 for SPI using config alt 2
+ *
+ * MO P1_5
+ * MI P1_4
+ * CLK P1_3
+ *
+ * Chip select is the responsibility of the caller
+ */
+
+#define XCK1_DDR DDRD
+#define XCK1_PORT PORTD
+#define XCK1 PORTD5
+#define XMS1_DDR DDRE
+#define XMS1_PORT PORTE
+#define XMS1 PORTE6
+
+void
+ao_spi_init(void)
+{
+ /* Ensure the USART is powered */
+ PRR1 &= ~(1 << PRUSART1);
+
+ /*
+ * Set pin directions
+ */
+ XCK1_DDR |= (1 << XCK1);
+
+ /* Clear chip select (which is negated) */
+ XMS1_PORT |= (1 < XMS1);
+ XMS1_DDR |= (1 << XMS1);
+
+ /* Set baud register to zero (required before turning transmitter on) */
+ UBRR1 = 0;
+
+ UCSR1C = ((0x3 << UMSEL10) | /* Master SPI mode */
+ (0 << UCSZ10) | /* SPI mode 0 */
+ (0 << UCPOL1)); /* SPI mode 0 */
+
+ /* Enable transmitter and receiver */
+ UCSR1B = ((1 << RXEN1) |
+ (1 << TXEN1));
+
+ /* It says that 0 is a legal value; we'll see... */
+ UBRR1 = 0;
+}
#define ao_arch_critical(b) __critical { b }
+struct ao_adc {
+ uint16_t tick; /* tick when the sample was read */
+ int16_t accel; /* accelerometer */
+ int16_t pres; /* pressure sensor */
+ int16_t temp; /* temperature sensor */
+ int16_t v_batt; /* battery voltage */
+ int16_t sense_d; /* drogue continuity sense */
+ int16_t sense_m; /* main continuity sense */
+};
+
+#define AO_ADC_RING 32
+
#endif /* _AO_ARCH_H_ */
/*
* One set of samples read from the A/D converter or telemetry
*/
-struct ao_adc {
- uint16_t tick; /* tick when the sample was read */
- int16_t accel; /* accelerometer */
- int16_t pres; /* pressure sensor */
- int16_t temp; /* temperature sensor */
- int16_t v_batt; /* battery voltage */
- int16_t sense_d; /* drogue continuity sense */
- int16_t sense_m; /* main continuity sense */
-};
#if HAS_ADC
* ao_adc.c
*/
-#define AO_ADC_RING 32
#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1))
#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1))
extern __xdata uint8_t ao_log_running;
extern __pdata enum flight_state ao_log_state;
+#define AO_LOG_TELESCIENCE_START ((uint8_t) 's')
+#define AO_LOG_TELESCIENCE_DATA ((uint8_t) 'd')
+
+#define AO_LOG_TELESCIENCE_NUM_ADC 12
+
+struct ao_log_telescience {
+ uint8_t type;
+ uint8_t csum;
+ uint16_t tick;
+ uint16_t tm_tick;
+ uint8_t tm_state;
+ uint8_t unused;
+ uint16_t adc[AO_LOG_TELESCIENCE_NUM_ADC];
+};
+
+extern struct ao_log_telescience ao_log_store;
+
/* required functions from the underlying log system */
#define AO_LOG_FORMAT_UNKNOWN 0 /* unknown; altosui will have to guess */
void
ao_spi_init(void);
+/*
+ * ao_spi_slave.c
+ */
+
+void
+ao_spi_slave_debug(void);
+
+void
+ao_spi_slave_init(void);
+
/*
* ao_telemetry.c
*/
};
extern __pdata uint8_t ao_companion_running;
-extern __xdata struct ao_companion_setup ao_companion_setup;
extern __xdata uint8_t ao_companion_mutex;
+extern __xdata struct ao_companion_command ao_companion_command;
+extern __xdata struct ao_companion_setup ao_companion_setup;
extern __xdata uint16_t ao_companion_data[AO_COMPANION_MAX_CHANNELS];
void
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+#include "ao_product.h"
+
+static struct ao_task ao_log_task;
+//static struct ao_task ao_spi_task;
+
+uint8_t ao_log_running;
+uint8_t ao_log_mutex;
+uint32_t ao_log_start_pos;
+uint32_t ao_log_end_pos;
+uint32_t ao_log_current_pos;
+
+#define AO_LOG_TELESCIENCE_START ((uint8_t) 's')
+#define AO_LOG_TELESCIENCE_DATA ((uint8_t) 'd')
+
+struct ao_log_telescience ao_log_store;
+struct ao_log_telescience ao_log_fetch;
+
+static uint8_t ao_log_adc_pos;
+
+__code uint8_t ao_log_format = AO_LOG_FORMAT_TELESCIENCE;
+
+static uint8_t
+ao_log_csum(__xdata uint8_t *b) __reentrant
+{
+ uint8_t sum = 0x5a;
+ uint8_t i;
+
+ for (i = 0; i < sizeof (struct ao_log_telescience); i++)
+ sum += *b++;
+ return -sum;
+}
+
+static uint8_t
+ao_log_telescience_write(void)
+{
+ uint8_t wrote = 0;
+
+ ao_log_store.csum = 0;
+ ao_log_store.csum = ao_log_csum((__xdata uint8_t *) &ao_log_store);
+ ao_mutex_get(&ao_log_mutex); {
+ if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
+ ao_log_stop();
+ if (ao_log_running) {
+ wrote = 1;
+ ao_storage_write(ao_log_current_pos,
+ (__xdata uint8_t *) &ao_log_store,
+ sizeof (struct ao_log_telescience));
+ ao_log_current_pos += sizeof (struct ao_log_telescience);
+ }
+ } ao_mutex_put(&ao_log_mutex);
+ return wrote;
+}
+
+static uint8_t
+ao_log_valid(struct ao_log_telescience *log)
+{
+ uint8_t *d;
+ uint8_t i;
+ d = (uint8_t *) log;
+ for (i = 0; i < sizeof (struct ao_log_telescience); i++)
+ if (d[i] != 0xff)
+ return 1;
+ return 0;
+}
+
+static uint8_t
+ao_log_telescience_read(uint32_t pos)
+{
+ if (!ao_storage_read(pos, &ao_log_fetch, sizeof (struct ao_log_telescience)))
+ return 0;
+ return ao_log_valid(&ao_log_fetch);
+}
+
+void
+ao_log_start(void)
+{
+ if (!ao_log_running) {
+ ao_log_running = 1;
+ ao_wakeup(&ao_log_running);
+ }
+}
+
+void
+ao_log_stop(void)
+{
+ if (ao_log_running) {
+ ao_log_running = 0;
+ }
+}
+
+void
+ao_log_restart(void)
+{
+ /* Find end of data */
+ ao_log_end_pos = ao_storage_config;
+ for (ao_log_current_pos = 0;
+ ao_log_current_pos < ao_storage_config;
+ ao_log_current_pos += ao_storage_block)
+ {
+ if (!ao_log_telescience_read(ao_log_current_pos))
+ break;
+ }
+ if (ao_log_current_pos > 0) {
+ ao_log_current_pos -= ao_storage_block;
+ for (; ao_log_current_pos < ao_storage_config;
+ ao_log_current_pos += sizeof (struct ao_log_telescience))
+ {
+ if (!ao_log_telescience_read(ao_log_current_pos))
+ break;
+ }
+ }
+}
+
+void
+ao_log_telescience(void)
+{
+ ao_storage_setup();
+
+ /* This can take a while, so let the rest
+ * of the system finish booting before we start
+ */
+ ao_delay(AO_SEC_TO_TICKS(10));
+
+ ao_log_restart();
+ for (;;) {
+ while (!ao_log_running)
+ ao_sleep(&ao_log_running);
+
+ ao_log_start_pos = ao_log_current_pos;
+ ao_log_store.type = AO_LOG_TELESCIENCE_START;
+ ao_log_store.tick = ao_time();
+ ao_log_store.adc[0] = ao_companion_command.serial;
+ ao_log_store.adc[1] = ao_companion_command.flight;
+ ao_log_telescience_write();
+ /* Write the whole contents of the ring to the log
+ * when starting up.
+ */
+ ao_log_adc_pos = ao_adc_ring_next(ao_adc_head);
+ ao_log_store.type = AO_LOG_TELESCIENCE_DATA;
+ while (ao_log_running) {
+ /* Write samples to EEPROM */
+ while (ao_log_adc_pos != ao_adc_head) {
+ ao_log_store.tick = ao_adc_ring[ao_log_adc_pos].tick;
+ memcpy(&ao_log_store.adc, (void *) ao_adc_ring[ao_log_adc_pos].adc,
+ AO_LOG_TELESCIENCE_NUM_ADC * sizeof (uint16_t));
+ ao_log_telescience_write();
+ ao_log_adc_pos = ao_adc_ring_next(ao_log_adc_pos);
+ }
+ /* Wait for more ADC data to arrive */
+ ao_sleep((void *) &ao_adc_head);
+ }
+ memset(&ao_log_store.adc, '\0', sizeof (ao_log_store.adc));
+ }
+}
+
+void
+ao_log_set(void)
+{
+ printf("Logging currently %s\n", ao_log_running ? "on" : "off");
+ ao_cmd_hex();
+ if (ao_cmd_status == ao_cmd_success) {
+ if (ao_cmd_lex_i) {
+ printf("Logging from %ld to %ld\n", ao_log_current_pos, ao_log_end_pos);
+ ao_log_start();
+ } else {
+ printf ("Log stopped at %ld\n", ao_log_current_pos);
+ ao_log_stop();
+ }
+ }
+ ao_cmd_status = ao_cmd_success;
+}
+
+void
+ao_log_list(void)
+{
+ uint32_t pos;
+ uint32_t start = 0;
+ uint8_t flight = 0;
+
+ for (pos = 0; ; pos += sizeof (struct ao_log_telescience)) {
+ if (pos >= ao_storage_config ||
+ !ao_log_telescience_read(pos) ||
+ ao_log_fetch.type == AO_LOG_TELESCIENCE_START)
+ {
+ if (pos != start) {
+ printf("flight %d start %x end %x\n",
+ flight,
+ (uint16_t) (start >> 8),
+ (uint16_t) ((pos + 0xff) >> 8)); flush();
+ }
+ if (ao_log_fetch.type != AO_LOG_TELESCIENCE_START)
+ break;
+ start = pos;
+ flight++;
+ }
+ }
+ printf ("done\n");
+}
+
+void
+ao_log_delete(void)
+{
+ uint32_t pos;
+
+ ao_cmd_hex();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ if (ao_cmd_lex_i != 1) {
+ ao_cmd_status = ao_cmd_syntax_error;
+ printf("No such flight: %d\n", ao_cmd_lex_i);
+ return;
+ }
+ ao_log_stop();
+ for (pos = 0; pos < ao_storage_config; pos += ao_storage_block) {
+ if (!ao_log_telescience_read(pos))
+ break;
+ ao_storage_erase(pos);
+ }
+ ao_log_current_pos = ao_log_start_pos = 0;
+ if (pos == 0)
+ printf("No such flight: %d\n", ao_cmd_lex_i);
+ else
+ printf ("Erased\n");
+}
+
+static void
+ao_log_query(void)
+{
+ printf("Logging enabled: %d\n", ao_log_running);
+ printf("Log start: %ld\n", ao_log_start_pos);
+ printf("Log cur: %ld\n", ao_log_current_pos);
+ printf("Log end: %ld\n", ao_log_end_pos);
+ printf("log data tick: %04x\n", ao_log_store.tick);
+ printf("TM data tick: %04x\n", ao_log_store.tm_tick);
+ printf("TM state: %d\n", ao_log_store.tm_state);
+ printf("TM serial: %d\n", ao_companion_command.serial);
+ printf("TM flight: %d\n", ao_companion_command.flight);
+}
+
+const struct ao_cmds ao_log_cmds[] = {
+ { ao_log_set, "L <0 off, 1 on>\0Set logging mode" },
+ { ao_log_list, "l\0List stored flight logs" },
+ { ao_log_delete, "d 1\0Delete all stored flights" },
+ { ao_log_query, "q\0Query log status" },
+ { 0, NULL },
+};
+
+void
+ao_log_init(void)
+{
+ ao_log_running = 0;
+
+ ao_cmd_register(&ao_log_cmds[0]);
+
+ ao_add_task(&ao_log_task, ao_log_telescience, "log");
+}
#if !HAS_BEEP
#define ao_beep(x)
#endif
+#if !LEDS_AVAILABLE
+#define ao_led_on(x)
+#define ao_led_off(x)
+#endif
static void
ao_panic_delay(uint8_t n)
#define COMPANION_SELECT() do { ao_spi_get_bit(COMPANION_CS); ao_spi_slow(); } while (0)
#define COMPANION_DESELECT() do { ao_spi_fast(); ao_spi_put_bit(COMPANION_CS); } while (0)
-static __xdata struct ao_companion_command ao_companion_command;
+__xdata struct ao_companion_command ao_companion_command;
__xdata struct ao_companion_setup ao_companion_setup;
__xdata uint16_t ao_companion_data[AO_COMPANION_MAX_CHANNELS];
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+#define LCD_PORT PORTB
+#define LCD_DDR DDRB
+
+#define PIN_RS 4
+#define PIN_E 5
+#define PIN_RW 6
+
+void
+ao_lcd_set_bits(uint8_t bits)
+{
+#if 0
+ printf("\tLCD data %x RS %d R/W %d E %d\n",
+ bits & 0xf,
+ (bits & (1 << PIN_RS)) ? 1 : 0,
+ (bits & (1 << PIN_RW)) ? 1 : 0,
+ (bits & (1 << PIN_E)) ? 1 : 0);
+#endif
+ LCD_PORT = bits;
+#if 0
+ ao_delay(1);
+ if (bits & (1 << PIN_RW))
+ printf("\tLCD input %x\n", PINB);
+#endif
+}
+
+uint8_t
+ao_lcd_get_nibble(uint8_t rs)
+{
+ uint8_t data = (rs ? (1 << PIN_RS) : 0) | (1 << PIN_RW);
+ uint8_t n;
+
+ DDRB = (1 << PIN_RS) | (1 << PIN_E) | (1 << PIN_RW);
+ ao_lcd_set_bits(data);
+ ao_lcd_set_bits(data | (1 << PIN_E));
+ n = PINB & 0xf;
+ ao_lcd_set_bits(data);
+ return n;
+}
+
+uint8_t
+ao_lcd_get_status(void)
+{
+ uint8_t high, low;
+ uint8_t data;
+
+ high = ao_lcd_get_nibble(0);
+ low = ao_lcd_get_nibble(0);
+ data = (high << 4) | low;
+ printf ("\tLCD status %02x\n", data);
+ return data;
+}
+
+uint8_t
+ao_lcd_get_data(void)
+{
+ uint8_t high, low;
+ uint8_t data;
+
+ high = ao_lcd_get_nibble(1);
+ low = ao_lcd_get_nibble(1);
+ data = (high << 4) | low;
+ printf ("\tLCD data %02x\n", data);
+ return data;
+}
+
+void
+ao_lcd_wait_idle(void)
+{
+ uint8_t status;
+ uint8_t count = 0;
+
+ do {
+ status = ao_lcd_get_status();
+ count++;
+ if (count > 100) {
+ printf("idle timeout\n");
+ break;
+ }
+ } while (0); /* status & 0x80); */
+}
+
+void
+ao_lcd_send_nibble(uint8_t rs, uint8_t data)
+{
+ data = (data & 0xf) | (rs ? (1 << PIN_RS) : 0);
+ DDRB = (0xf) | (1 << PIN_RS) | (1 << PIN_E) | (1 << PIN_RW);
+ ao_lcd_set_bits(data);
+ ao_lcd_set_bits(data | (1 << PIN_E));
+ ao_lcd_set_bits(data);
+}
+
+static uint16_t ao_lcd_time = 3;
+
+void
+ao_lcd_delay(void)
+{
+ volatile uint16_t count;
+
+ for (count = 0; count < ao_lcd_time; count++)
+ ;
+}
+
+void
+ao_lcd_send_ins(uint8_t data)
+{
+// printf("send ins %02x\n", data);
+// ao_lcd_wait_idle();
+// ao_delay(1);
+ ao_lcd_delay();
+ ao_lcd_send_nibble(0, data >> 4);
+ ao_lcd_send_nibble(0, data & 0xf);
+}
+
+void
+ao_lcd_send_data(uint8_t data)
+{
+// printf ("send data %02x\n", data);
+// ao_lcd_wait_idle();
+ ao_lcd_delay();
+ ao_lcd_send_nibble(1, data >> 4);
+ ao_lcd_send_nibble(1, data & 0x0f);
+}
+
+void
+ao_lcd_send_string(char *string)
+{
+ uint8_t c;
+
+ while ((c = (uint8_t) *string++))
+ ao_lcd_send_data(c);
+}
+
+#define AO_LCD_POWER_CONTROL 0x54
+
+void
+ao_lcd_contrast_set(uint8_t contrast)
+{
+ ao_lcd_send_ins(AO_LCD_POWER_CONTROL | ((contrast >> 4) & 0x3));
+ ao_lcd_send_ins(0x70 | (contrast & 0xf));
+}
+
+void
+ao_lcd_clear(void)
+{
+ ao_lcd_send_ins(0x01);
+ ao_delay(1);
+ /* Entry mode */
+ ao_lcd_send_ins(0x04 | 0x02);
+}
+
+void
+ao_lcd_start(void)
+{
+ /* get to 4bit mode */
+ ao_lcd_send_nibble(0, 0x3);
+ ao_lcd_send_nibble(0, 0x3);
+ ao_lcd_send_nibble(0, 0x3);
+ ao_lcd_send_nibble(0, 0x2);
+
+ /* function set */
+ ao_lcd_send_ins(0x28);
+ /* function set, instruction table 1 */
+ ao_lcd_send_ins(0x29);
+
+ /* freq set */
+ ao_lcd_send_ins(0x14);
+
+ /* Power/icon/contrast control*/
+ ao_lcd_send_ins(AO_LCD_POWER_CONTROL);
+
+ /* Follower control */
+ ao_lcd_send_ins(0x6d);
+ ao_delay(AO_MS_TO_TICKS(200));
+
+ /* contrast set */
+ ao_lcd_contrast_set(0x18);
+
+ /* Display on */
+ ao_lcd_send_ins(0x08 | 0x04);
+
+ /* Clear */
+ ao_lcd_clear();
+
+}
+
+void
+ao_lcd_contrast(void)
+{
+ ao_cmd_hex();
+ if (ao_cmd_status == ao_cmd_success) {
+ printf("setting contrast to %02x\n", ao_cmd_lex_i);
+ ao_lcd_contrast_set(ao_cmd_lex_i & 0x3f);
+ }
+}
+
+static uint8_t
+ao_cmd_hex_nibble(void)
+{
+ if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9')
+ return ao_cmd_lex_c - '0';
+ if ('a' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'f')
+ return ao_cmd_lex_c - ('a' - 10);
+ if ('A' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'F')
+ return ao_cmd_lex_c - ('A' - 10);
+ ao_cmd_status = ao_cmd_syntax_error;
+ return 0;
+}
+
+void
+ao_lcd_string(void)
+{
+ uint8_t col = 0;
+ uint8_t c;
+
+ ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ ao_lcd_send_ins(0x80 | (ao_cmd_lex_i ? 0x40 : 0x00));
+ ao_cmd_white();
+ while (ao_cmd_lex_c != '\n') {
+ c = ao_cmd_lex_c;
+ if (c == '\\') {
+ ao_cmd_lex();
+ c = ao_cmd_hex_nibble() << 4;
+ ao_cmd_lex();
+ c |= ao_cmd_hex_nibble();
+ }
+ ao_lcd_send_data(c);
+ ao_cmd_lex();
+ col++;
+ }
+ while (col < 16) {
+ ao_lcd_send_data(' ');
+ col++;
+ }
+}
+
+void
+ao_lcd_delay_set(void)
+{
+ ao_cmd_decimal();
+ if (ao_cmd_status == ao_cmd_success) {
+ printf("setting LCD delay to %d\n", ao_cmd_lex_i);
+ ao_lcd_time = ao_cmd_lex_i;
+ }
+}
+
+__code struct ao_cmds ao_lcd_cmds[] = {
+ { ao_lcd_start, "S\0Start LCD" },
+ { ao_lcd_contrast, "C <contrast>\0Set LCD contrast" },
+ { ao_lcd_string, "s <line> <string>\0Send string to LCD" },
+ { ao_lcd_delay_set, "t <delay>\0Set LCD delay" },
+ { 0, NULL },
+};
+
+void
+ao_lcd_init(void)
+{
+ DDRB = (1 << PIN_RS) | (1 << PIN_E) | (1 << PIN_RW);
+ PORTB = 0;
+ ao_cmd_register(&ao_lcd_cmds[0]);
+}
/* Set up chip select wires */
SPI_CS_PORT |= M25_CS_MASK; /* raise all CS pins */
SPI_CS_DIR |= M25_CS_MASK; /* set CS pins as outputs */
+#ifdef SPI_CS_SEL
SPI_CS_SEL &= ~M25_CS_MASK; /* set CS pins as GPIO */
+#endif
}
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+int
+main(void)
+{
+ ao_clock_init();
+
+ PORTE |= (1 << 6);
+ DDRE |= (1 << 6);
+
+ ao_avr_stdio_init();
+ ao_timer_init();
+ ao_cmd_init();
+ ao_spi_init();
+ ao_spi_slave_init();
+ ao_storage_init();
+ ao_usb_init();
+ ao_adc_init();
+ ao_log_init();
+ ao_start_scheduler();
+ return 0;
+}
--- /dev/null
+#
+# AltOS build
+#
+#
+vpath % ..:../core:../product:../drivers:../avr
+vpath ao-make-product.5c ../util
+
+MCU=atmega32u4
+DUDECPUTYPE=m32u4
+#PROGRAMMER=stk500v2 -P usb
+PROGRAMMER=usbtiny
+LOADCMD=avrdude
+LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w:
+CC=avr-gcc
+OBJCOPY=avr-objcopy
+
+ifndef VERSION
+include ../Version
+endif
+
+INC = \
+ ao.h \
+ ao_usb.h \
+ ao_pins.h \
+ altitude.h
+
+#
+# Common AltOS sources
+#
+TELESCIENCE_STORAGE= \
+ ao_m25.c \
+ ao_spi_usart.c \
+ ao_storage.c \
+
+ALTOS_SRC = \
+ ao_cmd.c \
+ ao_mutex.c \
+ ao_panic.c \
+ ao_product.c \
+ ao_stdio.c \
+ ao_task.c \
+ ao_timer.c \
+ ao_led.c \
+ ao_avr_stdio.c \
+ ao_romconfig.c \
+ ao_usb_avr.c \
+ ao_adc_avr.c \
+ ao_spi_slave.c \
+ ao_log_telescience.c \
+ $(TELESCIENCE_STORAGE)
+
+PRODUCT=TeleScience-v0.1
+MCU=atmega32u4
+PRODUCT_DEF=-DTELESCIENCE
+IDPRODUCT=0x0011
+CFLAGS = $(PRODUCT_DEF) -I. -I../avr -I../core -I..
+CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O3 -mcall-prologues -DAVR
+
+NICKLE=nickle
+
+PROG=telescience-v0.1
+
+SRC=$(ALTOS_SRC) ao_telescience.c
+OBJ=$(SRC:.c=.o)
+
+V=0
+# The user has explicitly enabled quiet compilation.
+ifeq ($(V),0)
+quiet = @printf " $1 $2 $@\n"; $($1)
+endif
+# Otherwise, print the full command line.
+quiet ?= $($1)
+
+all: $(PROG)
+
+CHECK=sh ../util/check-avr-mem
+
+$(PROG): Makefile $(OBJ)
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ)
+ $(call quiet,CHECK) $(PROG) || ($(RM) -f $(PROG); exit 1)
+
+$(PROG).hex: $(PROG)
+ avr-size $(PROG)
+ $(OBJCOPY) -R .eeprom -O ihex $(PROG) $@
+
+
+load: $(PROG).hex
+ $(LOADCMD) $(LOADARG)$(PROG).hex
+
+../altitude.h: make-altitude
+ nickle $< > $@
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+ao_product.rel: ao_product.c ao_product.h
+ $(call quiet,CC) -c $(CFLAGS) -D PRODUCT_DEFS='\"ao_product.h\"' -o$@ $<
+
+distclean: clean
+
+clean:
+ rm -f $(OBJ)
+ rm -f ao_product.h
+
+install:
+
+uninstall:
+
+$(OBJ): ao.h ao_product.h ao_usb.h
--- /dev/null
+#!/bin/sh
+nm "$@" |
+grep ' N _end' |
+awk '{ iram = strtonum("0x" $1) % 0x10000;
+if ( iram > 0xaff) {
+ printf ("%d bytes of ram more than %d available\n", iram, 0xaff);
+ exit(1);
+} else
+ exit(0); }'