From 9513be7f9d3d0b0ec29f6487fa9dc8f1ac24d0de Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 25 Aug 2011 20:43:44 -0700 Subject: altos: Restructure altos build to prepare for multi-arch support Split out sources into separate directories: core: architecture and product independent bits cc1111: cc1111-specific code drivers: architecture independent drivers product: product-specific sources and Makefile fragments util: scripts for building stuff This should have no effect on the built products, but testing is encouraged Signed-off-by: Keith Packard --- src/core/ao_task.c | 275 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 src/core/ao_task.c (limited to 'src/core/ao_task.c') diff --git a/src/core/ao_task.c b/src/core/ao_task.c new file mode 100644 index 00000000..f5850fa4 --- /dev/null +++ b/src/core/ao_task.c @@ -0,0 +1,275 @@ +/* + * Copyright © 2009 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" + +#define AO_NO_TASK_INDEX 0xff + +__xdata struct ao_task * __xdata ao_tasks[AO_NUM_TASKS]; +__data uint8_t ao_num_tasks; +__data uint8_t ao_cur_task_index; +__xdata struct ao_task *__data ao_cur_task; + +void +ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant +{ + uint8_t __xdata *stack; + uint8_t task_id; + uint8_t t; + if (ao_num_tasks == AO_NUM_TASKS) + ao_panic(AO_PANIC_NO_TASK); + for (task_id = 1; task_id != 0; task_id++) { + for (t = 0; t < ao_num_tasks; t++) + if (ao_tasks[t]->task_id == task_id) + break; + if (t == ao_num_tasks) + break; + } + ao_tasks[ao_num_tasks++] = task; + task->task_id = task_id; + task->name = name; + /* + * Construct a stack frame so that it will 'return' + * to the start of the task + */ + stack = task->stack; + + *stack++ = ((uint16_t) start); /* 0 */ + *stack++ = ((uint16_t) start) >> 8; /* 1 */ + + /* and the stuff saved by ao_switch */ + *stack++ = 0; /* 2 acc */ + *stack++ = 0x80; /* 3 IE */ + + /* 4 DPL + * 5 DPH + * 6 B + * 7 R2 + * 8 R3 + * 9 R4 + * 10 R5 + * 11 R6 + * 12 R7 + * 13 R0 + * 14 R1 + * 15 PSW + * 16 BP + */ + for (t = 0; t < 13; t++) + *stack++ = 0; + + task->stack_count = 17; + task->wchan = NULL; +} + +/* Task switching function. This must not use any stack variables */ +void +ao_yield(void) __naked +{ + + /* Save current context */ + _asm + /* Push ACC first, as when restoring the context it must be restored + * last (it is used to set the IE register). */ + push ACC + /* Store the IE register then enable interrupts. */ + push _IEN0 + setb _EA + push DPL + push DPH + push b + push ar2 + push ar3 + push ar4 + push ar5 + push ar6 + push ar7 + push ar0 + push ar1 + push PSW + _endasm; + PSW = 0; + _asm + push _bp + _endasm; + + if (ao_cur_task_index == AO_NO_TASK_INDEX) + ao_cur_task_index = ao_num_tasks-1; + else + { + uint8_t stack_len; + __data uint8_t *stack_ptr; + __xdata uint8_t *save_ptr; + /* Save the current stack */ + stack_len = SP - (AO_STACK_START - 1); + ao_cur_task->stack_count = stack_len; + stack_ptr = (uint8_t __data *) AO_STACK_START; + save_ptr = (uint8_t __xdata *) ao_cur_task->stack; + do + *save_ptr++ = *stack_ptr++; + while (--stack_len); + } + + /* Empty the stack; might as well let interrupts have the whole thing */ + SP = AO_STACK_START - 1; + + /* Find a task to run. If there isn't any runnable task, + * this loop will run forever, which is just fine + */ + { + __pdata uint8_t ao_next_task_index = ao_cur_task_index; + for (;;) { + ++ao_next_task_index; + if (ao_next_task_index == ao_num_tasks) + ao_next_task_index = 0; + + ao_cur_task = ao_tasks[ao_next_task_index]; + if (ao_cur_task->wchan == NULL) { + ao_cur_task_index = ao_next_task_index; + break; + } + + /* Check if the alarm is set for a time which has passed */ + if (ao_cur_task->alarm && + (int16_t) (ao_time() - ao_cur_task->alarm) >= 0) { + ao_cur_task_index = ao_next_task_index; + break; + } + + /* Enter lower power mode when there isn't anything to do */ + if (ao_next_task_index == ao_cur_task_index) + PCON = PCON_IDLE; + } + } + + { + uint8_t stack_len; + __data uint8_t *stack_ptr; + __xdata uint8_t *save_ptr; + + /* Restore the old stack */ + stack_len = ao_cur_task->stack_count; + SP = AO_STACK_START - 1 + stack_len; + + stack_ptr = (uint8_t __data *) AO_STACK_START; + save_ptr = (uint8_t __xdata *) ao_cur_task->stack; + do + *stack_ptr++ = *save_ptr++; + while (--stack_len); + } + + _asm + pop _bp + pop PSW + pop ar1 + pop ar0 + pop ar7 + pop ar6 + pop ar5 + pop ar4 + pop ar3 + pop ar2 + pop b + pop DPH + pop DPL + /* The next byte of the stack is the IE register. Only the global + enable bit forms part of the task context. Pop off the IE then set + the global enable bit to match that of the stored IE register. */ + pop ACC + JB ACC.7,0098$ + CLR _EA + LJMP 0099$ + 0098$: + SETB _EA + 0099$: + /* Finally pop off the ACC, which was the first register saved. */ + pop ACC + ret + _endasm; +} + +uint8_t +ao_sleep(__xdata void *wchan) +{ + __critical { + ao_cur_task->wchan = wchan; + } + ao_yield(); + ao_cur_task->alarm = 0; + if (ao_cur_task->wchan) { + ao_cur_task->wchan = NULL; + return 1; + } + return 0; +} + +void +ao_wakeup(__xdata void *wchan) +{ + uint8_t i; + + for (i = 0; i < ao_num_tasks; i++) + if (ao_tasks[i]->wchan == wchan) + ao_tasks[i]->wchan = NULL; +} + +void +ao_alarm(uint16_t delay) +{ + /* Make sure we sleep *at least* delay ticks, which means adding + * one to account for the fact that we may be close to the next tick + */ + if (!(ao_cur_task->alarm = ao_time() + delay + 1)) + ao_cur_task->alarm = 1; +} + +void +ao_exit(void) __critical +{ + uint8_t i; + ao_num_tasks--; + for (i = ao_cur_task_index; i < ao_num_tasks; i++) + ao_tasks[i] = ao_tasks[i+1]; + ao_cur_task_index = AO_NO_TASK_INDEX; + ao_yield(); + /* we'll never get back here */ +} + +void +ao_task_info(void) +{ + uint8_t i; + uint8_t pc_loc; + __xdata struct ao_task *task; + + for (i = 0; i < ao_num_tasks; i++) { + task = ao_tasks[i]; + pc_loc = task->stack_count - 17; + printf("%12s: wchan %04x pc %04x\n", + task->name, + (int16_t) task->wchan, + (task->stack[pc_loc]) | (task->stack[pc_loc+1] << 8)); + } +} + +void +ao_start_scheduler(void) +{ + ao_cur_task_index = AO_NO_TASK_INDEX; + ao_cur_task = NULL; + ao_yield(); +} -- cgit v1.2.3 From e9fab7dc99a0e7c22b511c5919adf7df85213252 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 25 Aug 2011 22:04:36 -0700 Subject: altos: add GCC/SDCC compat macros, init_stack, save_context and GCC stdio hooks More arch-indepdency bits. GCC stdio is different from SDCC, so create suitable code in avr/ao_avr_stdio.c Create macros to initialize the task stack frame and save the task context. Add GCC/SDCC type definition compatibility macros Signed-off-by: Keith Packard --- src/avr-demo/Makefile | 102 ++++++++++ src/avr/ao_arch.h | 67 ++++++- src/avr/ao_avr_stdio.c | 52 +++++ src/avr/ao_pins.h | 31 +++ src/cc1111/ao_arch.h | 99 ++++++++++ src/cc1111/ao_pins.h | 425 ++++++++++++++++++++++++++++++++++++++++ src/core/ao.h | 76 ++----- src/core/ao_panic.c | 2 +- src/core/ao_pins.h | 408 -------------------------------------- src/core/ao_task.c | 60 +----- src/product/Makefile.telebt | 2 +- src/product/Makefile.teledongle | 2 +- src/product/Makefile.telemetrum | 2 +- src/product/Makefile.telemini | 2 +- src/product/Makefile.telenano | 2 +- src/tidongle/Makefile | 2 +- 16 files changed, 805 insertions(+), 529 deletions(-) create mode 100644 src/avr-demo/Makefile create mode 100644 src/avr/ao_avr_stdio.c create mode 100644 src/avr/ao_pins.h create mode 100644 src/cc1111/ao_pins.h delete mode 100644 src/core/ao_pins.h (limited to 'src/core/ao_task.c') diff --git a/src/avr-demo/Makefile b/src/avr-demo/Makefile new file mode 100644 index 00000000..ea356654 --- /dev/null +++ b/src/avr-demo/Makefile @@ -0,0 +1,102 @@ +# +# AltOS build +# +# +vpath % ..:../core:../product:../driver +vpath make-altitude .. +vpath make-kalman .. +vpath kalman.5c ../kalman +vpath kalman_filter.5c ../kalman +vpath load_csv.5c ../kalman +vpath matrix.5c ../kalman +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_pins.h \ + altitude.h \ + ao_kalman.h + +# +# Common AltOS sources +# +ALTOS_SRC = \ + ao_cmd.c \ + ao_mutex.c \ + ao_panic.c \ + ao_product.c \ + ao_serial_avr.c \ + ao_avr_stdio.c \ + ao_stdio.c \ + ao_task.c \ + ao_timer.c \ + ao_led.c + +PRODUCT=AvrDemo-v0.0 +MCU=atmega32u4 +PRODUCT_DEF=-DAVR_DEMO +IDPRODUCT=0x000a +CFLAGS = $(PRODUCT_DEF) -I. -I../avr -I../core -I.. +CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -Os -mcall-prologues + +NICKLE=nickle + +PROG=avr-demo + +SRC=$(ALTOS_SRC) ao_demo.c ao_debug_avr.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) + +$(PROG): Makefile $(OBJ) + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) + +$(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 \ No newline at end of file diff --git a/src/avr/ao_arch.h b/src/avr/ao_arch.h index 2b566814..51a65880 100644 --- a/src/avr/ao_arch.h +++ b/src/avr/ao_arch.h @@ -18,8 +18,18 @@ #ifndef _AO_ARCH_H_ #define _AO_ARCH_H_ -#include "avr.h" +#include +#include +#ifdef AVR_DEMO +#define TEENSY 1 +#endif + +#if TEENSY +#define F_CPU 16000000UL // 16 MHz +#else +#define F_CPU 8000000UL // 8 MHz +#endif /* * AVR definitions and code fragments for AltOS @@ -29,8 +39,61 @@ /* Various definitions to make GCC look more like SDCC */ -#define __naked __attribute__((naked)) +#define ao_arch_naked_declare __attribute__((naked)) +#define ao_arch_naked_define +#define __pdata +#define __data +#define __xdata +#define __code const +#define __reentrant +#define __critical +#define __interrupt(n) #define ao_arch_reboot() /* XXX */ +#define ao_arch_nop() asm("nop") + +#define ao_arch_interrupt(n) /* nothing */ + +#undef putchar +#undef getchar +#define putchar(c) ao_putchar(c) +#define getchar ao_getchar + +extern void putchar(char c); +extern char getchar(void); + +extern int ao_serial_number; + +#define ao_arch_init_stack(task, start) do { \ + uint8_t *sp = task->stack + AO_STACK_SIZE - 1; \ + uint16_t a = (uint16_t) start; \ + int i; \ + \ + /* Return address */ \ + PUSH8(sp, a); \ + PUSH8(sp, (a >> 8)); \ + \ + /* Clear register values */ \ + i = 32; \ + while (i--) \ + PUSH8(sp, 0); \ + \ + /* SREG with interrupts enabled */ \ + PUSH8(sp, 0x80); \ + task->sp = sp; \ +} while (0); + +#define ao_arch_save_context() do { \ + asm("push r31" "\n\t" "push r30"); \ + asm("push r29" "\n\t" "push r28" "\n\t" "push r27" "\n\t" "push r26" "\n\t" "push r25"); \ + asm("push r24" "\n\t" "push r23" "\n\t" "push r22" "\n\t" "push r21" "\n\t" "push r20"); \ + asm("push r19" "\n\t" "push r18" "\n\t" "push r17" "\n\t" "push r16" "\n\t" "push r15"); \ + asm("push r14" "\n\t" "push r13" "\n\t" "push r12" "\n\t" "push r11" "\n\t" "push r10"); \ + asm("push r9" "\n\t" "push r8" "\n\t" "push r7" "\n\t" "push r6" "\n\t" "push r5"); \ + asm("push r4" "\n\t" "push r3" "\n\t" "push r2" "\n\t" "push r1" "\n\t" "push r0"); \ + asm("in r0, __SREG__" "\n\t" "push r0"); \ + sei(); \ + } while (0) + #endif /* _AO_ARCH_H_ */ diff --git a/src/avr/ao_avr_stdio.c b/src/avr/ao_avr_stdio.c new file mode 100644 index 00000000..2f358eb5 --- /dev/null +++ b/src/avr/ao_avr_stdio.c @@ -0,0 +1,52 @@ +/* + * 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" + +int +stdio_put(char c, FILE *stream) +{ + if (ao_cur_task && ao_num_stdios) + putchar(c); + else + { + if (c == '\n') + stdio_put('\r', stream); + loop_until_bit_is_set(UCSR1A, UDRE1); + UDR1 = c; + } + + return 0; +} + +int +stdio_get(FILE *stream) +{ + return (int) getchar() & 0xff; +} + +static FILE mystdout = FDEV_SETUP_STREAM(stdio_put, NULL, _FDEV_SETUP_WRITE); + +static FILE mystdin = FDEV_SETUP_STREAM(NULL, stdio_get, _FDEV_SETUP_READ); + +void +ao_stdio_init(void) +{ + stdout = &mystdout; + stdin = &mystdin; + printf("%d stdios registered\n", ao_num_stdios); +} diff --git a/src/avr/ao_pins.h b/src/avr/ao_pins.h new file mode 100644 index 00000000..ef41b59c --- /dev/null +++ b/src/avr/ao_pins.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#ifdef AVR_DEMO + #define AO_LED_RED (1<<7) + #define LEDS_AVAILABLE (AO_LED_RED) + #define USE_SERIAL_STDIN 1 + #define HAS_USB 0 + #define PACKET_HAS_SLAVE 0 + #define HAS_SERIAL_1 1 + #define HAS_BEEP 0 +#endif + +#endif /* _AO_PINS_H_ */ diff --git a/src/cc1111/ao_arch.h b/src/cc1111/ao_arch.h index 585fffe5..35fd66f8 100644 --- a/src/cc1111/ao_arch.h +++ b/src/cc1111/ao_arch.h @@ -24,9 +24,108 @@ #include "cc1111.h" +/* Convert a __data pointer into an __xdata pointer */ +#define DATA_TO_XDATA(a) ((void __xdata *) ((uint8_t) (a) | 0xff00)) + +/* Stack runs from above the allocated __data space to 0xfe, which avoids + * writing to 0xff as that triggers the stack overflow indicator + */ +#define AO_STACK_START 0x90 +#define AO_STACK_END 0xfe +#define AO_STACK_SIZE (AO_STACK_END - AO_STACK_START + 1) + #define ao_arch_reboot() do { \ WDCTL = WDCTL_EN | WDCTL_MODE_WATCHDOG | WDCTL_INT_64; \ ao_delay(AO_SEC_TO_TICKS(2)); \ } while (0) +#define ao_arch_nop() _asm nop _endasm +#define ao_arch_interrupt(n) __interrupt n + +#define ao_arch_naked_declare __naked +#define ao_arch_naked_define __naked + +/* CC1111-specific drivers */ + +/* + * ao_romconfig.c + */ + +#define AO_ROMCONFIG_VERSION 2 + +extern __code __at (0x00a0) uint16_t ao_romconfig_version; +extern __code __at (0x00a2) uint16_t ao_romconfig_check; +extern __code __at (0x00a4) uint16_t ao_serial_number; +extern __code __at (0x00a6) uint32_t ao_radio_cal; + +#ifndef HAS_USB +#error Please define HAS_USB +#endif + +#if HAS_USB +extern __code __at (0x00aa) uint8_t ao_usb_descriptors []; +#endif + +/* Initialize stack */ +#define ao_arch_init_stack(task, start) { \ + uint8_t __xdata *stack = task->stack; \ + uint8_t t; \ + *stack++ = ((uint16_t) start); /* 0 */ \ + *stack++ = ((uint16_t) start) >> 8; /* 1 */ \ + \ + /* and the stuff saved by ao_switch */ \ + *stack++ = 0; /* 2 acc */ \ + *stack++ = 0x80; /* 3 IE */ \ + \ + /* 4 DPL \ + * 5 DPH \ + * 6 B \ + * 7 R2 \ + * 8 R3 \ + * 9 R4 \ + * 10 R5 \ + * 11 R6 \ + * 12 R7 \ + * 13 R0 \ + * 14 R1 \ + * 15 PSW \ + * 16 BP \ + */ \ + for (t = 0; t < 13; t++) \ + *stack++ = 0; \ + task->stack_count = 17; \ + } + + + +/* Save current context */ + +#define ao_arch_save_context() \ + _asm \ + /* Push ACC first, as when restoring the context it must be restored \ + * last (it is used to set the IE register). */ \ + push ACC \ + /* Store the IE register then enable interrupts. */ \ + push _IEN0 \ + setb _EA \ + push DPL \ + push DPH \ + push b \ + push ar2 \ + push ar3 \ + push ar4 \ + push ar5 \ + push ar6 \ + push ar7 \ + push ar0 \ + push ar1 \ + push PSW \ + _endasm; \ + PSW = 0; \ + _asm \ + push _bp \ + _endasm + + + #endif /* _AO_ARCH_H_ */ diff --git a/src/cc1111/ao_pins.h b/src/cc1111/ao_pins.h new file mode 100644 index 00000000..4ac6a84b --- /dev/null +++ b/src/cc1111/ao_pins.h @@ -0,0 +1,425 @@ +/* + * 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_ + +#if defined(TELEMETRUM_V_1_0) + #define HAS_FLIGHT 1 + #define HAS_USB 1 + #define HAS_BEEP 1 + #define HAS_GPS 1 + #define HAS_SERIAL_1 1 + #define HAS_ADC 1 + #define USE_SERIAL_STDIN 0 + #define HAS_EEPROM 1 + #define USE_INTERNAL_FLASH 0 + #define HAS_DBG 1 + #define DBG_ON_P1 1 + #define DBG_ON_P0 0 + #define IGNITE_ON_P2 1 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 0 + #define PACKET_HAS_SLAVE 1 + + #define HAS_COMPANION 1 + #define COMPANION_CS_ON_P1 1 + #define COMPANION_CS_MASK 0x4 /* CS1 is P1_2 */ + #define COMPANION_CS P1_2 + + #define AO_LED_RED 1 + #define LEDS_AVAILABLE (AO_LED_RED) + #define HAS_EXTERNAL_TEMP 0 + #define HAS_ACCEL_REF 0 + #define HAS_ACCEL 1 + #define HAS_IGNITE 1 + #define HAS_MONITOR 0 +#endif + +#if defined(TELEMETRUM_V_1_1) + #define HAS_FLIGHT 1 + #define HAS_USB 1 + #define HAS_BEEP 1 + #define HAS_GPS 1 + #define HAS_SERIAL_1 1 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 1 + #define HAS_EEPROM 1 + #define USE_INTERNAL_FLASH 0 + #define HAS_DBG 1 + #define DBG_ON_P1 1 + #define DBG_ON_P0 0 + #define IGNITE_ON_P2 1 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 0 + #define PACKET_HAS_SLAVE 1 + + #define HAS_COMPANION 1 + #define COMPANION_CS_ON_P1 1 + #define COMPANION_CS_MASK 0x4 /* CS1 is P1_2 */ + #define COMPANION_CS P1_2 + + #define AO_LED_RED 1 + #define LEDS_AVAILABLE (AO_LED_RED) + #define HAS_EXTERNAL_TEMP 0 + #define HAS_ACCEL_REF 1 + #define SPI_CS_ON_P1 1 + #define SPI_CS_ON_P0 0 + #define M25_CS_MASK 0x02 /* CS0 is P1_1 */ + #define M25_MAX_CHIPS 1 + #define HAS_ACCEL 1 + #define HAS_IGNITE 1 + #define HAS_MONITOR 0 +#endif + +#if defined(TELEDONGLE_V_0_2) + #define HAS_FLIGHT 0 + #define HAS_USB 1 + #define HAS_BEEP 0 + #define HAS_SERIAL_1 0 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 0 + #define HAS_DBG 1 + #define HAS_EEPROM 0 + #define DBG_ON_P1 1 + #define DBG_ON_P0 0 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 1 + #define PACKET_HAS_SLAVE 0 + #define AO_LED_RED 1 + #define AO_LED_GREEN 2 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define SPI_CS_ON_P1 1 + #define SPI_CS_ON_P0 0 + #define HAS_IGNITE 0 + #define HAS_MONITOR 1 +#endif + +#if defined(TELEMINI_V_1_0) + #define HAS_FLIGHT 1 + #define HAS_USB 0 + #define HAS_BEEP 0 + #define HAS_GPS 0 + #define HAS_SERIAL_1 0 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 1 + #define HAS_EEPROM 1 + #define USE_INTERNAL_FLASH 1 + #define HAS_DBG 0 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 1 + #define PACKET_HAS_MASTER 0 + #define PACKET_HAS_SLAVE 1 + #define USE_FAST_ASCENT_LOG 1 + + #define AO_LED_GREEN 1 + #define AO_LED_RED 2 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define HAS_EXTERNAL_TEMP 0 + #define HAS_ACCEL 0 + #define HAS_IGNITE 1 + #define HAS_MONITOR 0 +#endif + +#if defined(TELENANO_V_0_1) + #define HAS_FLIGHT 1 + #define HAS_USB 0 + #define HAS_BEEP 0 + #define HAS_GPS 0 + #define HAS_SERIAL_1 0 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 1 + #define HAS_EEPROM 1 + #define USE_INTERNAL_FLASH 1 + #define HAS_DBG 0 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 1 + #define PACKET_HAS_MASTER 0 + #define PACKET_HAS_SLAVE 1 + + #define AO_LED_GREEN 1 + #define AO_LED_RED 2 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define HAS_EXTERNAL_TEMP 0 + #define HAS_ACCEL 0 + #define HAS_IGNITE 0 + #define HAS_MONITOR 0 +#endif + +#if defined(TELEMETRUM_V_0_1) + #define HAS_FLIGHT 1 + #define HAS_USB 1 + #define HAS_BEEP 1 + #define HAS_GPS 1 + #define HAS_SERIAL_1 1 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 1 + #define HAS_DBG 0 + #define HAS_EEPROM 1 + #define USE_INTERNAL_FLASH 0 + #define DBG_ON_P1 0 + #define DBG_ON_P0 1 + #define IGNITE_ON_P2 1 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 0 + #define PACKET_HAS_SLAVE 1 + #define AO_LED_RED 2 + #define AO_LED_GREEN 1 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define HAS_EXTERNAL_TEMP 1 + #define HAS_ACCEL_REF 0 + #define SPI_CS_ON_P1 1 + #define SPI_CS_ON_P0 0 + #define HAS_ACCEL 1 + #define HAS_IGNITE 1 + #define HAS_MONITOR 0 +#endif + +#if defined(TELEDONGLE_V_0_1) + #define HAS_FLIGHT 0 + #define HAS_USB 1 + #define HAS_BEEP 0 + #define HAS_SERIAL_1 0 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 0 + #define HAS_DBG 0 + #define HAS_EEPROM 0 + #define DBG_ON_P1 0 + #define DBG_ON_P0 1 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 1 + #define PACKET_HAS_SLAVE 0 + #define AO_LED_RED 2 + #define AO_LED_GREEN 1 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define SPI_CS_ON_P1 0 + #define SPI_CS_ON_P0 1 + #define HAS_IGNITE 0 + #define HAS_MONITOR 1 +#endif + +#if defined(TIDONGLE) + #define HAS_FLIGHT 0 + #define HAS_USB 1 + #define HAS_BEEP 0 + #define HAS_SERIAL_1 0 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 0 + #define HAS_DBG 1 + #define HAS_EEPROM 0 + #define DBG_ON_P1 0 + #define DBG_ON_P0 1 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 1 + #define PACKET_HAS_SLAVE 0 + #define AO_LED_RED 2 + #define LEDS_AVAILABLE (AO_LED_RED) + #define SPI_CS_ON_P1 0 + #define SPI_CS_ON_P0 1 + #define HAS_IGNITE 0 + #define HAS_MONITOR 1 +#endif + +#if defined(TELEBT_V_0_0) + #define HAS_FLIGHT 0 + #define HAS_USB 1 + #define HAS_BEEP 0 + #define HAS_SERIAL_1 1 + #define USE_SERIAL_STDIN 1 + #define HAS_ADC 0 + #define HAS_DBG 1 + #define HAS_EEPROM 0 + #define HAS_BTM 1 + #define DBG_ON_P1 0 + #define DBG_ON_P0 1 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 1 + #define PACKET_HAS_SLAVE 0 + #define AO_LED_RED 2 + #define AO_LED_GREEN 1 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define SPI_CS_ON_P1 1 + #define SPI_CS_ON_P0 0 + #define HAS_IGNITE 0 + #define BT_LINK_ON_P2 1 + #define BT_LINK_ON_P1 0 + #define BT_LINK_PIN_INDEX 7 + #define BT_LINK_PIN P2_1 + #define HAS_MONITOR 1 +#endif + +#if defined(TELEBT_V_0_1) + #define HAS_FLIGHT 0 + #define HAS_USB 1 + #define HAS_BEEP 1 + #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_STDIN 1 + #define HAS_ADC 0 + #define HAS_DBG 1 + #define HAS_EEPROM 1 + #define USE_INTERNAL_FLASH 0 + #define HAS_BTM 1 + #define DBG_ON_P1 1 + #define DBG_ON_P0 0 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 1 + #define PACKET_HAS_SLAVE 0 + #define AO_LED_RED 1 + #define AO_LED_GREEN 2 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define SPI_CS_ON_P1 1 + #define SPI_CS_ON_P0 0 + #define M25_CS_MASK 0x04 /* CS0 is P1_2 */ + #define M25_MAX_CHIPS 1 + #define HAS_ACCEL 0 + #define HAS_IGNITE 0 + #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 +#endif + +#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 */ + +#if COMPANION_CS_ON_P1 + #define COMPANION_CS_PORT P1 + #define COMPANION_CS_SEL P1SEL + #define COMPANION_CS_DIR P1DIR +#endif + +#if SPI_CS_ON_P1 + #define SPI_CS_PORT P1 + #define SPI_CS_SEL P1SEL + #define SPI_CS_DIR P1DIR +#endif + +#if SPI_CS_ON_P0 + #define SPI_CS_PORT P0 + #define SPI_CS_SEL P0SEL + #define SPI_CS_DIR P0DIR +#endif + +#ifndef IGNITE_ON_P2 +#error Please define IGNITE_ON_P2 +#endif + +#ifndef IGNITE_ON_P0 +#error Please define IGNITE_ON_P0 +#endif + +#ifndef HAS_SERIAL_1 +#error Please define HAS_SERIAL_1 +#endif + +#ifndef USE_SERIAL_STDIN +#error Please define USE_SERIAL_STDIN +#endif + +#ifndef HAS_ADC +#error Please define HAS_ADC +#endif + +#ifndef HAS_EEPROM +#error Please define HAS_EEPROM +#endif + +#if HAS_EEPROM +#ifndef USE_INTERNAL_FLASH +#error Please define USE_INTERNAL_FLASH +#endif +#endif + +#ifndef HAS_DBG +#error Please define HAS_DBG +#endif + +#ifndef HAS_IGNITE +#error Please define HAS_IGNITE +#endif + +#ifndef PACKET_HAS_MASTER +#error Please define PACKET_HAS_MASTER +#endif + +#ifndef PACKET_HAS_SLAVE +#error Please define PACKET_HAS_SLAVE +#endif + +#ifndef HAS_MONITOR +#error Please define HAS_MONITOR +#endif + +#ifndef HAS_ADC +#error Please define HAS_ADC +#endif + +#if HAS_ADC + +#if HAS_ACCEL +#ifndef HAS_ACCEL_REF +#error Please define HAS_ACCEL_REF +#endif +#else +#define HAS_ACCEL_REF 0 +#endif + +#endif /* HAS_ADC */ + +#endif /* _AO_PINS_H_ */ diff --git a/src/core/ao.h b/src/core/ao.h index 0f1a24ad..9b0bb545 100644 --- a/src/core/ao.h +++ b/src/core/ao.h @@ -22,21 +22,16 @@ #include #include #include -#include #include "ao_pins.h" +#include #define TRUE 1 #define FALSE 0 /* Convert a __data pointer into an __xdata pointer */ -#define DATA_TO_XDATA(a) ((void __xdata *) ((uint8_t) (a) | 0xff00)) - -/* Stack runs from above the allocated __data space to 0xfe, which avoids - * writing to 0xff as that triggers the stack overflow indicator - */ -#define AO_STACK_START 0x90 -#define AO_STACK_END 0xfe -#define AO_STACK_SIZE (AO_STACK_END - AO_STACK_START + 1) +#ifndef DATA_TO_XDATA +#define DATA_TO_XDATA(a) (a) +#endif /* An AltOS task */ struct ao_task { @@ -75,7 +70,7 @@ ao_alarm(uint16_t delay); /* Yield the processor to another task */ void -ao_yield(void) __naked; +ao_yield(void) ao_arch_naked_declare; /* Add a task to the run queue */ void @@ -136,7 +131,7 @@ ao_timer_set_adc_interval(uint8_t interval) __critical; /* Timer interrupt */ void -ao_timer_isr(void) __interrupt 9; +ao_timer_isr(void) ao_arch_interrupt(9); /* Initialize the timer */ void @@ -159,20 +154,8 @@ struct ao_adc { int16_t sense_m; /* main continuity sense */ }; -#ifndef HAS_ADC -#error Please define HAS_ADC -#endif - #if HAS_ADC -#if HAS_ACCEL -#ifndef HAS_ACCEL_REF -#error Please define HAS_ACCEL_REF -#endif -#else -#define HAS_ACCEL_REF 0 -#endif - /* * ao_adc.c */ @@ -207,7 +190,7 @@ ao_adc_get(__xdata struct ao_adc *packet); /* The A/D interrupt handler */ void -ao_adc_isr(void) __interrupt 1; +ao_adc_isr(void) ao_arch_interrupt(1); /* Initialize the A/D converter */ void @@ -298,25 +281,6 @@ ao_led_for(uint8_t colors, uint16_t ticks) __reentrant; void ao_led_init(uint8_t enable); -/* - * ao_romconfig.c - */ - -#define AO_ROMCONFIG_VERSION 2 - -extern __code __at (0x00a0) uint16_t ao_romconfig_version; -extern __code __at (0x00a2) uint16_t ao_romconfig_check; -extern __code __at (0x00a4) uint16_t ao_serial_number; -extern __code __at (0x00a6) uint32_t ao_radio_cal; - -#ifndef HAS_USB -#error Please define HAS_USB -#endif - -#if HAS_USB -extern __code __at (0x00aa) uint8_t ao_usb_descriptors []; -#endif - /* * ao_usb.c */ @@ -342,7 +306,7 @@ ao_usb_flush(void); #if HAS_USB /* USB interrupt handler */ void -ao_usb_isr(void) __interrupt 6; +ao_usb_isr(void) ao_arch_interrupt(6); #endif /* Enable the USB controller */ @@ -446,7 +410,7 @@ ao_dma_abort(uint8_t id); /* DMA interrupt routine */ void -ao_dma_isr(void) __interrupt 8; +ao_dma_isr(void) ao_arch_interrupt(8); /* * ao_mutex.c @@ -927,10 +891,10 @@ ao_dbg_init(void); #endif void -ao_serial_rx1_isr(void) __interrupt 3; +ao_serial_rx1_isr(void) ao_arch_interrupt(3); void -ao_serial_tx1_isr(void) __interrupt 14; +ao_serial_tx1_isr(void) ao_arch_interrupt(14); char ao_serial_getchar(void) __critical; @@ -1251,14 +1215,6 @@ struct ao_telemetry_tiny { char callsign[AO_MAX_CALLSIGN]; }; -/* - * ao_radio_recv tacks on rssi and status bytes - */ - -struct ao_telemetry_raw_recv { - uint8_t packet[AO_MAX_TELEMETRY + 2]; -}; - struct ao_telemetry_orig_recv { struct ao_telemetry_orig telemetry_orig; int8_t rssi; @@ -1271,6 +1227,14 @@ struct ao_telemetry_tiny_recv { uint8_t status; }; +/* + * ao_radio_recv tacks on rssi and status bytes + */ + +struct ao_telemetry_raw_recv { + uint8_t packet[AO_MAX_TELEMETRY + 2]; +}; + /* Set delay between telemetry reports (0 to disable) */ #define AO_TELEMETRY_INTERVAL_PAD AO_MS_TO_TICKS(1000) @@ -1302,7 +1266,7 @@ extern __xdata uint8_t ao_radio_done; extern __xdata uint8_t ao_radio_mutex; void -ao_radio_general_isr(void) __interrupt 16; +ao_radio_general_isr(void) ao_arch_interrupt(16); void ao_radio_get(uint8_t len); diff --git a/src/core/ao_panic.c b/src/core/ao_panic.c index fdada201..cbfdf399 100644 --- a/src/core/ao_panic.c +++ b/src/core/ao_panic.c @@ -33,7 +33,7 @@ ao_panic_delay(uint8_t n) while (n--) while (--j) while (--i) - _asm nop _endasm; + ao_arch_nop(); } void diff --git a/src/core/ao_pins.h b/src/core/ao_pins.h deleted file mode 100644 index e1f5459f..00000000 --- a/src/core/ao_pins.h +++ /dev/null @@ -1,408 +0,0 @@ -/* - * 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_ - -#if defined(TELEMETRUM_V_1_0) - #define HAS_FLIGHT 1 - #define HAS_USB 1 - #define HAS_BEEP 1 - #define HAS_GPS 1 - #define HAS_SERIAL_1 1 - #define HAS_ADC 1 - #define USE_SERIAL_STDIN 0 - #define HAS_EEPROM 1 - #define USE_INTERNAL_FLASH 0 - #define HAS_DBG 1 - #define DBG_ON_P1 1 - #define DBG_ON_P0 0 - #define IGNITE_ON_P2 1 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 0 - #define PACKET_HAS_SLAVE 1 - - #define HAS_COMPANION 1 - #define COMPANION_CS_ON_P1 1 - #define COMPANION_CS_MASK 0x4 /* CS1 is P1_2 */ - #define COMPANION_CS P1_2 - - #define AO_LED_RED 1 - #define LEDS_AVAILABLE (AO_LED_RED) - #define HAS_EXTERNAL_TEMP 0 - #define HAS_ACCEL_REF 0 - #define HAS_ACCEL 1 - #define HAS_IGNITE 1 - #define HAS_MONITOR 0 -#endif - -#if defined(TELEMETRUM_V_1_1) - #define HAS_FLIGHT 1 - #define HAS_USB 1 - #define HAS_BEEP 1 - #define HAS_GPS 1 - #define HAS_SERIAL_1 1 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 1 - #define HAS_EEPROM 1 - #define USE_INTERNAL_FLASH 0 - #define HAS_DBG 1 - #define DBG_ON_P1 1 - #define DBG_ON_P0 0 - #define IGNITE_ON_P2 1 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 0 - #define PACKET_HAS_SLAVE 1 - - #define HAS_COMPANION 1 - #define COMPANION_CS_ON_P1 1 - #define COMPANION_CS_MASK 0x4 /* CS1 is P1_2 */ - #define COMPANION_CS P1_2 - - #define AO_LED_RED 1 - #define LEDS_AVAILABLE (AO_LED_RED) - #define HAS_EXTERNAL_TEMP 0 - #define HAS_ACCEL_REF 1 - #define SPI_CS_ON_P1 1 - #define SPI_CS_ON_P0 0 - #define M25_CS_MASK 0x02 /* CS0 is P1_1 */ - #define M25_MAX_CHIPS 1 - #define HAS_ACCEL 1 - #define HAS_IGNITE 1 - #define HAS_MONITOR 0 -#endif - -#if defined(TELEDONGLE_V_0_2) - #define HAS_FLIGHT 0 - #define HAS_USB 1 - #define HAS_BEEP 0 - #define HAS_SERIAL_1 0 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 0 - #define HAS_DBG 1 - #define HAS_EEPROM 0 - #define DBG_ON_P1 1 - #define DBG_ON_P0 0 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 1 - #define PACKET_HAS_SLAVE 0 - #define AO_LED_RED 1 - #define AO_LED_GREEN 2 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define SPI_CS_ON_P1 1 - #define SPI_CS_ON_P0 0 - #define HAS_IGNITE 0 - #define HAS_MONITOR 1 -#endif - -#if defined(TELEMINI_V_1_0) - #define HAS_FLIGHT 1 - #define HAS_USB 0 - #define HAS_BEEP 0 - #define HAS_GPS 0 - #define HAS_SERIAL_1 0 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 1 - #define HAS_EEPROM 1 - #define USE_INTERNAL_FLASH 1 - #define HAS_DBG 0 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 1 - #define PACKET_HAS_MASTER 0 - #define PACKET_HAS_SLAVE 1 - #define USE_FAST_ASCENT_LOG 1 - - #define AO_LED_GREEN 1 - #define AO_LED_RED 2 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define HAS_EXTERNAL_TEMP 0 - #define HAS_ACCEL 0 - #define HAS_IGNITE 1 - #define HAS_MONITOR 0 -#endif - -#if defined(TELENANO_V_0_1) - #define HAS_FLIGHT 1 - #define HAS_USB 0 - #define HAS_BEEP 0 - #define HAS_GPS 0 - #define HAS_SERIAL_1 0 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 1 - #define HAS_EEPROM 1 - #define USE_INTERNAL_FLASH 1 - #define HAS_DBG 0 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 1 - #define PACKET_HAS_MASTER 0 - #define PACKET_HAS_SLAVE 1 - - #define AO_LED_GREEN 1 - #define AO_LED_RED 2 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define HAS_EXTERNAL_TEMP 0 - #define HAS_ACCEL 0 - #define HAS_IGNITE 0 - #define HAS_MONITOR 0 -#endif - -#if defined(TELEMETRUM_V_0_1) - #define HAS_FLIGHT 1 - #define HAS_USB 1 - #define HAS_BEEP 1 - #define HAS_GPS 1 - #define HAS_SERIAL_1 1 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 1 - #define HAS_DBG 0 - #define HAS_EEPROM 1 - #define USE_INTERNAL_FLASH 0 - #define DBG_ON_P1 0 - #define DBG_ON_P0 1 - #define IGNITE_ON_P2 1 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 0 - #define PACKET_HAS_SLAVE 1 - #define AO_LED_RED 2 - #define AO_LED_GREEN 1 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define HAS_EXTERNAL_TEMP 1 - #define HAS_ACCEL_REF 0 - #define SPI_CS_ON_P1 1 - #define SPI_CS_ON_P0 0 - #define HAS_ACCEL 1 - #define HAS_IGNITE 1 - #define HAS_MONITOR 0 -#endif - -#if defined(TELEDONGLE_V_0_1) - #define HAS_FLIGHT 0 - #define HAS_USB 1 - #define HAS_BEEP 0 - #define HAS_SERIAL_1 0 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 0 - #define HAS_DBG 0 - #define HAS_EEPROM 0 - #define DBG_ON_P1 0 - #define DBG_ON_P0 1 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 1 - #define PACKET_HAS_SLAVE 0 - #define AO_LED_RED 2 - #define AO_LED_GREEN 1 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define SPI_CS_ON_P1 0 - #define SPI_CS_ON_P0 1 - #define HAS_IGNITE 0 - #define HAS_MONITOR 1 -#endif - -#if defined(TIDONGLE) - #define HAS_FLIGHT 0 - #define HAS_USB 1 - #define HAS_BEEP 0 - #define HAS_SERIAL_1 0 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 0 - #define HAS_DBG 1 - #define HAS_EEPROM 0 - #define DBG_ON_P1 0 - #define DBG_ON_P0 1 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 1 - #define PACKET_HAS_SLAVE 0 - #define AO_LED_RED 2 - #define LEDS_AVAILABLE (AO_LED_RED) - #define SPI_CS_ON_P1 0 - #define SPI_CS_ON_P0 1 - #define HAS_IGNITE 0 - #define HAS_MONITOR 1 -#endif - -#if defined(TELEBT_V_0_0) - #define HAS_FLIGHT 0 - #define HAS_USB 1 - #define HAS_BEEP 0 - #define HAS_SERIAL_1 1 - #define USE_SERIAL_STDIN 1 - #define HAS_ADC 0 - #define HAS_DBG 1 - #define HAS_EEPROM 0 - #define HAS_BTM 1 - #define DBG_ON_P1 0 - #define DBG_ON_P0 1 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 1 - #define PACKET_HAS_SLAVE 0 - #define AO_LED_RED 2 - #define AO_LED_GREEN 1 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define SPI_CS_ON_P1 1 - #define SPI_CS_ON_P0 0 - #define HAS_IGNITE 0 - #define BT_LINK_ON_P2 1 - #define BT_LINK_ON_P1 0 - #define BT_LINK_PIN_INDEX 7 - #define BT_LINK_PIN P2_1 - #define HAS_MONITOR 1 -#endif - -#if defined(TELEBT_V_0_1) - #define HAS_FLIGHT 0 - #define HAS_USB 1 - #define HAS_BEEP 1 - #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_STDIN 1 - #define HAS_ADC 0 - #define HAS_DBG 1 - #define HAS_EEPROM 1 - #define USE_INTERNAL_FLASH 0 - #define HAS_BTM 1 - #define DBG_ON_P1 1 - #define DBG_ON_P0 0 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 1 - #define PACKET_HAS_SLAVE 0 - #define AO_LED_RED 1 - #define AO_LED_GREEN 2 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define SPI_CS_ON_P1 1 - #define SPI_CS_ON_P0 0 - #define M25_CS_MASK 0x04 /* CS0 is P1_2 */ - #define M25_MAX_CHIPS 1 - #define HAS_ACCEL 0 - #define HAS_IGNITE 0 - #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 -#endif - -#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 */ - -#if COMPANION_CS_ON_P1 - #define COMPANION_CS_PORT P1 - #define COMPANION_CS_SEL P1SEL - #define COMPANION_CS_DIR P1DIR -#endif - -#if SPI_CS_ON_P1 - #define SPI_CS_PORT P1 - #define SPI_CS_SEL P1SEL - #define SPI_CS_DIR P1DIR -#endif - -#if SPI_CS_ON_P0 - #define SPI_CS_PORT P0 - #define SPI_CS_SEL P0SEL - #define SPI_CS_DIR P0DIR -#endif - -#ifndef IGNITE_ON_P2 -#error Please define IGNITE_ON_P2 -#endif - -#ifndef IGNITE_ON_P0 -#error Please define IGNITE_ON_P0 -#endif - -#ifndef HAS_SERIAL_1 -#error Please define HAS_SERIAL_1 -#endif - -#ifndef USE_SERIAL_STDIN -#error Please define USE_SERIAL_STDIN -#endif - -#ifndef HAS_ADC -#error Please define HAS_ADC -#endif - -#ifndef HAS_EEPROM -#error Please define HAS_EEPROM -#endif - -#if HAS_EEPROM -#ifndef USE_INTERNAL_FLASH -#error Please define USE_INTERNAL_FLASH -#endif -#endif - -#ifndef HAS_DBG -#error Please define HAS_DBG -#endif - -#ifndef HAS_IGNITE -#error Please define HAS_IGNITE -#endif - -#ifndef PACKET_HAS_MASTER -#error Please define PACKET_HAS_MASTER -#endif - -#ifndef PACKET_HAS_SLAVE -#error Please define PACKET_HAS_SLAVE -#endif - -#ifndef HAS_MONITOR -#error Please define HAS_MONITOR -#endif -#endif /* _AO_PINS_H_ */ diff --git a/src/core/ao_task.c b/src/core/ao_task.c index f5850fa4..41520476 100644 --- a/src/core/ao_task.c +++ b/src/core/ao_task.c @@ -27,7 +27,6 @@ __xdata struct ao_task *__data ao_cur_task; void ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant { - uint8_t __xdata *stack; uint8_t task_id; uint8_t t; if (ao_num_tasks == AO_NUM_TASKS) @@ -42,70 +41,19 @@ ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *nam ao_tasks[ao_num_tasks++] = task; task->task_id = task_id; task->name = name; + task->wchan = NULL; /* * Construct a stack frame so that it will 'return' * to the start of the task */ - stack = task->stack; - - *stack++ = ((uint16_t) start); /* 0 */ - *stack++ = ((uint16_t) start) >> 8; /* 1 */ - - /* and the stuff saved by ao_switch */ - *stack++ = 0; /* 2 acc */ - *stack++ = 0x80; /* 3 IE */ - - /* 4 DPL - * 5 DPH - * 6 B - * 7 R2 - * 8 R3 - * 9 R4 - * 10 R5 - * 11 R6 - * 12 R7 - * 13 R0 - * 14 R1 - * 15 PSW - * 16 BP - */ - for (t = 0; t < 13; t++) - *stack++ = 0; - - task->stack_count = 17; - task->wchan = NULL; + ao_arch_init_stack(task, start); } /* Task switching function. This must not use any stack variables */ void -ao_yield(void) __naked +ao_yield(void) ao_arch_naked_define { - - /* Save current context */ - _asm - /* Push ACC first, as when restoring the context it must be restored - * last (it is used to set the IE register). */ - push ACC - /* Store the IE register then enable interrupts. */ - push _IEN0 - setb _EA - push DPL - push DPH - push b - push ar2 - push ar3 - push ar4 - push ar5 - push ar6 - push ar7 - push ar0 - push ar1 - push PSW - _endasm; - PSW = 0; - _asm - push _bp - _endasm; + ao_arch_save_context(); if (ao_cur_task_index == AO_NO_TASK_INDEX) ao_cur_task_index = ao_num_tasks-1; diff --git a/src/product/Makefile.telebt b/src/product/Makefile.telebt index 99730b9f..d9ef1ea7 100644 --- a/src/product/Makefile.telebt +++ b/src/product/Makefile.telebt @@ -79,7 +79,7 @@ all: ../$(PROG) ../$(PROG): $(REL) Makefile $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. - $(call quiet,CHECK_STACK) ../core/ao.h $(PMEM) + $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) ao_product.h: ao-make-product.5c ../Version $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ diff --git a/src/product/Makefile.teledongle b/src/product/Makefile.teledongle index f32c037f..cfd9b806 100644 --- a/src/product/Makefile.teledongle +++ b/src/product/Makefile.teledongle @@ -78,7 +78,7 @@ all: ../$(PROG) ../$(PROG): $(REL) Makefile $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. - $(call quiet,CHECK_STACK) ../core/ao.h $(PMEM) + $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) ao_product.h: ao-make-product.5c ../Version $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ diff --git a/src/product/Makefile.telemetrum b/src/product/Makefile.telemetrum index fd958aea..2759ac52 100644 --- a/src/product/Makefile.telemetrum +++ b/src/product/Makefile.telemetrum @@ -93,7 +93,7 @@ all: ../$(PROG) ../$(PROG): $(REL) Makefile $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. - $(call quiet,CHECK_STACK) ../core/ao.h $(PMEM) + $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) ao_product.h: ao-make-product.5c ../Version $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ diff --git a/src/product/Makefile.telemini b/src/product/Makefile.telemini index 3bd14226..7f251897 100644 --- a/src/product/Makefile.telemini +++ b/src/product/Makefile.telemini @@ -82,7 +82,7 @@ all: ../$(PROG) ../$(PROG): $(REL) Makefile $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. - $(call quiet,CHECK_STACK) ../core/ao.h $(PMEM) + $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) ao_product.h: ao-make-product.5c ../Version $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ diff --git a/src/product/Makefile.telenano b/src/product/Makefile.telenano index 72043044..c47e95ff 100644 --- a/src/product/Makefile.telenano +++ b/src/product/Makefile.telenano @@ -81,7 +81,7 @@ all: ../$(PROG) ../$(PROG): $(REL) Makefile $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. - $(call quiet,CHECK_STACK) ../core/ao.h $(PMEM) + $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) ao_product.h: ao-make-product.5c ../Version $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ diff --git a/src/tidongle/Makefile b/src/tidongle/Makefile index fc8df1f4..247f4fe0 100644 --- a/src/tidongle/Makefile +++ b/src/tidongle/Makefile @@ -73,7 +73,7 @@ all: ../$(PROG) ../$(PROG): $(REL) Makefile $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. - $(call quiet,CHECK_STACK) ../core/ao.h $(PMEM) + $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) ao_product.h: ao-make-product.5c ../Version $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ -- cgit v1.2.3 From 8125acc030574afed6f23aa8aa302d9c768bb04e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 25 Aug 2011 22:55:33 -0700 Subject: altos: get avr-demo to build. Pull in AVR drivers and LCD driver This completes the basic task of making an AVR version of altos by getting the Teensy 'avr-demo' program to build. Signed-off-by: Keith Packard --- src/avr-demo/Makefile | 7 +- src/avr-demo/ao_demo.c | 52 ++++ src/avr/ao_arch.h | 80 ++++-- src/avr/ao_avr_stdio.c | 2 +- src/avr/ao_debug_avr.c | 78 ++++++ src/avr/ao_led.c | 67 +++++ src/avr/ao_pins.h | 28 +- src/avr/ao_romconfig.c | 20 ++ src/avr/ao_serial_avr.c | 166 ++++++++++++ src/avr/ao_timer.c | 147 +++++++++++ src/avr/ao_usb.h | 100 +++++++ src/avr/ao_usb_avr.c | 688 ++++++++++++++++++++++++++++++++++++++++++++++++ src/cc1111/ao_arch.h | 118 +++++++-- src/core/ao.h | 11 +- src/core/ao_panic.c | 2 +- src/core/ao_task.c | 99 ++----- 16 files changed, 1542 insertions(+), 123 deletions(-) create mode 100644 src/avr-demo/ao_demo.c create mode 100644 src/avr/ao_debug_avr.c create mode 100644 src/avr/ao_led.c create mode 100644 src/avr/ao_romconfig.c create mode 100644 src/avr/ao_serial_avr.c create mode 100644 src/avr/ao_timer.c create mode 100644 src/avr/ao_usb.h create mode 100644 src/avr/ao_usb_avr.c (limited to 'src/core/ao_task.c') diff --git a/src/avr-demo/Makefile b/src/avr-demo/Makefile index ea356654..93295166 100644 --- a/src/avr-demo/Makefile +++ b/src/avr-demo/Makefile @@ -2,7 +2,7 @@ # AltOS build # # -vpath % ..:../core:../product:../driver +vpath % ..:../core:../product:../drivers:../avr vpath make-altitude .. vpath make-kalman .. vpath kalman.5c ../kalman @@ -38,12 +38,15 @@ ALTOS_SRC = \ ao_mutex.c \ ao_panic.c \ ao_product.c \ + ao_romconfig.c \ ao_serial_avr.c \ ao_avr_stdio.c \ ao_stdio.c \ ao_task.c \ ao_timer.c \ - ao_led.c + ao_led.c \ + ao_usb_avr.c \ + ao_lcd.c PRODUCT=AvrDemo-v0.0 MCU=atmega32u4 diff --git a/src/avr-demo/ao_demo.c b/src/avr-demo/ao_demo.c new file mode 100644 index 00000000..756dd0d4 --- /dev/null +++ b/src/avr-demo/ao_demo.c @@ -0,0 +1,52 @@ +/* + * 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" + +struct ao_task demo_task; + +void +ao_demo(void) +{ + for (;;) { + ao_led_toggle(AO_LED_RED); + printf ("hello %d\n", ao_time()); + ao_delay(AO_MS_TO_TICKS(200)); + } +} + +int +main(void) +{ + ao_clock_init(); + + ao_serial_init(); + + ao_led_init(LEDS_AVAILABLE); + ao_avr_stdio_init(); + printf ("stdio initialized\n"); +// ao_debug_init(); + ao_timer_init(); + ao_cmd_init(); + ao_usb_init(); + ao_lcd_init(); + +// ao_add_task(&demo_task, ao_demo, "demo"); + /* Turn on the LED until the system is stable */ + ao_start_scheduler(); + return 0; +} diff --git a/src/avr/ao_arch.h b/src/avr/ao_arch.h index 51a65880..0ed97361 100644 --- a/src/avr/ao_arch.h +++ b/src/avr/ao_arch.h @@ -18,8 +18,10 @@ #ifndef _AO_ARCH_H_ #define _AO_ARCH_H_ +#include #include #include +#include #ifdef AVR_DEMO #define TEENSY 1 @@ -48,6 +50,7 @@ #define __reentrant #define __critical #define __interrupt(n) +#define __at(n) #define ao_arch_reboot() /* XXX */ @@ -62,8 +65,18 @@ extern void putchar(char c); extern char getchar(void); +extern void ao_avr_stdio_init(void); -extern int ao_serial_number; +extern const uint16_t ao_serial_number; + +#define AVR_PUSH8(stack, val) (*((stack)--) = (val)) + +extern uint8_t ao_cpu_sleep_disable; + +#define ao_arch_task_globals uint8_t ao_cpu_sleep_disable; + +#define ao_arch_task_members\ + uint8_t *sp; /* saved stack pointer */ #define ao_arch_init_stack(task, start) do { \ uint8_t *sp = task->stack + AO_STACK_SIZE - 1; \ @@ -71,29 +84,66 @@ extern int ao_serial_number; int i; \ \ /* Return address */ \ - PUSH8(sp, a); \ - PUSH8(sp, (a >> 8)); \ + AVR_PUSH8(sp, a); \ + AVR_PUSH8(sp, (a >> 8)); \ \ /* Clear register values */ \ i = 32; \ while (i--) \ - PUSH8(sp, 0); \ + AVR_PUSH8(sp, 0); \ \ /* SREG with interrupts enabled */ \ - PUSH8(sp, 0x80); \ + AVR_PUSH8(sp, 0x80); \ task->sp = sp; \ } while (0); -#define ao_arch_save_context() do { \ - asm("push r31" "\n\t" "push r30"); \ - asm("push r29" "\n\t" "push r28" "\n\t" "push r27" "\n\t" "push r26" "\n\t" "push r25"); \ - asm("push r24" "\n\t" "push r23" "\n\t" "push r22" "\n\t" "push r21" "\n\t" "push r20"); \ - asm("push r19" "\n\t" "push r18" "\n\t" "push r17" "\n\t" "push r16" "\n\t" "push r15"); \ - asm("push r14" "\n\t" "push r13" "\n\t" "push r12" "\n\t" "push r11" "\n\t" "push r10"); \ - asm("push r9" "\n\t" "push r8" "\n\t" "push r7" "\n\t" "push r6" "\n\t" "push r5"); \ - asm("push r4" "\n\t" "push r3" "\n\t" "push r2" "\n\t" "push r1" "\n\t" "push r0"); \ - asm("in r0, __SREG__" "\n\t" "push r0"); \ - sei(); \ +#define ao_arch_save_regs() do { \ + asm("push r31" "\n\t" "push r30"); \ + asm("push r29" "\n\t" "push r28" "\n\t" "push r27" "\n\t" "push r26" "\n\t" "push r25"); \ + asm("push r24" "\n\t" "push r23" "\n\t" "push r22" "\n\t" "push r21" "\n\t" "push r20"); \ + asm("push r19" "\n\t" "push r18" "\n\t" "push r17" "\n\t" "push r16" "\n\t" "push r15"); \ + asm("push r14" "\n\t" "push r13" "\n\t" "push r12" "\n\t" "push r11" "\n\t" "push r10"); \ + asm("push r9" "\n\t" "push r8" "\n\t" "push r7" "\n\t" "push r6" "\n\t" "push r5"); \ + asm("push r4" "\n\t" "push r3" "\n\t" "push r2" "\n\t" "push r1" "\n\t" "push r0"); \ + cli(); \ + asm("in r0, __SREG__" "\n\t" "push r0"); \ + sei(); \ + } while (0) + +#define ao_arch_save_stack() do { \ + uint8_t sp_l, sp_h; \ + asm("in %0,__SP_L__" : "=&r" (sp_l) ); \ + asm("in %0,__SP_H__" : "=&r" (sp_h) ); \ + ao_cur_task->sp = (uint8_t *) ((uint16_t) sp_l | ((uint16_t) sp_h << 8)); \ } while (0) +#define ao_arch_isr_stack() /* nothing */ + +#define ao_arch_cpu_idle() do { \ + if (!ao_cpu_sleep_disable) \ + sleep_cpu(); \ + } while (0) + +#define ao_arch_restore_stack() do { \ + uint8_t sp_l, sp_h; \ + sp_l = (uint16_t) ao_cur_task->sp; \ + sp_h = ((uint16_t) ao_cur_task->sp) >> 8; \ + cli(); \ + asm("out __SP_H__,%0" : : "r" (sp_h) ); \ + asm("out __SP_L__,%0" : : "r" (sp_l) ); \ + asm("pop r0" "\n\t" \ + "out __SREG__, r0"); \ + asm("pop r0" "\n\t" "pop r1" "\n\t" "pop r2" "\n\t" "pop r3" "\n\t" "pop r4"); \ + asm("pop r5" "\n\t" "pop r6" "\n\t" "pop r7" "\n\t" "pop r8" "\n\t" "pop r9"); \ + asm("pop r10" "\n\t" "pop r11" "\n\t" "pop r12" "\n\t" "pop r13" "\n\t" "pop r14"); \ + asm("pop r15" "\n\t" "pop r16" "\n\t" "pop r17" "\n\t" "pop r18" "\n\t" "pop r19"); \ + asm("pop r20" "\n\t" "pop r21" "\n\t" "pop r22" "\n\t" "pop r23" "\n\t" "pop r24"); \ + asm("pop r25" "\n\t" "pop r26" "\n\t" "pop r27" "\n\t" "pop r28" "\n\t" "pop r29"); \ + asm("pop r30" "\n\t" "pop r31"); \ + asm("ret"); \ + } while(0) + +#define ao_arch_critical(b) do { cli(); b; sei(); } while (0) + #endif /* _AO_ARCH_H_ */ + diff --git a/src/avr/ao_avr_stdio.c b/src/avr/ao_avr_stdio.c index 2f358eb5..ba562dbf 100644 --- a/src/avr/ao_avr_stdio.c +++ b/src/avr/ao_avr_stdio.c @@ -44,7 +44,7 @@ static FILE mystdout = FDEV_SETUP_STREAM(stdio_put, NULL, _FDEV_SETUP_WRITE); static FILE mystdin = FDEV_SETUP_STREAM(NULL, stdio_get, _FDEV_SETUP_READ); void -ao_stdio_init(void) +ao_avr_stdio_init(void) { stdout = &mystdout; stdin = &mystdin; diff --git a/src/avr/ao_debug_avr.c b/src/avr/ao_debug_avr.c new file mode 100644 index 00000000..2e41e15a --- /dev/null +++ b/src/avr/ao_debug_avr.c @@ -0,0 +1,78 @@ +/* + * 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 +uart_send(char c) +{ + loop_until_bit_is_set(UCSR1A, UDRE1); + UDR1 = c; +} + +int +uart_put(char c, FILE *stream) +{ + if (c == '\n') + uart_send('\r'); + uart_send(c); + return 0; +} + +int +uart_get(FILE *stream) +{ + loop_until_bit_is_set(UCSR1A, RXC1); + return (int) UDR1 & 0xff; +} + +void +uart_init(uint16_t baud) +{ + PRR1 &= ~(1 << PRUSART1); + UBRR1L = baud; + UBRR1H = baud >> 8; + UCSR1A = 0; + UCSR1B = ((1 << RXEN1) | /* Enable receiver */ + (1 << TXEN1)); /* Enable transmitter */ + UCSR1C = ((0 << UMSEL10) | /* Asynchronous mode */ + (0 << UPM10) | /* No parity */ + (0 << USBS1) | /* 1 stop bit */ + (3 << UCSZ10) | /* 8 bit characters */ + (0 << UCPOL1)); /* MBZ for async mode */ +} + +static FILE mystdout = FDEV_SETUP_STREAM(uart_put, NULL, _FDEV_SETUP_WRITE); + +static FILE mystdin = FDEV_SETUP_STREAM(NULL, uart_get, _FDEV_SETUP_READ); + +void ao_debug_init(void) +{ + uart_init(F_CPU / (16UL * 9600UL) - 1); + + stdout = &mystdout; + stdin = &mystdin; + + if (DDRB & AO_LED_RED) { + printf ("oops, starting all over\n"); + for (;;) + ; + } + DDRB |= (1 << 7); + PORTB |= (1 << 7); + printf ("debug initialized\n"); +} diff --git a/src/avr/ao_led.c b/src/avr/ao_led.c new file mode 100644 index 00000000..91dfb85e --- /dev/null +++ b/src/avr/ao_led.c @@ -0,0 +1,67 @@ +/* + * Copyright © 2009 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" + +__pdata uint8_t ao_led_enable; + +#define LED_PORT PORTB +#define LED_DDR DDRB + +void +ao_led_on(uint8_t colors) +{ + LED_PORT |= (colors & ao_led_enable); +} + +void +ao_led_off(uint8_t colors) +{ + LED_PORT &= ~(colors & ao_led_enable); +} + +void +ao_led_set(uint8_t colors) +{ + LED_PORT = (LED_PORT & ~(ao_led_enable)) | (colors & ao_led_enable); +} + +void +ao_led_toggle(uint8_t colors) +{ + LED_PORT ^= (colors & ao_led_enable); +} + +void +ao_led_for(uint8_t colors, uint16_t ticks) __reentrant +{ + ao_led_on(colors); + ao_delay(ticks); + ao_led_off(colors); +} + +void +ao_led_init(uint8_t enable) +{ + ao_led_enable = enable; + if ((LED_DDR & enable)) { + printf ("oops! restarted\n"); + ao_panic(AO_PANIC_REBOOT); + } + LED_PORT &= ~enable; + LED_DDR |= enable; +} diff --git a/src/avr/ao_pins.h b/src/avr/ao_pins.h index ef41b59c..56435f18 100644 --- a/src/avr/ao_pins.h +++ b/src/avr/ao_pins.h @@ -22,10 +22,36 @@ #define AO_LED_RED (1<<7) #define LEDS_AVAILABLE (AO_LED_RED) #define USE_SERIAL_STDIN 1 - #define HAS_USB 0 + #define HAS_USB 1 #define PACKET_HAS_SLAVE 0 #define HAS_SERIAL_1 1 + #define TEENSY 1 + #define AVR_VCC_5V 1 + #define AVR_VCC_3V3 0 + #define AVR_CLOCK 16000000UL #define HAS_BEEP 0 #endif +#ifdef TELESCIENCE + #define LEDS_AVAILABLE 0 + #define HAS_USB 1 + #define HAS_LOG 1 + #define TEENSY 0 + #define USE_SERIAL_STDIN 1 + #define HAS_SERIAL_1 1 + #define HAS_USB 1 + #define HAS_ADC 1 + #define PACKET_HAS_SLAVE 0 + #define HAS_BEEP 0 + + #define AVR_VCC_5V 0 + #define AVR_VCC_3V3 1 + #define AVR_CLOCK 8000000UL + + #define SPI_CS_PORT PORTE + #define SPI_CS_DIR DDRE + #define M25_CS_MASK (1 << PORTE6) + #define M25_MAX_CHIPS 1 +#endif + #endif /* _AO_PINS_H_ */ diff --git a/src/avr/ao_romconfig.c b/src/avr/ao_romconfig.c new file mode 100644 index 00000000..bbb677e2 --- /dev/null +++ b/src/avr/ao_romconfig.c @@ -0,0 +1,20 @@ +/* + * 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" + +const uint16_t ao_serial_number = 0; diff --git a/src/avr/ao_serial_avr.c b/src/avr/ao_serial_avr.c new file mode 100644 index 00000000..2fe39755 --- /dev/null +++ b/src/avr/ao_serial_avr.c @@ -0,0 +1,166 @@ +/* + * 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" + +__xdata struct ao_fifo ao_usart1_rx_fifo; +__xdata struct ao_fifo ao_usart1_tx_fifo; + +void +ao_debug_out(char c) +{ + if (c == '\n') + ao_debug_out('\r'); + loop_until_bit_is_set(UCSR1A, UDRE1); + UDR1 = c; +} + +ISR(USART1_RX_vect) +{ + if (!ao_fifo_full(ao_usart1_rx_fifo)) + ao_fifo_insert(ao_usart1_rx_fifo, UDR1); + ao_wakeup(&ao_usart1_rx_fifo); +#if USE_SERIAL_STDIN + ao_wakeup(&ao_stdin_ready); +#endif +} + +static __xdata uint8_t ao_serial_tx1_started; + +static void +ao_serial_tx1_start(void) +{ + if (!ao_fifo_empty(ao_usart1_tx_fifo) && + !ao_serial_tx1_started) + { + ao_serial_tx1_started = 1; + ao_fifo_remove(ao_usart1_tx_fifo, UDR1); + } +} + +ISR(USART1_UDRE_vect) +{ + ao_serial_tx1_started = 0; + ao_serial_tx1_start(); + ao_wakeup(&ao_usart1_tx_fifo); +} + +char +ao_serial_getchar(void) __critical +{ + char c; + cli(); + while (ao_fifo_empty(ao_usart1_rx_fifo)) + ao_sleep(&ao_usart1_rx_fifo); + ao_fifo_remove(ao_usart1_rx_fifo, c); + sei(); + return c; +} + +#if USE_SERIAL_STDIN +char +ao_serial_pollchar(void) __critical +{ + char c; + cli(); + if (ao_fifo_empty(ao_usart1_rx_fifo)) { + sei(); + return AO_READ_AGAIN; + } + ao_fifo_remove(ao_usart1_rx_fifo,c); + sei(); + return c; +} +#endif + +void +ao_serial_putchar(char c) __critical +{ + cli(); + while (ao_fifo_full(ao_usart1_tx_fifo)) + ao_sleep(&ao_usart1_tx_fifo); + ao_fifo_insert(ao_usart1_tx_fifo, c); + ao_serial_tx1_start(); + sei(); +} + +void +ao_serial_drain(void) __critical +{ + cli(); + while (!ao_fifo_empty(ao_usart1_tx_fifo)) + ao_sleep(&ao_usart1_tx_fifo); + sei(); +} + +static const struct { + uint16_t ubrr; +} ao_serial_speeds[] = { + /* [AO_SERIAL_SPEED_4800] = */ { + F_CPU / (16UL * 4800UL) - 1 + }, + /* [AO_SERIAL_SPEED_9600] = */ { + F_CPU / (16UL * 9600UL) - 1 + }, + /* [AO_SERIAL_SPEED_19200] = */ { + F_CPU / (16UL * 19200UL) - 1 + }, + /* [AO_SERIAL_SPEED_57600] = */ { + F_CPU / (16UL * 57600UL) - 1 + }, +}; + +void +ao_serial_set_speed(uint8_t speed) +{ + ao_serial_drain(); + if (speed > AO_SERIAL_SPEED_57600) + return; + UBRR1L = ao_serial_speeds[speed].ubrr; + UBRR1H = ao_serial_speeds[speed].ubrr >> 8; +} + +void +ao_serial_init(void) +{ + /* Ensure the uart is powered up */ + + PRR1 &= ~(1 << PRUSART1); + + /* Pick a 9600 baud rate */ + ao_serial_set_speed(AO_SERIAL_SPEED_9600); + + UCSR1A = 0; + UCSR1C = ((0 << UMSEL10) | /* Asynchronous mode */ + (0 << UPM10) | /* No parity */ + (0 << USBS1) | /* 1 stop bit */ + (3 << UCSZ10) | /* 8 bit characters */ + (0 << UCPOL1)); /* MBZ for async mode */ + UCSR1B = ((1 << RXEN1) | /* Enable receiver */ + (1 << TXEN1) | /* Enable transmitter */ + (1 << RXCIE1) | /* Enable receive interrupts */ + (1 << UDRIE1)); /* Enable transmit empty interrupts */ +#if 0 +#if USE_SERIAL_STDIN + int8_t i; + i = ao_add_stdio(ao_serial_pollchar, + ao_serial_putchar, + NULL); + printf("Register serial stdio as %d\n", i); +#endif +#endif +} diff --git a/src/avr/ao_timer.c b/src/avr/ao_timer.c new file mode 100644 index 00000000..1e374c75 --- /dev/null +++ b/src/avr/ao_timer.c @@ -0,0 +1,147 @@ +/* + * Copyright © 2009 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 volatile __data uint16_t ao_tick_count; + +uint16_t ao_time(void) +{ + uint16_t v; + ao_arch_critical( + v = ao_tick_count; + ); + return v; +} + +static __xdata uint8_t ao_forever; + +void +ao_delay(uint16_t ticks) +{ + ao_alarm(ticks); + ao_sleep(&ao_forever); +} + +#define T1_CLOCK_DIVISOR 8 /* 24e6/8 = 3e6 */ +#define T1_SAMPLE_TIME 30000 /* 3e6/30000 = 100 */ + +#if HAS_ADC +volatile __data uint8_t ao_adc_interval = 1; +volatile __data uint8_t ao_adc_count; +#endif + +void +ao_debug_out(char c); + +ISR(TIMER1_COMPA_vect) +{ + ++ao_tick_count; +#if HAS_ADC + if (++ao_adc_count == ao_adc_interval) { + ao_adc_count = 0; + ao_adc_poll(); + } +#endif +} + +#if HAS_ADC +void +ao_timer_set_adc_interval(uint8_t interval) __critical +{ + ao_adc_interval = interval; + ao_adc_count = 0; +} +#endif + +void +ao_timer_init(void) +{ + TCCR1A = ((0 << WGM11) | /* CTC mode, OCR1A */ + (0 << WGM10)); /* CTC mode, OCR1A */ + TCCR1B = ((0 << ICNC1) | /* no input capture noise canceler */ + (0 << ICES1) | /* input capture on falling edge (don't care) */ + (0 << WGM13) | /* CTC mode, OCR1A */ + (1 << WGM12) | /* CTC mode, OCR1A */ + (3 << CS10)); /* clk/64 from prescaler */ + +#if TEENSY + OCR1A = 2500; /* 16MHz clock */ +#else + OCR1A = 1250; /* 8MHz clock */ +#endif + + TIMSK1 = (1 << OCIE1A); /* Interrupt on compare match */ +} + +/* + * AltOS always cranks the clock to the max frequency + */ +void +ao_clock_init(void) +{ + /* disable RC clock */ + CLKSEL0 &= ~(1 << RCE); + + /* Disable PLL */ + PLLCSR &= ~(1 << PLLE); + + /* Enable external clock */ + CLKSEL0 |= (1 << EXTE); + + /* wait for external clock to be ready */ + while ((CLKSTA & (1 << EXTON)) == 0) + ; + + /* select external clock */ + CLKSEL0 |= (1 << CLKS); + + /* Disable the clock prescaler */ + cli(); + CLKPR = (1 << CLKPCE); + + /* Always run the system clock at 8MHz */ +#if AVR_CLOCK > 12000000UL + CLKPR = 1; +#else + CLKPR = 0; +#endif + sei(); + + /* Set up the PLL to use the crystal */ + + /* Use primary system clock as PLL source */ + PLLFRQ = ((0 << PINMUX) | /* Use primary clock */ + (0 << PLLUSB) | /* No divide by 2 for USB */ + (0 << PLLTM0) | /* Disable high speed timer */ + (0x4 << PDIV0)); /* 48MHz PLL clock */ + + /* Set the frequency of the crystal */ +#if AVR_CLOCK > 12000000UL + PLLCSR |= (1 << PINDIV); /* For 16MHz crystal on Teensy board */ +#else + PLLCSR &= ~(1 << PINDIV); /* For 8MHz crystal on TeleScience board */ +#endif + + /* Enable the PLL */ + PLLCSR |= (1 << PLLE); + while (!(PLLCSR & (1 << PLOCK))) + ; + + set_sleep_mode(SLEEP_MODE_IDLE); + sleep_enable(); +} diff --git a/src/avr/ao_usb.h b/src/avr/ao_usb.h new file mode 100644 index 00000000..6633dafc --- /dev/null +++ b/src/avr/ao_usb.h @@ -0,0 +1,100 @@ +/* + * Copyright © 2009 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_USB_H_ +#define _AO_USB_H_ + +#define AO_USB_SETUP_DIR_MASK (0x01 << 7) +#define AO_USB_SETUP_TYPE_MASK (0x03 << 5) +#define AO_USB_SETUP_RECIP_MASK (0x1f) + +#define AO_USB_DIR_OUT 0 +#define AO_USB_DIR_IN (1 << 7) + +#define AO_USB_TYPE_STANDARD 0 +#define AO_USB_TYPE_CLASS (1 << 5) +#define AO_USB_TYPE_VENDOR (2 << 5) +#define AO_USB_TYPE_RESERVED (3 << 5) + +#define AO_USB_RECIP_DEVICE 0 +#define AO_USB_RECIP_INTERFACE 1 +#define AO_USB_RECIP_ENDPOINT 2 +#define AO_USB_RECIP_OTHER 3 + +/* standard requests */ +#define AO_USB_REQ_GET_STATUS 0x00 +#define AO_USB_REQ_CLEAR_FEATURE 0x01 +#define AO_USB_REQ_SET_FEATURE 0x03 +#define AO_USB_REQ_SET_ADDRESS 0x05 +#define AO_USB_REQ_GET_DESCRIPTOR 0x06 +#define AO_USB_REQ_SET_DESCRIPTOR 0x07 +#define AO_USB_REQ_GET_CONFIGURATION 0x08 +#define AO_USB_REQ_SET_CONFIGURATION 0x09 +#define AO_USB_REQ_GET_INTERFACE 0x0A +#define AO_USB_REQ_SET_INTERFACE 0x0B +#define AO_USB_REQ_SYNCH_FRAME 0x0C + +#define AO_USB_DESC_DEVICE 1 +#define AO_USB_DESC_CONFIGURATION 2 +#define AO_USB_DESC_STRING 3 +#define AO_USB_DESC_INTERFACE 4 +#define AO_USB_DESC_ENDPOINT 5 +#define AO_USB_DESC_DEVICE_QUALIFIER 6 +#define AO_USB_DESC_OTHER_SPEED 7 +#define AO_USB_DESC_INTERFACE_POWER 8 + +#define AO_USB_GET_DESC_TYPE(x) (((x)>>8)&0xFF) +#define AO_USB_GET_DESC_INDEX(x) ((x)&0xFF) + +#define AO_USB_CONTROL_EP 0 +#define AO_USB_INT_EP 1 +#define AO_USB_OUT_EP 4 +#define AO_USB_IN_EP 5 +#define AO_USB_CONTROL_SIZE 32 +/* + * Double buffer IN and OUT EPs, so each + * gets half of the available space + * + * Ah, but USB bulk packets can only come in 8, 16, 32 and 64 + * byte sizes, so we'll use 64 for everything + */ +#define AO_USB_IN_SIZE 64 +#define AO_USB_OUT_SIZE 64 + +#define AO_USB_EP0_IDLE 0 +#define AO_USB_EP0_DATA_IN 1 +#define AO_USB_EP0_DATA_OUT 2 + +#define LE_WORD(x) ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8)) + +/* CDC definitions */ +#define CS_INTERFACE 0x24 +#define CS_ENDPOINT 0x25 + +#define SET_LINE_CODING 0x20 +#define GET_LINE_CODING 0x21 +#define SET_CONTROL_LINE_STATE 0x22 + +/* Data structure for GET_LINE_CODING / SET_LINE_CODING class requests */ +struct ao_usb_line_coding { + uint32_t rate; + uint8_t char_format; + uint8_t parity; + uint8_t data_bits; +} ; + +#endif /* _AO_USB_H_ */ diff --git a/src/avr/ao_usb_avr.c b/src/avr/ao_usb_avr.c new file mode 100644 index 00000000..74bdea23 --- /dev/null +++ b/src/avr/ao_usb_avr.c @@ -0,0 +1,688 @@ +/* + * 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" +#include "ao_usb.h" + +#define USB_DEBUG 0 + +#if USB_DEBUG +#define debug(format, args...) printf(format, ## args) +#else +#define debug(format, args...) +#endif + +struct ao_task __xdata ao_usb_task; + +struct ao_usb_setup { + uint8_t dir_type_recip; + uint8_t request; + uint16_t value; + uint16_t index; + uint16_t length; +} __xdata ao_usb_setup; + +static __xdata uint8_t ao_usb_ep0_state; +static const uint8_t * __xdata ao_usb_ep0_in_data; +static __xdata uint8_t ao_usb_ep0_in_len; +static __xdata uint8_t ao_usb_ep0_in_pending; +static __xdata uint8_t ao_usb_addr_pending; +static __xdata uint8_t ao_usb_ep0_in_buf[2]; +static __xdata uint8_t ao_usb_ep0_out_len; +static __xdata uint8_t *__xdata ao_usb_ep0_out_data; + +static __xdata uint8_t ao_usb_in_flushed; +static __xdata uint8_t ao_usb_running; +static __xdata uint8_t ao_usb_configuration; +static __xdata uint8_t ueienx_0; + +void +ao_usb_set_address(uint8_t address) +{ + UDADDR = (0 << ADDEN) | address; + ao_usb_addr_pending = 1; +} + +#define EP_SIZE(s) ((s) == 64 ? 0x30 : \ + ((s) == 32 ? 0x20 : \ + ((s) == 16 ? 0x10 : \ + 0x00))) + +static void +ao_usb_dump_ep(uint8_t ep) +{ + UENUM = ep; + debug ("EP %d: UECONX %02x UECFG0X %02x UECFG1X %02x UEIENX %02x UESTA0X %02x UESTA1X %02X\n", + ep, UECONX, UECFG0X, UECFG1X, UEIENX, UESTA0X, UESTA1X); +} + +static void +ao_usb_set_ep0(void) +{ + debug ("set_ep0\n"); + /* Set the CONTROL max packet size, single buffered */ + UENUM = 0; + UECONX = (1 << EPEN); /* Enable */ + + UECFG0X = ((0 << EPTYPE0) | /* Control */ + (0 << EPDIR)); /* Out (ish) */ + + UECFG1X = (EP_SIZE(AO_USB_CONTROL_SIZE) | /* Size */ + (0 << EPBK0) | /* Single bank */ + (1 << ALLOC)); + + ueienx_0 = ((1 << RXSTPE) | /* Enable SETUP interrupt */ + (1 << RXOUTE)); /* Enable OUT interrupt */ + +// ao_usb_dump_ep(0); + ao_usb_addr_pending = 0; +} + +static void +ao_usb_set_configuration(void) +{ + /* Set the IN max packet size, double buffered */ + UENUM = AO_USB_IN_EP; + UECONX = (1 << EPEN); /* Enable */ + + UECFG0X = ((2 << EPTYPE0) | /* Bulk */ + (1 << EPDIR)); /* In */ + + UECFG1X = (EP_SIZE(AO_USB_IN_SIZE) | /* Size */ + (1 << EPBK0) | /* Double bank */ + (1 << ALLOC)); /* Allocate */ + +#if 0 + UEIENX = ((1 << TXINE)); /* Enable IN complete interrupt */ +#endif + + ao_usb_dump_ep(AO_USB_IN_EP); + + /* Set the OUT max packet size, double buffered */ + UENUM = AO_USB_OUT_EP; + UECONX |= (1 << EPEN); /* Enable */ + + UECFG0X = ((2 << EPTYPE0) | /* Bulk */ + (0 << EPDIR)); /* Out */ + + UECFG1X = (EP_SIZE(AO_USB_OUT_SIZE) | /* Size */ + (1 << EPBK0) | /* Double bank */ + (1 << ALLOC)); /* Allocate */ + + UEIENX = ((1 << RXOUTE)); /* Enable OUT complete interrupt */ + + ao_usb_dump_ep(AO_USB_OUT_EP); + ao_usb_running = 1; +} + +ISR(USB_GEN_vect) +{ + ao_wakeup(&ao_usb_task); +} + + +__xdata static struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8}; + +/* Walk through the list of descriptors and find a match + */ +static void +ao_usb_get_descriptor(uint16_t value) +{ + const uint8_t *__xdata descriptor; + __xdata uint8_t type = value >> 8; + __xdata uint8_t index = value; + + descriptor = ao_usb_descriptors; + while (descriptor[0] != 0) { + if (descriptor[1] == type && index-- == 0) { + if (type == AO_USB_DESC_CONFIGURATION) + ao_usb_ep0_in_len = descriptor[2]; + else + ao_usb_ep0_in_len = descriptor[0]; + ao_usb_ep0_in_data = descriptor; + break; + } + descriptor += descriptor[0]; + } +} + +static void +ao_usb_ep0_set_in_pending(uint8_t in_pending) +{ + ao_usb_ep0_in_pending = in_pending; + + if (in_pending) + ueienx_0 = ((1 << RXSTPE) | (1 << RXOUTE) | (1 << TXINE)); /* Enable IN interrupt */ +} + +/* Send an IN data packet */ +static void +ao_usb_ep0_flush(void) +{ + __xdata uint8_t this_len; + + cli(); + UENUM = 0; + if (!(UEINTX & (1 << TXINI))) { + debug("EP0 not accepting IN data\n"); + ao_usb_ep0_set_in_pending(1); + } else { + this_len = ao_usb_ep0_in_len; + if (this_len > AO_USB_CONTROL_SIZE) + this_len = AO_USB_CONTROL_SIZE; + + ao_usb_ep0_in_len -= this_len; + + /* Set IN interrupt enable */ + if (ao_usb_ep0_in_len == 0 && this_len != AO_USB_CONTROL_SIZE) + ao_usb_ep0_set_in_pending(0); + else + ao_usb_ep0_set_in_pending(1); + + debug ("Flush EP0 len %d:", this_len); + while (this_len--) { + uint8_t c = *ao_usb_ep0_in_data++; + debug(" %02x", c); + UEDATX = c; + } + debug ("\n"); + + /* Clear the TXINI bit to send the packet */ + UEINTX &= ~(1 << TXINI); + } + sei(); +} + +/* Read data from the ep0 OUT fifo */ +static void +ao_usb_ep0_fill(uint8_t len, uint8_t ack) +{ + if (len > ao_usb_ep0_out_len) + len = ao_usb_ep0_out_len; + ao_usb_ep0_out_len -= len; + +// debug ("EP0 UEINTX %02x UEBCLX %d UEBCHX %d\n", +// UEINTX, UEBCLX, UEBCHX); + /* Pull all of the data out of the packet */ + debug ("Fill EP0 len %d:", len); + UENUM = 0; + while (len--) { + uint8_t c = UEDATX; + *ao_usb_ep0_out_data++ = c; + debug (" %02x", c); + } + debug ("\n"); + + /* ACK the packet */ + UEINTX &= ~ack; +} + +void +ao_usb_ep0_queue_byte(uint8_t a) +{ + ao_usb_ep0_in_buf[ao_usb_ep0_in_len++] = a; +} + +static void +ao_usb_ep0_setup(void) +{ + /* Pull the setup packet out of the fifo */ + ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_setup; + ao_usb_ep0_out_len = 8; + ao_usb_ep0_fill(8, (1 << RXSTPI) | (1 << RXOUTI) | (1 << TXINI)); + if (ao_usb_ep0_out_len != 0) { + debug ("invalid setup packet length\n"); + return; + } + + /* Figure out how to ACK the setup packet */ + if (ao_usb_setup.dir_type_recip & AO_USB_DIR_IN) { + if (ao_usb_setup.length) + ao_usb_ep0_state = AO_USB_EP0_DATA_IN; + else + ao_usb_ep0_state = AO_USB_EP0_IDLE; + } else { + if (ao_usb_setup.length) + ao_usb_ep0_state = AO_USB_EP0_DATA_OUT; + else + ao_usb_ep0_state = AO_USB_EP0_IDLE; + } +/* + UENUM = 0; + if (ao_usb_ep0_state == AO_USB_EP0_IDLE) + USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END; + else + USBCS0 = USBCS0_CLR_OUTPKT_RDY; +*/ + + ao_usb_ep0_in_data = ao_usb_ep0_in_buf; + ao_usb_ep0_in_len = 0; + switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_TYPE_MASK) { + case AO_USB_TYPE_STANDARD: + debug ("Standard setup packet\n"); + switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_RECIP_MASK) { + case AO_USB_RECIP_DEVICE: + debug ("Device setup packet\n"); + switch(ao_usb_setup.request) { + case AO_USB_REQ_GET_STATUS: + debug ("get status\n"); + ao_usb_ep0_queue_byte(0); + ao_usb_ep0_queue_byte(0); + break; + case AO_USB_REQ_SET_ADDRESS: + debug ("set address %d\n", ao_usb_setup.value); + ao_usb_set_address(ao_usb_setup.value); + break; + case AO_USB_REQ_GET_DESCRIPTOR: + debug ("get descriptor %d\n", ao_usb_setup.value); + ao_usb_get_descriptor(ao_usb_setup.value); + break; + case AO_USB_REQ_GET_CONFIGURATION: + debug ("get configuration %d\n", ao_usb_configuration); + ao_usb_ep0_queue_byte(ao_usb_configuration); + break; + case AO_USB_REQ_SET_CONFIGURATION: + ao_usb_configuration = ao_usb_setup.value; + debug ("set configuration %d\n", ao_usb_configuration); + ao_usb_set_configuration(); + break; + } + break; + case AO_USB_RECIP_INTERFACE: +#ifndef AVR + #pragma disable_warning 110 +#endif + debug ("Interface setup packet\n"); + switch(ao_usb_setup.request) { + case AO_USB_REQ_GET_STATUS: + ao_usb_ep0_queue_byte(0); + ao_usb_ep0_queue_byte(0); + break; + case AO_USB_REQ_GET_INTERFACE: + ao_usb_ep0_queue_byte(0); + break; + case AO_USB_REQ_SET_INTERFACE: + break; + } + break; + case AO_USB_RECIP_ENDPOINT: + debug ("Endpoint setup packet\n"); + switch(ao_usb_setup.request) { + case AO_USB_REQ_GET_STATUS: + ao_usb_ep0_queue_byte(0); + ao_usb_ep0_queue_byte(0); + break; + } + break; + } + break; + case AO_USB_TYPE_CLASS: + debug ("Class setup packet\n"); + switch (ao_usb_setup.request) { + case SET_LINE_CODING: + debug ("set line coding\n"); + ao_usb_ep0_out_len = 7; + ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_line_coding; + break; + case GET_LINE_CODING: + debug ("get line coding\n"); + ao_usb_ep0_in_len = 7; + ao_usb_ep0_in_data = (uint8_t *) &ao_usb_line_coding; + break; + case SET_CONTROL_LINE_STATE: + break; + } + break; + } + if (ao_usb_ep0_state != AO_USB_EP0_DATA_OUT) { + if (ao_usb_setup.length < ao_usb_ep0_in_len) + ao_usb_ep0_in_len = ao_usb_setup.length; + debug ("Start ep0 in delivery %d\n", ao_usb_ep0_in_len); + ao_usb_ep0_set_in_pending(1); + } +} + +/* End point 0 receives all of the control messages. */ +static void +ao_usb_ep0(void) +{ + uint8_t intx, udint; + + debug ("usb task started\n"); + ao_usb_ep0_state = AO_USB_EP0_IDLE; + for (;;) { + cli(); + for (;;) { + udint = UDINT; + UDINT = 0; +// debug ("UDINT %02x\n", udint); + if (udint & (1 << EORSTI)) { + ao_usb_configuration = 0; + ao_usb_set_ep0(); + } + UENUM = 0; + intx = UEINTX; +// debug ("UEINTX %02x\n", intx); + if (intx & ((1 << RXSTPI) | (1 << RXOUTI))) + break; + if ((intx & (1 << TXINI))) { + if (ao_usb_ep0_in_pending) + break; + else + { + if (ao_usb_addr_pending) { + UDADDR |= (1 << ADDEN); + ao_usb_addr_pending = 0; + } + ueienx_0 = ((1 << RXSTPE) | (1 << RXOUTE)); /* Disable IN interrupt */ + } + } +// debug ("usb task sleeping...\n"); + UENUM = 0; + UEIENX = ueienx_0; + ao_sleep(&ao_usb_task); + } + sei(); +// debug ("UEINTX for ep0 is %02x\n", intx); + if (intx & (1 << RXSTPI)) { + ao_usb_ep0_setup(); + } + if (intx & (1 << RXOUTI)) { + ao_usb_ep0_fill(UEBCLX, (1 << RXOUTI)); + ao_usb_ep0_set_in_pending(1); + } + if (intx & (1 << TXINI) && ao_usb_ep0_in_pending) { + debug ("continue sending ep0 IN data\n"); + ao_usb_ep0_flush(); + } + } +} + +/* Wait for a free IN buffer */ +static void +ao_usb_in_wait(void) +{ + for (;;) { + /* Check if the current buffer is writable */ + UENUM = AO_USB_IN_EP; + if (UEINTX & (1 << RWAL)) + break; + + cli(); + /* Wait for an IN buffer to be ready */ + for (;;) { + UENUM = AO_USB_IN_EP; + if ((UEINTX & (1 << TXINI))) + break; + UEIENX = (1 << TXINE); + ao_sleep(&ao_usb_in_flushed); + } + /* Ack the interrupt */ + UEINTX &= ~(1 << TXINI); + sei(); + } +} + +/* Queue the current IN buffer for transmission */ +static void +ao_usb_in_send(void) +{ + UENUM = AO_USB_IN_EP; + UEINTX &= ~(1 << FIFOCON); +} + +void +ao_usb_flush(void) __critical +{ + if (!ao_usb_running) + return; + + /* Anytime we've sent a character since + * the last time we flushed, we'll need + * to send a packet -- the only other time + * we would send a packet is when that + * packet was full, in which case we now + * want to send an empty packet + */ + if (!ao_usb_in_flushed) { + ao_usb_in_flushed = 1; + ao_usb_in_wait(); + ao_usb_in_send(); + } +} + +void +ao_usb_putchar(char c) __critical __reentrant +{ + if (!ao_usb_running) + return; + + ao_usb_in_wait(); + + /* Queue a byte */ + UENUM = AO_USB_IN_EP; + UEDATX = c; + + /* Send the packet when full */ + if ((UEINTX & (1 << RWAL)) == 0) + ao_usb_in_send(); + ao_usb_in_flushed = 0; +} + +static char +_ao_usb_pollchar(void) +{ + char c; + uint8_t intx; + + if (!ao_usb_running) + return AO_READ_AGAIN; + + for (;;) { + UENUM = AO_USB_OUT_EP; + intx = UEINTX; + debug("usb_pollchar UEINTX %02d\n", intx); + if (intx & (1 << RWAL)) + break; + + if (intx & (1 << FIFOCON)) { + /* Ack the last packet */ + UEINTX = (uint8_t) ~(1 << FIFOCON); + } + + /* Check to see if a packet has arrived */ + if ((intx & (1 << RXOUTI)) == 0) { + UENUM = AO_USB_OUT_EP; + UEIENX = (1 << RXOUTE); + return AO_READ_AGAIN; + } + + /* Ack the interrupt */ + UEINTX = ~(1 << RXOUTI); + } + + /* Pull a character out of the fifo */ + c = UEDATX; + return c; +} + +char +ao_usb_pollchar(void) +{ + char c; + cli(); + c = _ao_usb_pollchar(); + sei(); + return c; +} + +char +ao_usb_getchar(void) __critical +{ + char c; + + cli(); + while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN) + ao_sleep(&ao_stdin_ready); + sei(); + return c; +} + +uint16_t control_count; +uint16_t in_count; +uint16_t out_count; + +/* Endpoint interrupt */ +ISR(USB_COM_vect) +{ + uint8_t old_num = UENUM; + uint8_t i = UEINT; + +#ifdef AO_LED_RED + ao_led_toggle(AO_LED_RED); +#endif + UEINT = 0; + if (i & (1 << 0)) { + UENUM = 0; + UEIENX = 0; + ao_wakeup(&ao_usb_task); + ++control_count; + } + if (i & (1 << AO_USB_IN_EP)) { + UENUM = AO_USB_IN_EP; + UEIENX = 0; + ao_wakeup(&ao_usb_in_flushed); + in_count++; + } + if (i & (1 << AO_USB_OUT_EP)) { + UENUM = AO_USB_OUT_EP; + UEIENX = 0; + ao_wakeup(&ao_stdin_ready); + ++out_count; + } + UENUM = old_num; +} + +#if AVR_VCC_5V +#define AO_PAD_REGULATOR_INIT (1 << UVREGE) /* Turn on pad regulator */ +#endif +#if AVR_VCC_3V3 +/* TeleScience V0.1 has a hardware bug -- UVcc is hooked up, but UCap is not + * Make this work by running power through UVcc to the USB system + */ +#define AO_PAD_REGULATOR_INIT (1 << UVREGE) /* Turn off pad regulator */ +#endif + +#if AVR_CLOCK == 16000000UL +#define AO_USB_PLL_INPUT_PRESCALER (1 << PINDIV) /* Divide 16MHz clock by 2 */ +#endif +#if AVR_CLOCK == 8000000UL +#define AO_USB_PLL_INPUT_PRESCALER 0 /* Don't divide clock */ +#endif + +void +ao_usb_disable(void) +{ + /* Unplug from the bus */ + UDCON = (1 << DETACH); + + /* Disable the interface */ + USBCON = 0; + + /* Disable the PLL */ + PLLCSR = 0; + + /* Turn off the pad regulator */ + UHWCON = 0; +} + +#define AO_USB_CON ((1 << USBE) | /* USB enable */ \ + (0 << RSTCPU) | /* do not reset CPU */ \ + (0 << LSM) | /* Full speed mode */ \ + (0 << RMWKUP)) /* no remote wake-up */ \ + +void +ao_usb_enable(void) +{ + /* Configure pad regulator */ + UHWCON = AO_PAD_REGULATOR_INIT; + + /* Enable USB device, but freeze the clocks until initialized */ + USBCON = AO_USB_CON | (1 <stack_count = stack_len; \ + stack_ptr = (uint8_t __data *) AO_STACK_START; \ + save_ptr = (uint8_t __xdata *) ao_cur_task->stack; \ + do \ + *save_ptr++ = *stack_ptr++; \ + while (--stack_len); \ + } +#define ao_arch_isr_stack() \ + /* Empty the stack; might as well let interrupts have the whole thing */ \ + (SP = AO_STACK_START - 1) + +#define ao_arch_cpu_idle() (PCON = PCON_IDLE) + +#define ao_arch_restore_stack() { \ + uint8_t stack_len; \ + __data uint8_t *stack_ptr; \ + __xdata uint8_t *save_ptr; \ + \ + /* Restore the old stack */ \ + stack_len = ao_cur_task->stack_count; \ + SP = AO_STACK_START - 1 + stack_len; \ + \ + stack_ptr = (uint8_t __data *) AO_STACK_START; \ + save_ptr = (uint8_t __xdata *) ao_cur_task->stack; \ + do \ + *stack_ptr++ = *save_ptr++; \ + while (--stack_len); \ + \ + _asm \ + pop _bp \ + pop PSW \ + pop ar1 \ + pop ar0 \ + pop ar7 \ + pop ar6 \ + pop ar5 \ + pop ar4 \ + pop ar3 \ + pop ar2 \ + pop b \ + pop DPH \ + pop DPL \ + /* The next byte of the stack is the IE register. Only the global \ + enable bit forms part of the task context. Pop off the IE then set \ + the global enable bit to match that of the stored IE register. */ \ + pop ACC \ + JB ACC.7,0098$ \ + CLR _EA \ + LJMP 0099$ \ + 0098$: \ + SETB _EA \ + 0099$: \ + /* Finally pop off the ACC, which was the first register saved. */ \ + pop ACC \ + ret \ + _endasm; \ +} + +#define ao_arch_critical(b) __critical { b } #endif /* _AO_ARCH_H_ */ diff --git a/src/core/ao.h b/src/core/ao.h index 9b0bb545..98a01a4a 100644 --- a/src/core/ao.h +++ b/src/core/ao.h @@ -37,9 +37,9 @@ struct ao_task { __xdata void *wchan; /* current wait channel (NULL if running) */ uint16_t alarm; /* abort ao_sleep time */ - uint8_t stack_count; /* amount of saved stack */ uint8_t task_id; /* unique id */ __code char *name; /* task name */ + ao_arch_task_members /* any architecture-specific fields */ uint8_t stack[AO_STACK_SIZE]; /* saved stack */ }; @@ -321,6 +321,10 @@ ao_usb_disable(void); void ao_usb_init(void); +#if HAS_USB +extern __code __at (0x00aa) uint8_t ao_usb_descriptors []; +#endif + /* * ao_cmd.c */ @@ -1571,4 +1575,9 @@ extern __xdata uint16_t ao_companion_data[AO_COMPANION_MAX_CHANNELS]; void ao_companion_init(void); +/* ao_lcd.c */ + +void +ao_lcd_init(void); + #endif /* _AO_H_ */ diff --git a/src/core/ao_panic.c b/src/core/ao_panic.c index cbfdf399..0668dad2 100644 --- a/src/core/ao_panic.c +++ b/src/core/ao_panic.c @@ -53,7 +53,7 @@ ao_panic(uint8_t reason) } ao_beep(AO_BEEP_OFF); ao_panic_delay(2); -#pragma disable_warning 126 + for (n = 0; n < reason; n++) { ao_led_on(AO_LED_RED); ao_beep(AO_BEEP_MID); diff --git a/src/core/ao_task.c b/src/core/ao_task.c index 41520476..32826114 100644 --- a/src/core/ao_task.c +++ b/src/core/ao_task.c @@ -24,6 +24,10 @@ __data uint8_t ao_num_tasks; __data uint8_t ao_cur_task_index; __xdata struct ao_task *__data ao_cur_task; +#ifdef ao_arch_task_globals +ao_arch_task_globals +#endif + void ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant { @@ -53,27 +57,16 @@ ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *nam void ao_yield(void) ao_arch_naked_define { - ao_arch_save_context(); + ao_arch_save_regs(); if (ao_cur_task_index == AO_NO_TASK_INDEX) ao_cur_task_index = ao_num_tasks-1; else { - uint8_t stack_len; - __data uint8_t *stack_ptr; - __xdata uint8_t *save_ptr; - /* Save the current stack */ - stack_len = SP - (AO_STACK_START - 1); - ao_cur_task->stack_count = stack_len; - stack_ptr = (uint8_t __data *) AO_STACK_START; - save_ptr = (uint8_t __xdata *) ao_cur_task->stack; - do - *save_ptr++ = *stack_ptr++; - while (--stack_len); + ao_arch_save_stack(); } - /* Empty the stack; might as well let interrupts have the whole thing */ - SP = AO_STACK_START - 1; + ao_arch_isr_stack(); /* Find a task to run. If there isn't any runnable task, * this loop will run forever, which is just fine @@ -99,63 +92,20 @@ ao_yield(void) ao_arch_naked_define } /* Enter lower power mode when there isn't anything to do */ - if (ao_next_task_index == ao_cur_task_index) - PCON = PCON_IDLE; + if (ao_next_task_index == ao_cur_task_index) { + ao_arch_cpu_idle(); + } } } - - { - uint8_t stack_len; - __data uint8_t *stack_ptr; - __xdata uint8_t *save_ptr; - - /* Restore the old stack */ - stack_len = ao_cur_task->stack_count; - SP = AO_STACK_START - 1 + stack_len; - - stack_ptr = (uint8_t __data *) AO_STACK_START; - save_ptr = (uint8_t __xdata *) ao_cur_task->stack; - do - *stack_ptr++ = *save_ptr++; - while (--stack_len); - } - - _asm - pop _bp - pop PSW - pop ar1 - pop ar0 - pop ar7 - pop ar6 - pop ar5 - pop ar4 - pop ar3 - pop ar2 - pop b - pop DPH - pop DPL - /* The next byte of the stack is the IE register. Only the global - enable bit forms part of the task context. Pop off the IE then set - the global enable bit to match that of the stored IE register. */ - pop ACC - JB ACC.7,0098$ - CLR _EA - LJMP 0099$ - 0098$: - SETB _EA - 0099$: - /* Finally pop off the ACC, which was the first register saved. */ - pop ACC - ret - _endasm; + ao_arch_restore_stack(); } uint8_t ao_sleep(__xdata void *wchan) { - __critical { + ao_arch_critical( ao_cur_task->wchan = wchan; - } + ); ao_yield(); ao_cur_task->alarm = 0; if (ao_cur_task->wchan) { @@ -186,14 +136,16 @@ ao_alarm(uint16_t delay) } void -ao_exit(void) __critical +ao_exit(void) { - uint8_t i; - ao_num_tasks--; - for (i = ao_cur_task_index; i < ao_num_tasks; i++) - ao_tasks[i] = ao_tasks[i+1]; - ao_cur_task_index = AO_NO_TASK_INDEX; - ao_yield(); + ao_arch_critical( + uint8_t i; + ao_num_tasks--; + for (i = ao_cur_task_index; i < ao_num_tasks; i++) + ao_tasks[i] = ao_tasks[i+1]; + ao_cur_task_index = AO_NO_TASK_INDEX; + ao_yield(); + ); /* we'll never get back here */ } @@ -201,16 +153,13 @@ void ao_task_info(void) { uint8_t i; - uint8_t pc_loc; __xdata struct ao_task *task; for (i = 0; i < ao_num_tasks; i++) { task = ao_tasks[i]; - pc_loc = task->stack_count - 17; - printf("%12s: wchan %04x pc %04x\n", + printf("%12s: wchan %04x\n", task->name, - (int16_t) task->wchan, - (task->stack[pc_loc]) | (task->stack[pc_loc+1] << 8)); + (int16_t) task->wchan); } } -- cgit v1.2.3 From 4299b5a36a2f6f9f7bbbc3a1b935dd2357c1fb0f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 21 Jul 2011 20:04:05 -0700 Subject: altos: Implement remote launch protocol Uses the radio_cmac module to provide secure communication. Keeps igniter closed for 500ms. Provides remote status for arming and ignition. Signed-off-by: Keith Packard --- src/ao_launch.c | 170 +++++++++++++++++++++++--- src/ao_radio_cmac.c | 278 ++++++++++++++++++++++++++++++------------ src/ao_telelaunch.c | 1 - src/cc1111/ao_ignite.c | 6 - src/cc1111/ao_packet_master.c | 6 +- src/cc1111/ao_timer.c | 1 + src/core/ao.h | 59 ++++++++- src/core/ao_cmd.c | 44 +++++-- src/core/ao_config.c | 36 ++++++ src/core/ao_task.c | 7 +- 10 files changed, 497 insertions(+), 111 deletions(-) (limited to 'src/core/ao_task.c') diff --git a/src/ao_launch.c b/src/ao_launch.c index 4870869e..6c154719 100644 --- a/src/ao_launch.c +++ b/src/ao_launch.c @@ -17,43 +17,183 @@ #include "ao.h" +__xdata uint16_t ao_launch_ignite; + +static void +ao_launch_run(void) +{ + for (;;) { + while (!ao_launch_ignite) + ao_sleep(&ao_launch_ignite); + while (ao_launch_ignite) { + ao_launch_ignite = 0; + + ao_ignition[ao_igniter_drogue].firing = 1; + ao_ignition[ao_igniter_main].firing = 1; + AO_IGNITER_DROGUE = 1; + ao_delay(AO_MS_TO_TICKS(500)); + AO_IGNITER_DROGUE = 0; + ao_ignition[ao_igniter_drogue].firing = 0; + ao_ignition[ao_igniter_main].firing = 0; + } + } +} + +static void +ao_launch_status(void) +{ + uint8_t i; + for (;;) { + ao_delay(AO_SEC_TO_TICKS(1)); + if (ao_igniter_status(ao_igniter_drogue) == ao_igniter_ready) { + if (ao_igniter_status(ao_igniter_main) == ao_igniter_ready) { + for (i = 0; i < 5; i++) { + ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(50)); + ao_delay(AO_MS_TO_TICKS(100)); + } + } else { + ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200)); + } + } + } +} + +static __pdata uint8_t ao_launch_armed; +static __pdata uint16_t ao_launch_arm_time; + static void ao_launch(void) { - enum ao_igniter_status arm_status, ignite_status; + static __xdata struct ao_launch_command command; + static __xdata struct ao_launch_query query; + int16_t time_difference; ao_led_off(AO_LED_RED); ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200)); for (;;) { - arm_status = ao_igniter_status(ao_igniter_drogue); + if (ao_radio_cmac_recv(&command, sizeof (command), 0) != AO_RADIO_CMAC_OK) + continue; + + printf ("tick %d serial %d cmd %d channel %d\n", + command.tick, command.serial, command.cmd, command.channel); + + if (command.serial != ao_serial_number) { + printf ("serial number mismatch\n"); + continue; + } - switch (arm_status) { - case ao_igniter_unknown: + switch (command.cmd) { + case AO_LAUNCH_QUERY: + if (command.channel == 0) { + query.valid = 1; + query.arm_status = ao_igniter_status(ao_igniter_drogue); + query.igniter_status = ao_igniter_status(ao_igniter_main); + } else { + query.valid = 0; + } + query.tick = ao_time(); + query.serial = ao_serial_number; + query.channel = command.channel; + printf ("query tick %d serial %d channel %d valid %d arm %d igniter %d\n", + query.tick, query.serial, query.channel, query.valid, query.arm_status, + query.igniter_status); + ao_radio_cmac_send(&query, sizeof (query)); break; - case ao_igniter_active: - case ao_igniter_open: + case AO_LAUNCH_ARM: + if (command.channel != 0) + break; + time_difference = command.tick - ao_time(); + printf ("arm tick %d local tick %d\n", command.tick, ao_time()); + if (time_difference < 0) + time_difference = -time_difference; + if (time_difference > 10) { + printf ("time difference too large %d\n", time_difference); + break; + } + printf ("armed\n"); + ao_launch_armed = 1; + ao_launch_arm_time = ao_time(); break; - case ao_igniter_ready: - ignite_status = ao_igniter_status(ao_igniter_main); - switch (ignite_status) { - case ao_igniter_unknown: - /* some kind of failure signal here */ + case AO_LAUNCH_FIRE: + if (command.channel != 0) break; - case ao_igniter_active: + if (!ao_launch_armed) { + printf ("not armed\n"); break; - case ao_igniter_open: + } + if ((uint16_t) (ao_launch_arm_time - ao_time()) > AO_SEC_TO_TICKS(20)) { + printf ("late launch arm_time %d time %d\n", + ao_launch_arm_time, ao_time()); + break; + } + time_difference = command.tick - ao_time(); + if (time_difference < 0) + time_difference = -time_difference; + if (time_difference > 10) { + printf ("time different too large %d\n", time_difference); break; } + printf ("ignite\n"); + ao_launch_ignite = 1; + ao_wakeup(&ao_launch_ignite); break; } - ao_delay(AO_SEC_TO_TICKS(1)); } } +void +ao_launch_test(void) +{ + switch (ao_igniter_status(ao_igniter_drogue)) { + case ao_igniter_ready: + case ao_igniter_active: + printf ("Armed: "); + switch (ao_igniter_status(ao_igniter_main)) { + default: + printf("unknown status\n"); + break; + case ao_igniter_ready: + printf("igniter good\n"); + break; + case ao_igniter_open: + printf("igniter bad\n"); + break; + } + break; + default: + printf("Disarmed\n"); + } +} + +void +ao_launch_manual(void) +{ + ao_cmd_white(); + if (!ao_match_word("DoIt")) + return; + ao_cmd_white(); + ao_launch_ignite = 1; + ao_wakeup(&ao_launch_ignite); +} + static __xdata struct ao_task ao_launch_task; +static __xdata struct ao_task ao_launch_ignite_task; +static __xdata struct ao_task ao_launch_status_task; + +__code struct ao_cmds ao_launch_cmds[] = { + { ao_launch_test, "t\0Test launch continuity" }, + { ao_launch_manual, "i \0Fire igniter. is doit with D&I" }, + { 0, NULL } +}; void ao_launch_init(void) { - ao_add_task(&ao_launch_task, ao_launch, "launch status"); + AO_IGNITER_DROGUE = 0; + AO_IGNITER_MAIN = 0; + AO_IGNITER_DIR |= AO_IGNITER_DROGUE_BIT | AO_IGNITER_MAIN_BIT; + ao_cmd_register(&ao_launch_cmds[0]); + ao_add_task(&ao_launch_task, ao_launch, "launch listener"); + ao_add_task(&ao_launch_ignite_task, ao_launch_run, "launch igniter"); + ao_add_task(&ao_launch_status_task, ao_launch_status, "launch status"); } diff --git a/src/ao_radio_cmac.c b/src/ao_radio_cmac.c index 7648a2f5..9694b5b3 100644 --- a/src/ao_radio_cmac.c +++ b/src/ao_radio_cmac.c @@ -17,27 +17,24 @@ #include "ao.h" -#define AO_CMAC_KEY_LEN 16 +#define AO_CMAC_KEY_LEN AO_AES_LEN #define AO_CMAC_MAX_LEN (128 - AO_CMAC_KEY_LEN) -static __xdata uint8_t cmac_key[AO_CMAC_KEY_LEN]; +static __xdata uint8_t ao_radio_cmac_mutex; static __xdata uint8_t cmac_data[AO_CMAC_MAX_LEN + AO_CMAC_KEY_LEN + 2 + AO_CMAC_KEY_LEN]; static __pdata uint8_t ao_radio_cmac_len; static uint8_t getnibble(void) { - __pdata char c; - - c = getchar(); - if ('0' <= c && c <= '9') - return c - '0'; - if ('a' <= c && c <= 'f') - return c - ('a' - 10); - if ('A' <= c && c <= 'F') - return c - ('A' - 10); - ao_cmd_status = ao_cmd_lex_error; - return 0; + int8_t b; + + b = ao_cmd_hexchar(getchar()); + if (b < 0) { + ao_cmd_status = ao_cmd_lex_error; + return 0; + } + return (uint8_t) b; } static uint8_t @@ -49,20 +46,137 @@ getbyte(void) return b; } +static uint8_t +round_len(uint8_t len) +{ + uint8_t rem; + + /* Make sure we transfer at least one packet, and + * then make sure every packet is full. Note that + * there is no length encoded, and that the receiver + * must deal with any extra bytes in the packet + */ + if (len < AO_CMAC_KEY_LEN) + len = AO_CMAC_KEY_LEN; + rem = len % AO_CMAC_KEY_LEN; + if (rem != 0) + len += (AO_CMAC_KEY_LEN - rem); + return len; +} + +/* + * Sign and deliver the data sitting in the cmac buffer + */ static void -ao_radio_cmac_key(void) __reentrant +radio_cmac_send(uint8_t len) __reentrant { uint8_t i; - for (i = 0; i < AO_CMAC_KEY_LEN; i++) { - cmac_key[i] = getbyte(); - if (ao_cmd_status != ao_cmd_success) - return; + len = round_len(len); + /* Make sure the AES key is loaded */ + ao_config_get(); + +#if HAS_MONITOR + ao_set_monitor(0); +#endif + + ao_mutex_get(&ao_aes_mutex); + ao_aes_set_mode(ao_aes_mode_cbc_mac); + ao_aes_set_key(ao_config.aes_key); + ao_aes_zero_iv(); + for (i = 0; i < len; i += AO_CMAC_KEY_LEN) { + if (i + AO_CMAC_KEY_LEN < len) + ao_aes_run(&cmac_data[i], NULL); + else + ao_aes_run(&cmac_data[i], &cmac_data[len]); } + ao_mutex_put(&ao_aes_mutex); + + ao_radio_send(cmac_data, len + AO_CMAC_KEY_LEN); +} + +/* + * Receive and validate an incoming packet + */ + +static int8_t +radio_cmac_recv(uint8_t len, uint16_t timeout) __reentrant +{ + uint8_t i; + + len = round_len(len); +#if HAS_MONITOR + ao_set_monitor(0); +#endif + if (timeout) + ao_alarm(timeout); + + i = ao_radio_recv(cmac_data, len + AO_CMAC_KEY_LEN + 2); + ao_clear_alarm(); + + if (!i) + return AO_RADIO_CMAC_TIMEOUT; + + if (!(cmac_data[len + AO_CMAC_KEY_LEN +1] & PKT_APPEND_STATUS_1_CRC_OK)) + return AO_RADIO_CMAC_CRC_ERROR; + + ao_config_get(); + + /* Compute the packet signature + */ + ao_mutex_get(&ao_aes_mutex); + ao_aes_set_mode(ao_aes_mode_cbc_mac); + ao_aes_set_key(ao_config.aes_key); + ao_aes_zero_iv(); + for (i = 0; i < len; i += AO_CMAC_KEY_LEN) { + if (i + AO_CMAC_KEY_LEN < len) + ao_aes_run(&cmac_data[i], NULL); + else + ao_aes_run(&cmac_data[i], &cmac_data[len + AO_CMAC_KEY_LEN + 2]); + } + ao_mutex_put(&ao_aes_mutex); + + /* Check the packet signature against the signature provided + * over the link + */ + + if (memcmp(&cmac_data[len], + &cmac_data[len + AO_CMAC_KEY_LEN + 2], + AO_CMAC_KEY_LEN) != 0) { + return AO_RADIO_CMAC_MAC_ERROR; + } + + return AO_RADIO_CMAC_OK; +} + +int8_t +ao_radio_cmac_send(__xdata void *packet, uint8_t len) __reentrant +{ + if (len > AO_CMAC_MAX_LEN) + return AO_RADIO_CMAC_LEN_ERROR; + ao_mutex_get(&ao_radio_cmac_mutex); + memcpy(cmac_data, packet, len); + radio_cmac_send(len); + ao_mutex_put(&ao_radio_cmac_mutex); + return AO_RADIO_CMAC_OK; +} + +int8_t +ao_radio_cmac_recv(__xdata void *packet, uint8_t len, uint16_t timeout) __reentrant +{ + uint8_t i; + if (len > AO_CMAC_MAX_LEN) + return AO_RADIO_CMAC_LEN_ERROR; + ao_mutex_get(&ao_radio_cmac_mutex); + i = radio_cmac_recv(len, timeout); + if (i == AO_RADIO_CMAC_OK) + memcpy(packet, cmac_data, len); + ao_mutex_put(&ao_radio_cmac_mutex); + return i; } static void -ao_radio_cmac_send(void) __reentrant +radio_cmac_send_cmd(void) __reentrant { uint8_t i; uint8_t len; @@ -70,43 +184,25 @@ ao_radio_cmac_send(void) __reentrant ao_cmd_decimal(); if (ao_cmd_status != ao_cmd_success) return; - if (ao_cmd_lex_i < AO_CMAC_KEY_LEN || - ao_cmd_lex_i > AO_CMAC_MAX_LEN || - ao_cmd_lex_i % AO_CMAC_KEY_LEN != 0) - { + len = ao_cmd_lex_i; + if (len > AO_CMAC_MAX_LEN) { ao_cmd_status = ao_cmd_syntax_error; return; } flush(); + ao_mutex_get(&ao_radio_cmac_mutex); len = ao_cmd_lex_i; for (i = 0; i < len; i++) { cmac_data[i] = getbyte(); if (ao_cmd_status != ao_cmd_success) return; } - ao_mutex_get(&ao_aes_mutex); - ao_aes_set_mode(ao_aes_mode_cbc_mac); - ao_aes_set_key(cmac_key); - ao_aes_zero_iv(); - for (i = 0; i < len; i += AO_CMAC_KEY_LEN) { - if (i + AO_CMAC_KEY_LEN < len) - ao_aes_run(&cmac_data[i], NULL); - else - ao_aes_run(&cmac_data[i], &cmac_data[len]); - } - ao_mutex_put(&ao_aes_mutex); -#if HAS_MONITOR - ao_set_monitor(0); -#endif - printf("send:"); - for (i = 0; i < len + AO_CMAC_KEY_LEN; i++) - printf(" %02x", cmac_data[i]); - printf("\n"); flush(); - ao_radio_send(cmac_data, len + AO_CMAC_KEY_LEN); + radio_cmac_send(len); + ao_mutex_put(&ao_radio_cmac_mutex); } static void -ao_radio_cmac_recv(void) __reentrant +radio_cmac_recv_cmd(void) __reentrant { uint8_t len, i; uint16_t timeout; @@ -114,47 +210,79 @@ ao_radio_cmac_recv(void) __reentrant ao_cmd_decimal(); if (ao_cmd_status != ao_cmd_success) return; - if (ao_cmd_lex_i < AO_CMAC_KEY_LEN || - ao_cmd_lex_i > AO_CMAC_MAX_LEN || - ao_cmd_lex_i % AO_CMAC_KEY_LEN != 0) - { - ao_cmd_status = ao_cmd_syntax_error; - return; - } len = ao_cmd_lex_i; ao_cmd_decimal(); if (ao_cmd_status != ao_cmd_success) return; - timeout = ao_cmd_lex_i; -#if HAS_MONITOR - ao_set_monitor(0); -#endif - if (timeout) - ao_alarm(timeout); - if (!ao_radio_recv(cmac_data, len + AO_CMAC_KEY_LEN + 2)) { - printf("timeout\n"); + timeout = AO_MS_TO_TICKS(ao_cmd_lex_i); + ao_mutex_get(&ao_radio_cmac_mutex); + i = radio_cmac_recv(len, timeout); + if (i == AO_RADIO_CMAC_OK) { + printf ("PACKET "); + for (i = 0; i < len; i++) + printf("%02x", cmac_data[i]); + printf ("\n"); + } else + printf ("ERROR %d\n", i); + ao_mutex_put(&ao_radio_cmac_mutex); +} + +static void +launch_report_cmd(void) __reentrant +{ + static __xdata struct ao_launch_command command; + static __xdata struct ao_launch_query query; + uint8_t channel; + uint16_t serial; + uint8_t i; + + ao_cmd_decimal(); + serial = ao_cmd_lex_i; + ao_cmd_decimal(); + channel = ao_cmd_lex_i; + if (ao_cmd_status != ao_cmd_success) return; + flush(); + for (i = 0; i < 10; i++) { + printf ("."); flush(); + command.tick = 0; + command.serial = serial; + command.cmd = AO_LAUNCH_QUERY; + command.channel = channel; + ao_radio_cmac_send(&command, sizeof (command)); + switch (ao_radio_cmac_recv(&query, sizeof (query), AO_MS_TO_TICKS(500))) { + case AO_RADIO_CMAC_OK: + printf("\n"); + switch (query.arm_status) { + case ao_igniter_ready: + case ao_igniter_active: + printf ("Armed: "); + switch (query.igniter_status) { + default: + printf("unknown status\n"); + break; + case ao_igniter_ready: + printf("igniter good\n"); + break; + case ao_igniter_open: + printf("igniter bad\n"); + break; + } + default: + printf("Disarmed\n"); + } + return; + default: + continue; + } } - ao_mutex_get(&ao_aes_mutex); - ao_aes_set_mode(ao_aes_mode_cbc_mac); - ao_aes_set_key(cmac_key); - ao_aes_zero_iv(); - for (i = 0; i < len; i += AO_CMAC_KEY_LEN) { - if (i + AO_CMAC_KEY_LEN < len) - ao_aes_run(&cmac_data[i], NULL); - else - ao_aes_run(&cmac_data[i], &cmac_data[len + AO_CMAC_KEY_LEN + 2]); - } - printf ("PACKET "); - for (i = 0; i < len + AO_CMAC_KEY_LEN + 2 + AO_CMAC_KEY_LEN; i++) - printf("%02x", cmac_data[i]); - printf ("\n"); + printf ("Timeout\n"); } static __code struct ao_cmds ao_radio_cmac_cmds[] = { - { ao_radio_cmac_key, "k\0Set AES-CMAC key. 16 key bytes follow on next line" }, - { ao_radio_cmac_send, "s \0Send AES-CMAC packet. Bytes to send follow on next line" }, - { ao_radio_cmac_recv, "S \0Receive AES-CMAC packet. Timeout in ms" }, + { radio_cmac_send_cmd, "s \0Send AES-CMAC packet. Bytes to send follow on next line" }, + { radio_cmac_recv_cmd, "S \0Receive AES-CMAC packet. Timeout in ms" }, + { launch_report_cmd, "l \0Get remote launch status" }, { 0, NULL }, }; diff --git a/src/ao_telelaunch.c b/src/ao_telelaunch.c index b5404710..506431de 100644 --- a/src/ao_telelaunch.c +++ b/src/ao_telelaunch.c @@ -35,7 +35,6 @@ main(void) ao_storage_init(); ao_usb_init(); ao_radio_init(); - ao_igniter_init(); #if HAS_DBG ao_dbg_init(); #endif diff --git a/src/cc1111/ao_ignite.c b/src/cc1111/ao_ignite.c index 5238beb4..0fd2b4bf 100644 --- a/src/cc1111/ao_ignite.c +++ b/src/cc1111/ao_ignite.c @@ -39,12 +39,6 @@ #define AO_IGNITER_FIRE_TIME AO_MS_TO_TICKS(50) #define AO_IGNITER_CHARGE_TIME AO_MS_TO_TICKS(2000) -struct ao_ignition { - uint8_t request; - uint8_t fired; - uint8_t firing; -}; - __xdata struct ao_ignition ao_ignition[2]; void diff --git a/src/cc1111/ao_packet_master.c b/src/cc1111/ao_packet_master.c index b0fdf5a8..0d0be30e 100644 --- a/src/cc1111/ao_packet_master.c +++ b/src/cc1111/ao_packet_master.c @@ -80,13 +80,16 @@ ao_packet_master(void) ao_packet_master_time = ao_time(); ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT; while (ao_packet_enable) { + uint8_t r; memcpy(ao_tx_packet.callsign, ao_config.callsign, AO_MAX_CALLSIGN); ao_packet_send(); if (ao_tx_packet.len) ao_packet_master_busy(); ao_packet_master_check_busy(); ao_alarm(ao_packet_master_delay); - if (ao_packet_recv()) { + r = ao_packet_recv(); + ao_clear_alarm(); + if (r) { /* if we can transmit data, do so */ if (ao_packet_tx_used && ao_tx_packet.len == 0) continue; @@ -95,6 +98,7 @@ ao_packet_master(void) ao_packet_master_sleeping = 1; ao_alarm(ao_packet_master_delay); ao_sleep(&ao_packet_master_sleeping); + ao_clear_alarm(); ao_packet_master_sleeping = 0; } } diff --git a/src/cc1111/ao_timer.c b/src/cc1111/ao_timer.c index c977fbc8..aadee71e 100644 --- a/src/cc1111/ao_timer.c +++ b/src/cc1111/ao_timer.c @@ -31,6 +31,7 @@ ao_delay(uint16_t ticks) { ao_alarm(ticks); ao_sleep(&ao_forever); + ao_clear_alarm(); } #define T1_CLOCK_DIVISOR 8 /* 24e6/8 = 3e6 */ diff --git a/src/core/ao.h b/src/core/ao.h index 2898852b..a5bbb6f1 100644 --- a/src/core/ao.h +++ b/src/core/ao.h @@ -68,6 +68,10 @@ ao_wakeup(__xdata void *wchan); void ao_alarm(uint16_t delay); +/* Clear any pending alarm */ +void +ao_clear_alarm(void); + /* Yield the processor to another task */ void ao_yield(void) ao_arch_naked_declare; @@ -342,6 +346,12 @@ ao_cmd_put16(uint16_t v); void ao_cmd_white(void); +int8_t +ao_cmd_hexchar(char c); + +void +ao_cmd_hexbyte(void); + void ao_cmd_hex(void); @@ -1417,6 +1427,14 @@ enum ao_igniter_status { ao_igniter_open, /* open circuit detected */ }; +struct ao_ignition { + uint8_t request; + uint8_t fired; + uint8_t firing; +}; + +extern __xdata struct ao_ignition ao_ignition[2]; + enum ao_igniter_status ao_igniter_status(enum ao_igniter igniter); @@ -1431,7 +1449,8 @@ ao_igniter_init(void); */ #define AO_CONFIG_MAJOR 1 -#define AO_CONFIG_MINOR 8 +#define AO_CONFIG_MINOR 9 +#define AO_AES_LEN 16 struct ao_config { uint8_t major; @@ -1448,6 +1467,7 @@ struct ao_config { uint8_t pad_orientation; /* minor version 6 */ uint32_t radio_setting; /* minor version 7 */ uint8_t radio_enable; /* minor version 8 */ + uint8_t aes_key[AO_AES_LEN]; /* minor version 9 */ }; #define AO_IGNITE_MODE_DUAL 0 @@ -1635,8 +1655,6 @@ __xdata uint8_t ao_aes_mutex; /* AES keys and blocks are 128 bits */ -#define AO_AES_LEN 16 - enum ao_aes_mode { ao_aes_mode_cbc_mac }; @@ -1664,10 +1682,45 @@ ao_aes_init(void); /* ao_radio_cmac.c */ +int8_t +ao_radio_cmac_send(__xdata void *packet, uint8_t len) __reentrant; + +#define AO_RADIO_CMAC_OK 0 +#define AO_RADIO_CMAC_LEN_ERROR -1 +#define AO_RADIO_CMAC_CRC_ERROR -2 +#define AO_RADIO_CMAC_MAC_ERROR -3 +#define AO_RADIO_CMAC_TIMEOUT -4 + +int8_t +ao_radio_cmac_recv(__xdata void *packet, uint8_t len, uint16_t timeout) __reentrant; + void ao_radio_cmac_init(void); /* ao_launch.c */ + +struct ao_launch_command { + uint16_t tick; + uint16_t serial; + uint8_t cmd; + uint8_t channel; + uint16_t unused; +}; + +#define AO_LAUNCH_QUERY 1 + +struct ao_launch_query { + uint16_t tick; + uint16_t serial; + uint8_t channel; + uint8_t valid; + uint8_t arm_status; + uint8_t igniter_status; +}; + +#define AO_LAUNCH_ARM 2 +#define AO_LAUNCH_FIRE 3 + void ao_launch_init(void); diff --git a/src/core/ao_cmd.c b/src/core/ao_cmd.c index 7663d875..9e14c221 100644 --- a/src/core/ao_cmd.c +++ b/src/core/ao_cmd.c @@ -22,7 +22,7 @@ __pdata uint32_t ao_cmd_lex_u32; __pdata char ao_cmd_lex_c; __pdata enum ao_cmd_status ao_cmd_status; -#define CMD_LEN 32 +#define CMD_LEN 48 static __xdata char cmd_line[CMD_LEN]; static __pdata uint8_t cmd_len; @@ -128,22 +128,48 @@ ao_cmd_white(void) ao_cmd_lex(); } +int8_t +ao_cmd_hexchar(char c) +{ + if ('0' <= c && c <= '9') + return (c - '0'); + if ('a' <= c && c <= 'f') + return (c - 'a' + 10); + if ('A' <= c && c <= 'F') + return (c - 'A' + 10); + return -1; +} + +void +ao_cmd_hexbyte(void) +{ + uint8_t i; + int8_t n; + + ao_cmd_lex_i = 0; + ao_cmd_white(); + for (i = 0; i < 2; i++) { + n = ao_cmd_hexchar(ao_cmd_lex_c); + if (n < 0) { + ao_cmd_status = ao_cmd_syntax_error; + break; + } + ao_cmd_lex_i = (ao_cmd_lex_i << 4) | n; + ao_cmd_lex(); + } +} + void ao_cmd_hex(void) { __pdata uint8_t r = ao_cmd_lex_error; - uint8_t n; + int8_t n; ao_cmd_lex_i = 0; ao_cmd_white(); for(;;) { - if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9') - n = (ao_cmd_lex_c - '0'); - else if ('a' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'f') - n = (ao_cmd_lex_c - 'a' + 10); - else if ('A' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'F') - n = (ao_cmd_lex_c - 'A' + 10); - else + n = ao_cmd_hexchar(ao_cmd_lex_c); + if (n < 0) break; ao_cmd_lex_i = (ao_cmd_lex_i << 4) | n; r = ao_cmd_success; diff --git a/src/core/ao_config.c b/src/core/ao_config.c index ec2b61f6..7f999feb 100644 --- a/src/core/ao_config.c +++ b/src/core/ao_config.c @@ -74,11 +74,14 @@ _ao_config_get(void) if (ao_config.major != AO_CONFIG_MAJOR) { ao_config.major = AO_CONFIG_MAJOR; ao_config.minor = 0; + + /* Version 0 stuff */ ao_config.main_deploy = AO_CONFIG_DEFAULT_MAIN_DEPLOY; ao_config.radio_channel = AO_CONFIG_DEFAULT_RADIO_CHANNEL; memset(&ao_config.callsign, '\0', sizeof (ao_config.callsign)); memcpy(&ao_config.callsign, AO_CONFIG_DEFAULT_CALLSIGN, sizeof(AO_CONFIG_DEFAULT_CALLSIGN) - 1); + ao_config_dirty = 1; } if (ao_config.minor < AO_CONFIG_MINOR) { /* Fixups for minor version 1 */ @@ -104,6 +107,8 @@ _ao_config_get(void) ao_config.radio_setting = ao_config.radio_cal; if (ao_config.minor < 8) ao_config.radio_enable = TRUE; + if (ao_config.minor < 9) + memset(&ao_config.aes_key, '\0', AO_AES_LEN); ao_config.minor = AO_CONFIG_MINOR; ao_config_dirty = 1; } @@ -414,6 +419,33 @@ ao_config_radio_enable_set(void) __reentrant _ao_config_edit_finish(); } +#if HAS_AES +void +ao_config_key_show(void) __reentrant +{ + uint8_t i; + printf("AES key: "); + for (i = 0; i < AO_AES_LEN; i++) + printf ("%02x", ao_config.aes_key[i]); + printf("\n"); +} + +void +ao_config_key_set(void) __reentrant +{ + uint8_t i; + + _ao_config_edit_start(); + for (i = 0; i < AO_AES_LEN; i++) { + ao_cmd_hexbyte(); + if (ao_cmd_status != ao_cmd_success) + break; + ao_config.aes_key[i] = ao_cmd_lex_i; + } + _ao_config_edit_finish(); +} +#endif + struct ao_config_var { __code char *str; void (*set)(void) __reentrant; @@ -461,6 +493,10 @@ __code struct ao_config_var ao_config_vars[] = { #if HAS_ACCEL { "o <0 antenna up, 1 antenna down>\0Set pad orientation", ao_config_pad_orientation_set,ao_config_pad_orientation_show }, +#endif +#if HAS_AES + { "k <32 hex digits>\0Set AES encryption key", + ao_config_key_set, ao_config_key_show }, #endif { "s\0Show", ao_config_show, 0 }, diff --git a/src/core/ao_task.c b/src/core/ao_task.c index 32826114..a19a6a6f 100644 --- a/src/core/ao_task.c +++ b/src/core/ao_task.c @@ -107,7 +107,6 @@ ao_sleep(__xdata void *wchan) ao_cur_task->wchan = wchan; ); ao_yield(); - ao_cur_task->alarm = 0; if (ao_cur_task->wchan) { ao_cur_task->wchan = NULL; return 1; @@ -135,6 +134,12 @@ ao_alarm(uint16_t delay) ao_cur_task->alarm = 1; } +void +ao_clear_alarm(void) +{ + ao_cur_task->alarm = 0; +} + void ao_exit(void) { -- cgit v1.2.3 From 93481fd3d9305a107b88c8a64de4194a6d94dc0e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 18 Mar 2012 22:05:46 -0700 Subject: Incorrect type in ao_task_info for wchan Would truncate 32-bit pointers on arm. Signed-off-by: Keith Packard --- src/core/ao_task.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/ao_task.c') diff --git a/src/core/ao_task.c b/src/core/ao_task.c index a19a6a6f..d7d0e8a2 100644 --- a/src/core/ao_task.c +++ b/src/core/ao_task.c @@ -164,7 +164,7 @@ ao_task_info(void) task = ao_tasks[i]; printf("%12s: wchan %04x\n", task->name, - (int16_t) task->wchan); + (int) task->wchan); } } -- cgit v1.2.3 From 9d3fe2a80d0925e3eded6d738d05c5b4ea61504c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 17 Jun 2012 16:12:18 -0700 Subject: altos: Don't lose IRQ disabled state in ao_sleep Using ao_arch_critical around the wchan setting will force interrupts to be re-enabled before ao_yield records the state of that bit, potentially causing problems with functions not atomically testing and sleeping. Tasks that need to set wchan with interrupts disabled should have interrupts disabled when entering ao_sleep already. Signed-off-by: Keith Packard --- src/core/ao_task.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/core/ao_task.c') diff --git a/src/core/ao_task.c b/src/core/ao_task.c index d7d0e8a2..910f1587 100644 --- a/src/core/ao_task.c +++ b/src/core/ao_task.c @@ -103,9 +103,7 @@ ao_yield(void) ao_arch_naked_define uint8_t ao_sleep(__xdata void *wchan) { - ao_arch_critical( - ao_cur_task->wchan = wchan; - ); + ao_cur_task->wchan = wchan; ao_yield(); if (ao_cur_task->wchan) { ao_cur_task->wchan = NULL; -- cgit v1.2.3 From 8efac8eb99a9aabb45d9fbf742e4be91e4b331a5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 26 Jun 2012 23:21:04 -0700 Subject: altos: Add debugging code to check for stack overflow Stack overflow often happens from interrupt handlers sitting on top of a task stack. Check for this during ao_wakeup as that is often called during interrupt processing. Signed-off-by: Keith Packard --- src/core/ao_task.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'src/core/ao_task.c') diff --git a/src/core/ao_task.c b/src/core/ao_task.c index 910f1587..4011a36e 100644 --- a/src/core/ao_task.c +++ b/src/core/ao_task.c @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include "ao.h" +#include #define AO_NO_TASK_INDEX 0xff @@ -28,6 +28,20 @@ __xdata struct ao_task *__data ao_cur_task; ao_arch_task_globals #endif +#define AO_CHECK_STACK 0 + +#if AO_CHECK_STACK +static uint8_t in_yield; + +static inline void ao_check_stack(void) { + uint8_t q; + if (!in_yield && ao_cur_task && &q < &ao_cur_task->stack[0]) + ao_panic(AO_PANIC_STACK); +} +#else +#define ao_check_stack() +#endif + void ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant { @@ -68,6 +82,9 @@ ao_yield(void) ao_arch_naked_define ao_arch_isr_stack(); +#if CHECK_STACK + in_yield = 1; +#endif /* Find a task to run. If there isn't any runnable task, * this loop will run forever, which is just fine */ @@ -97,6 +114,10 @@ ao_yield(void) ao_arch_naked_define } } } +#if CHECK_STACK + cli(); + in_yield = 0; +#endif ao_arch_restore_stack(); } @@ -117,6 +138,7 @@ ao_wakeup(__xdata void *wchan) { uint8_t i; + ao_check_stack(); for (i = 0; i < ao_num_tasks; i++) if (ao_tasks[i]->wchan == wchan) ao_tasks[i]->wchan = NULL; -- cgit v1.2.3 From d13d0fbfcb0fd6d8a1af46f6270a968d746c830e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 26 Aug 2012 09:49:34 -0700 Subject: altos: Make ao_cur_task_index track ao_cur_task in ao_yield This keeps the two main task references (index and pointer) in agreement during task switching, avoiding an extra assignment at the end of the task switching loop. Signed-off-by: Keith Packard --- src/core/ao_task.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) (limited to 'src/core/ao_task.c') diff --git a/src/core/ao_task.c b/src/core/ao_task.c index 4011a36e..4593bd79 100644 --- a/src/core/ao_task.c +++ b/src/core/ao_task.c @@ -82,39 +82,36 @@ ao_yield(void) ao_arch_naked_define ao_arch_isr_stack(); -#if CHECK_STACK +#if AO_CHECK_STACK in_yield = 1; #endif /* Find a task to run. If there isn't any runnable task, * this loop will run forever, which is just fine */ { - __pdata uint8_t ao_next_task_index = ao_cur_task_index; + __pdata uint8_t ao_last_task_index = ao_cur_task_index; for (;;) { - ++ao_next_task_index; - if (ao_next_task_index == ao_num_tasks) - ao_next_task_index = 0; + ++ao_cur_task_index; + if (ao_cur_task_index == ao_num_tasks) + ao_cur_task_index = 0; + + ao_cur_task = ao_tasks[ao_cur_task_index]; - ao_cur_task = ao_tasks[ao_next_task_index]; - if (ao_cur_task->wchan == NULL) { - ao_cur_task_index = ao_next_task_index; + /* Check for ready task */ + if (ao_cur_task->wchan == NULL) break; - } /* Check if the alarm is set for a time which has passed */ if (ao_cur_task->alarm && - (int16_t) (ao_time() - ao_cur_task->alarm) >= 0) { - ao_cur_task_index = ao_next_task_index; + (int16_t) (ao_time() - ao_cur_task->alarm) >= 0) break; - } /* Enter lower power mode when there isn't anything to do */ - if (ao_next_task_index == ao_cur_task_index) { + if (ao_cur_task_index == ao_last_task_index) ao_arch_cpu_idle(); - } } } -#if CHECK_STACK +#if AO_CHECK_STACK cli(); in_yield = 0; #endif @@ -177,7 +174,7 @@ ao_exit(void) void ao_task_info(void) { - uint8_t i; + uint8_t i; __xdata struct ao_task *task; for (i = 0; i < ao_num_tasks; i++) { -- cgit v1.2.3 From 31b42b99edbb976534ac432c07e218f13d1f5f9b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 28 Aug 2012 18:03:52 -0700 Subject: altos: Fix ao_delay function and move from per-chip code to ao_task.c ao_delay hasn't been chip-specific for a long time, and it had a bug in not calling ao_clear_alarm. Signed-off-by: Keith Packard --- src/avr/ao_timer.c | 9 --------- src/cc1111/ao_timer.c | 10 ---------- src/core/ao_task.c | 11 +++++++++++ src/stm/ao_timer.c | 9 --------- 4 files changed, 11 insertions(+), 28 deletions(-) (limited to 'src/core/ao_task.c') diff --git a/src/avr/ao_timer.c b/src/avr/ao_timer.c index cd81b163..d2ea2be7 100644 --- a/src/avr/ao_timer.c +++ b/src/avr/ao_timer.c @@ -28,15 +28,6 @@ uint16_t ao_time(void) return v; } -static __xdata uint8_t ao_forever; - -void -ao_delay(uint16_t ticks) -{ - ao_alarm(ticks); - ao_sleep(&ao_forever); -} - #define T1_CLOCK_DIVISOR 8 /* 24e6/8 = 3e6 */ #define T1_SAMPLE_TIME 30000 /* 3e6/30000 = 100 */ diff --git a/src/cc1111/ao_timer.c b/src/cc1111/ao_timer.c index 602f98c8..a64b5aba 100644 --- a/src/cc1111/ao_timer.c +++ b/src/cc1111/ao_timer.c @@ -24,16 +24,6 @@ uint16_t ao_time(void) __critical return ao_tick_count; } -static __xdata uint8_t ao_forever; - -void -ao_delay(uint16_t ticks) -{ - ao_alarm(ticks); - ao_sleep(&ao_forever); - ao_clear_alarm(); -} - #define T1_CLOCK_DIVISOR 8 /* 24e6/8 = 3e6 */ #define T1_SAMPLE_TIME 30000 /* 3e6/30000 = 100 */ diff --git a/src/core/ao_task.c b/src/core/ao_task.c index 4593bd79..65654731 100644 --- a/src/core/ao_task.c +++ b/src/core/ao_task.c @@ -125,6 +125,7 @@ ao_sleep(__xdata void *wchan) ao_yield(); if (ao_cur_task->wchan) { ao_cur_task->wchan = NULL; + ao_cur_task->alarm = 0; return 1; } return 0; @@ -157,6 +158,16 @@ ao_clear_alarm(void) ao_cur_task->alarm = 0; } +static __xdata uint8_t ao_forever; + +void +ao_delay(uint16_t ticks) +{ + ao_alarm(ticks); + ao_sleep(&ao_forever); + ao_clear_alarm(); +} + void ao_exit(void) { diff --git a/src/stm/ao_timer.c b/src/stm/ao_timer.c index 78228e65..f561e6b5 100644 --- a/src/stm/ao_timer.c +++ b/src/stm/ao_timer.c @@ -28,15 +28,6 @@ uint16_t ao_time(void) return v; } -static __xdata uint8_t ao_forever; - -void -ao_delay(uint16_t ticks) -{ - ao_alarm(ticks); - ao_sleep(&ao_forever); -} - #if AO_DATA_ALL volatile __data uint8_t ao_data_interval = 1; volatile __data uint8_t ao_data_count; -- cgit v1.2.3