summaryrefslogtreecommitdiff
path: root/src/cc1111
diff options
context:
space:
mode:
Diffstat (limited to 'src/cc1111')
-rw-r--r--src/cc1111/Makefile.cc111127
-rw-r--r--src/cc1111/_bp.c26
-rw-r--r--src/cc1111/ao_adc.c200
-rw-r--r--src/cc1111/ao_arch.h207
-rw-r--r--src/cc1111/ao_beep.c52
-rw-r--r--src/cc1111/ao_dbg.c364
-rw-r--r--src/cc1111/ao_dma.c131
-rw-r--r--src/cc1111/ao_ignite.c190
-rw-r--r--src/cc1111/ao_intflash.c209
-rw-r--r--src/cc1111/ao_launch.c209
-rw-r--r--src/cc1111/ao_led.c61
-rw-r--r--src/cc1111/ao_packet.c148
-rw-r--r--src/cc1111/ao_packet_master.c148
-rw-r--r--src/cc1111/ao_packet_slave.c66
-rw-r--r--src/cc1111/ao_pins.h514
-rw-r--r--src/cc1111/ao_radio.c463
-rw-r--r--src/cc1111/ao_reboot.c28
-rw-r--r--src/cc1111/ao_romconfig.c32
-rw-r--r--src/cc1111/ao_serial.c175
-rw-r--r--src/cc1111/ao_spi.c157
-rw-r--r--src/cc1111/ao_timer.c112
-rw-r--r--src/cc1111/ao_usb.c460
-rw-r--r--src/cc1111/ao_usb.h100
-rw-r--r--src/cc1111/cc1111.h1328
24 files changed, 5407 insertions, 0 deletions
diff --git a/src/cc1111/Makefile.cc1111 b/src/cc1111/Makefile.cc1111
new file mode 100644
index 00000000..8de4a9b2
--- /dev/null
+++ b/src/cc1111/Makefile.cc1111
@@ -0,0 +1,27 @@
+CC=sdcc
+
+CFLAGS=--model-small --debug --opt-code-speed -DCODESIZE=$(CODESIZE)
+
+CFLAGS += $(PRODUCT_DEF) -I. -I.. -I../core -I../cc1111 -I../driver -I../product
+
+CODESIZE ?= 0x8000
+
+LDFLAGS=--out-fmt-ihx --code-loc 0x0000 --code-size $(CODESIZE) \
+ --xram-loc 0xf000 --xram-size 0xda2 --iram-size 0xff
+
+REL=$(SRC:.c=.rel) ao_product.rel
+ADB=$(REL:.rel=.adb)
+ASM=$(REL:.rel=.asm)
+LNK=$(REL:.rel=.lnk)
+LST=$(REL:.rel=.lst)
+RST=$(REL:.rel=.rst)
+SYM=$(REL:.rel=.sym)
+
+PCDB=$(PROG:.ihx=.cdb)
+PLNK=$(PROG:.ihx=.lnk)
+PMAP=$(PROG:.ihx=.map)
+PMEM=$(PROG:.ihx=.mem)
+PAOM=$(PROG:.ihx=)
+
+%.rel : %.c $(INC)
+ $(call quiet,CC,$(PRODUCT_DEF)) $(CFLAGS) -c -o$@ $<
diff --git a/src/cc1111/_bp.c b/src/cc1111/_bp.c
new file mode 100644
index 00000000..6bf135bc
--- /dev/null
+++ b/src/cc1111/_bp.c
@@ -0,0 +1,26 @@
+/*-------------------------------------------------------------------------
+
+ _bp.c :- just declares bp as a variable
+
+ Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999)
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This library 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 Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding!
+-------------------------------------------------------------------------*/
+
+__data unsigned char bp ;
diff --git a/src/cc1111/ao_adc.c b/src/cc1111/ao_adc.c
new file mode 100644
index 00000000..6aa6e018
--- /dev/null
+++ b/src/cc1111/ao_adc.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+#include "ao_pins.h"
+
+volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING];
+#if HAS_ACCEL_REF
+volatile __xdata uint16_t ao_accel_ref[AO_ADC_RING];
+#endif
+volatile __data uint8_t ao_adc_head;
+
+void
+ao_adc_poll(void)
+{
+#if HAS_ACCEL_REF
+ ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 2;
+#else
+# ifdef TELENANO_V_0_1
+ ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 1;
+# else
+ ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 0;
+# endif
+#endif
+}
+
+void
+ao_adc_get(__xdata struct ao_adc *packet)
+{
+#if HAS_FLIGHT
+ uint8_t i = ao_adc_ring_prev(ao_sample_adc);
+#else
+ uint8_t i = ao_adc_ring_prev(ao_adc_head);
+#endif
+ memcpy(packet, &ao_adc_ring[i], sizeof (struct ao_adc));
+}
+
+void
+ao_adc_isr(void) __interrupt 1
+{
+ uint8_t sequence;
+ uint8_t __xdata *a;
+
+ sequence = (ADCCON2 & ADCCON2_SCH_MASK) >> ADCCON2_SCH_SHIFT;
+#if IGNITE_ON_P2
+ /* TeleMetrum readings */
+#if HAS_ACCEL_REF
+ if (sequence == 2) {
+ a = (uint8_t __xdata *) (&ao_accel_ref[ao_adc_head]);
+ sequence = 0;
+ } else
+#endif
+ {
+ if (sequence == ADCCON3_ECH_TEMP)
+ sequence = 2;
+ a = (uint8_t __xdata *) (&ao_adc_ring[ao_adc_head].accel + sequence);
+ sequence++;
+ }
+#define GOT_ADC
+ a[0] = ADCL;
+ a[1] = ADCH;
+ if (sequence < 6) {
+#if HAS_EXTERNAL_TEMP == 0
+ /* start next channel conversion */
+ /* v0.2 replaces external temp sensor with internal one */
+ if (sequence == 2)
+ ADCCON3 = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP;
+ else
+#endif
+ ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | sequence;
+ }
+#endif
+
+#if IGNITE_ON_P0
+ /* TeleMini readings */
+ a = (uint8_t __xdata *) (&ao_adc_ring[ao_adc_head].pres);
+#ifdef TELEMINI_V_1_0
+ switch (sequence) {
+ case 0:
+ /* pressure */
+ a += 0;
+ sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 1;
+ break;
+ case 1:
+ /* drogue sense */
+ a += 6;
+ sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 2;
+ break;
+ case 2:
+ /* main sense */
+ a += 8;
+ sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 3;
+ break;
+ case 3:
+ /* battery */
+ a += 4;
+ sequence = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP;
+ break;
+ case ADCCON3_ECH_TEMP:
+ a += 2;
+ sequence = 0;
+ break;
+ }
+#define GOT_ADC
+#endif
+#ifdef TELENANO_V_0_1
+ switch (sequence) {
+ case 1:
+ /* pressure */
+ a += 0;
+ sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 3;
+ break;
+ case 3:
+ /* battery */
+ a += 4;
+ sequence = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP;
+ break;
+ case ADCCON3_ECH_TEMP:
+ a += 2;
+ sequence = 0;
+ break;
+ }
+#define GOT_ADC
+#endif
+ a[0] = ADCL;
+ a[1] = ADCH;
+ if (sequence) {
+ /* Start next conversion */
+ ADCCON3 = sequence;
+ }
+#endif
+#ifndef GOT_ADC
+#error No known ADC configuration set
+#endif
+
+ else {
+ /* record this conversion series */
+ ao_adc_ring[ao_adc_head].tick = ao_time();
+ ao_adc_head = ao_adc_ring_next(ao_adc_head);
+ ao_wakeup(DATA_TO_XDATA(&ao_adc_head));
+ }
+}
+
+static void
+ao_adc_dump(void) __reentrant
+{
+ static __xdata struct ao_adc packet;
+ ao_adc_get(&packet);
+ printf("tick: %5u accel: %5d pres: %5d temp: %5d batt: %5d drogue: %5d main: %5d\n",
+ packet.tick, packet.accel, packet.pres, packet.temp,
+ packet.v_batt, packet.sense_d, packet.sense_m);
+}
+
+__code struct ao_cmds ao_adc_cmds[] = {
+ { ao_adc_dump, "a\0Current ADC" },
+ { 0, NULL },
+};
+
+void
+ao_adc_init(void)
+{
+#if IGNITE_ON_P2
+ /* TeleMetrum configuration */
+ ADCCFG = ((1 << 0) | /* acceleration */
+ (1 << 1) | /* pressure */
+#if HAS_EXTERNAL_TEMP
+ (1 << 2) | /* v0.1 temperature */
+#endif
+ (1 << 3) | /* battery voltage */
+ (1 << 4) | /* drogue sense */
+ (1 << 5)); /* main sense */
+#endif
+
+#if IGNITE_ON_P0
+ /* TeleMini configuration */
+ ADCCFG = ((1 << 0) | /* pressure */
+ (1 << 1) | /* drogue sense */
+ (1 << 2) | /* main sense */
+ (1 << 3)); /* battery voltage */
+#endif
+
+ /* enable interrupts */
+ ADCIF = 0;
+ IEN0 |= IEN0_ADCIE;
+ ao_cmd_register(&ao_adc_cmds[0]);
+}
diff --git a/src/cc1111/ao_arch.h b/src/cc1111/ao_arch.h
new file mode 100644
index 00000000..8a41791f
--- /dev/null
+++ b/src/cc1111/ao_arch.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+/*
+ * CC1111 definitions and code fragments for AltOS
+ */
+
+#ifndef _AO_ARCH_H_
+#define _AO_ARCH_H_
+
+#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
+
+#define ao_arch_task_members\
+ uint8_t stack_count; /* amount of saved stack */
+
+/* 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_regs() \
+ _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
+
+#define ao_arch_save_stack() { \
+ 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); \
+ }
+
+#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 }
+
+struct ao_adc {
+ uint16_t tick; /* tick when the sample was read */
+ int16_t accel; /* accelerometer */
+ int16_t pres; /* pressure sensor */
+ int16_t temp; /* temperature sensor */
+ int16_t v_batt; /* battery voltage */
+ int16_t sense_d; /* drogue continuity sense */
+ int16_t sense_m; /* main continuity sense */
+};
+
+#define AO_ADC_RING 32
+
+#endif /* _AO_ARCH_H_ */
diff --git a/src/cc1111/ao_beep.c b/src/cc1111/ao_beep.c
new file mode 100644
index 00000000..3642f4c6
--- /dev/null
+++ b/src/cc1111/ao_beep.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+void
+ao_beep(uint8_t beep)
+{
+ if (beep == 0) {
+ P2_0 = 0;
+ P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_GPIO;
+ T4CTL = 0;
+ } else {
+ P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_PERIPHERAL;
+ T4CC0 = beep;
+ T4CTL = TxCTL_DIV_32 | TxCTL_MODE_MODULO | TxCTL_START;
+ }
+}
+
+void
+ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant
+{
+ ao_beep(beep);
+ ao_delay(ticks);
+ ao_beep(0);
+}
+
+void
+ao_beep_init(void)
+{
+ /* Our beeper is on P2_0, which is hooked to timer 4 using
+ * configuration alternative 2
+ */
+ P2_0 = 0;
+ P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_GPIO;
+ PERCFG = (PERCFG & ~PERCFG_T4CFG_ALT_MASK) | PERCFG_T4CFG_ALT_2;
+ T4CCTL0 = TxCCTLy_CMP_TOGGLE|TxCCTLy_CMP_MODE_ENABLE;
+}
diff --git a/src/cc1111/ao_dbg.c b/src/cc1111/ao_dbg.c
new file mode 100644
index 00000000..d4c9567f
--- /dev/null
+++ b/src/cc1111/ao_dbg.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+#include "ao_pins.h"
+
+static void
+ao_dbg_send_bits(uint8_t msk, uint8_t val) __reentrant
+{
+ DBG_PORT = (DBG_PORT & ~msk) | (val & msk);
+ _asm
+ nop
+ nop
+ _endasm;
+}
+
+void
+ao_dbg_send_byte(uint8_t byte)
+{
+ __pdata uint8_t b, d;
+
+ DBG_PORT |= DBG_DATA;
+ DBG_PORT_DIR |= DBG_DATA;
+ for (b = 0; b < 8; b++) {
+ d = 0;
+ if (byte & 0x80)
+ d = DBG_DATA;
+ byte <<= 1;
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA, DBG_CLOCK|d);
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA, 0 |d);
+ }
+ DBG_PORT_DIR &= ~DBG_DATA;
+}
+
+uint8_t
+ao_dbg_recv_byte(void)
+{
+ __pdata uint8_t byte, b;
+
+ byte = 0;
+ for (b = 0; b < 8; b++) {
+ byte = byte << 1;
+ ao_dbg_send_bits(DBG_CLOCK, DBG_CLOCK);
+ if (DBG_DATA_PIN)
+ byte |= 1;
+ ao_dbg_send_bits(DBG_CLOCK, 0);
+ }
+ return byte;
+}
+
+/* 8051 instructions
+ */
+#define NOP 0x00
+#define MOV_direct_data 0x75
+#define LJMP 0x02
+#define MOV_Rn_data(n) (0x78 | (n))
+#define DJNZ_Rn_rel(n) (0xd8 | (n))
+#define MOV_A_direct 0xe5
+#define MOV_direct1_direct2 0x85
+#define MOV_direct_A 0xf5
+#define MOV_DPTR_data16 0x90
+#define MOV_A_data 0x74
+#define MOVX_atDPTR_A 0xf0
+#define MOVX_A_atDPTR 0xe0
+#define INC_DPTR 0xa3
+#define TRAP 0xa5
+#define SJMP 0x80
+#define JB 0x20
+
+#define DEBUG_INSTR(l) (0x54 | (l))
+
+#define SFR_PSW 0xD0
+#define SFR_DPL0 0x82
+#define SFR_DPH0 0x83
+#define SFR_DPL1 0x84
+#define SFR_DPH1 0x85
+
+__pdata uint8_t save_acc;
+__pdata uint8_t save_psw;
+__pdata uint8_t save_dpl0;
+__pdata uint8_t save_dph0;
+__pdata uint8_t save_dpl1;
+__pdata uint8_t save_dph1;
+
+static uint8_t
+ao_dbg_inst1(uint8_t a) __reentrant
+{
+ ao_dbg_send_byte(DEBUG_INSTR(1));
+ ao_dbg_send_byte(a);
+ return ao_dbg_recv_byte();
+}
+
+static uint8_t
+ao_dbg_inst2(uint8_t a, uint8_t b) __reentrant
+{
+ ao_dbg_send_byte(DEBUG_INSTR(2));
+ ao_dbg_send_byte(a);
+ ao_dbg_send_byte(b);
+ return ao_dbg_recv_byte();
+}
+
+static uint8_t
+ao_dbg_inst3(uint8_t a, uint8_t b, uint8_t c) __reentrant
+{
+ ao_dbg_send_byte(DEBUG_INSTR(3));
+ ao_dbg_send_byte(a);
+ ao_dbg_send_byte(b);
+ ao_dbg_send_byte(c);
+ return ao_dbg_recv_byte();
+}
+
+void
+ao_dbg_start_transfer(uint16_t addr)
+{
+ save_acc = ao_dbg_inst1(NOP);
+ save_psw = ao_dbg_inst2(MOV_A_direct, SFR_PSW);
+ save_dpl0 = ao_dbg_inst2(MOV_A_direct, SFR_DPL0);
+ save_dph0 = ao_dbg_inst2(MOV_A_direct, SFR_DPH0);
+ save_dpl1 = ao_dbg_inst2(MOV_A_direct, SFR_DPL1);
+ save_dph1 = ao_dbg_inst2(MOV_A_direct, SFR_DPH1);
+ ao_dbg_inst3(MOV_DPTR_data16, addr >> 8, addr);
+}
+
+void
+ao_dbg_end_transfer(void)
+{
+ ao_dbg_inst3(MOV_direct_data, SFR_DPL0, save_dpl0);
+ ao_dbg_inst3(MOV_direct_data, SFR_DPH0, save_dph0);
+ ao_dbg_inst3(MOV_direct_data, SFR_DPL1, save_dpl1);
+ ao_dbg_inst3(MOV_direct_data, SFR_DPH1, save_dph1);
+ ao_dbg_inst3(MOV_direct_data, SFR_PSW, save_psw);
+ ao_dbg_inst2(MOV_A_data, save_acc);
+}
+
+void
+ao_dbg_write_byte(uint8_t byte)
+{
+ ao_dbg_inst2(MOV_A_data, byte);
+ ao_dbg_inst1(MOVX_atDPTR_A);
+ ao_dbg_inst1(INC_DPTR);
+}
+
+uint8_t
+ao_dbg_read_byte(void)
+{
+ ao_dbg_inst1(MOVX_A_atDPTR);
+ return ao_dbg_inst1(INC_DPTR);
+}
+
+static void
+ao_dbg_set_pins(void)
+{
+ /* Make the DBG pins GPIOs. On TeleMetrum, this will
+ * disable the SPI link, so don't expect SPI to work after
+ * using the debugger.
+ */
+ DBG_PORT_SEL &= ~(DBG_CLOCK|DBG_DATA|DBG_RESET_N);
+
+ /* make DBG_DATA tri-state */
+ DBG_PORT_INP |= DBG_DATA;
+
+ /* Raise RESET_N and CLOCK */
+ DBG_PORT |= DBG_RESET_N | DBG_CLOCK;
+
+ /* RESET_N and CLOCK are outputs now */
+ DBG_PORT_DIR |= DBG_RESET_N | DBG_CLOCK;
+ DBG_PORT_DIR &= ~DBG_DATA;
+}
+
+static void
+ao_dbg_long_delay(void)
+{
+ uint8_t n;
+
+ for (n = 0; n < 20; n++)
+ _asm nop _endasm;
+}
+
+#define AO_RESET_LOW_DELAY AO_MS_TO_TICKS(100)
+#define AO_RESET_HIGH_DELAY AO_MS_TO_TICKS(100)
+
+void
+ao_dbg_debug_mode(void)
+{
+ ao_dbg_set_pins();
+ ao_dbg_long_delay();
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
+ ao_dbg_long_delay();
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA| 0 );
+ ao_delay(AO_RESET_LOW_DELAY);
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 );
+ ao_dbg_long_delay();
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA| 0 );
+ ao_dbg_long_delay();
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 );
+ ao_dbg_long_delay();
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA|DBG_RESET_N);
+ ao_delay(AO_RESET_HIGH_DELAY);
+}
+
+void
+ao_dbg_reset(void)
+{
+ ao_dbg_set_pins();
+ ao_dbg_long_delay();
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
+ ao_dbg_long_delay();
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 );
+ ao_delay(AO_RESET_LOW_DELAY);
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 );
+ ao_dbg_long_delay();
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 );
+ ao_dbg_long_delay();
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 );
+ ao_dbg_long_delay();
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
+ ao_delay(AO_RESET_HIGH_DELAY);
+}
+
+static void
+debug_enable(void)
+{
+ ao_dbg_debug_mode();
+}
+
+static void
+debug_reset(void)
+{
+ ao_dbg_reset();
+}
+
+static void
+debug_put(void)
+{
+ for (;;) {
+ ao_cmd_white ();
+ if (ao_cmd_lex_c == '\n')
+ break;
+ ao_cmd_hex();
+ if (ao_cmd_status != ao_cmd_success)
+ break;
+ ao_dbg_send_byte(ao_cmd_lex_i);
+ }
+}
+
+static void
+debug_get(void)
+{
+ __pdata uint16_t count;
+ __pdata uint16_t i;
+ __pdata uint8_t byte;
+ ao_cmd_hex();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ count = ao_cmd_lex_i;
+ if (count > 256) {
+ ao_cmd_status = ao_cmd_syntax_error;
+ return;
+ }
+ for (i = 0; i < count; i++) {
+ if (i && (i & 7) == 0)
+ putchar('\n');
+ byte = ao_dbg_recv_byte();
+ ao_cmd_put8(byte);
+ putchar(' ');
+ }
+ putchar('\n');
+}
+
+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;
+}
+
+static void
+debug_input(void)
+{
+ __pdata uint16_t count;
+ __pdata uint16_t addr;
+ __pdata uint8_t b;
+ __pdata uint8_t i;
+
+ ao_cmd_hex();
+ count = ao_cmd_lex_i;
+ ao_cmd_hex();
+ addr = ao_cmd_lex_i;
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ ao_dbg_start_transfer(addr);
+ i = 0;
+ while (count--) {
+ if (!(i++ & 7))
+ putchar('\n');
+ b = ao_dbg_read_byte();
+ ao_cmd_put8(b);
+ }
+ ao_dbg_end_transfer();
+ putchar('\n');
+}
+
+static void
+debug_output(void)
+{
+ __pdata uint16_t count;
+ __pdata uint16_t addr;
+ __pdata uint8_t b;
+
+ ao_cmd_hex();
+ count = ao_cmd_lex_i;
+ ao_cmd_hex();
+ addr = ao_cmd_lex_i;
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ ao_dbg_start_transfer(addr);
+ while (count--) {
+ b = getnibble() << 4;
+ b |= getnibble();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ ao_dbg_write_byte(b);
+ }
+ ao_dbg_end_transfer();
+}
+
+__code struct ao_cmds ao_dbg_cmds[7] = {
+ { debug_enable, "D\0Enable debug" },
+ { debug_get, "G <count>\0Get data" },
+ { debug_input, "I <count> <addr>\0Input <count> at <addr>" },
+ { debug_output, "O <count> <addr>\0Output <count> at <addr>" },
+ { debug_put, "P <byte> ...\0Put data" },
+ { debug_reset, "R\0Reset" },
+ { 0, NULL },
+};
+
+void
+ao_dbg_init(void)
+{
+ ao_cmd_register(&ao_dbg_cmds[0]);
+}
diff --git a/src/cc1111/ao_dma.c b/src/cc1111/ao_dma.c
new file mode 100644
index 00000000..6052964a
--- /dev/null
+++ b/src/cc1111/ao_dma.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+#define NUM_DMA 5
+
+/*
+ * The config address for DMA0 is programmed
+ * separately from that of DMA1-4, but for simplicity,
+ * we make them all contiguous.
+ */
+
+static __xdata struct cc_dma_channel ao_dma_config[NUM_DMA];
+static __xdata uint8_t * __xdata ao_dma_done[NUM_DMA];
+static __data uint8_t ao_next_dma;
+
+uint8_t
+ao_dma_alloc(__xdata uint8_t *done)
+{
+ uint8_t id;
+
+ if (ao_next_dma == NUM_DMA)
+ ao_panic(AO_PANIC_DMA);
+ id = ao_next_dma++;
+ ao_dma_done[id] = done;
+
+ /* When the first dma object is allocated, set up the DMA
+ * controller
+ */
+ if (id == 0) {
+ DMAIRQ = 0;
+ DMAIF = 0;
+ IEN1 |= IEN1_DMAIE;
+ }
+
+ return id;
+}
+
+void
+ao_dma_set_transfer(uint8_t id,
+ void __xdata *srcaddr,
+ void __xdata *dstaddr,
+ uint16_t count,
+ uint8_t cfg0,
+ uint8_t cfg1)
+{
+ if (DMAARM & (1 << id))
+ ao_panic(AO_PANIC_DMA);
+ ao_dma_config[id].src_high = ((uint16_t) srcaddr) >> 8;
+ ao_dma_config[id].src_low = ((uint16_t) srcaddr);
+ ao_dma_config[id].dst_high = ((uint16_t) dstaddr) >> 8;
+ ao_dma_config[id].dst_low = ((uint16_t) dstaddr);
+ ao_dma_config[id].len_high = count >> 8;
+ ao_dma_config[id].len_low = count;
+ ao_dma_config[id].cfg0 = cfg0;
+ ao_dma_config[id].cfg1 = cfg1 | DMA_CFG1_IRQMASK;
+ if (id == 0) {
+ DMA0CFGH = ((uint16_t) (&ao_dma_config[0])) >> 8;
+ DMA0CFGL = ((uint16_t) (&ao_dma_config[0]));
+ } else {
+ DMA1CFGH = ((uint16_t) (&ao_dma_config[1])) >> 8;
+ DMA1CFGL = ((uint16_t) (&ao_dma_config[1]));
+ }
+}
+
+#define nop() _asm nop _endasm;
+
+void
+ao_dma_start(uint8_t id)
+{
+ uint8_t mask = (1 << id);
+ DMAIRQ &= ~mask;
+ DMAARM = 0x80 | mask;
+ nop(); nop(); nop(); nop();
+ nop(); nop(); nop(); nop();
+ *(ao_dma_done[id]) = 0;
+ DMAARM = mask;
+ nop(); nop(); nop(); nop();
+ nop(); nop(); nop(); nop();
+ nop();
+}
+
+void
+ao_dma_trigger(uint8_t id)
+{
+ DMAREQ |= (1 << id);
+}
+
+void
+ao_dma_abort(uint8_t id)
+{
+ uint8_t mask = (1 << id);
+ DMAARM = 0x80 | mask;
+ DMAIRQ &= ~mask;
+}
+
+void
+ao_dma_isr(void) __interrupt 8
+{
+ uint8_t id, mask;
+
+ /* Find the first DMA channel which is done */
+ mask = 1;
+ for (id = 0; id < ao_next_dma; id++) {
+ if (DMAIRQ & mask) {
+ /* Clear CPU interrupt flag */
+ DMAIF = 0;
+ /* Clear the completed ID */
+ DMAIRQ = ~mask;
+ *(ao_dma_done[id]) = 1;
+ ao_wakeup(ao_dma_done[id]);
+ break;
+ }
+ mask <<= 1;
+ }
+}
diff --git a/src/cc1111/ao_ignite.c b/src/cc1111/ao_ignite.c
new file mode 100644
index 00000000..289263ab
--- /dev/null
+++ b/src/cc1111/ao_ignite.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+__xdata struct ao_ignition ao_ignition[2];
+
+void
+ao_ignite(enum ao_igniter igniter) __critical
+{
+ ao_ignition[igniter].request = 1;
+ ao_wakeup(&ao_ignition);
+}
+
+enum ao_igniter_status
+ao_igniter_status(enum ao_igniter igniter)
+{
+ __xdata struct ao_adc adc;
+ __pdata int16_t value;
+ __pdata uint8_t request, firing, fired;
+
+ __critical {
+ ao_adc_get(&adc);
+ request = ao_ignition[igniter].request;
+ fired = ao_ignition[igniter].fired;
+ firing = ao_ignition[igniter].firing;
+ }
+ if (firing || (request && !fired))
+ return ao_igniter_active;
+
+ value = (AO_IGNITER_CLOSED>>1);
+ switch (igniter) {
+ case ao_igniter_drogue:
+ value = adc.sense_d;
+ break;
+ case ao_igniter_main:
+ value = adc.sense_m;
+ break;
+ }
+ if (value < AO_IGNITER_OPEN)
+ return ao_igniter_open;
+ else if (value > AO_IGNITER_CLOSED)
+ return ao_igniter_ready;
+ else
+ return ao_igniter_unknown;
+}
+
+void
+ao_igniter_fire(enum ao_igniter igniter) __critical
+{
+ ao_ignition[igniter].firing = 1;
+ switch(ao_config.ignite_mode) {
+ case AO_IGNITE_MODE_DUAL:
+ switch (igniter) {
+ case ao_igniter_drogue:
+ AO_IGNITER_DROGUE = 1;
+ ao_delay(AO_IGNITER_FIRE_TIME);
+ AO_IGNITER_DROGUE = 0;
+ break;
+ case ao_igniter_main:
+ AO_IGNITER_MAIN = 1;
+ ao_delay(AO_IGNITER_FIRE_TIME);
+ AO_IGNITER_MAIN = 0;
+ break;
+ }
+ break;
+ case AO_IGNITE_MODE_APOGEE:
+ switch (igniter) {
+ case ao_igniter_drogue:
+ AO_IGNITER_DROGUE = 1;
+ ao_delay(AO_IGNITER_FIRE_TIME);
+ AO_IGNITER_DROGUE = 0;
+ ao_delay(AO_IGNITER_CHARGE_TIME);
+ AO_IGNITER_MAIN = 1;
+ ao_delay(AO_IGNITER_FIRE_TIME);
+ AO_IGNITER_MAIN = 0;
+ break;
+ }
+ break;
+ case AO_IGNITE_MODE_MAIN:
+ switch (igniter) {
+ case ao_igniter_main:
+ AO_IGNITER_DROGUE = 1;
+ ao_delay(AO_IGNITER_FIRE_TIME);
+ AO_IGNITER_DROGUE = 0;
+ ao_delay(AO_IGNITER_CHARGE_TIME);
+ AO_IGNITER_MAIN = 1;
+ ao_delay(AO_IGNITER_FIRE_TIME);
+ AO_IGNITER_MAIN = 0;
+ break;
+ }
+ break;
+ }
+ ao_ignition[igniter].firing = 0;
+}
+
+void
+ao_igniter(void)
+{
+ __xdata enum ao_ignter igniter;
+
+ ao_config_get();
+ for (;;) {
+ ao_sleep(&ao_ignition);
+ for (igniter = ao_igniter_drogue; igniter <= ao_igniter_main; igniter++) {
+ if (ao_ignition[igniter].request && !ao_ignition[igniter].fired) {
+ if (igniter == ao_igniter_drogue && ao_config.apogee_delay)
+ ao_delay(AO_SEC_TO_TICKS(ao_config.apogee_delay));
+
+ ao_igniter_fire(igniter);
+ ao_delay(AO_IGNITER_CHARGE_TIME);
+ ao_ignition[igniter].fired = 1;
+ }
+ }
+ }
+}
+
+void
+ao_ignite_manual(void)
+{
+ ao_cmd_white();
+ if (!ao_match_word("DoIt"))
+ return;
+ ao_cmd_white();
+ if (ao_cmd_lex_c == 'm') {
+ if(ao_match_word("main"))
+ ao_igniter_fire(ao_igniter_main);
+ } else {
+ if(ao_match_word("drogue"))
+ ao_igniter_fire(ao_igniter_drogue);
+ }
+}
+
+static __code char * __code igniter_status_names[] = {
+ "unknown", "ready", "active", "open"
+};
+
+void
+ao_ignite_print_status(enum ao_igniter igniter, __code char *name) __reentrant
+{
+ enum ao_igniter_status status = ao_igniter_status(igniter);
+ printf("Igniter: %6s Status: %s\n",
+ name,
+ igniter_status_names[status]);
+}
+
+void
+ao_ignite_test(void)
+{
+ ao_ignite_print_status(ao_igniter_drogue, "drogue");
+ ao_ignite_print_status(ao_igniter_main, "main");
+}
+
+__code struct ao_cmds ao_ignite_cmds[] = {
+ { ao_ignite_manual, "i <key> {main|drogue}\0Fire igniter. <key> is doit with D&I" },
+ { ao_ignite_test, "t\0Test igniter" },
+ { 0, NULL },
+};
+
+__xdata struct ao_task ao_igniter_task;
+
+void
+ao_ignite_set_pins(void)
+{
+ AO_IGNITER_DROGUE = 0;
+ AO_IGNITER_MAIN = 0;
+ AO_IGNITER_DIR |= AO_IGNITER_DROGUE_BIT | AO_IGNITER_MAIN_BIT;
+}
+
+void
+ao_igniter_init(void)
+{
+ ao_ignite_set_pins();
+ ao_cmd_register(&ao_ignite_cmds[0]);
+ ao_add_task(&ao_igniter_task, ao_igniter, "igniter");
+}
diff --git a/src/cc1111/ao_intflash.c b/src/cc1111/ao_intflash.c
new file mode 100644
index 00000000..d76d954e
--- /dev/null
+++ b/src/cc1111/ao_intflash.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright © 2011 Anthony Towns <aj@erisian.com.au>
+ *
+ * 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 "cc1111.h"
+
+#define ENDOFCODE (CODESIZE)
+#define AO_INTFLASH_BLOCK 1024
+#define AO_INTFLASH_BLOCKS ((0x8000 - ENDOFCODE)/AO_INTFLASH_BLOCK)
+#define AO_INTFLASH_SIZE (AO_INTFLASH_BLOCK * AO_INTFLASH_BLOCKS)
+#define AO_INTFLASH_LOCATION (0x8000 - AO_INTFLASH_SIZE)
+
+/*
+ * 21000 * 24e6
+ * FWT = ------------
+ * 16e9
+ *
+ * = 31.5
+ *
+ * Round up and use 32
+ */
+
+#define FLASH_TIMING 0x20
+
+#if AO_INTFLASH_BLOCKS < 2
+#error "Too few pages"
+#endif
+
+#if AO_INFTLASH_LOCATION % 1024 != 0
+#error "Pages aren't aligned properly"
+#endif
+
+__xdata __at(AO_INTFLASH_LOCATION) uint8_t ao_intflash[AO_INTFLASH_SIZE];
+
+/* Total bytes of available storage */
+__pdata uint32_t ao_storage_total = sizeof(ao_intflash);
+
+/* Block size - device is erased in these units. */
+__pdata uint32_t ao_storage_block = AO_INTFLASH_BLOCK;
+
+/* Byte offset of config block. Will be ao_storage_block bytes long */
+__pdata uint32_t ao_storage_config = sizeof(ao_intflash) - AO_INTFLASH_BLOCK;
+
+/* Storage unit size - device reads and writes must be within blocks of this size. */
+__pdata uint16_t ao_storage_unit = AO_INTFLASH_BLOCK;
+
+__xdata static uint8_t ao_intflash_dma_done;
+static uint8_t ao_intflash_dma;
+
+/*
+ * The internal flash chip is arranged in 1kB sectors; the
+ * chip cannot erase in units smaller than that.
+ *
+ * Writing happens in units of 2 bytes and
+ * can only change bits from 1 to 0. So, you can rewrite
+ * the same contents, or append to an existing page easily enough
+ */
+
+/*
+ * Erase the specified sector
+ */
+uint8_t
+ao_storage_erase(uint32_t pos) __reentrant
+{
+ uint16_t addr;
+
+ if (pos >= ao_storage_total || pos + ao_storage_block > ao_storage_total)
+ return 0;
+
+ addr = ((uint16_t)(ao_intflash + pos) >> 1);
+
+ FADDRH = addr >> 8;
+ FADDRL = addr;
+
+ __critical {
+ _asm
+ .even
+ orl _FCTL, #FCTL_ERASE; ; FCTL |= FCTL_ERASE
+ nop ; Required, see datasheet.
+ _endasm;
+ }
+
+ return 1;
+}
+
+/*
+ * Write to flash
+ */
+
+static void
+ao_intflash_write_aligned(uint16_t pos, __xdata void *d, uint16_t len) __reentrant
+{
+ pos = ((uint16_t) ao_intflash + pos) >> 1;
+
+ ao_dma_set_transfer(ao_intflash_dma,
+ d,
+ &FWDATAXADDR,
+ len,
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_FLASH,
+ DMA_CFG1_SRCINC_1 |
+ DMA_CFG1_DESTINC_0 |
+ DMA_CFG1_PRIORITY_HIGH);
+
+ FADDRH = pos >> 8;
+ FADDRL = pos;
+
+ ao_dma_start(ao_intflash_dma);
+
+ __critical {
+ _asm
+ .even
+ orl _FCTL, #FCTL_WRITE; ; FCTL |= FCTL_WRITE
+ nop
+ _endasm;
+ }
+}
+
+static void
+ao_intflash_write_byte(uint16_t pos, uint8_t byte) __reentrant
+{
+ static __xdata uint8_t b[2];
+
+ if (pos & 1) {
+ b[0] = 0xff;
+ b[1] = byte;
+ } else {
+ b[0] = byte;
+ b[1] = 0xff;
+ }
+ ao_intflash_write_aligned(pos, b, 2);
+}
+
+uint8_t
+ao_storage_device_write(uint32_t pos32, __xdata void *v, uint16_t len) __reentrant
+{
+ uint16_t pos = pos32;
+ __xdata uint8_t *d = v;
+ uint8_t oddlen;
+
+ if (pos >= ao_storage_total || pos + len > ao_storage_total)
+ return 0;
+ if (len == 0)
+ return 1;
+
+ if (pos & 1) {
+ ao_intflash_write_byte(pos++, *d++);
+ len--;
+ }
+ oddlen = len & 1;
+ len -= oddlen;
+ if (len)
+ ao_intflash_write_aligned(pos, d, len);
+ if (oddlen)
+ ao_intflash_write_byte(pos + len, d[len]);
+
+ return 1;
+}
+
+/*
+ * Read from flash
+ */
+uint8_t
+ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
+{
+ if (pos >= ao_storage_total || pos + len > ao_storage_total)
+ return 0;
+ memcpy(d, ao_intflash+pos, len);
+ return 1;
+}
+
+void
+ao_storage_flush(void) __reentrant
+{
+}
+
+void
+ao_storage_setup(void)
+{
+}
+
+void
+ao_storage_device_info(void) __reentrant
+{
+ printf ("Using internal flash, starting at 0x%04x\n", AO_INTFLASH_LOCATION);
+}
+
+void
+ao_storage_device_init(void)
+{
+ ao_intflash_dma = ao_dma_alloc(&ao_intflash_dma_done);
+
+ FWT = FLASH_TIMING;
+}
diff --git a/src/cc1111/ao_launch.c b/src/cc1111/ao_launch.c
new file mode 100644
index 00000000..a593d0b2
--- /dev/null
+++ b/src/cc1111/ao_launch.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+__xdata uint16_t ao_launch_ignite;
+
+#if 0
+#define PRINTD(...) printf(__VA_ARGS__)
+#else
+#define PRINTD(...)
+#endif
+
+static void
+ao_launch_run(void)
+{
+ for (;;) {
+ while (!ao_launch_ignite)
+ ao_sleep(&ao_launch_ignite);
+ ao_ignition[ao_igniter_drogue].firing = 1;
+ ao_ignition[ao_igniter_main].firing = 1;
+ AO_IGNITER_DIR |= AO_IGNITER_DROGUE_BIT | AO_IGNITER_MAIN_BIT;
+ AO_IGNITER_DROGUE = 1;
+ while (ao_launch_ignite) {
+ ao_launch_ignite = 0;
+ 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)
+{
+ 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 (;;) {
+ flush();
+ if (ao_radio_cmac_recv(&command, sizeof (command), 0) != AO_RADIO_CMAC_OK)
+ continue;
+
+ PRINTD ("tick %d serial %d cmd %d channel %d\n",
+ command.tick, command.serial, command.cmd, command.channel);
+
+ switch (command.cmd) {
+ case AO_LAUNCH_QUERY:
+ if (command.serial != ao_serial_number) {
+ PRINTD ("serial number mismatch\n");
+ break;
+ }
+
+ 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;
+ PRINTD ("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_LAUNCH_ARM:
+ if (command.serial != ao_serial_number) {
+ PRINTD ("serial number mismatch\n");
+ break;
+ }
+
+ if (command.channel != 0)
+ break;
+ time_difference = command.tick - ao_time();
+ PRINTD ("arm tick %d local tick %d\n", command.tick, ao_time());
+ if (time_difference < 0)
+ time_difference = -time_difference;
+ if (time_difference > 10) {
+ PRINTD ("time difference too large %d\n", time_difference);
+ break;
+ }
+ PRINTD ("armed\n");
+ ao_launch_armed = 1;
+ ao_launch_arm_time = ao_time();
+ break;
+ case AO_LAUNCH_FIRE:
+ if (!ao_launch_armed) {
+ PRINTD ("not armed\n");
+ break;
+ }
+ if ((uint16_t) (ao_time() - ao_launch_arm_time) > AO_SEC_TO_TICKS(20)) {
+ PRINTD ("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) {
+ PRINTD ("time different too large %d\n", time_difference);
+ break;
+ }
+ PRINTD ("ignite\n");
+ ao_launch_ignite = 1;
+ ao_wakeup(&ao_launch_ignite);
+ break;
+ }
+ }
+}
+
+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 <key>\0Fire igniter. <key> is doit with D&I" },
+ { 0, NULL }
+};
+
+void
+ao_launch_init(void)
+{
+ 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/cc1111/ao_led.c b/src/cc1111/ao_led.c
new file mode 100644
index 00000000..5beed58d
--- /dev/null
+++ b/src/cc1111/ao_led.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+__pdata uint8_t ao_led_enable;
+
+void
+ao_led_on(uint8_t colors)
+{
+ P1 |= (colors & ao_led_enable);
+}
+
+void
+ao_led_off(uint8_t colors)
+{
+ P1 &= ~(colors & ao_led_enable);
+}
+
+void
+ao_led_set(uint8_t colors)
+{
+ P1 = (P1 & ~(ao_led_enable)) | (colors & ao_led_enable);
+}
+
+void
+ao_led_toggle(uint8_t colors)
+{
+ P1 ^= (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;
+ P1SEL &= ~enable;
+ P1 &= ~enable;
+ P1DIR |= enable;
+}
diff --git a/src/cc1111/ao_packet.c b/src/cc1111/ao_packet.c
new file mode 100644
index 00000000..f627e02b
--- /dev/null
+++ b/src/cc1111/ao_packet.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+__xdata struct ao_packet_recv ao_rx_packet;
+__xdata struct ao_packet ao_tx_packet;
+__pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used;
+
+static __xdata char tx_data[AO_PACKET_MAX];
+static __xdata char rx_data[AO_PACKET_MAX];
+static __pdata uint8_t rx_seq;
+
+__xdata struct ao_task ao_packet_task;
+__xdata uint8_t ao_packet_enable;
+__xdata uint8_t ao_packet_master_sleeping;
+
+void
+ao_packet_send(void)
+{
+ ao_led_on(AO_LED_RED);
+ /* If any tx data is pending then copy it into the tx packet */
+ if (ao_packet_tx_used && ao_tx_packet.len == 0) {
+ memcpy(&ao_tx_packet.d, tx_data, ao_packet_tx_used);
+ ao_tx_packet.len = ao_packet_tx_used;
+ ao_tx_packet.seq++;
+ ao_packet_tx_used = 0;
+ ao_wakeup(&tx_data);
+ }
+ ao_radio_send(&ao_tx_packet, sizeof (ao_tx_packet));
+ ao_led_off(AO_LED_RED);
+}
+
+uint8_t
+ao_packet_recv(void)
+{
+ uint8_t dma_done;
+
+#ifdef AO_LED_GREEN
+ ao_led_on(AO_LED_GREEN);
+#endif
+ dma_done = ao_radio_recv(&ao_rx_packet, sizeof (struct ao_packet_recv));
+#ifdef AO_LED_GREEN
+ ao_led_off(AO_LED_GREEN);
+#endif
+
+ /* Check to see if we got a valid packet */
+ if (!dma_done)
+ return 0;
+ if (!(ao_rx_packet.status & PKT_APPEND_STATUS_1_CRC_OK))
+ return 0;
+
+ /* SYN packets carry no data */
+ if (ao_rx_packet.packet.len == AO_PACKET_SYN) {
+ rx_seq = ao_rx_packet.packet.seq;
+ ao_tx_packet.seq = ao_rx_packet.packet.ack;
+ ao_tx_packet.ack = rx_seq;
+ } else if (ao_rx_packet.packet.len) {
+
+ /* Check for incoming data at the next sequence and
+ * for an empty data buffer
+ */
+ if (ao_rx_packet.packet.seq == (uint8_t) (rx_seq + (uint8_t) 1) &&
+ ao_packet_rx_used == ao_packet_rx_len) {
+
+ /* Copy data to the receive data buffer and set up the
+ * offsets
+ */
+ memcpy(rx_data, ao_rx_packet.packet.d, ao_rx_packet.packet.len);
+ ao_packet_rx_used = 0;
+ ao_packet_rx_len = ao_rx_packet.packet.len;
+
+ /* Mark the sequence that we've received to
+ * let the sender know when we return a packet
+ */
+ rx_seq = ao_rx_packet.packet.seq;
+ ao_tx_packet.ack = rx_seq;
+
+ /* Poke anyone looking for received data */
+ ao_wakeup(&ao_stdin_ready);
+ }
+ }
+
+ /* If the other side has seen the latest data we queued,
+ * wake up any task waiting to send data and let them go again
+ */
+ if (ao_rx_packet.packet.ack == ao_tx_packet.seq) {
+ ao_tx_packet.len = 0;
+ ao_wakeup(&ao_tx_packet);
+ }
+ return 1;
+}
+
+#ifndef PACKET_HAS_MASTER
+#define PACKET_HAS_MASTER 1
+#endif
+
+#if PACKET_HAS_MASTER
+void
+ao_packet_flush(void)
+{
+ /* If there is data to send, and this is the master,
+ * then poke the master to send all queued data
+ */
+ if (ao_packet_tx_used && ao_packet_master_sleeping)
+ ao_wakeup(&ao_packet_master_sleeping);
+}
+#endif /* PACKET_HAS_MASTER */
+
+void
+ao_packet_putchar(char c) __reentrant
+{
+ while (ao_packet_tx_used == AO_PACKET_MAX && ao_packet_enable) {
+#if PACKET_HAS_MASTER
+ ao_packet_flush();
+#endif
+ ao_sleep(&tx_data);
+ }
+
+ if (ao_packet_enable)
+ tx_data[ao_packet_tx_used++] = c;
+}
+
+char
+ao_packet_pollchar(void) __critical
+{
+ if (!ao_packet_enable)
+ return AO_READ_AGAIN;
+
+ if (ao_packet_rx_used == ao_packet_rx_len)
+ return AO_READ_AGAIN;
+
+ return rx_data[ao_packet_rx_used++];
+}
diff --git a/src/cc1111/ao_packet_master.c b/src/cc1111/ao_packet_master.c
new file mode 100644
index 00000000..0d0be30e
--- /dev/null
+++ b/src/cc1111/ao_packet_master.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+static char
+ao_packet_getchar(void) __critical
+{
+ char c;
+ while ((c = ao_packet_pollchar()) == AO_READ_AGAIN) {
+ if (!ao_packet_enable)
+ break;
+ if (ao_packet_master_sleeping)
+ ao_wakeup(&ao_packet_master_sleeping);
+ flush();
+ ao_sleep(&ao_stdin_ready);
+ }
+ return c;
+}
+
+static void
+ao_packet_echo(void) __reentrant
+{
+ char c;
+ while (ao_packet_enable) {
+ c = ao_packet_getchar();
+ if (c != AO_READ_AGAIN)
+ putchar(c);
+ }
+ ao_exit();
+}
+
+static __xdata struct ao_task ao_packet_echo_task;
+static __xdata uint16_t ao_packet_master_delay;
+static __xdata uint16_t ao_packet_master_time;
+
+#define AO_PACKET_MASTER_DELAY_SHORT AO_MS_TO_TICKS(100)
+#define AO_PACKET_MASTER_DELAY_LONG AO_MS_TO_TICKS(1000)
+#define AO_PACKET_MASTER_DELAY_TIMEOUT AO_MS_TO_TICKS(2000)
+
+static void
+ao_packet_master_busy(void)
+{
+ ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT;
+ ao_packet_master_time = ao_time();
+}
+
+static void
+ao_packet_master_check_busy(void)
+{
+ int16_t idle;
+ if (ao_packet_master_delay != AO_PACKET_MASTER_DELAY_SHORT)
+ return;
+ idle = (int16_t) (ao_time() - ao_packet_master_time);
+
+ if (idle > AO_PACKET_MASTER_DELAY_TIMEOUT)
+ ao_packet_master_delay = AO_PACKET_MASTER_DELAY_LONG;
+}
+
+void
+ao_packet_master(void)
+{
+ ao_config_get();
+ ao_tx_packet.addr = ao_serial_number;
+ ao_tx_packet.len = AO_PACKET_SYN;
+ 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);
+ 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;
+ if (ao_rx_packet.packet.len)
+ ao_packet_master_busy();
+ 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;
+ }
+ }
+ ao_exit();
+}
+
+static void
+ao_packet_forward(void) __reentrant
+{
+ char c;
+ ao_packet_enable = 1;
+ ao_cmd_white();
+
+ flush();
+#if HAS_MONITOR
+ ao_set_monitor(0);
+#endif
+ ao_add_task(&ao_packet_task, ao_packet_master, "master");
+ ao_add_task(&ao_packet_echo_task, ao_packet_echo, "echo");
+ while ((c = getchar()) != '~') {
+ if (c == '\r') c = '\n';
+ ao_packet_putchar(c);
+ }
+
+ /* Wait for a second if there is any pending data */
+ for (c = 0; (ao_packet_tx_used || ao_tx_packet.len) && c < 10; c++)
+ ao_delay(AO_MS_TO_TICKS(100));
+ ao_packet_enable = 0;
+ while (ao_packet_echo_task.wchan || ao_packet_task.wchan) {
+ ao_radio_recv_abort();
+ ao_wakeup(&ao_stdin_ready);
+ ao_delay(AO_MS_TO_TICKS(10));
+ }
+}
+
+
+
+__code struct ao_cmds ao_packet_master_cmds[] = {
+ { ao_packet_forward, "p\0Remote packet link." },
+ { 0, NULL },
+};
+
+void
+ao_packet_master_init(void)
+{
+ ao_cmd_register(&ao_packet_master_cmds[0]);
+}
diff --git a/src/cc1111/ao_packet_slave.c b/src/cc1111/ao_packet_slave.c
new file mode 100644
index 00000000..d7cafa68
--- /dev/null
+++ b/src/cc1111/ao_packet_slave.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+void
+ao_packet_slave(void)
+{
+ ao_tx_packet.addr = ao_serial_number;
+ ao_tx_packet.len = AO_PACKET_SYN;
+ while (ao_packet_enable) {
+ if (ao_packet_recv()) {
+ memcpy(&ao_tx_packet.callsign, &ao_rx_packet.packet.callsign, AO_MAX_CALLSIGN);
+#if HAS_FLIGHT
+ ao_flight_force_idle = TRUE;
+#endif
+ ao_packet_send();
+ }
+ }
+ ao_exit();
+}
+
+void
+ao_packet_slave_start(void)
+{
+ if (!ao_packet_enable) {
+ ao_packet_enable = 1;
+ ao_add_task(&ao_packet_task, ao_packet_slave, "slave");
+ }
+}
+
+void
+ao_packet_slave_stop(void)
+{
+ if (ao_packet_enable) {
+ ao_packet_enable = 0;
+ while (ao_packet_task.wchan) {
+ ao_radio_recv_abort();
+ ao_delay(AO_MS_TO_TICKS(10));
+ }
+ }
+}
+
+void
+ao_packet_slave_init(uint8_t enable)
+{
+ ao_add_stdio(ao_packet_pollchar,
+ ao_packet_putchar,
+ NULL);
+ if (enable)
+ ao_packet_slave_start();
+}
diff --git a/src/cc1111/ao_pins.h b/src/cc1111/ao_pins.h
new file mode 100644
index 00000000..723f1500
--- /dev/null
+++ b/src/cc1111/ao_pins.h
@@ -0,0 +1,514 @@
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#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 HAS_LOG 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 HAS_LOG 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 HAS_LOG 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
+ #define HAS_RSSI 1
+ #define HAS_AES 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 HAS_LOG 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 HAS_LOG 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 HAS_LOG 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 HAS_LOG 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
+ #define HAS_RSSI 1
+ #define HAS_AES 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 HAS_LOG 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
+ #define HAS_RSSI 1
+ #define HAS_AES 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_LOG 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 HAS_IGNITE_REPORT 1
+ #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
+ #define HAS_RSSI 0
+ #define HAS_AES 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 HAS_LOG 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 HAS_IGNITE_REPORT 1
+ #define BT_LINK_ON_P2 0
+ #define BT_LINK_ON_P1 1
+ #define BT_LINK_PIN_INDEX 7
+ #define BT_LINK_PIN P1_7
+ #define HAS_MONITOR 1
+ #define HAS_RSSI 0
+ #define HAS_AES 1
+#endif
+
+#if defined(TELELAUNCH_V_0_1)
+ #define HAS_FLIGHT 0
+ #define HAS_USB 1
+ #define HAS_BEEP 1
+ #define HAS_GPS 0
+ #define HAS_SERIAL_1 1
+ #define USE_SERIAL_STDIN 0
+ #define HAS_ADC 1
+ #define HAS_DBG 0
+ #define HAS_EEPROM 1
+ #define HAS_LOG 0
+ #define USE_INTERNAL_FLASH 1
+ #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 0
+ #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 0
+ #define HAS_IGNITE 1
+ #define HAS_MONITOR 0
+ #define HAS_AES 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
+
+#ifndef HAS_LOG
+#error Please define HAS_LOG
+#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
+
+#if HAS_IGNITE
+#define HAS_IGNITE_REPORT 1
+#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
+
+#if HAS_MONITOR
+#ifndef HAS_RSSI
+#error Please define HAS_RSSI
+#endif
+#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 */
+
+#if IGNITE_ON_P2
+#define AO_IGNITER_DROGUE P2_3
+#define AO_IGNITER_MAIN P2_4
+#define AO_IGNITER_DIR P2DIR
+#define AO_IGNITER_DROGUE_BIT (1 << 3)
+#define AO_IGNITER_MAIN_BIT (1 << 4)
+#endif
+
+#if IGNITE_ON_P0
+#define AO_IGNITER_DROGUE P0_5
+#define AO_IGNITER_MAIN P0_4
+#define AO_IGNITER_DIR P0DIR
+#define AO_IGNITER_DROGUE_BIT (1 << 5)
+#define AO_IGNITER_MAIN_BIT (1 << 4)
+#endif
+
+/* test these values with real igniters */
+#define AO_IGNITER_OPEN 1000
+#define AO_IGNITER_CLOSED 7000
+#define AO_IGNITER_FIRE_TIME AO_MS_TO_TICKS(50)
+#define AO_IGNITER_CHARGE_TIME AO_MS_TO_TICKS(2000)
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/cc1111/ao_radio.c b/src/cc1111/ao_radio.c
new file mode 100644
index 00000000..75f241d4
--- /dev/null
+++ b/src/cc1111/ao_radio.c
@@ -0,0 +1,463 @@
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+/* Values from SmartRF® Studio for:
+ *
+ * Deviation: 20.507812 kHz
+ * Datarate: 38.360596 kBaud
+ * Modulation: GFSK
+ * RF Freq: 434.549927 MHz
+ * Channel: 99.975586 kHz
+ * Channel: 0
+ * RX filter: 93.75 kHz
+ */
+
+/*
+ * For IF freq of 140.62kHz, the IF value is:
+ *
+ * 140.62e3 / (24e6 / 2**10) = 6
+ */
+
+#define IF_FREQ_CONTROL 6
+
+/*
+ * For channel bandwidth of 93.75 kHz, the CHANBW_E and CHANBW_M values are
+ *
+ * BW = 24e6 / (8 * (4 + M) * 2 ** E)
+ *
+ * So, M = 0 and E = 3
+ */
+
+#define CHANBW_M 0
+#define CHANBW_E 3
+
+/*
+ * For a symbol rate of 38360kBaud, the DRATE_E and DRATE_M values are:
+ *
+ * R = (256 + M) * 2** E * 24e6 / 2**28
+ *
+ * So M is 163 and E is 10
+ */
+
+#define DRATE_E 10
+#define DRATE_M 163
+
+/*
+ * For a channel deviation of 20.5kHz, the DEVIATION_E and DEVIATION_M values are:
+ *
+ * F = 24e6/2**17 * (8 + DEVIATION_M) * 2**DEVIATION_E
+ *
+ * So M is 6 and E is 3
+ */
+
+#define DEVIATION_M 6
+#define DEVIATION_E 3
+
+/*
+ * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone),
+ * so the DRATE_E and DRATE_M values are:
+ *
+ * M is 94 and E is 6
+ *
+ * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes
+ */
+
+#define RDF_DRATE_E 6
+#define RDF_DRATE_M 94
+#define RDF_PACKET_LEN 50
+
+/*
+ * RDF deviation should match the normal NFM value of 5kHz
+ *
+ * M is 6 and E is 1
+ *
+ */
+
+#define RDF_DEVIATION_M 6
+#define RDF_DEVIATION_E 1
+
+/* This are from the table for 433MHz */
+
+#define RF_POWER_M30_DBM 0x12
+#define RF_POWER_M20_DBM 0x0e
+#define RF_POWER_M15_DBM 0x1d
+#define RF_POWER_M10_DBM 0x34
+#define RF_POWER_M5_DBM 0x2c
+#define RF_POWER_0_DBM 0x60
+#define RF_POWER_5_DBM 0x84
+#define RF_POWER_7_DBM 0xc8
+#define RF_POWER_10_DBM 0xc0
+
+#define RF_POWER RF_POWER_10_DBM
+
+static __code uint8_t radio_setup[] = {
+ RF_PA_TABLE7_OFF, RF_POWER,
+ RF_PA_TABLE6_OFF, RF_POWER,
+ RF_PA_TABLE5_OFF, RF_POWER,
+ RF_PA_TABLE4_OFF, RF_POWER,
+ RF_PA_TABLE3_OFF, RF_POWER,
+ RF_PA_TABLE2_OFF, RF_POWER,
+ RF_PA_TABLE1_OFF, RF_POWER,
+ RF_PA_TABLE0_OFF, RF_POWER,
+
+ RF_FSCTRL1_OFF, (IF_FREQ_CONTROL << RF_FSCTRL1_FREQ_IF_SHIFT),
+ RF_FSCTRL0_OFF, (0 << RF_FSCTRL0_FREQOFF_SHIFT),
+
+ RF_MDMCFG4_OFF, ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) |
+ (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) |
+ (DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)),
+ RF_MDMCFG3_OFF, (DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT),
+ RF_MDMCFG2_OFF, (RF_MDMCFG2_DEM_DCFILT_OFF |
+ RF_MDMCFG2_MOD_FORMAT_GFSK |
+ RF_MDMCFG2_SYNC_MODE_15_16_THRES),
+ RF_MDMCFG1_OFF, (RF_MDMCFG1_FEC_EN |
+ RF_MDMCFG1_NUM_PREAMBLE_4 |
+ (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)),
+ RF_MDMCFG0_OFF, (17 << RF_MDMCFG0_CHANSPC_M_SHIFT),
+
+ RF_CHANNR_OFF, 0,
+
+ RF_DEVIATN_OFF, ((DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) |
+ (DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)),
+
+ /* SmartRF says set LODIV_BUF_CURRENT_TX to 0
+ * And, we're not using power ramping, so use PA_POWER 0
+ */
+ RF_FREND0_OFF, ((1 << RF_FREND0_LODIV_BUF_CURRENT_TX_SHIFT) |
+ (0 << RF_FREND0_PA_POWER_SHIFT)),
+
+ RF_FREND1_OFF, ((1 << RF_FREND1_LNA_CURRENT_SHIFT) |
+ (1 << RF_FREND1_LNA2MIX_CURRENT_SHIFT) |
+ (1 << RF_FREND1_LODIV_BUF_CURRENT_RX_SHIFT) |
+ (2 << RF_FREND1_MIX_CURRENT_SHIFT)),
+
+ RF_FSCAL3_OFF, 0xE9,
+ RF_FSCAL2_OFF, 0x0A,
+ RF_FSCAL1_OFF, 0x00,
+ RF_FSCAL0_OFF, 0x1F,
+
+ RF_TEST2_OFF, 0x88,
+ RF_TEST1_OFF, 0x31,
+ RF_TEST0_OFF, 0x09,
+
+ /* default sync values */
+ RF_SYNC1_OFF, 0xD3,
+ RF_SYNC0_OFF, 0x91,
+
+ /* max packet length */
+ RF_PKTCTRL1_OFF, ((1 << PKTCTRL1_PQT_SHIFT)|
+ PKTCTRL1_APPEND_STATUS|
+ PKTCTRL1_ADR_CHK_NONE),
+ RF_PKTCTRL0_OFF, (RF_PKTCTRL0_WHITE_DATA|
+ RF_PKTCTRL0_PKT_FORMAT_NORMAL|
+ RF_PKTCTRL0_CRC_EN|
+ RF_PKTCTRL0_LENGTH_CONFIG_FIXED),
+ RF_ADDR_OFF, 0x00,
+ RF_MCSM2_OFF, (RF_MCSM2_RX_TIME_END_OF_PACKET),
+ RF_MCSM1_OFF, (RF_MCSM1_CCA_MODE_RSSI_BELOW_UNLESS_RECEIVING|
+ RF_MCSM1_RXOFF_MODE_IDLE|
+ RF_MCSM1_TXOFF_MODE_IDLE),
+ RF_MCSM0_OFF, (RF_MCSM0_FS_AUTOCAL_FROM_IDLE|
+ RF_MCSM0_MAGIC_3|
+ RF_MCSM0_CLOSE_IN_RX_0DB),
+ RF_FOCCFG_OFF, (RF_FOCCFG_FOC_PRE_K_3K,
+ RF_FOCCFG_FOC_POST_K_PRE_K,
+ RF_FOCCFG_FOC_LIMIT_BW_OVER_4),
+ RF_BSCFG_OFF, (RF_BSCFG_BS_PRE_K_2K|
+ RF_BSCFG_BS_PRE_KP_3KP|
+ RF_BSCFG_BS_POST_KI_PRE_KI|
+ RF_BSCFG_BS_POST_KP_PRE_KP|
+ RF_BSCFG_BS_LIMIT_0),
+ RF_AGCCTRL2_OFF, 0x43,
+ RF_AGCCTRL1_OFF, 0x40,
+ RF_AGCCTRL0_OFF, 0x91,
+
+ RF_IOCFG2_OFF, 0x00,
+ RF_IOCFG1_OFF, 0x00,
+ RF_IOCFG0_OFF, 0x00,
+};
+
+static __code uint8_t rdf_setup[] = {
+ RF_MDMCFG4_OFF, ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) |
+ (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) |
+ (RDF_DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)),
+ RF_MDMCFG3_OFF, (RDF_DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT),
+ RF_MDMCFG2_OFF, (RF_MDMCFG2_DEM_DCFILT_OFF |
+ RF_MDMCFG2_MOD_FORMAT_GFSK |
+ RF_MDMCFG2_SYNC_MODE_15_16_THRES),
+ RF_MDMCFG1_OFF, (RF_MDMCFG1_FEC_DIS |
+ RF_MDMCFG1_NUM_PREAMBLE_2 |
+ (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)),
+
+ RF_DEVIATN_OFF, ((RDF_DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) |
+ (RDF_DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)),
+
+ /* packet length is set in-line */
+ RF_PKTCTRL1_OFF, ((1 << PKTCTRL1_PQT_SHIFT)|
+ PKTCTRL1_ADR_CHK_NONE),
+ RF_PKTCTRL0_OFF, (RF_PKTCTRL0_PKT_FORMAT_NORMAL|
+ RF_PKTCTRL0_LENGTH_CONFIG_FIXED),
+};
+
+static __code uint8_t fixed_pkt_setup[] = {
+ RF_MDMCFG4_OFF, ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) |
+ (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) |
+ (DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)),
+ RF_MDMCFG3_OFF, (DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT),
+ RF_MDMCFG2_OFF, (RF_MDMCFG2_DEM_DCFILT_OFF |
+ RF_MDMCFG2_MOD_FORMAT_GFSK |
+ RF_MDMCFG2_SYNC_MODE_15_16_THRES),
+ RF_MDMCFG1_OFF, (RF_MDMCFG1_FEC_EN |
+ RF_MDMCFG1_NUM_PREAMBLE_4 |
+ (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)),
+
+ RF_DEVIATN_OFF, ((DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) |
+ (DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)),
+
+ /* max packet length -- now set inline */
+ RF_PKTCTRL1_OFF, ((1 << PKTCTRL1_PQT_SHIFT)|
+ PKTCTRL1_APPEND_STATUS|
+ PKTCTRL1_ADR_CHK_NONE),
+ RF_PKTCTRL0_OFF, (RF_PKTCTRL0_WHITE_DATA|
+ RF_PKTCTRL0_PKT_FORMAT_NORMAL|
+ RF_PKTCTRL0_CRC_EN|
+ RF_PKTCTRL0_LENGTH_CONFIG_FIXED),
+};
+
+__xdata uint8_t ao_radio_dma;
+__xdata uint8_t ao_radio_dma_done;
+__xdata uint8_t ao_radio_done;
+__xdata uint8_t ao_radio_abort;
+__xdata uint8_t ao_radio_mutex;
+
+void
+ao_radio_general_isr(void) __interrupt 16
+{
+ S1CON &= ~0x03;
+ if (RFIF & RFIF_IM_TIMEOUT) {
+ ao_radio_recv_abort();
+ RFIF &= ~ RFIF_IM_TIMEOUT;
+ } else if (RFIF & RFIF_IM_DONE) {
+ ao_radio_done = 1;
+ ao_wakeup(&ao_radio_done);
+ RFIF &= ~RFIF_IM_DONE;
+ }
+}
+
+void
+ao_radio_set_packet(void)
+{
+ uint8_t i;
+ for (i = 0; i < sizeof (fixed_pkt_setup); i += 2)
+ RF[fixed_pkt_setup[i]] = fixed_pkt_setup[i+1];
+}
+
+void
+ao_radio_idle(void)
+{
+ if (RF_MARCSTATE != RF_MARCSTATE_IDLE)
+ {
+ do {
+ RFST = RFST_SIDLE;
+ ao_yield();
+ } while (RF_MARCSTATE != RF_MARCSTATE_IDLE);
+ }
+}
+
+void
+ao_radio_get(uint8_t len)
+{
+ ao_config_get();
+ ao_mutex_get(&ao_radio_mutex);
+ ao_radio_idle();
+ RF_CHANNR = ao_config.radio_channel;
+ RF_FREQ2 = (uint8_t) (ao_config.radio_setting >> 16);
+ RF_FREQ1 = (uint8_t) (ao_config.radio_setting >> 8);
+ RF_FREQ0 = (uint8_t) (ao_config.radio_setting);
+ RF_PKTLEN = len;
+}
+
+
+void
+ao_radio_send(__xdata void *packet, uint8_t size) __reentrant
+{
+ ao_radio_get(size);
+ ao_radio_done = 0;
+ ao_dma_set_transfer(ao_radio_dma,
+ packet,
+ &RFDXADDR,
+ size,
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_RADIO,
+ DMA_CFG1_SRCINC_1 |
+ DMA_CFG1_DESTINC_0 |
+ DMA_CFG1_PRIORITY_HIGH);
+ ao_dma_start(ao_radio_dma);
+ RFST = RFST_STX;
+ __critical while (!ao_radio_done)
+ ao_sleep(&ao_radio_done);
+ ao_radio_put();
+}
+
+uint8_t
+ao_radio_recv(__xdata void *packet, uint8_t size) __reentrant
+{
+ ao_radio_abort = 0;
+ ao_radio_get(size - 2);
+ ao_dma_set_transfer(ao_radio_dma,
+ &RFDXADDR,
+ packet,
+ size,
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_RADIO,
+ DMA_CFG1_SRCINC_0 |
+ DMA_CFG1_DESTINC_1 |
+ DMA_CFG1_PRIORITY_HIGH);
+ ao_dma_start(ao_radio_dma);
+ RFST = RFST_SRX;
+
+ /* Wait for DMA to be done, for the radio receive process to
+ * get aborted or for a receive timeout to fire
+ */
+ __critical while (!ao_radio_dma_done && !ao_radio_abort)
+ if (ao_sleep(&ao_radio_dma_done))
+ break;
+
+ /* If recv was aborted, clean up by stopping the DMA engine
+ * and idling the radio
+ */
+ if (!ao_radio_dma_done) {
+ ao_dma_abort(ao_radio_dma);
+ ao_radio_idle();
+ }
+ ao_radio_put();
+ return ao_radio_dma_done;
+}
+
+/*
+ * Wake up a task waiting to receive a radio packet
+ * and tell them to abort the transfer
+ */
+
+void
+ao_radio_recv_abort(void)
+{
+ ao_radio_abort = 1;
+ ao_wakeup(&ao_radio_dma_done);
+}
+
+__xdata ao_radio_rdf_value = 0x55;
+
+void
+ao_radio_rdf(uint8_t pkt_len)
+{
+ uint8_t i;
+
+ ao_radio_abort = 0;
+ ao_radio_get(pkt_len);
+ ao_radio_done = 0;
+ for (i = 0; i < sizeof (rdf_setup); i += 2)
+ RF[rdf_setup[i]] = rdf_setup[i+1];
+
+ ao_dma_set_transfer(ao_radio_dma,
+ &ao_radio_rdf_value,
+ &RFDXADDR,
+ pkt_len,
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_RADIO,
+ DMA_CFG1_SRCINC_0 |
+ DMA_CFG1_DESTINC_0 |
+ DMA_CFG1_PRIORITY_HIGH);
+ ao_dma_start(ao_radio_dma);
+ RFST = RFST_STX;
+ __critical while (!ao_radio_done && !ao_radio_abort)
+ ao_sleep(&ao_radio_done);
+ if (!ao_radio_done) {
+ ao_dma_abort(ao_radio_dma);
+ ao_radio_idle();
+ }
+ ao_radio_set_packet();
+ ao_radio_put();
+}
+
+void
+ao_radio_rdf_abort(void)
+{
+ ao_radio_abort = 1;
+ ao_wakeup(&ao_radio_done);
+}
+
+
+/* Output carrier */
+void
+ao_radio_test(void)
+{
+ uint8_t mode = 2;
+ static __xdata radio_on;
+ ao_cmd_white();
+ if (ao_cmd_lex_c != '\n') {
+ ao_cmd_decimal();
+ mode = (uint8_t) ao_cmd_lex_u32;
+ }
+ mode++;
+ if ((mode & 2) && !radio_on) {
+#if HAS_MONITOR
+ ao_set_monitor(0);
+#endif
+#if PACKET_HAS_SLAVE
+ ao_packet_slave_stop();
+#endif
+ ao_radio_get(0xff);
+ RFST = RFST_STX;
+ radio_on = 1;
+ }
+ if (mode == 3) {
+ printf ("Hit a character to stop..."); flush();
+ getchar();
+ putchar('\n');
+ }
+ if ((mode & 1) && radio_on) {
+ ao_radio_idle();
+ ao_radio_put();
+ radio_on = 0;
+ }
+}
+
+__code struct ao_cmds ao_radio_cmds[] = {
+ { ao_radio_test, "C <1 start, 0 stop, none both>\0Radio carrier test" },
+ { 0, NULL },
+};
+
+void
+ao_radio_init(void)
+{
+ uint8_t i;
+ for (i = 0; i < sizeof (radio_setup); i += 2)
+ RF[radio_setup[i]] = radio_setup[i+1];
+ ao_radio_set_packet();
+ ao_radio_dma_done = 1;
+ ao_radio_dma = ao_dma_alloc(&ao_radio_dma_done);
+ RFIF = 0;
+ RFIM = RFIM_IM_TIMEOUT|RFIM_IM_DONE;
+ IEN2 |= IEN2_RFIE;
+ ao_cmd_register(&ao_radio_cmds[0]);
+}
diff --git a/src/cc1111/ao_reboot.c b/src/cc1111/ao_reboot.c
new file mode 100644
index 00000000..8c47b893
--- /dev/null
+++ b/src/cc1111/ao_reboot.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+/* Use the watchdog timer to force a complete reboot
+ */
+void
+ao_reboot(void)
+{
+ WDCTL = WDCTL_EN | WDCTL_MODE_WATCHDOG | WDCTL_INT_32768;
+ ao_delay(AO_SEC_TO_TICKS(2));
+ ao_panic(AO_PANIC_REBOOT);
+}
diff --git a/src/cc1111/ao_romconfig.c b/src/cc1111/ao_romconfig.c
new file mode 100644
index 00000000..f3fe61b1
--- /dev/null
+++ b/src/cc1111/ao_romconfig.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+__code __at (0x00a0) uint16_t ao_romconfig_version = AO_ROMCONFIG_VERSION;
+__code __at (0x00a2) uint16_t ao_romconfig_check = ~AO_ROMCONFIG_VERSION;
+__code __at (0x00a4) uint16_t ao_serial_number = 0;
+/*
+ * For 434.550MHz, the frequency value is:
+ *
+ * 434.550e6 / (24e6 / 2**16) = 1186611.2
+ *
+ * This value is stored in a const variable so that
+ * ao-load can change it during programming for
+ * devices that have no eeprom for config data.
+ */
+__code __at (0x00a6) uint32_t ao_radio_cal = 1186611;
diff --git a/src/cc1111/ao_serial.c b/src/cc1111/ao_serial.c
new file mode 100644
index 00000000..82370c64
--- /dev/null
+++ b/src/cc1111/ao_serial.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+volatile __xdata struct ao_fifo ao_usart1_rx_fifo;
+volatile __xdata struct ao_fifo ao_usart1_tx_fifo;
+
+void
+ao_serial_rx1_isr(void) __interrupt 3
+{
+ if (!ao_fifo_full(ao_usart1_rx_fifo))
+ ao_fifo_insert(ao_usart1_rx_fifo, U1DBUF);
+ 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, U1DBUF);
+ }
+}
+
+void
+ao_serial_tx1_isr(void) __interrupt 14
+{
+ UTX1IF = 0;
+ ao_serial_tx1_started = 0;
+ ao_serial_tx1_start();
+ ao_wakeup(&ao_usart1_tx_fifo);
+}
+
+char
+ao_serial_getchar(void) __critical
+{
+ char c;
+ while (ao_fifo_empty(ao_usart1_rx_fifo))
+ ao_sleep(&ao_usart1_rx_fifo);
+ ao_fifo_remove(ao_usart1_rx_fifo, c);
+ return c;
+}
+
+#if USE_SERIAL_STDIN
+char
+ao_serial_pollchar(void) __critical
+{
+ char c;
+ if (ao_fifo_empty(ao_usart1_rx_fifo))
+ return AO_READ_AGAIN;
+ ao_fifo_remove(ao_usart1_rx_fifo,c);
+ return c;
+}
+#endif
+
+void
+ao_serial_putchar(char c) __critical
+{
+ 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();
+}
+
+void
+ao_serial_drain(void) __critical
+{
+ while (!ao_fifo_empty(ao_usart1_tx_fifo))
+ ao_sleep(&ao_usart1_tx_fifo);
+}
+
+static __code struct {
+ uint8_t baud;
+ uint8_t gcr;
+} ao_serial_speeds[] = {
+ /* [AO_SERIAL_SPEED_4800] = */ {
+ /* .baud = */ 163,
+ /* .gcr = */ (7 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
+ },
+ /* [AO_SERIAL_SPEED_9600] = */ {
+ /* .baud = */ 163,
+ /* .gcr = */ (8 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
+ },
+ /* [AO_SERIAL_SPEED_19200] = */ {
+ /* .baud = */ 163,
+ /* .gcr = */ (9 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
+ },
+ /* [AO_SERIAL_SPEED_57600] = */ {
+ /* .baud = */ 59,
+ /* .gcr = */ (11 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
+ },
+};
+
+void
+ao_serial_set_speed(uint8_t speed)
+{
+ ao_serial_drain();
+ if (speed > AO_SERIAL_SPEED_57600)
+ return;
+ U1UCR |= UxUCR_FLUSH;
+ U1BAUD = ao_serial_speeds[speed].baud;
+ U1GCR = ao_serial_speeds[speed].gcr;
+}
+
+void
+ao_serial_init(void)
+{
+#if HAS_SERIAL_1_ALT_1
+ /* Set up the USART pin assignment */
+ PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_1;
+
+ P2DIR = (P2DIR & ~P2DIR_PRIP0_MASK) | P2DIR_PRIP0_USART1_USART0;
+
+ /* Make the USART pins be controlled by the USART */
+ P0SEL |= (1 << 5) | (1 << 4);
+#if HAS_SERIAL_1_HW_FLOW
+ P0SEL |= (1 << 3) | (1 << 2);
+#endif
+#else
+ /* Set up the USART pin assignment */
+ PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_2;
+
+ P2SEL = (P2SEL & ~(P2SEL_PRI3P1_MASK | P2SEL_PRI2P1_MASK)) |
+ (P2SEL_PRI3P1_USART1 | P2SEL_PRI2P1_USART1);
+
+ /* Make the USART pins be controlled by the USART */
+ P1SEL |= (1 << 6) | (1 << 7);
+ P1SEL |= (1 << 5) | (1 << 4);
+#endif
+
+ /* UART mode with receiver enabled */
+ U1CSR = (UxCSR_MODE_UART | UxCSR_RE);
+
+ /* Pick a 4800 baud rate */
+ ao_serial_set_speed(AO_SERIAL_SPEED_4800);
+
+ /* Reasonable serial parameters */
+ U1UCR = (UxUCR_FLUSH |
+#if HAS_SERIAL_1_HW_FLOW
+ UxUCR_FLOW_ENABLE |
+#else
+ UxUCR_FLOW_DISABLE |
+#endif
+ UxUCR_D9_EVEN_PARITY |
+ UxUCR_BIT9_8_BITS |
+ UxUCR_PARITY_DISABLE |
+ UxUCR_SPB_1_STOP_BIT |
+ UxUCR_STOP_HIGH |
+ UxUCR_START_LOW);
+
+ IEN0 |= IEN0_URX1IE;
+ IEN2 |= IEN2_UTX1IE;
+}
diff --git a/src/cc1111/ao_spi.c b/src/cc1111/ao_spi.c
new file mode 100644
index 00000000..fbe613c7
--- /dev/null
+++ b/src/cc1111/ao_spi.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+/* Shared mutex to protect SPI bus, must cover the entire
+ * operation, from CS low to CS high. This means that any SPI
+ * user must protect the SPI bus with this mutex
+ */
+__xdata uint8_t ao_spi_mutex;
+__xdata uint8_t ao_spi_dma_in_done;
+__xdata uint8_t ao_spi_dma_out_done;
+
+uint8_t ao_spi_dma_out_id;
+uint8_t ao_spi_dma_in_id;
+
+static __xdata uint8_t ao_spi_const = 0xff;
+
+/* Send bytes over SPI.
+ *
+ * This sets up two DMA engines, one writing the data and another reading
+ * bytes coming back. We use the bytes coming back to tell when the transfer
+ * is complete, as the transmit register is double buffered and hence signals
+ * completion one byte before the transfer is actually complete
+ */
+void
+ao_spi_send(void __xdata *block, uint16_t len) __reentrant
+{
+ ao_dma_set_transfer(ao_spi_dma_in_id,
+ &U0DBUFXADDR,
+ &ao_spi_const,
+ len,
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_URX0,
+ DMA_CFG1_SRCINC_0 |
+ DMA_CFG1_DESTINC_0 |
+ DMA_CFG1_PRIORITY_NORMAL);
+
+ ao_dma_set_transfer(ao_spi_dma_out_id,
+ block,
+ &U0DBUFXADDR,
+ len,
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_UTX0,
+ DMA_CFG1_SRCINC_1 |
+ DMA_CFG1_DESTINC_0 |
+ DMA_CFG1_PRIORITY_NORMAL);
+
+ ao_dma_start(ao_spi_dma_in_id);
+ ao_dma_start(ao_spi_dma_out_id);
+ ao_dma_trigger(ao_spi_dma_out_id);
+ __critical while (!ao_spi_dma_in_done)
+ ao_sleep(&ao_spi_dma_in_done);
+}
+
+/* Receive bytes over SPI.
+ *
+ * This sets up tow DMA engines, one reading the data and another
+ * writing constant values to the SPI transmitter as that is what
+ * clocks the data coming in.
+ */
+void
+ao_spi_recv(void __xdata *block, uint16_t len) __reentrant
+{
+ ao_dma_set_transfer(ao_spi_dma_in_id,
+ &U0DBUFXADDR,
+ block,
+ len,
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_URX0,
+ DMA_CFG1_SRCINC_0 |
+ DMA_CFG1_DESTINC_1 |
+ DMA_CFG1_PRIORITY_NORMAL);
+
+ ao_dma_set_transfer(ao_spi_dma_out_id,
+ &ao_spi_const,
+ &U0DBUFXADDR,
+ len,
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_UTX0,
+ DMA_CFG1_SRCINC_0 |
+ DMA_CFG1_DESTINC_0 |
+ DMA_CFG1_PRIORITY_NORMAL);
+
+ ao_dma_start(ao_spi_dma_in_id);
+ ao_dma_start(ao_spi_dma_out_id);
+ ao_dma_trigger(ao_spi_dma_out_id);
+ __critical while (!ao_spi_dma_in_done)
+ ao_sleep(&ao_spi_dma_in_done);
+}
+
+/*
+ * Initialize USART0 for SPI using config alt 2
+ *
+ * MO P1_5
+ * MI P1_4
+ * CLK P1_3
+ *
+ * Chip select is the responsibility of the caller
+ */
+
+void
+ao_spi_init(void)
+{
+ /* Set up the USART pin assignment */
+ PERCFG = (PERCFG & ~PERCFG_U0CFG_ALT_MASK) | PERCFG_U0CFG_ALT_2;
+
+ /* Ensure that USART0 takes precidence over USART1 for pins that
+ * they share
+ */
+ P2SEL = (P2SEL & ~P2SEL_PRI3P1_MASK) | P2SEL_PRI3P1_USART0;
+
+ /* Make the SPI pins be controlled by the USART peripheral */
+ P1SEL |= ((1 << 5) | (1 << 4) | (1 << 3));
+
+ /* Set up OUT DMA */
+ ao_spi_dma_out_id = ao_dma_alloc(&ao_spi_dma_out_done);
+
+ /* Set up IN DMA */
+ ao_spi_dma_in_id = ao_dma_alloc(&ao_spi_dma_in_done);
+
+ /* Set up the USART.
+ *
+ * SPI master mode
+ */
+ U0CSR = (UxCSR_MODE_SPI | UxCSR_RE | UxCSR_MASTER);
+
+ /* Set the baud rate and signal parameters
+ *
+ * The cc1111 is limited to a 24/8 MHz SPI clock.
+ * Every peripheral I've ever seen goes faster than that,
+ * so set the clock to 3MHz (BAUD_E 17, BAUD_M 0)
+ */
+ U0BAUD = 0;
+ U0GCR = (UxGCR_CPOL_NEGATIVE |
+ UxGCR_CPHA_FIRST_EDGE |
+ UxGCR_ORDER_MSB |
+ (17 << UxGCR_BAUD_E_SHIFT));
+}
diff --git a/src/cc1111/ao_timer.c b/src/cc1111/ao_timer.c
new file mode 100644
index 00000000..aadee71e
--- /dev/null
+++ b/src/cc1111/ao_timer.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+static volatile __data uint16_t ao_tick_count;
+
+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 */
+
+#if HAS_ADC
+volatile __data uint8_t ao_adc_interval = 1;
+volatile __data uint8_t ao_adc_count;
+#endif
+
+void ao_timer_isr(void) __interrupt 9
+{
+ ++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)
+{
+ /* NOTE: This uses a timer only present on cc1111 architecture. */
+
+ /* disable timer 1 */
+ T1CTL = 0;
+
+ /* set the sample rate */
+ T1CC0H = T1_SAMPLE_TIME >> 8;
+ T1CC0L = (uint8_t) T1_SAMPLE_TIME;
+
+ T1CCTL0 = T1CCTL_MODE_COMPARE;
+ T1CCTL1 = 0;
+ T1CCTL2 = 0;
+
+ /* clear timer value */
+ T1CNTL = 0;
+
+ /* enable overflow interrupt */
+ OVFIM = 1;
+ /* enable timer 1 interrupt */
+ T1IE = 1;
+
+ /* enable timer 1 in module mode, dividing by 8 */
+ T1CTL = T1CTL_MODE_MODULO | T1CTL_DIV_8;
+}
+
+/*
+ * AltOS always cranks the clock to the max frequency
+ */
+void
+ao_clock_init(void)
+{
+ /* Switch system clock to crystal oscilator */
+ CLKCON = (CLKCON & ~CLKCON_OSC_MASK) | (CLKCON_OSC_XTAL);
+
+ while (!(SLEEP & SLEEP_XOSC_STB))
+ ;
+
+ /* Crank up the timer tick and system clock speed */
+ CLKCON = ((CLKCON & ~(CLKCON_TICKSPD_MASK | CLKCON_CLKSPD_MASK)) |
+ (CLKCON_TICKSPD_1 | CLKCON_CLKSPD_1));
+
+ while ((CLKCON & (CLKCON_TICKSPD_MASK|CLKCON_CLKSPD_MASK)) !=
+ (CLKCON_TICKSPD_1 | CLKCON_CLKSPD_1))
+ ;
+}
diff --git a/src/cc1111/ao_usb.c b/src/cc1111/ao_usb.c
new file mode 100644
index 00000000..08cb7390
--- /dev/null
+++ b/src/cc1111/ao_usb.c
@@ -0,0 +1,460 @@
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+#include "ao_usb.h"
+
+struct ao_task __xdata ao_usb_task;
+
+static __xdata uint16_t ao_usb_in_bytes;
+static __pdata uint16_t ao_usb_in_bytes_last;
+static __xdata uint16_t ao_usb_out_bytes;
+static __pdata uint8_t ao_usb_iif;
+static __pdata uint8_t ao_usb_running;
+
+static void
+ao_usb_set_interrupts(void)
+{
+ /* IN interrupts on the control an IN endpoints */
+ USBIIE = (1 << AO_USB_CONTROL_EP) | (1 << AO_USB_IN_EP);
+
+ /* OUT interrupts on the OUT endpoint */
+ USBOIE = (1 << AO_USB_OUT_EP);
+
+ /* Only care about reset */
+ USBCIE = USBCIE_RSTIE;
+}
+
+/* This interrupt is shared with port 2,
+ * so when we hook that up, fix this
+ */
+void
+ao_usb_isr(void) __interrupt 6
+{
+ USBIF = 0;
+ ao_usb_iif |= USBIIF;
+ if (ao_usb_iif & 1)
+ ao_wakeup(&ao_usb_task);
+ if (ao_usb_iif & (1 << AO_USB_IN_EP))
+ ao_wakeup(&ao_usb_in_bytes);
+
+ if (USBOIF & (1 << AO_USB_OUT_EP))
+ ao_wakeup(&ao_stdin_ready);
+
+ if (USBCIF & USBCIF_RSTIF)
+ ao_usb_set_interrupts();
+#if HAS_BTM
+#if BT_LINK_ON_P2
+ ao_btm_isr();
+#endif
+#endif
+}
+
+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;
+
+__pdata uint8_t ao_usb_ep0_state;
+uint8_t * __pdata ao_usb_ep0_in_data;
+__pdata uint8_t ao_usb_ep0_in_len;
+__pdata uint8_t ao_usb_ep0_in_buf[2];
+__pdata uint8_t ao_usb_ep0_out_len;
+__xdata uint8_t *__pdata ao_usb_ep0_out_data;
+__pdata uint8_t ao_usb_configuration;
+
+/* Send an IN data packet */
+static void
+ao_usb_ep0_flush(void)
+{
+ __pdata uint8_t this_len;
+ __pdata uint8_t cs0;
+
+ /* If the IN packet hasn't been picked up, just return */
+ USBINDEX = 0;
+ cs0 = USBCS0;
+ if (cs0 & USBCS0_INPKT_RDY)
+ return;
+
+ this_len = ao_usb_ep0_in_len;
+ if (this_len > AO_USB_CONTROL_SIZE)
+ this_len = AO_USB_CONTROL_SIZE;
+ cs0 = USBCS0_INPKT_RDY;
+ if (this_len != AO_USB_CONTROL_SIZE) {
+ cs0 = USBCS0_INPKT_RDY | USBCS0_DATA_END;
+ ao_usb_ep0_state = AO_USB_EP0_IDLE;
+ }
+ ao_usb_ep0_in_len -= this_len;
+ while (this_len--)
+ USBFIFO[0] = *ao_usb_ep0_in_data++;
+ USBINDEX = 0;
+ USBCS0 = cs0;
+}
+
+__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)
+{
+ __code uint8_t *__pdata descriptor;
+ __pdata uint8_t type = value >> 8;
+ __pdata 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];
+ }
+}
+
+/* Read data from the ep0 OUT fifo
+ */
+static void
+ao_usb_ep0_fill(void)
+{
+ __pdata uint8_t len;
+
+ USBINDEX = 0;
+ len = USBCNT0;
+ if (len > ao_usb_ep0_out_len)
+ len = ao_usb_ep0_out_len;
+ ao_usb_ep0_out_len -= len;
+ while (len--)
+ *ao_usb_ep0_out_data++ = USBFIFO[0];
+}
+
+void
+ao_usb_ep0_queue_byte(uint8_t a)
+{
+ ao_usb_ep0_in_buf[ao_usb_ep0_in_len++] = a;
+}
+
+void
+ao_usb_set_address(uint8_t address)
+{
+ ao_usb_running = 1;
+ USBADDR = address | 0x80;
+ while (USBADDR & 0x80)
+ ;
+}
+
+static void
+ao_usb_set_configuration(void)
+{
+ /* Set the IN max packet size, double buffered */
+ USBINDEX = AO_USB_IN_EP;
+ USBMAXI = AO_USB_IN_SIZE >> 3;
+ USBCSIH |= USBCSIH_IN_DBL_BUF;
+
+ /* Set the OUT max packet size, double buffered */
+ USBINDEX = AO_USB_OUT_EP;
+ USBMAXO = AO_USB_OUT_SIZE >> 3;
+ USBCSOH = USBCSOH_OUT_DBL_BUF;
+}
+
+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();
+ if (ao_usb_ep0_out_len != 0)
+ 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;
+ }
+ USBINDEX = 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:
+ switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_RECIP_MASK) {
+ case AO_USB_RECIP_DEVICE:
+ 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_SET_ADDRESS:
+ ao_usb_set_address(ao_usb_setup.value);
+ break;
+ case AO_USB_REQ_GET_DESCRIPTOR:
+ ao_usb_get_descriptor(ao_usb_setup.value);
+ break;
+ case AO_USB_REQ_GET_CONFIGURATION:
+ ao_usb_ep0_queue_byte(ao_usb_configuration);
+ break;
+ case AO_USB_REQ_SET_CONFIGURATION:
+ ao_usb_configuration = ao_usb_setup.value;
+ ao_usb_set_configuration();
+ break;
+ }
+ break;
+ case AO_USB_RECIP_INTERFACE:
+ #pragma disable_warning 110
+ 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:
+ 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:
+ switch (ao_usb_setup.request) {
+ case SET_LINE_CODING:
+ ao_usb_ep0_out_len = 7;
+ ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_line_coding;
+ break;
+ case GET_LINE_CODING:
+ 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;
+ ao_usb_ep0_flush();
+ }
+}
+
+/* End point 0 receives all of the control messages. */
+static void
+ao_usb_ep0(void)
+{
+ __pdata uint8_t cs0;
+
+ ao_usb_ep0_state = AO_USB_EP0_IDLE;
+ for (;;) {
+ __critical for (;;) {
+ if (ao_usb_iif & 1) {
+ ao_usb_iif &= ~1;
+ break;
+ }
+ ao_sleep(&ao_usb_task);
+ }
+ USBINDEX = 0;
+ cs0 = USBCS0;
+ if (cs0 & USBCS0_SETUP_END) {
+ ao_usb_ep0_state = AO_USB_EP0_IDLE;
+ USBCS0 = USBCS0_CLR_SETUP_END;
+ }
+ if (cs0 & USBCS0_SENT_STALL) {
+ ao_usb_ep0_state = AO_USB_EP0_IDLE;
+ USBCS0 &= ~USBCS0_SENT_STALL;
+ }
+ if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN &&
+ (cs0 & USBCS0_INPKT_RDY) == 0)
+ {
+ ao_usb_ep0_flush();
+ }
+ if (cs0 & USBCS0_OUTPKT_RDY) {
+ switch (ao_usb_ep0_state) {
+ case AO_USB_EP0_IDLE:
+ ao_usb_ep0_setup();
+ break;
+ case AO_USB_EP0_DATA_OUT:
+ ao_usb_ep0_fill();
+ if (ao_usb_ep0_out_len == 0)
+ ao_usb_ep0_state = AO_USB_EP0_IDLE;
+ USBINDEX = 0;
+ if (ao_usb_ep0_state == AO_USB_EP0_IDLE)
+ USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END;
+ else
+ USBCS0 = USBCS0_CLR_OUTPKT_RDY;
+ break;
+ }
+ }
+ }
+}
+
+/* Wait for a free IN buffer */
+static void
+ao_usb_in_wait(void)
+{
+ for (;;) {
+ USBINDEX = AO_USB_IN_EP;
+ if ((USBCSIL & USBCSIL_INPKT_RDY) == 0)
+ break;
+ ao_sleep(&ao_usb_in_bytes);
+ }
+}
+
+/* Send the current IN packet */
+static void
+ao_usb_in_send(void)
+{
+ USBINDEX = AO_USB_IN_EP;
+ USBCSIL |= USBCSIL_INPKT_RDY;
+ ao_usb_in_bytes_last = ao_usb_in_bytes;
+ ao_usb_in_bytes = 0;
+}
+
+void
+ao_usb_flush(void) __critical
+{
+ if (!ao_usb_running)
+ return;
+
+ /* If there are pending bytes, or if the last packet was full,
+ * send another IN packet
+ */
+ if (ao_usb_in_bytes || (ao_usb_in_bytes_last == AO_USB_IN_SIZE)) {
+ 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, sending the packet when full */
+ USBFIFO[AO_USB_IN_EP << 1] = c;
+ if (++ao_usb_in_bytes == AO_USB_IN_SIZE)
+ ao_usb_in_send();
+}
+
+char
+ao_usb_pollchar(void) __critical
+{
+ char c;
+ if (ao_usb_out_bytes == 0) {
+ USBINDEX = AO_USB_OUT_EP;
+ if ((USBCSOL & USBCSOL_OUTPKT_RDY) == 0)
+ return AO_READ_AGAIN;
+ ao_usb_out_bytes = (USBCNTH << 8) | USBCNTL;
+ if (ao_usb_out_bytes == 0) {
+ USBINDEX = AO_USB_OUT_EP;
+ USBCSOL &= ~USBCSOL_OUTPKT_RDY;
+ return AO_READ_AGAIN;
+ }
+ }
+ --ao_usb_out_bytes;
+ c = USBFIFO[AO_USB_OUT_EP << 1];
+ if (ao_usb_out_bytes == 0) {
+ USBINDEX = AO_USB_OUT_EP;
+ USBCSOL &= ~USBCSOL_OUTPKT_RDY;
+ }
+ return c;
+}
+
+char
+ao_usb_getchar(void) __critical
+{
+ char c;
+
+ while ((c = ao_usb_pollchar()) == AO_READ_AGAIN)
+ ao_sleep(&ao_stdin_ready);
+ return c;
+}
+
+void
+ao_usb_enable(void)
+{
+ /* Turn on the USB controller */
+ SLEEP |= SLEEP_USB_EN;
+
+ ao_usb_set_configuration();
+
+ ao_usb_set_interrupts();
+
+ /* enable USB interrupts */
+ IEN2 |= IEN2_USBIE;
+
+ /* Clear any pending interrupts */
+ USBCIF = 0;
+ USBOIF = 0;
+ USBIIF = 0;
+}
+
+void
+ao_usb_disable(void)
+{
+ /* Disable USB interrupts */
+ USBIIE = 0;
+ USBOIE = 0;
+ USBCIE = 0;
+ IEN2 &= ~IEN2_USBIE;
+
+ /* Clear any pending interrupts */
+ USBCIF = 0;
+ USBOIF = 0;
+ USBIIF = 0;
+
+ /* Turn off the USB controller */
+ SLEEP &= ~SLEEP_USB_EN;
+}
+
+void
+ao_usb_init(void)
+{
+ ao_usb_enable();
+
+ ao_add_task(&ao_usb_task, ao_usb_ep0, "usb");
+ ao_add_stdio(ao_usb_pollchar, ao_usb_putchar, ao_usb_flush);
+}
diff --git a/src/cc1111/ao_usb.h b/src/cc1111/ao_usb.h
new file mode 100644
index 00000000..6633dafc
--- /dev/null
+++ b/src/cc1111/ao_usb.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#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/cc1111/cc1111.h b/src/cc1111/cc1111.h
new file mode 100644
index 00000000..11ea8bbb
--- /dev/null
+++ b/src/cc1111/cc1111.h
@@ -0,0 +1,1328 @@
+/*-------------------------------------------------------------------------
+ Register Declarations for the ChipCon CC1111 Processor Range
+
+ Copyright © 2008 Keith Packard <keithp@keithp.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+ Adapted from the Cygnal C8051F12x config file which is:
+
+ Copyright (C) 2003 - Maarten Brock, sourceforge.brock@dse.nl
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-------------------------------------------------------------------------*/
+
+#ifndef _CC1111_H_
+#define _CC1111_H_
+#include <cc1110.h>
+#include <stdint.h>
+
+__sfr __at 0xA8 IEN0; /* Interrupt Enable 0 Register */
+
+sbit __at 0xA8 RFTXRXIE; /* RF TX/RX done interrupt enable */
+sbit __at 0xA9 ADCIE; /* ADC interrupt enable */
+sbit __at 0xAA URX0IE; /* USART0 RX interrupt enable */
+sbit __at 0xAB URX1IE; /* USART1 RX interrupt enable (shared with I2S RX) */
+sbit __at 0xAB I2SRXIE; /* I2S RX interrupt enable (shared with USART1 RX) */
+sbit __at 0xAC ENCIE; /* AES encryption/decryption interrupt enable */
+sbit __at 0xAD STIE; /* Sleep Timer interrupt enable */
+sbit __at 0xAF EA; /* Enable All */
+
+#define IEN0_EA (1 << 7)
+#define IEN0_STIE (1 << 5)
+#define IEN0_ENCIE (1 << 4)
+#define IEN0_URX1IE (1 << 3)
+#define IEN0_I2SRXIE (1 << 3)
+#define IEN0_URX0IE (1 << 2)
+#define IEN0_ADCIE (1 << 1)
+#define IEN0_RFTXRXIE (1 << 0)
+
+__sfr __at 0xB8 IEN1; /* Interrupt Enable 1 Register */
+
+#define IEN1_P0IE (1 << 5) /* Port 0 interrupt enable */
+#define IEN1_T4IE (1 << 4) /* Timer 4 interrupt enable */
+#define IEN1_T3IE (1 << 3) /* Timer 3 interrupt enable */
+#define IEN1_T2IE (1 << 2) /* Timer 2 interrupt enable */
+#define IEN1_T1IE (1 << 1) /* Timer 1 interrupt enable */
+#define IEN1_DMAIE (1 << 0) /* DMA transfer interrupt enable */
+
+/* IEN2 */
+__sfr __at 0x9A IEN2; /* Interrupt Enable 2 Register */
+
+#define IEN2_WDTIE (1 << 5) /* Watchdog timer interrupt enable */
+#define IEN2_P1IE (1 << 4) /* Port 1 interrupt enable */
+#define IEN2_UTX1IE (1 << 3) /* USART1 TX interrupt enable */
+#define IEN2_I2STXIE (1 << 3) /* I2S TX interrupt enable */
+#define IEN2_UTX0IE (1 << 2) /* USART0 TX interrupt enable */
+#define IEN2_P2IE (1 << 1) /* Port 2 interrupt enable */
+#define IEN2_USBIE (1 << 1) /* USB interrupt enable */
+#define IEN2_RFIE (1 << 0) /* RF general interrupt enable */
+
+/* CLKCON 0xC6 */
+__sfr __at 0xC6 CLKCON; /* Clock Control */
+
+#define CLKCON_OSC32K_RC (1 << 7)
+#define CLKCON_OSC32K_XTAL (0 << 7)
+#define CLKCON_OSC32K_MASK (1 << 7)
+#define CLKCON_OSC_RC (1 << 6)
+#define CLKCON_OSC_XTAL (0 << 6)
+#define CLKCON_OSC_MASK (1 << 6)
+#define CLKCON_TICKSPD_MASK (7 << 3)
+# define CLKCON_TICKSPD_1 (0 << 3)
+# define CLKCON_TICKSPD_1_2 (1 << 3)
+# define CLKCON_TICKSPD_1_4 (2 << 3)
+# define CLKCON_TICKSPD_1_8 (3 << 3)
+# define CLKCON_TICKSPD_1_16 (4 << 3)
+# define CLKCON_TICKSPD_1_32 (5 << 3)
+# define CLKCON_TICKSPD_1_64 (6 << 3)
+# define CLKCON_TICKSPD_1_128 (7 << 3)
+
+#define CLKCON_CLKSPD_MASK (7 << 0)
+# define CLKCON_CLKSPD_1 (0 << 0)
+# define CLKCON_CLKSPD_1_2 (1 << 0)
+# define CLKCON_CLKSPD_1_4 (2 << 0)
+# define CLKCON_CLKSPD_1_8 (3 << 0)
+# define CLKCON_CLKSPD_1_16 (4 << 0)
+# define CLKCON_CLKSPD_1_32 (5 << 0)
+# define CLKCON_CLKSPD_1_64 (6 << 0)
+# define CLKCON_CLKSPD_1_128 (7 << 0)
+
+/* SLEEP 0xBE */
+#define SLEEP_USB_EN (1 << 7)
+#define SLEEP_XOSC_STB (1 << 6)
+#define SLEEP_HFRC_STB (1 << 5)
+#define SLEEP_RST_POWER (0 << 3)
+#define SLEEP_RST_EXTERNAL (1 << 3)
+#define SLEEP_RST_WATCHDOG (2 << 3)
+#define SLEEP_RST_MASK (3 << 3)
+#define SLEEP_OSC_PD (1 << 2)
+#define SLEEP_MODE_PM0 (0 << 0)
+#define SLEEP_MODE_PM1 (1 << 0)
+#define SLEEP_MODE_PM2 (2 << 0)
+#define SLEEP_MODE_PM3 (3 << 0)
+#define SLEEP_MODE_MASK (3 << 0)
+
+/* PCON 0x87 */
+__sfr __at 0x87 PCON; /* Power Mode Control Register */
+
+#define PCON_IDLE (1 << 0)
+
+/*
+ * TCON
+ */
+__sfr __at 0x88 TCON; /* CPU Interrupt Flag 1 */
+
+sbit __at 0x8F URX1IF; /* USART1 RX interrupt flag. Automatically cleared */
+sbit __at 0x8F I2SRXIF; /* I2S RX interrupt flag. Automatically cleared */
+sbit __at 0x8D ADCIF; /* ADC interrupt flag. Automatically cleared */
+sbit __at 0x8B URX0IF; /* USART0 RX interrupt flag. Automatically cleared */
+sbit __at 0x89 RFTXRXIF; /* RF TX/RX complete interrupt flag. Automatically cleared */
+
+#define TCON_URX1IF (1 << 7)
+#define TCON_I2SRXIF (1 << 7)
+#define TCON_ADCIF (1 << 5)
+#define TCON_URX0IF (1 << 3)
+#define TCON_RFTXRXIF (1 << 1)
+
+/*
+ * S0CON
+ */
+__sfr __at 0x98 S0CON; /* CPU Interrupt Flag 2 */
+
+sbit __at 0x98 ENCIF_0; /* AES interrupt 0. */
+sbit __at 0x99 ENCIF_1; /* AES interrupt 1. */
+
+#define S0CON_ENCIF_1 (1 << 1)
+#define S0CON_ENCIF_0 (1 << 0)
+
+/*
+ * S1CON
+ */
+__sfr __at 0x9B S1CON; /* CPU Interrupt Flag 3 */
+
+#define S1CON_RFIF_1 (1 << 1)
+#define S1CON_RFIF_0 (1 << 0)
+
+/*
+ * IRCON
+ */
+__sfr __at 0xC0 IRCON; /* CPU Interrupt Flag 4 */
+
+sbit __at 0xC0 DMAIF; /* DMA complete interrupt flag */
+sbit __at 0xC1 T1IF; /* Timer 1 interrupt flag. Automatically cleared */
+sbit __at 0xC2 T2IF; /* Timer 2 interrupt flag. Automatically cleared */
+sbit __at 0xC3 T3IF; /* Timer 3 interrupt flag. Automatically cleared */
+sbit __at 0xC4 T4IF; /* Timer 4 interrupt flag. Automatically cleared */
+sbit __at 0xC5 P0IF; /* Port0 interrupt flag */
+sbit __at 0xC7 STIF; /* Sleep Timer interrupt flag */
+
+#define IRCON_DMAIF (1 << 0) /* DMA complete interrupt flag */
+#define IRCON_T1IF (1 << 1) /* Timer 1 interrupt flag. Automatically cleared */
+#define IRCON_T2IF (1 << 2) /* Timer 2 interrupt flag. Automatically cleared */
+#define IRCON_T3IF (1 << 3) /* Timer 3 interrupt flag. Automatically cleared */
+#define IRCON_T4IF (1 << 4) /* Timer 4 interrupt flag. Automatically cleared */
+#define IRCON_P0IF (1 << 5) /* Port0 interrupt flag */
+#define IRCON_STIF (1 << 7) /* Sleep Timer interrupt flag */
+
+/*
+ * IRCON2
+ */
+__sfr __at 0xE8 IRCON2; /* CPU Interrupt Flag 5 */
+
+sbit __at 0xE8 USBIF; /* USB interrupt flag (shared with Port2) */
+sbit __at 0xE8 P2IF; /* Port2 interrupt flag (shared with USB) */
+sbit __at 0xE9 UTX0IF; /* USART0 TX interrupt flag */
+sbit __at 0xEA UTX1IF; /* USART1 TX interrupt flag (shared with I2S TX) */
+sbit __at 0xEA I2STXIF; /* I2S TX interrupt flag (shared with USART1 TX) */
+sbit __at 0xEB P1IF; /* Port1 interrupt flag */
+sbit __at 0xEC WDTIF; /* Watchdog timer interrupt flag */
+
+#define IRCON2_USBIF (1 << 0) /* USB interrupt flag (shared with Port2) */
+#define IRCON2_P2IF (1 << 0) /* Port2 interrupt flag (shared with USB) */
+#define IRCON2_UTX0IF (1 << 1) /* USART0 TX interrupt flag */
+#define IRCON2_UTX1IF (1 << 2) /* USART1 TX interrupt flag (shared with I2S TX) */
+#define IRCON2_I2STXIF (1 << 2) /* I2S TX interrupt flag (shared with USART1 TX) */
+#define IRCON2_P1IF (1 << 3) /* Port1 interrupt flag */
+#define IRCON2_WDTIF (1 << 4) /* Watchdog timer interrupt flag */
+
+/*
+ * IP1 - Interrupt Priority 1
+ */
+
+/*
+ * Interrupt priority groups:
+ *
+ * IPG0 RFTXRX RF DMA
+ * IPG1 ADC T1 P2INT/USB
+ * IPG2 URX0 T2 UTX0
+ * IPG3 URX1/I2SRX T3 UTX1 / I2STX
+ * IPG4 ENC T4 P1INT
+ * IPG5 ST P0INT WDT
+ *
+ * Priority = (IP1 << 1) | IP0. Higher priority interrupts served first
+ */
+
+__sfr __at 0xB9 IP1; /* Interrupt Priority 1 */
+__sfr __at 0xA9 IP0; /* Interrupt Priority 0 */
+
+#define IP1_IPG5 (1 << 5)
+#define IP1_IPG4 (1 << 4)
+#define IP1_IPG3 (1 << 3)
+#define IP1_IPG2 (1 << 2)
+#define IP1_IPG1 (1 << 1)
+#define IP1_IPG0 (1 << 0)
+
+#define IP0_IPG5 (1 << 5)
+#define IP0_IPG4 (1 << 4)
+#define IP0_IPG3 (1 << 3)
+#define IP0_IPG2 (1 << 2)
+#define IP0_IPG1 (1 << 1)
+#define IP0_IPG0 (1 << 0)
+
+/*
+ * Timer 1
+ */
+#define T1CTL_MODE_SUSPENDED (0 << 0)
+#define T1CTL_MODE_FREE (1 << 0)
+#define T1CTL_MODE_MODULO (2 << 0)
+#define T1CTL_MODE_UP_DOWN (3 << 0)
+#define T1CTL_MODE_MASK (3 << 0)
+#define T1CTL_DIV_1 (0 << 2)
+#define T1CTL_DIV_8 (1 << 2)
+#define T1CTL_DIV_32 (2 << 2)
+#define T1CTL_DIV_128 (3 << 2)
+#define T1CTL_DIV_MASK (3 << 2)
+#define T1CTL_OVFIF (1 << 4)
+#define T1CTL_CH0IF (1 << 5)
+#define T1CTL_CH1IF (1 << 6)
+#define T1CTL_CH2IF (1 << 7)
+
+#define T1CCTL_NO_CAPTURE (0 << 0)
+#define T1CCTL_CAPTURE_RISING (1 << 0)
+#define T1CCTL_CAPTURE_FALLING (2 << 0)
+#define T1CCTL_CAPTURE_BOTH (3 << 0)
+#define T1CCTL_CAPTURE_MASK (3 << 0)
+
+#define T1CCTL_MODE_CAPTURE (0 << 2)
+#define T1CCTL_MODE_COMPARE (1 << 2)
+
+#define T1CTL_CMP_SET (0 << 3)
+#define T1CTL_CMP_CLEAR (1 << 3)
+#define T1CTL_CMP_TOGGLE (2 << 3)
+#define T1CTL_CMP_SET_CLEAR (3 << 3)
+#define T1CTL_CMP_CLEAR_SET (4 << 3)
+
+#define T1CTL_IM_DISABLED (0 << 6)
+#define T1CTL_IM_ENABLED (1 << 6)
+
+#define T1CTL_CPSEL_NORMAL (0 << 7)
+#define T1CTL_CPSEL_RF (1 << 7)
+
+/*
+ * Timer 3 and Timer 4
+ */
+
+/* Timer count */
+__sfr __at 0xCA T3CNT;
+__sfr __at 0xEA T4CNT;
+
+/* Timer control */
+
+__sfr __at 0xCB T3CTL;
+__sfr __at 0xEB T4CTL;
+
+#define TxCTL_DIV_1 (0 << 5)
+#define TxCTL_DIV_2 (1 << 5)
+#define TxCTL_DIV_4 (2 << 5)
+#define TxCTL_DIV_8 (3 << 5)
+#define TxCTL_DIV_16 (4 << 5)
+#define TxCTL_DIV_32 (5 << 5)
+#define TxCTL_DIV_64 (6 << 5)
+#define TxCTL_DIV_128 (7 << 5)
+#define TxCTL_START (1 << 4)
+#define TxCTL_OVFIM (1 << 3)
+#define TxCTL_CLR (1 << 2)
+#define TxCTL_MODE_FREE (0 << 0)
+#define TxCTL_MODE_DOWN (1 << 0)
+#define TxCTL_MODE_MODULO (2 << 0)
+#define TxCTL_MODE_UP_DOWN (3 << 0)
+
+/* Timer 4 channel 0 compare control */
+
+__sfr __at 0xCC T3CCTL0;
+__sfr __at 0xCE T3CCTL1;
+__sfr __at 0xEC T4CCTL0;
+__sfr __at 0xEE T4CCTL1;
+
+#define TxCCTLy_IM (1 << 6)
+#define TxCCTLy_CMP_SET (0 << 3)
+#define TxCCTLy_CMP_CLEAR (1 << 3)
+#define TxCCTLy_CMP_TOGGLE (2 << 3)
+#define TxCCTLy_CMP_SET_UP_CLEAR_DOWN (3 << 3)
+#define TxCCTLy_CMP_CLEAR_UP_SET_DOWN (4 << 3)
+#define TxCCTLy_CMP_SET_CLEAR_FF (5 << 3)
+#define TxCCTLy_CMP_CLEAR_SET_00 (6 << 3)
+#define TxCCTLy_CMP_MODE_ENABLE (1 << 2)
+
+/* Timer compare value */
+__sfr __at 0xCD T3CC0;
+__sfr __at 0xCF T3CC1;
+__sfr __at 0xED T4CC0;
+__sfr __at 0xEF T4CC1;
+
+/*
+ * Peripheral control
+ */
+
+__sfr __at 0xf1 PERCFG;
+#define PERCFG_T1CFG_ALT_1 (0 << 6)
+#define PERCFG_T1CFG_ALT_2 (1 << 6)
+#define PERCFG_T1CFG_ALT_MASK (1 << 6)
+
+#define PERCFG_T3CFG_ALT_1 (0 << 5)
+#define PERCFG_T3CFG_ALT_2 (1 << 5)
+#define PERCFG_T3CFG_ALT_MASK (1 << 5)
+
+#define PERCFG_T4CFG_ALT_1 (0 << 4)
+#define PERCFG_T4CFG_ALT_2 (1 << 4)
+#define PERCFG_T4CFG_ALT_MASK (1 << 4)
+
+#define PERCFG_U1CFG_ALT_1 (0 << 1)
+#define PERCFG_U1CFG_ALT_2 (1 << 1)
+#define PERCFG_U1CFG_ALT_MASK (1 << 1)
+
+#define PERCFG_U0CFG_ALT_1 (0 << 0)
+#define PERCFG_U0CFG_ALT_2 (1 << 0)
+#define PERCFG_U0CFG_ALT_MASK (1 << 0)
+
+/* directly addressed USB registers */
+__xdata __at (0xde00) volatile uint8_t USBADDR;
+__xdata __at (0xde01) volatile uint8_t USBPOW;
+__xdata __at (0xde02) volatile uint8_t USBIIF;
+
+__xdata __at (0xde04) volatile uint8_t USBOIF;
+
+__xdata __at (0xde06) volatile uint8_t USBCIF;
+
+# define USBCIF_SOFIF (1 << 3)
+# define USBCIF_RSTIF (1 << 2)
+# define USBCIF_RESUMEIF (1 << 1)
+# define USBCIF_SUSPENDIF (1 << 0)
+
+__xdata __at (0xde07) volatile uint8_t USBIIE;
+
+__xdata __at (0xde09) volatile uint8_t USBOIE;
+
+__xdata __at (0xde0b) volatile uint8_t USBCIE;
+
+# define USBCIE_SOFIE (1 << 3)
+# define USBCIE_RSTIE (1 << 2)
+# define USBCIE_RESUMEIE (1 << 1)
+# define USBCIE_SUSPENDIE (1 << 0)
+
+__xdata __at (0xde0c) volatile uint8_t USBFRML;
+__xdata __at (0xde0d) volatile uint8_t USBFRMH;
+__xdata __at (0xde0e) volatile uint8_t USBINDEX;
+
+/* indexed USB registers, must set USBINDEX to 0-5 */
+__xdata __at (0xde10) volatile uint8_t USBMAXI;
+__xdata __at (0xde11) volatile uint8_t USBCS0;
+
+# define USBCS0_CLR_SETUP_END (1 << 7)
+# define USBCS0_CLR_OUTPKT_RDY (1 << 6)
+# define USBCS0_SEND_STALL (1 << 5)
+# define USBCS0_SETUP_END (1 << 4)
+# define USBCS0_DATA_END (1 << 3)
+# define USBCS0_SENT_STALL (1 << 2)
+# define USBCS0_INPKT_RDY (1 << 1)
+# define USBCS0_OUTPKT_RDY (1 << 0)
+
+__xdata __at (0xde11) volatile uint8_t USBCSIL;
+
+# define USBCSIL_CLR_DATA_TOG (1 << 6)
+# define USBCSIL_SENT_STALL (1 << 5)
+# define USBCSIL_SEND_STALL (1 << 4)
+# define USBCSIL_FLUSH_PACKET (1 << 3)
+# define USBCSIL_UNDERRUN (1 << 2)
+# define USBCSIL_PKT_PRESENT (1 << 1)
+# define USBCSIL_INPKT_RDY (1 << 0)
+
+__xdata __at (0xde12) volatile uint8_t USBCSIH;
+
+# define USBCSIH_AUTOSET (1 << 7)
+# define USBCSIH_ISO (1 << 6)
+# define USBCSIH_FORCE_DATA_TOG (1 << 3)
+# define USBCSIH_IN_DBL_BUF (1 << 0)
+
+__xdata __at (0xde13) volatile uint8_t USBMAXO;
+__xdata __at (0xde14) volatile uint8_t USBCSOL;
+
+# define USBCSOL_CLR_DATA_TOG (1 << 7)
+# define USBCSOL_SENT_STALL (1 << 6)
+# define USBCSOL_SEND_STALL (1 << 5)
+# define USBCSOL_FLUSH_PACKET (1 << 4)
+# define USBCSOL_DATA_ERROR (1 << 3)
+# define USBCSOL_OVERRUN (1 << 2)
+# define USBCSOL_FIFO_FULL (1 << 1)
+# define USBCSOL_OUTPKT_RDY (1 << 0)
+
+__xdata __at (0xde15) volatile uint8_t USBCSOH;
+
+# define USBCSOH_AUTOCLEAR (1 << 7)
+# define USBCSOH_ISO (1 << 6)
+# define USBCSOH_OUT_DBL_BUF (1 << 0)
+
+__xdata __at (0xde16) volatile uint8_t USBCNT0;
+__xdata __at (0xde16) volatile uint8_t USBCNTL;
+__xdata __at (0xde17) volatile uint8_t USBCNTH;
+
+__xdata __at (0xde20) volatile uint8_t USBFIFO[12];
+
+/* ADC Data register, low and high */
+__sfr at 0xBA ADCL;
+__sfr at 0xBB ADCH;
+__xdata __at (0xDFBA) volatile uint16_t ADCXDATA;
+
+/* ADC Control Register 1 */
+__sfr at 0xB4 ADCCON1;
+
+# define ADCCON1_EOC (1 << 7) /* conversion complete */
+# define ADCCON1_ST (1 << 6) /* start conversion */
+
+# define ADCCON1_STSEL_MASK (3 << 4) /* start select */
+# define ADCCON1_STSEL_EXTERNAL (0 << 4) /* P2_0 pin triggers */
+# define ADCCON1_STSEL_FULLSPEED (1 << 4) /* full speed, no waiting */
+# define ADCCON1_STSEL_TIMER1 (2 << 4) /* timer 1 channel 0 */
+# define ADCCON1_STSEL_START (3 << 4) /* set start bit */
+
+# define ADCCON1_RCTRL_MASK (3 << 2) /* random number control */
+# define ADCCON1_RCTRL_COMPLETE (0 << 2) /* operation completed */
+# define ADCCON1_RCTRL_CLOCK_LFSR (1 << 2) /* Clock the LFSR once */
+
+/* ADC Control Register 2 */
+__sfr at 0xB5 ADCCON2;
+
+# define ADCCON2_SREF_MASK (3 << 6) /* reference voltage */
+# define ADCCON2_SREF_1_25V (0 << 6) /* internal 1.25V */
+# define ADCCON2_SREF_EXTERNAL (1 << 6) /* external on AIN7 cc1110 */
+# define ADCCON2_SREF_VDD (2 << 6) /* VDD on the AVDD pin */
+# define ADCCON2_SREF_EXTERNAL_DIFF (3 << 6) /* external on AIN6-7 cc1110 */
+
+# define ADCCON2_SDIV_MASK (3 << 4) /* decimation rate */
+# define ADCCON2_SDIV_64 (0 << 4) /* 7 bits */
+# define ADCCON2_SDIV_128 (1 << 4) /* 9 bits */
+# define ADCCON2_SDIV_256 (2 << 4) /* 10 bits */
+# define ADCCON2_SDIV_512 (3 << 4) /* 12 bits */
+
+# define ADCCON2_SCH_MASK (0xf << 0) /* Sequence channel select */
+# define ADCCON2_SCH_SHIFT 0
+# define ADCCON2_SCH_AIN0 (0 << 0)
+# define ADCCON2_SCH_AIN1 (1 << 0)
+# define ADCCON2_SCH_AIN2 (2 << 0)
+# define ADCCON2_SCH_AIN3 (3 << 0)
+# define ADCCON2_SCH_AIN4 (4 << 0)
+# define ADCCON2_SCH_AIN5 (5 << 0)
+# define ADCCON2_SCH_AIN6 (6 << 0)
+# define ADCCON2_SCH_AIN7 (7 << 0)
+# define ADCCON2_SCH_AIN0_AIN1 (8 << 0)
+# define ADCCON2_SCH_AIN2_AIN3 (9 << 0)
+# define ADCCON2_SCH_AIN4_AIN5 (0xa << 0)
+# define ADCCON2_SCH_AIN6_AIN7 (0xb << 0)
+# define ADCCON2_SCH_GND (0xc << 0)
+# define ADCCON2_SCH_VREF (0xd << 0)
+# define ADCCON2_SCH_TEMP (0xe << 0)
+# define ADCCON2_SCH_VDD_3 (0xf << 0)
+
+
+/* ADC Control Register 3 */
+__sfr at 0xB6 ADCCON3;
+
+# define ADCCON3_EREF_MASK (3 << 6) /* extra conversion reference */
+# define ADCCON3_EREF_1_25 (0 << 6) /* internal 1.25V */
+# define ADCCON3_EREF_EXTERNAL (1 << 6) /* external AIN7 cc1110 */
+# define ADCCON3_EREF_VDD (2 << 6) /* VDD on the AVDD pin */
+# define ADCCON3_EREF_EXTERNAL_DIFF (3 << 6) /* external AIN6-7 cc1110 */
+# define ADCCON3_EDIV_MASK (3 << 4) /* extral decimation */
+# define ADCCON3_EDIV_64 (0 << 4) /* 7 bits */
+# define ADCCON3_EDIV_128 (1 << 4) /* 9 bits */
+# define ADCCON3_EDIV_256 (2 << 4) /* 10 bits */
+# define ADCCON3_EDIV_512 (3 << 4) /* 12 bits */
+# define ADCCON3_ECH_MASK (0xf << 0) /* Sequence channel select */
+# define ADCCON3_ECH_SHIFT 0
+# define ADCCON3_ECH_AIN0 (0 << 0)
+# define ADCCON3_ECH_AIN1 (1 << 0)
+# define ADCCON3_ECH_AIN2 (2 << 0)
+# define ADCCON3_ECH_AIN3 (3 << 0)
+# define ADCCON3_ECH_AIN4 (4 << 0)
+# define ADCCON3_ECH_AIN5 (5 << 0)
+# define ADCCON3_ECH_AIN6 (6 << 0)
+# define ADCCON3_ECH_AIN7 (7 << 0)
+# define ADCCON3_ECH_AIN0_AIN1 (8 << 0)
+# define ADCCON3_ECH_AIN2_AIN3 (9 << 0)
+# define ADCCON3_ECH_AIN4_AIN5 (0xa << 0)
+# define ADCCON3_ECH_AIN6_AIN7 (0xb << 0)
+# define ADCCON3_ECH_GND (0xc << 0)
+# define ADCCON3_ECH_VREF (0xd << 0)
+# define ADCCON3_ECH_TEMP (0xe << 0)
+# define ADCCON3_ECH_VDD_3 (0xf << 0)
+
+/*
+ * ADC configuration register, this selects which
+ * GPIO pins are to be used as ADC inputs
+ */
+__sfr at 0xF2 ADCCFG;
+
+/*
+ * Watchdog timer
+ */
+
+__sfr at 0xc9 WDCTL;
+
+#define WDCTL_CLEAR_FIRST (0xa << 4)
+#define WDCTL_CLEAR_SECOND (0x5 << 4)
+#define WDCTL_EN (1 << 3)
+#define WDCTL_MODE_WATCHDOG (0 << 2)
+#define WDCTL_MODE_TIMER (1 << 2)
+#define WDCTL_MODE_MASK (1 << 2)
+#define WDCTL_INT_32768 (0 << 0)
+#define WDCTL_INT_8192 (1 << 0)
+#define WDCTL_INT_512 (2 << 0)
+#define WDCTL_INT_64 (3 << 0)
+
+/*
+ * Pin selectors, these set which pins are
+ * using their peripheral function
+ */
+__sfr at 0xF3 P0SEL;
+__sfr at 0xF4 P1SEL;
+__sfr at 0xF5 P2SEL;
+
+#define P2SEL_PRI3P1_USART0 (0 << 6)
+#define P2SEL_PRI3P1_USART1 (1 << 6)
+#define P2SEL_PRI3P1_MASK (1 << 6)
+#define P2SEL_PRI2P1_USART1 (0 << 5)
+#define P2SEL_PRI2P1_TIMER3 (1 << 5)
+#define P2SEL_PRI2P1_MASK (1 << 5)
+#define P2SEL_PRI1P1_TIMER1 (0 << 4)
+#define P2SEL_PRI1P1_TIMER4 (1 << 4)
+#define P2SEL_PRI1P1_MASK (1 << 4)
+#define P2SEL_PRI0P1_USART0 (0 << 3)
+#define P2SEL_PRI0P1_TIMER1 (1 << 3)
+#define P2SEL_PRI0P1_MASK (1 << 3)
+#define P2SEL_SELP2_4_GPIO (0 << 2)
+#define P2SEL_SELP2_4_PERIPHERAL (1 << 2)
+#define P2SEL_SELP2_4_MASK (1 << 2)
+#define P2SEL_SELP2_3_GPIO (0 << 1)
+#define P2SEL_SELP2_3_PERIPHERAL (1 << 1)
+#define P2SEL_SELP2_3_MASK (1 << 1)
+#define P2SEL_SELP2_0_GPIO (0 << 0)
+#define P2SEL_SELP2_0_PERIPHERAL (1 << 0)
+#define P2SEL_SELP2_0_MASK (1 << 0)
+
+/*
+ * For pins used as GPIOs, these set which are used as outputs
+ */
+__sfr at 0xFD P0DIR;
+__sfr at 0xFE P1DIR;
+__sfr at 0xFF P2DIR;
+
+#define P2DIR_PRIP0_USART0_USART1 (0 << 6)
+#define P2DIR_PRIP0_USART1_USART0 (1 << 6)
+#define P2DIR_PRIP0_TIMER1_01_USART1 (2 << 6)
+#define P2DIR_PRIP0_TIMER1_2_USART0 (3 << 6)
+#define P2DIR_PRIP0_MASK (3 << 6)
+
+__sfr at 0x8F P0INP;
+
+/* Select between tri-state and pull up/down
+ * for pins P0_0 - P0_7.
+ */
+#define P0INP_MDP0_7_PULL (0 << 7)
+#define P0INP_MDP0_7_TRISTATE (1 << 7)
+#define P0INP_MDP0_6_PULL (0 << 6)
+#define P0INP_MDP0_6_TRISTATE (1 << 6)
+#define P0INP_MDP0_5_PULL (0 << 5)
+#define P0INP_MDP0_5_TRISTATE (1 << 5)
+#define P0INP_MDP0_4_PULL (0 << 4)
+#define P0INP_MDP0_4_TRISTATE (1 << 4)
+#define P0INP_MDP0_3_PULL (0 << 3)
+#define P0INP_MDP0_3_TRISTATE (1 << 3)
+#define P0INP_MDP0_2_PULL (0 << 2)
+#define P0INP_MDP0_2_TRISTATE (1 << 2)
+#define P0INP_MDP0_1_PULL (0 << 1)
+#define P0INP_MDP0_1_TRISTATE (1 << 1)
+#define P0INP_MDP0_0_PULL (0 << 0)
+#define P0INP_MDP0_0_TRISTATE (1 << 0)
+
+__sfr at 0xF6 P1INP;
+
+/* Select between tri-state and pull up/down
+ * for pins P1_2 - P1_7. Pins P1_0 and P1_1 are
+ * always tri-stated
+ */
+#define P1INP_MDP1_7_PULL (0 << 7)
+#define P1INP_MDP1_7_TRISTATE (1 << 7)
+#define P1INP_MDP1_6_PULL (0 << 6)
+#define P1INP_MDP1_6_TRISTATE (1 << 6)
+#define P1INP_MDP1_5_PULL (0 << 5)
+#define P1INP_MDP1_5_TRISTATE (1 << 5)
+#define P1INP_MDP1_4_PULL (0 << 4)
+#define P1INP_MDP1_4_TRISTATE (1 << 4)
+#define P1INP_MDP1_3_PULL (0 << 3)
+#define P1INP_MDP1_3_TRISTATE (1 << 3)
+#define P1INP_MDP1_2_PULL (0 << 2)
+#define P1INP_MDP1_2_TRISTATE (1 << 2)
+
+__sfr at 0xF7 P2INP;
+/* P2INP has three extra bits which are used to choose
+ * between pull-up and pull-down when they are not tri-stated
+ */
+#define P2INP_PDUP2_PULL_UP (0 << 7)
+#define P2INP_PDUP2_PULL_DOWN (1 << 7)
+#define P2INP_PDUP1_PULL_UP (0 << 6)
+#define P2INP_PDUP1_PULL_DOWN (1 << 6)
+#define P2INP_PDUP0_PULL_UP (0 << 5)
+#define P2INP_PDUP0_PULL_DOWN (1 << 5)
+
+/* For the P2 pins, choose between tri-state and pull up/down
+ * mode
+ */
+#define P2INP_MDP2_4_PULL (0 << 4)
+#define P2INP_MDP2_4_TRISTATE (1 << 4)
+#define P2INP_MDP2_3_PULL (0 << 3)
+#define P2INP_MDP2_3_TRISTATE (1 << 3)
+#define P2INP_MDP2_2_PULL (0 << 2)
+#define P2INP_MDP2_2_TRISTATE (1 << 2)
+#define P2INP_MDP2_1_PULL (0 << 1)
+#define P2INP_MDP2_1_TRISTATE (1 << 1)
+#define P2INP_MDP2_0_PULL (0 << 0)
+#define P2INP_MDP2_0_TRISTATE (1 << 0)
+
+/* GPIO interrupt status flags */
+__sfr at 0x89 P0IFG;
+__sfr at 0x8A P1IFG;
+__sfr at 0x8B P2IFG;
+
+#define P0IFG_USB_RESUME (1 << 7)
+
+__sfr at 0x8C PICTL;
+#define PICTL_P2IEN (1 << 5)
+#define PICTL_P0IENH (1 << 4)
+#define PICTL_P0IENL (1 << 3)
+#define PICTL_P2ICON (1 << 2)
+#define PICTL_P1ICON (1 << 1)
+#define PICTL_P0ICON (1 << 0)
+
+/* GPIO pins */
+__sfr at 0x80 P0;
+
+sbit at 0x80 P0_0;
+sbit at 0x81 P0_1;
+sbit at 0x82 P0_2;
+sbit at 0x83 P0_3;
+sbit at 0x84 P0_4;
+sbit at 0x85 P0_5;
+sbit at 0x86 P0_6;
+sbit at 0x87 P0_7;
+
+__sfr at 0x90 P1;
+
+sbit at 0x90 P1_0;
+sbit at 0x91 P1_1;
+sbit at 0x92 P1_2;
+sbit at 0x93 P1_3;
+sbit at 0x94 P1_4;
+sbit at 0x95 P1_5;
+sbit at 0x96 P1_6;
+sbit at 0x97 P1_7;
+
+__sfr at 0xa0 P2;
+
+sbit at 0xa0 P2_0;
+sbit at 0xa1 P2_1;
+sbit at 0xa2 P2_2;
+sbit at 0xa3 P2_3;
+sbit at 0xa4 P2_4;
+
+/* DMA controller */
+struct cc_dma_channel {
+ uint8_t src_high;
+ uint8_t src_low;
+ uint8_t dst_high;
+ uint8_t dst_low;
+ uint8_t len_high;
+ uint8_t len_low;
+ uint8_t cfg0;
+ uint8_t cfg1;
+};
+
+# define DMA_LEN_HIGH_VLEN_MASK (7 << 5)
+# define DMA_LEN_HIGH_VLEN_LEN (0 << 5)
+# define DMA_LEN_HIGH_VLEN_PLUS_1 (1 << 5)
+# define DMA_LEN_HIGH_VLEN (2 << 5)
+# define DMA_LEN_HIGH_VLEN_PLUS_2 (3 << 5)
+# define DMA_LEN_HIGH_VLEN_PLUS_3 (4 << 5)
+# define DMA_LEN_HIGH_MASK (0x1f)
+
+# define DMA_CFG0_WORDSIZE_8 (0 << 7)
+# define DMA_CFG0_WORDSIZE_16 (1 << 7)
+# define DMA_CFG0_TMODE_MASK (3 << 5)
+# define DMA_CFG0_TMODE_SINGLE (0 << 5)
+# define DMA_CFG0_TMODE_BLOCK (1 << 5)
+# define DMA_CFG0_TMODE_REPEATED_SINGLE (2 << 5)
+# define DMA_CFG0_TMODE_REPEATED_BLOCK (3 << 5)
+
+/*
+ * DMA triggers
+ */
+# define DMA_CFG0_TRIGGER_NONE 0
+# define DMA_CFG0_TRIGGER_PREV 1
+# define DMA_CFG0_TRIGGER_T1_CH0 2
+# define DMA_CFG0_TRIGGER_T1_CH1 3
+# define DMA_CFG0_TRIGGER_T1_CH2 4
+# define DMA_CFG0_TRIGGER_T2_OVFL 6
+# define DMA_CFG0_TRIGGER_T3_CH0 7
+# define DMA_CFG0_TRIGGER_T3_CH1 8
+# define DMA_CFG0_TRIGGER_T4_CH0 9
+# define DMA_CFG0_TRIGGER_T4_CH1 10
+# define DMA_CFG0_TRIGGER_IOC_0 12
+# define DMA_CFG0_TRIGGER_IOC_1 13
+# define DMA_CFG0_TRIGGER_URX0 14
+# define DMA_CFG0_TRIGGER_UTX0 15
+# define DMA_CFG0_TRIGGER_URX1 16
+# define DMA_CFG0_TRIGGER_UTX1 17
+# define DMA_CFG0_TRIGGER_FLASH 18
+# define DMA_CFG0_TRIGGER_RADIO 19
+# define DMA_CFG0_TRIGGER_ADC_CHALL 20
+# define DMA_CFG0_TRIGGER_ADC_CH0 21
+# define DMA_CFG0_TRIGGER_ADC_CH1 22
+# define DMA_CFG0_TRIGGER_ADC_CH2 23
+# define DMA_CFG0_TRIGGER_ADC_CH3 24
+# define DMA_CFG0_TRIGGER_ADC_CH4 25
+# define DMA_CFG0_TRIGGER_ADC_CH5 26
+# define DMA_CFG0_TRIGGER_ADC_CH6 27
+# define DMA_CFG0_TRIGGER_I2SRX 27
+# define DMA_CFG0_TRIGGER_ADC_CH7 28
+# define DMA_CFG0_TRIGGER_I2STX 28
+# define DMA_CFG0_TRIGGER_ENC_DW 29
+# define DMA_CFG0_TRIGGER_ENC_UP 30
+
+# define DMA_CFG1_SRCINC_MASK (3 << 6)
+# define DMA_CFG1_SRCINC_0 (0 << 6)
+# define DMA_CFG1_SRCINC_1 (1 << 6)
+# define DMA_CFG1_SRCINC_2 (2 << 6)
+# define DMA_CFG1_SRCINC_MINUS_1 (3 << 6)
+
+# define DMA_CFG1_DESTINC_MASK (3 << 4)
+# define DMA_CFG1_DESTINC_0 (0 << 4)
+# define DMA_CFG1_DESTINC_1 (1 << 4)
+# define DMA_CFG1_DESTINC_2 (2 << 4)
+# define DMA_CFG1_DESTINC_MINUS_1 (3 << 4)
+
+# define DMA_CFG1_IRQMASK (1 << 3)
+# define DMA_CFG1_M8 (1 << 2)
+
+# define DMA_CFG1_PRIORITY_MASK (3 << 0)
+# define DMA_CFG1_PRIORITY_LOW (0 << 0)
+# define DMA_CFG1_PRIORITY_NORMAL (1 << 0)
+# define DMA_CFG1_PRIORITY_HIGH (2 << 0)
+
+/*
+ * DMAARM - DMA Channel Arm
+ */
+
+__sfr at 0xD6 DMAARM;
+
+# define DMAARM_ABORT (1 << 7)
+# define DMAARM_DMAARM4 (1 << 4)
+# define DMAARM_DMAARM3 (1 << 3)
+# define DMAARM_DMAARM2 (1 << 2)
+# define DMAARM_DMAARM1 (1 << 1)
+# define DMAARM_DMAARM0 (1 << 0)
+
+/*
+ * DMAREQ - DMA Channel Start Request and Status
+ */
+
+__sfr at 0xD7 DMAREQ;
+
+# define DMAREQ_DMAREQ4 (1 << 4)
+# define DMAREQ_DMAREQ3 (1 << 3)
+# define DMAREQ_DMAREQ2 (1 << 2)
+# define DMAREQ_DMAREQ1 (1 << 1)
+# define DMAREQ_DMAREQ0 (1 << 0)
+
+/*
+ * DMA configuration 0 address
+ */
+
+__sfr at 0xD5 DMA0CFGH;
+__sfr at 0xD4 DMA0CFGL;
+
+/*
+ * DMA configuration 1-4 address
+ */
+
+__sfr at 0xD3 DMA1CFGH;
+__sfr at 0xD2 DMA1CFGL;
+
+/*
+ * DMAIRQ - DMA Interrupt Flag
+ */
+
+__sfr at 0xD1 DMAIRQ;
+
+# define DMAIRQ_DMAIF4 (1 << 4)
+# define DMAIRQ_DMAIF3 (1 << 3)
+# define DMAIRQ_DMAIF2 (1 << 2)
+# define DMAIRQ_DMAIF1 (1 << 1)
+# define DMAIRQ_DMAIF0 (1 << 0)
+
+/*
+ * UART registers
+ */
+
+/* USART config/status registers */
+__sfr at 0x86 U0CSR;
+__sfr at 0xF8 U1CSR;
+
+# define UxCSR_MODE_UART (1 << 7)
+# define UxCSR_MODE_SPI (0 << 7)
+# define UxCSR_RE (1 << 6)
+# define UxCSR_SLAVE (1 << 5)
+# define UxCSR_MASTER (0 << 5)
+# define UxCSR_FE (1 << 4)
+# define UxCSR_ERR (1 << 3)
+# define UxCSR_RX_BYTE (1 << 2)
+# define UxCSR_TX_BYTE (1 << 1)
+# define UxCSR_ACTIVE (1 << 0)
+
+/* UART configuration registers */
+__sfr at 0xc4 U0UCR;
+__sfr at 0xfb U1UCR;
+
+# define UxUCR_FLUSH (1 << 7)
+# define UxUCR_FLOW_DISABLE (0 << 6)
+# define UxUCR_FLOW_ENABLE (1 << 6)
+# define UxUCR_D9_EVEN_PARITY (0 << 5)
+# define UxUCR_D9_ODD_PARITY (1 << 5)
+# define UxUCR_BIT9_8_BITS (0 << 4)
+# define UxUCR_BIT9_9_BITS (1 << 4)
+# define UxUCR_PARITY_DISABLE (0 << 3)
+# define UxUCR_PARITY_ENABLE (1 << 3)
+# define UxUCR_SPB_1_STOP_BIT (0 << 2)
+# define UxUCR_SPB_2_STOP_BITS (1 << 2)
+# define UxUCR_STOP_LOW (0 << 1)
+# define UxUCR_STOP_HIGH (1 << 1)
+# define UxUCR_START_LOW (0 << 0)
+# define UxUCR_START_HIGH (1 << 0)
+
+/* USART General configuration registers (mostly SPI) */
+__sfr at 0xc5 U0GCR;
+__sfr at 0xfc U1GCR;
+
+# define UxGCR_CPOL_NEGATIVE (0 << 7)
+# define UxGCR_CPOL_POSITIVE (1 << 7)
+# define UxGCR_CPHA_FIRST_EDGE (0 << 6)
+# define UxGCR_CPHA_SECOND_EDGE (1 << 6)
+# define UxGCR_ORDER_LSB (0 << 5)
+# define UxGCR_ORDER_MSB (1 << 5)
+# define UxGCR_BAUD_E_MASK (0x1f)
+# define UxGCR_BAUD_E_SHIFT 0
+
+/* USART data registers */
+__sfr at 0xc1 U0DBUF;
+__xdata __at (0xDFC1) volatile uint8_t U0DBUFXADDR;
+__sfr at 0xf9 U1DBUF;
+__xdata __at (0xDFF9) volatile uint8_t U1DBUFXADDR;
+
+/* USART baud rate registers, M value */
+__sfr at 0xc2 U0BAUD;
+__sfr at 0xfa U1BAUD;
+
+/* Flash controller */
+
+__sfr at 0xAE FCTL;
+#define FCTL_BUSY (1 << 7)
+#define FCTL_SWBSY (1 << 6)
+#define FCTL_CONTRD_ENABLE (1 << 4)
+#define FCTL_WRITE (1 << 1)
+#define FCTL_ERASE (1 << 0)
+
+/* Flash write data. Write two bytes here */
+__sfr at 0xAF FWDATA;
+__xdata __at (0xDFAF) volatile uint8_t FWDATAXADDR;
+
+/* Flash write/erase address */
+__sfr at 0xAD FADDRH;
+__sfr at 0xAC FADDRL;
+
+/* Flash timing */
+__sfr at 0xAB FWT;
+
+/* Radio */
+
+__sfr at 0xD9 RFD;
+__xdata at (0xDFD9) volatile uint8_t RFDXADDR;
+
+__sfr at 0xE9 RFIF;
+#define RFIF_IM_TXUNF (1 << 7)
+#define RFIF_IM_RXOVF (1 << 6)
+#define RFIF_IM_TIMEOUT (1 << 5)
+#define RFIF_IM_DONE (1 << 4)
+#define RFIF_IM_CS (1 << 3)
+#define RFIF_IM_PQT (1 << 2)
+#define RFIF_IM_CCA (1 << 1)
+#define RFIF_IM_SFD (1 << 0)
+
+__sfr at 0x91 RFIM;
+#define RFIM_IM_TXUNF (1 << 7)
+#define RFIM_IM_RXOVF (1 << 6)
+#define RFIM_IM_TIMEOUT (1 << 5)
+#define RFIM_IM_DONE (1 << 4)
+#define RFIM_IM_CS (1 << 3)
+#define RFIM_IM_PQT (1 << 2)
+#define RFIM_IM_CCA (1 << 1)
+#define RFIM_IM_SFD (1 << 0)
+
+__sfr at 0xE1 RFST;
+
+#define RFST_SFSTXON 0x00
+#define RFST_SCAL 0x01
+#define RFST_SRX 0x02
+#define RFST_STX 0x03
+#define RFST_SIDLE 0x04
+
+__xdata __at (0xdf00) uint8_t RF[0x3c];
+
+__xdata __at (0xdf2f) uint8_t RF_IOCFG2;
+#define RF_IOCFG2_OFF 0x2f
+
+__xdata __at (0xdf30) uint8_t RF_IOCFG1;
+#define RF_IOCFG1_OFF 0x30
+
+__xdata __at (0xdf31) uint8_t RF_IOCFG0;
+#define RF_IOCFG0_OFF 0x31
+
+__xdata __at (0xdf00) uint8_t RF_SYNC1;
+#define RF_SYNC1_OFF 0x00
+
+__xdata __at (0xdf01) uint8_t RF_SYNC0;
+#define RF_SYNC0_OFF 0x01
+
+__xdata __at (0xdf02) uint8_t RF_PKTLEN;
+#define RF_PKTLEN_OFF 0x02
+
+__xdata __at (0xdf03) uint8_t RF_PKTCTRL1;
+#define RF_PKTCTRL1_OFF 0x03
+#define PKTCTRL1_PQT_MASK (0x7 << 5)
+#define PKTCTRL1_PQT_SHIFT 5
+#define PKTCTRL1_APPEND_STATUS (1 << 2)
+#define PKTCTRL1_ADR_CHK_NONE (0 << 0)
+#define PKTCTRL1_ADR_CHK_NO_BROADCAST (1 << 0)
+#define PKTCTRL1_ADR_CHK_00_BROADCAST (2 << 0)
+#define PKTCTRL1_ADR_CHK_00_FF_BROADCAST (3 << 0)
+
+/* If APPEND_STATUS is used, two bytes will be added to the packet data */
+#define PKT_APPEND_STATUS_0_RSSI_MASK (0xff)
+#define PKT_APPEND_STATUS_0_RSSI_SHIFT 0
+#define PKT_APPEND_STATUS_1_CRC_OK (1 << 7)
+#define PKT_APPEND_STATUS_1_LQI_MASK (0x7f)
+#define PKT_APPEND_STATUS_1_LQI_SHIFT 0
+
+__xdata __at (0xdf04) uint8_t RF_PKTCTRL0;
+#define RF_PKTCTRL0_OFF 0x04
+#define RF_PKTCTRL0_WHITE_DATA (1 << 6)
+#define RF_PKTCTRL0_PKT_FORMAT_NORMAL (0 << 4)
+#define RF_PKTCTRL0_PKT_FORMAT_RANDOM (2 << 4)
+#define RF_PKTCTRL0_CRC_EN (1 << 2)
+#define RF_PKTCTRL0_LENGTH_CONFIG_FIXED (0 << 0)
+#define RF_PKTCTRL0_LENGTH_CONFIG_VARIABLE (1 << 0)
+
+__xdata __at (0xdf05) uint8_t RF_ADDR;
+#define RF_ADDR_OFF 0x05
+
+__xdata __at (0xdf06) uint8_t RF_CHANNR;
+#define RF_CHANNR_OFF 0x06
+
+__xdata __at (0xdf07) uint8_t RF_FSCTRL1;
+#define RF_FSCTRL1_OFF 0x07
+
+#define RF_FSCTRL1_FREQ_IF_SHIFT (0)
+
+__xdata __at (0xdf08) uint8_t RF_FSCTRL0;
+#define RF_FSCTRL0_OFF 0x08
+
+#define RF_FSCTRL0_FREQOFF_SHIFT (0)
+
+__xdata __at (0xdf09) uint8_t RF_FREQ2;
+#define RF_FREQ2_OFF 0x09
+
+__xdata __at (0xdf0a) uint8_t RF_FREQ1;
+#define RF_FREQ1_OFF 0x0a
+
+__xdata __at (0xdf0b) uint8_t RF_FREQ0;
+#define RF_FREQ0_OFF 0x0b
+
+__xdata __at (0xdf0c) uint8_t RF_MDMCFG4;
+#define RF_MDMCFG4_OFF 0x0c
+
+#define RF_MDMCFG4_CHANBW_E_SHIFT 6
+#define RF_MDMCFG4_CHANBW_M_SHIFT 4
+#define RF_MDMCFG4_DRATE_E_SHIFT 0
+
+__xdata __at (0xdf0d) uint8_t RF_MDMCFG3;
+#define RF_MDMCFG3_OFF 0x0d
+
+#define RF_MDMCFG3_DRATE_M_SHIFT 0
+
+__xdata __at (0xdf0e) uint8_t RF_MDMCFG2;
+#define RF_MDMCFG2_OFF 0x0e
+
+#define RF_MDMCFG2_DEM_DCFILT_OFF (1 << 7)
+#define RF_MDMCFG2_DEM_DCFILT_ON (0 << 7)
+
+#define RF_MDMCFG2_MOD_FORMAT_MASK (7 << 4)
+#define RF_MDMCFG2_MOD_FORMAT_2_FSK (0 << 4)
+#define RF_MDMCFG2_MOD_FORMAT_GFSK (1 << 4)
+#define RF_MDMCFG2_MOD_FORMAT_ASK_OOK (3 << 4)
+#define RF_MDMCFG2_MOD_FORMAT_MSK (7 << 4)
+
+#define RF_MDMCFG2_MANCHESTER_EN (1 << 3)
+
+#define RF_MDMCFG2_SYNC_MODE_MASK (0x7 << 0)
+#define RF_MDMCFG2_SYNC_MODE_NONE (0x0 << 0)
+#define RF_MDMCFG2_SYNC_MODE_15_16 (0x1 << 0)
+#define RF_MDMCFG2_SYNC_MODE_16_16 (0x2 << 0)
+#define RF_MDMCFG2_SYNC_MODE_30_32 (0x3 << 0)
+#define RF_MDMCFG2_SYNC_MODE_NONE_THRES (0x4 << 0)
+#define RF_MDMCFG2_SYNC_MODE_15_16_THRES (0x5 << 0)
+#define RF_MDMCFG2_SYNC_MODE_16_16_THRES (0x6 << 0)
+#define RF_MDMCFG2_SYNC_MODE_30_32_THRES (0x7 << 0)
+
+__xdata __at (0xdf0f) uint8_t RF_MDMCFG1;
+#define RF_MDMCFG1_OFF 0x0f
+
+#define RF_MDMCFG1_FEC_EN (1 << 7)
+#define RF_MDMCFG1_FEC_DIS (0 << 7)
+
+#define RF_MDMCFG1_NUM_PREAMBLE_MASK (7 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_2 (0 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_3 (1 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_4 (2 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_6 (3 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_8 (4 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_12 (5 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_16 (6 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_24 (7 << 4)
+
+#define RF_MDMCFG1_CHANSPC_E_MASK (3 << 0)
+#define RF_MDMCFG1_CHANSPC_E_SHIFT (0)
+
+__xdata __at (0xdf10) uint8_t RF_MDMCFG0;
+#define RF_MDMCFG0_OFF 0x10
+
+#define RF_MDMCFG0_CHANSPC_M_SHIFT (0)
+
+__xdata __at (0xdf11) uint8_t RF_DEVIATN;
+#define RF_DEVIATN_OFF 0x11
+
+#define RF_DEVIATN_DEVIATION_E_SHIFT 4
+#define RF_DEVIATN_DEVIATION_M_SHIFT 0
+
+__xdata __at (0xdf12) uint8_t RF_MCSM2;
+#define RF_MCSM2_OFF 0x12
+#define RF_MCSM2_RX_TIME_RSSI (1 << 4)
+#define RF_MCSM2_RX_TIME_QUAL (1 << 3)
+#define RF_MCSM2_RX_TIME_MASK (0x7)
+#define RF_MCSM2_RX_TIME_SHIFT 0
+#define RF_MCSM2_RX_TIME_END_OF_PACKET (7)
+
+__xdata __at (0xdf13) uint8_t RF_MCSM1;
+#define RF_MCSM1_OFF 0x13
+#define RF_MCSM1_CCA_MODE_ALWAYS (0 << 4)
+#define RF_MCSM1_CCA_MODE_RSSI_BELOW (1 << 4)
+#define RF_MCSM1_CCA_MODE_UNLESS_RECEIVING (2 << 4)
+#define RF_MCSM1_CCA_MODE_RSSI_BELOW_UNLESS_RECEIVING (3 << 4)
+#define RF_MCSM1_RXOFF_MODE_IDLE (0 << 2)
+#define RF_MCSM1_RXOFF_MODE_FSTXON (1 << 2)
+#define RF_MCSM1_RXOFF_MODE_TX (2 << 2)
+#define RF_MCSM1_RXOFF_MODE_RX (3 << 2)
+#define RF_MCSM1_TXOFF_MODE_IDLE (0 << 0)
+#define RF_MCSM1_TXOFF_MODE_FSTXON (1 << 0)
+#define RF_MCSM1_TXOFF_MODE_TX (2 << 0)
+#define RF_MCSM1_TXOFF_MODE_RX (3 << 0)
+
+__xdata __at (0xdf14) uint8_t RF_MCSM0;
+#define RF_MCSM0_OFF 0x14
+#define RF_MCSM0_FS_AUTOCAL_NEVER (0 << 4)
+#define RF_MCSM0_FS_AUTOCAL_FROM_IDLE (1 << 4)
+#define RF_MCSM0_FS_AUTOCAL_TO_IDLE (2 << 4)
+#define RF_MCSM0_FS_AUTOCAL_TO_IDLE_EVERY_4 (3 << 4)
+#define RF_MCSM0_MAGIC_3 (1 << 3)
+#define RF_MCSM0_MAGIC_2 (1 << 2)
+#define RF_MCSM0_CLOSE_IN_RX_0DB (0 << 0)
+#define RF_MCSM0_CLOSE_IN_RX_6DB (1 << 0)
+#define RF_MCSM0_CLOSE_IN_RX_12DB (2 << 0)
+#define RF_MCSM0_CLOSE_IN_RX_18DB (3 << 0)
+
+__xdata __at (0xdf15) uint8_t RF_FOCCFG;
+#define RF_FOCCFG_OFF 0x15
+#define RF_FOCCFG_FOC_BS_CS_GATE (1 << 5)
+#define RF_FOCCFG_FOC_PRE_K_1K (0 << 3)
+#define RF_FOCCFG_FOC_PRE_K_2K (1 << 3)
+#define RF_FOCCFG_FOC_PRE_K_3K (2 << 3)
+#define RF_FOCCFG_FOC_PRE_K_4K (3 << 3)
+#define RF_FOCCFG_FOC_POST_K_PRE_K (0 << 2)
+#define RF_FOCCFG_FOC_POST_K_PRE_K_OVER_2 (1 << 2)
+#define RF_FOCCFG_FOC_LIMIT_0 (0 << 0)
+#define RF_FOCCFG_FOC_LIMIT_BW_OVER_8 (1 << 0)
+#define RF_FOCCFG_FOC_LIMIT_BW_OVER_4 (2 << 0)
+#define RF_FOCCFG_FOC_LIMIT_BW_OVER_2 (3 << 0)
+
+__xdata __at (0xdf16) uint8_t RF_BSCFG;
+#define RF_BSCFG_OFF 0x16
+#define RF_BSCFG_BS_PRE_K_1K (0 << 6)
+#define RF_BSCFG_BS_PRE_K_2K (1 << 6)
+#define RF_BSCFG_BS_PRE_K_3K (2 << 6)
+#define RF_BSCFG_BS_PRE_K_4K (3 << 6)
+#define RF_BSCFG_BS_PRE_KP_1KP (0 << 4)
+#define RF_BSCFG_BS_PRE_KP_2KP (1 << 4)
+#define RF_BSCFG_BS_PRE_KP_3KP (2 << 4)
+#define RF_BSCFG_BS_PRE_KP_4KP (3 << 4)
+#define RF_BSCFG_BS_POST_KI_PRE_KI (0 << 3)
+#define RF_BSCFG_BS_POST_KI_PRE_KI_OVER_2 (1 << 3)
+#define RF_BSCFG_BS_POST_KP_PRE_KP (0 << 2)
+#define RF_BSCFG_BS_POST_KP_PRE_KP_OVER_2 (1 << 2)
+#define RF_BSCFG_BS_LIMIT_0 (0 << 0)
+#define RF_BSCFG_BS_LIMIT_3_125 (1 << 0)
+#define RF_BSCFG_BS_LIMIT_6_25 (2 << 0)
+#define RF_BSCFG_BS_LIMIT_12_5 (3 << 0)
+
+__xdata __at (0xdf17) uint8_t RF_AGCCTRL2;
+#define RF_AGCCTRL2_OFF 0x17
+
+__xdata __at (0xdf18) uint8_t RF_AGCCTRL1;
+#define RF_AGCCTRL1_OFF 0x18
+
+__xdata __at (0xdf19) uint8_t RF_AGCCTRL0;
+#define RF_AGCCTRL0_OFF 0x19
+
+__xdata __at (0xdf1a) uint8_t RF_FREND1;
+#define RF_FREND1_OFF 0x1a
+
+#define RF_FREND1_LNA_CURRENT_SHIFT 6
+#define RF_FREND1_LNA2MIX_CURRENT_SHIFT 4
+#define RF_FREND1_LODIV_BUF_CURRENT_RX_SHIFT 2
+#define RF_FREND1_MIX_CURRENT_SHIFT 0
+
+__xdata __at (0xdf1b) uint8_t RF_FREND0;
+#define RF_FREND0_OFF 0x1b
+
+#define RF_FREND0_LODIV_BUF_CURRENT_TX_MASK (0x3 << 4)
+#define RF_FREND0_LODIV_BUF_CURRENT_TX_SHIFT 4
+#define RF_FREND0_PA_POWER_MASK (0x7)
+#define RF_FREND0_PA_POWER_SHIFT 0
+
+__xdata __at (0xdf1c) uint8_t RF_FSCAL3;
+#define RF_FSCAL3_OFF 0x1c
+
+__xdata __at (0xdf1d) uint8_t RF_FSCAL2;
+#define RF_FSCAL2_OFF 0x1d
+
+__xdata __at (0xdf1e) uint8_t RF_FSCAL1;
+#define RF_FSCAL1_OFF 0x1e
+
+__xdata __at (0xdf1f) uint8_t RF_FSCAL0;
+#define RF_FSCAL0_OFF 0x1f
+
+__xdata __at (0xdf23) uint8_t RF_TEST2;
+#define RF_TEST2_OFF 0x23
+
+#define RF_TEST2_NORMAL_MAGIC 0x88
+#define RF_TEST2_RX_LOW_DATA_RATE_MAGIC 0x81
+
+__xdata __at (0xdf24) uint8_t RF_TEST1;
+#define RF_TEST1_OFF 0x24
+
+#define RF_TEST1_TX_MAGIC 0x31
+#define RF_TEST1_RX_LOW_DATA_RATE_MAGIC 0x35
+
+__xdata __at (0xdf25) uint8_t RF_TEST0;
+#define RF_TEST0_OFF 0x25
+
+#define RF_TEST0_7_2_MASK (0xfc)
+#define RF_TEST0_VCO_SEL_CAL_EN (1 << 1)
+#define RF_TEST0_0_MASK (1)
+
+/* These are undocumented, and must be computed
+ * using the provided tool.
+ */
+__xdata __at (0xdf27) uint8_t RF_PA_TABLE7;
+#define RF_PA_TABLE7_OFF 0x27
+
+__xdata __at (0xdf28) uint8_t RF_PA_TABLE6;
+#define RF_PA_TABLE6_OFF 0x28
+
+__xdata __at (0xdf29) uint8_t RF_PA_TABLE5;
+#define RF_PA_TABLE5_OFF 0x29
+
+__xdata __at (0xdf2a) uint8_t RF_PA_TABLE4;
+#define RF_PA_TABLE4_OFF 0x2a
+
+__xdata __at (0xdf2b) uint8_t RF_PA_TABLE3;
+#define RF_PA_TABLE3_OFF 0x2b
+
+__xdata __at (0xdf2c) uint8_t RF_PA_TABLE2;
+#define RF_PA_TABLE2_OFF 0x2c
+
+__xdata __at (0xdf2d) uint8_t RF_PA_TABLE1;
+#define RF_PA_TABLE1_OFF 0x2d
+
+__xdata __at (0xdf2e) uint8_t RF_PA_TABLE0;
+#define RF_PA_TABLE0_OFF 0x2e
+
+__xdata __at (0xdf36) uint8_t RF_PARTNUM;
+#define RF_PARTNUM_OFF 0x36
+
+__xdata __at (0xdf37) uint8_t RF_VERSION;
+#define RF_VERSION_OFF 0x37
+
+__xdata __at (0xdf38) uint8_t RF_FREQEST;
+#define RF_FREQEST_OFF 0x38
+
+__xdata __at (0xdf39) uint8_t RF_LQI;
+#define RF_LQI_OFF 0x39
+
+#define RF_LQI_CRC_OK (1 << 7)
+#define RF_LQI_LQI_EST_MASK (0x7f)
+
+__xdata __at (0xdf3a) uint8_t RF_RSSI;
+#define RF_RSSI_OFF 0x3a
+
+__xdata __at (0xdf3b) uint8_t RF_MARCSTATE;
+#define RF_MARCSTATE_OFF 0x3b
+
+#define RF_MARCSTATE_MASK 0x1f
+#define RF_MARCSTATE_SLEEP 0x00
+#define RF_MARCSTATE_IDLE 0x01
+#define RF_MARCSTATE_VCOON_MC 0x03
+#define RF_MARCSTATE_REGON_MC 0x04
+#define RF_MARCSTATE_MANCAL 0x05
+#define RF_MARCSTATE_VCOON 0x06
+#define RF_MARCSTATE_REGON 0x07
+#define RF_MARCSTATE_STARTCAL 0x08
+#define RF_MARCSTATE_BWBOOST 0x09
+#define RF_MARCSTATE_FS_LOCK 0x0a
+#define RF_MARCSTATE_IFADCON 0x0b
+#define RF_MARCSTATE_ENDCAL 0x0c
+#define RF_MARCSTATE_RX 0x0d
+#define RF_MARCSTATE_RX_END 0x0e
+#define RF_MARCSTATE_RX_RST 0x0f
+#define RF_MARCSTATE_TXRX_SWITCH 0x10
+#define RF_MARCSTATE_RX_OVERFLOW 0x11
+#define RF_MARCSTATE_FSTXON 0x12
+#define RF_MARCSTATE_TX 0x13
+#define RF_MARCSTATE_TX_END 0x14
+#define RF_MARCSTATE_RXTX_SWITCH 0x15
+#define RF_MARCSTATE_TX_UNDERFLOW 0x16
+
+
+__xdata __at (0xdf3c) uint8_t RF_PKTSTATUS;
+#define RF_PKTSTATUS_OFF 0x3c
+
+#define RF_PKTSTATUS_CRC_OK (1 << 7)
+#define RF_PKTSTATUS_CS (1 << 6)
+#define RF_PKTSTATUS_PQT_REACHED (1 << 5)
+#define RF_PKTSTATUS_CCA (1 << 4)
+#define RF_PKTSTATUS_SFD (1 << 3)
+
+__xdata __at (0xdf3d) uint8_t RF_VCO_VC_DAC;
+#define RF_VCO_VC_DAC_OFF 0x3d
+
+/* AES engine */
+
+__sfr at 0xB1 ENCDI;
+__sfr at 0xB2 ENCDO;
+__xdata at (0xDFB1) volatile uint8_t ENCDIXADDR;
+__xdata at (0xDFB2) volatile uint8_t ENCDOXADDR;
+
+__sfr at 0xB3 ENCCCS;
+
+#define ENCCCS_MODE_CBC (0 << 4)
+#define ENCCCS_MODE_CFB (1 << 4)
+#define ENCCCS_MODE_OFB (2 << 4)
+#define ENCCCS_MODE_CTR (3 << 4)
+#define ENCCCS_MODE_ECB (4 << 4)
+#define ENCCCS_MODE_CBC_MAC (5 << 4)
+#define ENCCCS_RDY (1 << 3)
+#define ENCCCS_CMD_ENCRYPT (0 << 1)
+#define ENCCCS_CMD_DECRYPT (1 << 1)
+#define ENCCCS_CMD_LOAD_KEY (2 << 1)
+#define ENCCCS_CMD_LOAD_IV (3 << 1)
+#define ENCCCS_START (1 << 0)
+
+#endif