extern const uint8_t ao_fec_whiten_table[];
+#if AO_FEC_DEBUG
void
-ao_fec_dump_bytes(uint8_t *bytes, uint16_t len, char *name);
+ao_fec_dump_bytes(const uint8_t *bytes, uint16_t len, const char *name);
+#endif
+
+static uint16_t inline
+ao_fec_crc_byte(uint8_t byte, uint16_t crc)
+{
+ uint8_t bit;
+
+ for (bit = 0; bit < 8; bit++) {
+ if (((crc & 0x8000) >> 8) ^ (byte & 0x80))
+ crc = (crc << 1) ^ 0x8005;
+ else
+ crc = (crc << 1);
+ byte <<= 1;
+ }
+ return crc;
+}
uint16_t
-ao_fec_crc(uint8_t *bytes, uint8_t len);
+ao_fec_crc(const uint8_t *bytes, uint8_t len);
/*
* 'len' is the length of the original data; 'bytes'
* two after 'len' must be the received crc
*/
uint8_t
-ao_fec_check_crc(uint8_t *bytes, uint8_t len);
-
-/*
- * Append CRC and terminator bytes, returns resulting length.
- * 'out' must be at least len + AO_FEC_PREPARE_EXTRA bytes long
- */
-uint8_t
-ao_fec_prepare(uint8_t *in, uint8_t len, uint8_t *out);
-
-/*
- * Whiten data using the cc1111 PN9 sequence. 'out'
- * must be 'len' bytes long. 'out' and 'in' can be
- * the same array
- */
-void
-ao_fec_whiten(uint8_t *in, uint8_t len, uint8_t *out);
+ao_fec_check_crc(const uint8_t *bytes, uint8_t len);
/*
- * Encode and interleave data. 'out' must be len*2 bytes long
+ * Compute CRC, whiten, convolve and interleave data. 'out' must be (len + 4) * 2 bytes long
*/
uint8_t
-ao_fec_encode(uint8_t *in, uint8_t len, uint8_t *out);
+ao_fec_encode(const uint8_t *in, uint8_t len, uint8_t *out);
/*
* Decode data. 'in' is one byte per bit, soft decision
* 'out' must be len/8 bytes long
*/
-#define AO_FEC_DECODE_BLOCK (8 * 32) /* callback must return multiples of this many bits */
+#define AO_FEC_DECODE_BLOCK (32) /* callback must return multiples of this many bits */
uint8_t
-ao_fec_decode(uint8_t *in, uint16_t in_len, uint8_t *out, uint8_t out_len, uint16_t (*callback)());
+ao_fec_decode(const uint8_t *in, uint16_t in_len, uint8_t *out, uint8_t out_len, uint16_t (*callback)());
/*
* Interleave data packed in bytes. 'out' must be 'len' bytes long.
#include <ao_fec.h>
#include <stdio.h>
+#ifdef MEGAMETRUM
+#include <ao.h>
+#endif
+
+#if AO_PROFILE
+#include <ao_profile.h>
+
+uint32_t ao_fec_decode_start, ao_fec_decode_end;
+#endif
+
/*
* byte order repeats through 3 2 1 0
*
* 18/19 10/11 08/09 00/01
*/
+static const uint8_t ao_interleave_order[] = {
+ 0x1e, 0x16, 0x0e, 0x06,
+ 0x1c, 0x14, 0x0c, 0x04,
+ 0x1a, 0x12, 0x0a, 0x02,
+ 0x18, 0x10, 0x08, 0x00
+};
+
static inline uint16_t ao_interleave_index(uint16_t i) {
- uint8_t l = i & 0x1e;
- uint16_t h = i & ~0x1e;
- uint8_t o = 0x1e ^ (((l >> 2) & 0x6) | ((l << 2) & 0x18));
- return h | o;
+ return (i & ~0x1e) | ao_interleave_order[(i & 0x1e) >> 1];
}
-struct ao_soft_sym {
- uint8_t a, b;
-};
-
#define NUM_STATE 8
#define NUM_HIST 8
-#define MOD_HIST(b) ((b) & 7)
-
-#define V_0 0xc0
-#define V_1 0x40
-
-static const struct ao_soft_sym ao_fec_decode_table[NUM_STATE][2] = {
-/* next 0 1 state */
- { { V_0, V_0 }, { V_1, V_1 } } , /* 000 */
- { { V_0, V_1 }, { V_1, V_0 } }, /* 001 */
- { { V_1, V_1 }, { V_0, V_0 } }, /* 010 */
- { { V_1, V_0 }, { V_0, V_1 } }, /* 011 */
- { { V_1, V_1 }, { V_0, V_0 } }, /* 100 */
- { { V_1, V_0 }, { V_0, V_1 } }, /* 101 */
- { { V_0, V_0 }, { V_1, V_1 } }, /* 110 */
- { { V_0, V_1 }, { V_1, V_0 } } /* 111 */
+
+#define V_0 0xff
+#define V_1 0x00
+
+/*
+ * These are just the 'zero' states; the 'one' states mirror them
+ */
+static const uint8_t ao_fec_decode_table[NUM_STATE*2] = {
+ V_0, V_0, /* 000 */
+ V_0, V_1, /* 001 */
+ V_1, V_1, /* 010 */
+ V_1, V_0, /* 011 */
+ V_1, V_1, /* 100 */
+ V_1, V_0, /* 101 */
+ V_0, V_0, /* 110 */
+ V_0, V_1 /* 111 */
};
static inline uint8_t
return ((state << 1) | bit) & 0x7;
}
-static inline uint16_t ao_abs(int16_t x) { return x < 0 ? -x : x; }
-
-static inline uint16_t
-ao_cost(struct ao_soft_sym a, struct ao_soft_sym b)
-{
- return ao_abs(a.a - b.a) + ao_abs(a.b - b.b);
-}
-
/*
* 'in' is 8-bits per symbol soft decision data
* 'len' is input byte length. 'out' must be
*/
uint8_t
-ao_fec_decode(uint8_t *in, uint16_t len, uint8_t *out, uint8_t out_len, uint16_t (*callback)())
+ao_fec_decode(const uint8_t *in, uint16_t len, uint8_t *out, uint8_t out_len, uint16_t (*callback)())
{
- static uint16_t cost[2][NUM_STATE]; /* path cost */
+ static uint32_t cost[2][NUM_STATE]; /* path cost */
static uint16_t bits[2][NUM_STATE]; /* save bits to quickly output them */
+
uint16_t i; /* input byte index */
uint16_t b; /* encoded symbol index (bytes/2) */
uint16_t o; /* output bit index */
uint8_t p; /* previous cost/bits index */
uint8_t n; /* next cost/bits index */
uint8_t state; /* state index */
- uint8_t bit; /* original encoded bit index */
const uint8_t *whiten = ao_fec_whiten_table;
uint16_t interleave; /* input byte array index */
- struct ao_soft_sym s; /* input symbol pair */
+ uint8_t s0, s1;
uint16_t avail;
+ uint16_t crc = AO_FEC_CRC_INIT;
+#if AO_PROFILE
+ uint32_t start_tick;
+#endif
p = 0;
for (state = 0; state < NUM_STATE; state++) {
- cost[0][state] = 0xffff;
+ cost[0][state] = 0x7fffffff;
bits[0][state] = 0;
}
cost[0][0] = 0;
else
avail = len;
+#if AO_PROFILE
+ if (!avail) {
+ avail = callback();
+ if (!avail)
+ return 0;
+ }
+ start_tick = ao_profile_tick();
+#endif
o = 0;
for (i = 0; i < len; i += 2) {
b = i/2;
if (!avail) {
avail = callback();
if (!avail)
- break;
+ return 0;
}
/* Fetch one pair of input bytes, de-interleaving
* the input.
*/
interleave = ao_interleave_index(i);
- s.a = in[interleave];
- s.b = in[interleave+1];
+ s0 = in[interleave];
+ s1 = in[interleave+1];
+
+ avail -= 2;
/* Reset next costs to 'impossibly high' values so that
* the first path through this state is cheaper than this
*/
for (state = 0; state < NUM_STATE; state++)
- cost[n][state] = 0xffff;
+ cost[n][state] = 0x7fffffff;
/* Compute path costs and accumulate output bit path
* for each state and encoded bit value
*/
for (state = 0; state < NUM_STATE; state++) {
- for (bit = 0; bit < 2; bit++) {
- int bit_cost = cost[p][state] + ao_cost(s, ao_fec_decode_table[state][bit]);
- uint8_t bit_state = ao_next_state(state, bit);
-
- /* Only track the minimal cost to reach
- * this state; the best path can never
- * go through the higher cost paths as
- * total path cost is cumulative
- */
- if (bit_cost < cost[n][bit_state]) {
- cost[n][bit_state] = bit_cost;
- bits[n][bit_state] = (bits[p][state] << 1) | (state & 1);
+ uint32_t bitcost = ((uint32_t) (s0 ^ ao_fec_decode_table[(state<<1)]) +
+ (uint32_t) (s1 ^ ao_fec_decode_table[(state<<1)+1]));
+ {
+ uint32_t cost0 = cost[p][state] + bitcost;
+ uint8_t state0 = ao_next_state(state, 0);
+
+ if (cost0 < cost[n][state0]) {
+ cost[n][state0] = cost0;
+ bits[n][state0] = (bits[p][state] << 1) | (state & 1);
+ }
+ }
+ {
+ uint32_t cost1 = cost[p][state] + 510 - bitcost;
+ uint8_t state1 = ao_next_state(state, 1);
+
+ if (cost1 < cost[n][state1]) {
+ cost[n][state1] = cost1;
+ bits[n][state1] = (bits[p][state] << 1) | (state & 1);
}
}
}
#if 0
- printf ("bit %3d symbol %2x %2x:", i/2, s.a, s.b);
+ printf ("bit %3d symbol %2x %2x:", i/2, s0, s1);
for (state = 0; state < NUM_STATE; state++) {
printf (" %5d(%04x)", cost[n][state], bits[n][state]);
}
* it will be seven.
*/
int8_t dist = b - (o + 8); /* distance to last ready-for-writing bit */
- uint16_t min_cost; /* lowest cost */
+ uint32_t min_cost; /* lowest cost */
uint8_t min_state; /* lowest cost state */
/* Find the best fit at the current point
i/2, min_cost, o + 8, min_state, (bits[p][min_state] >> dist) & 0xff, *whiten);
#endif
if (out_len) {
- *out++ = (bits[p][min_state] >> dist) ^ *whiten++;
+ uint8_t byte = (bits[p][min_state] >> dist) ^ *whiten++;
+
+ if (out_len > 2) {
+ crc = ao_fec_crc_byte(byte, crc);
+ *out++ = byte;
+ } else {
+ *out++ = byte ^ (crc >> 8);
+ crc <<= 8;
+ }
--out_len;
}
o += 8;
}
}
+#if AO_PROFILE
+ ao_fec_decode_start = start_tick;
+ ao_fec_decode_end = ao_profile_tick();
+#endif
return len/16;
}
#include <ao_fec.h>
#include <stdio.h>
+#if AO_FEC_DEBUG
void
-ao_fec_dump_bytes(uint8_t *bytes, uint16_t len, char *name)
+ao_fec_dump_bytes(const uint8_t *bytes, uint16_t len, const char *name)
{
uint16_t i;
}
printf ("\n");
}
-
-static uint16_t inline
-crc_byte(uint8_t byte, uint16_t crc)
-{
- uint8_t bit;
-
- for (bit = 0; bit < 8; bit++) {
- if (((crc & 0x8000) >> 8) ^ (byte & 0x80))
- crc = (crc << 1) ^ 0x8005;
- else
- crc = (crc << 1);
- byte <<= 1;
- }
- return crc;
-}
+#endif
uint16_t
-ao_fec_crc(uint8_t *bytes, uint8_t len)
+ao_fec_crc(const uint8_t *bytes, uint8_t len)
{
uint16_t crc = AO_FEC_CRC_INIT;
while (len--)
- crc = crc_byte(*bytes++, crc);
+ crc = ao_fec_crc_byte(*bytes++, crc);
return crc;
}
*/
uint8_t
-ao_fec_check_crc(uint8_t *bytes, uint8_t len)
+ao_fec_check_crc(const uint8_t *bytes, uint8_t len)
{
uint16_t computed_crc = ao_fec_crc(bytes, len);
uint16_t received_crc = (bytes[len] << 8) | (bytes[len+1]);
return computed_crc == received_crc;
}
-uint8_t
-ao_fec_prepare(uint8_t *in, uint8_t len, uint8_t *extra)
+/*
+ * Compute CRC and trellis-terminator/interleave-pad bytes
+ */
+static uint8_t
+ao_fec_prepare(const uint8_t *in, uint8_t len, uint8_t *extra)
{
uint16_t crc = ao_fec_crc (in, len);
uint8_t i = 0;
#include "ao_whiten.h"
};
-#if 0
-void
-ao_fec_whiten(uint8_t *in, uint8_t len, uint8_t *out)
-{
- const uint8_t *w = ao_fec_whiten_table;
-
- while (len--)
- *out++ = *in++ ^ *w++;
-}
-
-/*
- * Unused as interleaving is now built in to ao_fec_encode
- */
-
-static void
-ao_fec_interleave(uint8_t *d, uint8_t len)
-{
- uint8_t i, j;
-
- for (i = 0; i < len; i += 4) {
- uint32_t interleaved = 0;
-
- for (j = 0; j < 4 * 4; j++) {
- interleaved <<= 2;
- interleaved |= (d[i + (~j & 0x3)] >> (2 * ((j & 0xc) >> 2))) & 0x03;
- }
- d[i+0] = interleaved >> 24;
- d[i+1] = interleaved >> 16;
- d[i+2] = interleaved >> 8;
- d[i+3] = interleaved;
- }
-}
-#endif
-
static const uint8_t ao_fec_encode_table[16] = {
/* next 0 1 state */
0, 3, /* 000 */
};
uint8_t
-ao_fec_encode(uint8_t *in, uint8_t len, uint8_t *out)
+ao_fec_encode(const uint8_t *in, uint8_t len, uint8_t *out)
{
uint8_t extra[AO_FEC_PREPARE_EXTRA];
uint8_t extra_len;
uint8_t ao_radio_wake;
uint8_t ao_radio_mutex;
uint8_t ao_radio_abort;
+uint8_t ao_radio_in_recv;
-#define CC1120_DEBUG 1
+#define CC1120_DEBUG AO_FEC_DEBUG
#define CC1120_TRACE 0
#if CC1120_TRACE
#define fec_dump_bytes(b,l,n)
#endif
-uint32_t ao_radio_cal = 0x6ca333;
+const uint32_t ao_radio_cal = 0x6ca333;
#define FOSC 32000000
return status;
}
+static uint8_t
+ao_radio_tx_fifo_space(void)
+{
+ return CC1120_FIFO_SIZE - ao_radio_reg_read(CC1120_NUM_TXBYTES);
+}
+
static uint8_t
ao_radio_status(void)
{
#define ao_radio_rdf_value 0x55
+static uint8_t
+ao_radio_marc_status(void)
+{
+ return ao_radio_reg_read(CC1120_MARC_STATUS1);
+}
+
+static void
+ao_radio_tx_isr(void)
+{
+ ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
+ ao_radio_wake = 1;
+ ao_wakeup(&ao_radio_wake);
+}
+
+static void
+ao_radio_start_tx(void)
+{
+ ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_tx_isr);
+ ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
+ ao_radio_strobe(CC1120_STX);
+}
+
+static void
+ao_radio_idle(void)
+{
+ for (;;) {
+ uint8_t state = ao_radio_strobe(CC1120_SIDLE);
+ if ((state >> CC1120_STATUS_STATE) == CC1120_STATUS_STATE_IDLE)
+ break;
+ }
+}
+
+/*
+ * Packet deviation is 20.5kHz
+ *
+ * fdev = fosc >> 24 * (256 + dev_m) << dev_e
+ *
+ * 32e6Hz / (2 ** 24) * (256 + 80) * (2 ** 5) = 20508Hz
+ */
+
+#define PACKET_DEV_E 5
+#define PACKET_DEV_M 80
+
+/*
+ * For our packet data, set the symbol rate to 38360 Baud
+ *
+ * (2**20 + DATARATE_M) * 2 ** DATARATE_E
+ * Rdata = -------------------------------------- * fosc
+ * 2 ** 39
+ *
+ *
+ * DATARATE_M = 239914
+ * DATARATE_E = 9
+ */
+#define PACKET_DRATE_E 9
+#define PACKET_DRATE_M 239914
+
+static const uint16_t packet_setup[] = {
+ CC1120_DEVIATION_M, PACKET_DEV_M,
+ CC1120_MODCFG_DEV_E, ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
+ (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
+ (PACKET_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
+ CC1120_DRATE2, ((PACKET_DRATE_E << CC1120_DRATE2_DATARATE_E) |
+ (((PACKET_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
+ CC1120_DRATE1, ((PACKET_DRATE_M >> 8) & 0xff),
+ CC1120_DRATE0, ((PACKET_DRATE_M >> 0) & 0xff),
+ CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
+ (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
+ CC1120_PKT_CFG1, ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
+ (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
+ (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
+ (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
+ CC1120_PKT_CFG0, ((0 << CC1120_PKT_CFG0_RESERVED7) |
+ (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
+ (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
+ (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
+ (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
+};
+
+static const uint16_t packet_tx_setup[] = {
+ CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
+ (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
+ CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG,
+};
+
+static const uint16_t packet_rx_setup[] = {
+ CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
+ (CC1120_PKT_CFG2_PKT_FORMAT_SYNCHRONOUS_SERIAL << CC1120_PKT_CFG2_PKT_FORMAT)),
+ CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT,
+};
+
/*
* RDF deviation is 5kHz
*
(0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
};
-static uint8_t
-ao_radio_marc_status(void)
-{
- return ao_radio_reg_read(CC1120_MARC_STATUS1);
-}
+static uint8_t ao_radio_mode;
-static uint8_t
-ao_radio_tx_done(void)
-{
- return ao_radio_marc_status() == CC1120_MARC_STATUS1_TX_FINISHED;
-}
+#define AO_RADIO_MODE_BITS_PACKET 1
+#define AO_RADIO_MODE_BITS_PACKET_TX 2
+#define AO_RADIO_MODE_BITS_TX_BUF 4
+#define AO_RADIO_MODE_BITS_TX_FINISH 8
+#define AO_RADIO_MODE_BITS_PACKET_RX 16
+#define AO_RADIO_MODE_BITS_RDF 32
-static uint8_t
-ao_radio_rx_done(void)
+#define AO_RADIO_MODE_NONE 0
+#define AO_RADIO_MODE_PACKET_TX_BUF (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_BUF)
+#define AO_RADIO_MODE_PACKET_TX_FINISH (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_FINISH)
+#define AO_RADIO_MODE_PACKET_RX (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_RX)
+#define AO_RADIO_MODE_RDF (AO_RADIO_MODE_BITS_RDF | AO_RADIO_MODE_BITS_TX_FINISH)
+
+static void
+ao_radio_set_mode(uint8_t new_mode)
{
- return ao_radio_marc_status() == CC1120_MARC_STATUS1_RX_FINISHED;
+ uint8_t changes;
+ int i;
+
+ if (new_mode == ao_radio_mode)
+ return;
+
+ changes = new_mode & (~ao_radio_mode);
+ if (changes & AO_RADIO_MODE_BITS_PACKET)
+ for (i = 0; i < sizeof (packet_setup) / sizeof (packet_setup[0]); i += 2)
+ ao_radio_reg_write(packet_setup[i], packet_setup[i+1]);
+
+ if (changes & AO_RADIO_MODE_BITS_PACKET_TX)
+ for (i = 0; i < sizeof (packet_tx_setup) / sizeof (packet_tx_setup[0]); i += 2)
+ ao_radio_reg_write(packet_tx_setup[i], packet_tx_setup[i+1]);
+
+ if (changes & AO_RADIO_MODE_BITS_TX_BUF)
+ ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_TXFIFO_THR);
+
+ if (changes & AO_RADIO_MODE_BITS_TX_FINISH)
+ ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG);
+
+ if (changes & AO_RADIO_MODE_BITS_PACKET_RX)
+ for (i = 0; i < sizeof (packet_rx_setup) / sizeof (packet_rx_setup[0]); i += 2)
+ ao_radio_reg_write(packet_rx_setup[i], packet_rx_setup[i+1]);
+
+ if (changes & AO_RADIO_MODE_BITS_RDF)
+ for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
+ ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]);
+ ao_radio_mode = new_mode;
}
+static const uint16_t radio_setup[] = {
+#include "ao_cc1120_CC1120.h"
+};
+
+static uint8_t ao_radio_configured = 0;
+
static void
-ao_radio_tx_isr(void)
+ao_radio_setup(void)
{
- ao_exti_disable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
- ao_radio_wake = 1;
- ao_wakeup(&ao_radio_wake);
+ int i;
+
+ ao_radio_strobe(CC1120_SRES);
+
+ for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
+ ao_radio_reg_write(radio_setup[i], radio_setup[i+1]);
+
+ ao_radio_mode = 0;
+
+ ao_config_get();
+
+ ao_radio_configured = 1;
}
static void
-ao_radio_start_tx(void)
+ao_radio_get(uint8_t len)
{
- ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG);
- ao_exti_set_callback(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_tx_isr);
- ao_exti_enable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
- ao_radio_strobe(CC1120_STX);
+ static uint32_t last_radio_setting;
+ static uint8_t last_len;
+
+ ao_mutex_get(&ao_radio_mutex);
+ if (!ao_radio_configured)
+ ao_radio_setup();
+ if (ao_config.radio_setting != last_radio_setting) {
+ ao_radio_reg_write(CC1120_FREQ2, ao_config.radio_setting >> 16);
+ ao_radio_reg_write(CC1120_FREQ1, ao_config.radio_setting >> 8);
+ ao_radio_reg_write(CC1120_FREQ0, ao_config.radio_setting);
+ last_radio_setting = ao_config.radio_setting;
+ }
+ if (len != last_len) {
+ ao_radio_reg_write(CC1120_PKT_LEN, len);
+ last_len = len;
+ }
}
+#define ao_radio_put() ao_mutex_put(&ao_radio_mutex)
+
void
ao_radio_rdf(uint8_t len)
{
int i;
+ ao_radio_abort = 0;
ao_radio_get(len);
+
+ ao_radio_set_mode(AO_RADIO_MODE_RDF);
ao_radio_wake = 0;
- for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
- ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]);
ao_radio_fifo_write_fixed(ao_radio_rdf_value, len);
cli();
while (!ao_radio_wake && !ao_radio_abort)
ao_sleep(&ao_radio_wake);
-
sei();
- if (!ao_radio_tx_done())
+ if (!ao_radio_wake)
ao_radio_idle();
- ao_radio_set_packet();
ao_radio_put();
}
}
void
-ao_radio_send(void *d, uint8_t size)
+ao_radio_send(const void *d, uint8_t size)
{
uint8_t marc_status;
- uint8_t encode[size + AO_FEC_PREPARE_EXTRA];
+ static uint8_t encode[256];
+ uint8_t *e = encode;
uint8_t encode_len;
+ uint8_t this_len;
+ uint8_t started = 0;
+ uint8_t fifo_space;
encode_len = ao_fec_encode(d, size, encode);
ao_radio_get(encode_len);
- ao_radio_fifo_write(encode, encode_len);
- ao_radio_wake = 0;
+ started = 0;
+ fifo_space = CC1120_FIFO_SIZE;
+ while (encode_len) {
+ this_len = encode_len;
- ao_radio_start_tx();
+ if (this_len > fifo_space) {
+ this_len = fifo_space;
+ ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_BUF);
+ } else {
+ ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_FINISH);
+ }
- cli();
- while (!ao_radio_wake && !ao_radio_abort)
- ao_sleep(&ao_radio_wake);
- sei();
- if (!ao_radio_tx_done())
- ao_radio_idle();
+ ao_radio_fifo_write(e, this_len);
+ e += this_len;
+ encode_len -= this_len;
+
+ if (!started) {
+ ao_radio_start_tx();
+ started = 1;
+ } else {
+ ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
+ }
+
+ do {
+ ao_radio_wake = 0;
+ cli();
+ while (!ao_radio_wake)
+ ao_sleep(&ao_radio_wake);
+ sei();
+ if (!encode_len)
+ break;
+ fifo_space = ao_radio_tx_fifo_space();
+ } while (!fifo_space);
+ }
ao_radio_put();
}
#define AO_RADIO_MAX_RECV 90
-static uint8_t rx_data[2048];
-static uint16_t rx_data_count;
-static uint16_t rx_data_consumed;
-static uint16_t rx_data_cur;
-static uint8_t rx_ignore;
+uint8_t rx_data[(AO_RADIO_MAX_RECV + 4) * 2 * 8];
+uint16_t rx_data_count;
+uint16_t rx_data_consumed;
+uint16_t rx_data_cur;
+uint8_t rx_ignore;
+uint8_t rx_waiting;
+
+#if AO_PROFILE
+static uint32_t rx_start_tick, rx_packet_tick, rx_done_tick, rx_last_done_tick;
+
+uint32_t ao_rx_start_tick, ao_rx_packet_tick, ao_rx_done_tick, ao_rx_last_done_tick;
+
+#include <ao_profile.h>
+#endif
static void
ao_radio_rx_isr(void)
{
+ uint8_t d;
+
+ d = stm_spi2.dr;
+ stm_spi2.dr = 0;
if (rx_ignore == 0) {
- rx_data[rx_data_cur++] = stm_spi2.dr;
if (rx_data_cur >= rx_data_count)
- ao_exti_disable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
- if (rx_data_cur - rx_data_consumed >= AO_FEC_DECODE_BLOCK) {
+ ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
+ else
+ rx_data[rx_data_cur++] = d;
+ if (rx_waiting && rx_data_cur - rx_data_consumed >= AO_FEC_DECODE_BLOCK) {
+#if AO_PROFILE
+ if (rx_data_consumed == 0)
+ rx_packet_tick = ao_profile_tick();
+#endif
+ rx_waiting = 0;
ao_wakeup(&ao_radio_wake);
}
} else {
- (void) stm_spi2.dr;
--rx_ignore;
}
- stm_spi2.dr = 0x00;
}
static uint16_t
ao_radio_rx_wait(void)
{
cli();
+ rx_waiting = 1;
while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK &&
- !ao_radio_abort)
+ !ao_radio_abort) {
ao_sleep(&ao_radio_wake);
+ }
+ rx_waiting = 0;
sei();
if (ao_radio_abort)
return 0;
+ rx_data_consumed += AO_FEC_DECODE_BLOCK;
return AO_FEC_DECODE_BLOCK;
}
uint8_t len;
uint16_t i;
uint8_t rssi;
+ uint8_t ret;
+ static int been_here = 0;
size -= 2; /* status bytes */
+ if (size > AO_RADIO_MAX_RECV) {
+ ao_delay(AO_SEC_TO_TICKS(1));
+ return 0;
+ }
+#if AO_PROFILE
+ rx_start_tick = ao_profile_tick();
+#endif
len = size + 2; /* CRC bytes */
len += 1 + ~(len & 1); /* 1 or two pad bytes */
len *= 2; /* 1/2 rate convolution */
rx_data_consumed = 0;
rx_ignore = 2;
- printf ("len %d rx_data_count %d\n", len, rx_data_count);
-
+ ao_radio_abort = 0;
+ ao_radio_in_recv = 1;
/* configure interrupt pin */
ao_radio_get(len);
- ao_radio_wake = 0;
- ao_radio_abort = 0;
-
- ao_radio_reg_write(CC1120_PKT_CFG2,
- (CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
- (CC1120_PKT_CFG2_PKT_FORMAT_SYNCHRONOUS_SERIAL << CC1120_PKT_CFG2_PKT_FORMAT));
+ ao_radio_set_mode(AO_RADIO_MODE_PACKET_RX);
- ao_radio_reg_write(CC1120_EXT_CTRL, 0);
-
- ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT);
+ ao_radio_wake = 0;
stm_spi2.cr2 = 0;
/* clear any RXNE */
(void) stm_spi2.dr;
- ao_exti_set_callback(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr);
- ao_exti_enable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
+ ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr);
+ ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
ao_radio_strobe(CC1120_SRX);
ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
- ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait);
+ ret = ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait);
ao_radio_burst_read_stop();
+ ao_radio_strobe(CC1120_SIDLE);
+
/* Convert from 'real' rssi to cc1111-style values */
rssi = (((int8_t) ao_radio_reg_read(CC1120_RSSI1)) + 74) * 2;
- ao_radio_strobe(CC1120_SIDLE);
-
ao_radio_put();
/* Construct final packet */
- ao_fec_decode(rx_data, rx_data_cur, d, size + 2, 0);
-
- if (ao_fec_check_crc(d, size))
+ if (ret && ((uint8_t *) d)[size] == 0 && ((uint8_t *)d)[size+1] == 0)
((uint8_t *) d)[size + 1] = 0x80;
else
((uint8_t *) d)[size + 1] = 0x00;
((uint8_t *) d)[size] = (uint8_t) rssi;
- return 1;
-}
-
-/*
- * Packet deviation is 20.5kHz
- *
- * fdev = fosc >> 24 * (256 + dev_m) << dev_e
- *
- * 32e6Hz / (2 ** 24) * (256 + 80) * (2 ** 5) = 20508Hz
- */
-
-#define PACKET_DEV_E 5
-#define PACKET_DEV_M 80
-
-/*
- * For our packet data, set the symbol rate to 38360 Baud
- *
- * (2**20 + DATARATE_M) * 2 ** DATARATE_E
- * Rdata = -------------------------------------- * fosc
- * 2 ** 39
- *
- *
- * DATARATE_M = 239914
- * DATARATE_E = 9
- */
-#define PACKET_DRATE_E 9
-#define PACKET_DRATE_M 239914
+ ao_radio_in_recv = 0;
-static const uint16_t packet_setup[] = {
- CC1120_DEVIATION_M, PACKET_DEV_M,
- CC1120_MODCFG_DEV_E, ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
- (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
- (PACKET_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
- CC1120_DRATE2, ((PACKET_DRATE_E << CC1120_DRATE2_DATARATE_E) |
- (((PACKET_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
- CC1120_DRATE1, ((PACKET_DRATE_M >> 8) & 0xff),
- CC1120_DRATE0, ((PACKET_DRATE_M >> 0) & 0xff),
- CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
- (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
- CC1120_PKT_CFG1, ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
- (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
- (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
- (1 << CC1120_PKT_CFG1_APPEND_STATUS)),
- CC1120_PKT_CFG0, ((0 << CC1120_PKT_CFG0_RESERVED7) |
- (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
- (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
- (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
- (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
-};
-
-void
-ao_radio_set_packet(void)
-{
- int i;
-
- for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
- ao_radio_reg_write(packet_setup[i], packet_setup[i+1]);
-}
-
-void
-ao_radio_idle(void)
-{
- for (;;) {
- uint8_t state = ao_radio_strobe(CC1120_SIDLE);
- if ((state >> CC1120_STATUS_STATE) == CC1120_STATUS_STATE_IDLE)
- break;
- }
- ao_radio_strobe(CC1120_SFTX);
- ao_radio_strobe(CC1120_SFRX);
-}
-
-static const uint16_t radio_setup[] = {
-#include "ao_cc1120_CC1120.h"
-};
-
-static uint8_t ao_radio_configured = 0;
-
-
-static void
-ao_radio_setup(void)
-{
- int i;
-
- ao_radio_strobe(CC1120_SRES);
-
- for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
- ao_radio_reg_write(radio_setup[i], radio_setup[i+1]);
+ if (ao_radio_abort)
+ ao_delay(1);
- ao_radio_set_packet();
+#if AO_PROFILE
+ rx_last_done_tick = rx_done_tick;
+ rx_done_tick = ao_profile_tick();
- ao_config_get();
+ ao_rx_start_tick = rx_start_tick;
+ ao_rx_packet_tick = rx_packet_tick;
+ ao_rx_done_tick = rx_done_tick;
+ ao_rx_last_done_tick = rx_last_done_tick;
+#endif
- ao_radio_configured = 1;
+ return ret;
}
-void
-ao_radio_get(uint8_t len)
-{
- ao_mutex_get(&ao_radio_mutex);
- if (!ao_radio_configured)
- ao_radio_setup();
- ao_radio_reg_write(CC1120_FREQ2, ao_config.radio_setting >> 16);
- ao_radio_reg_write(CC1120_FREQ1, ao_config.radio_setting >> 8);
- ao_radio_reg_write(CC1120_FREQ0, ao_config.radio_setting);
- ao_radio_reg_write(CC1120_PKT_LEN, len);
-}
#if CC1120_DEBUG
static char *cc1120_state_name[] = {
}
static void ao_radio_packet(void) {
- static uint8_t packet[] = {
+ static const uint8_t packet[] = {
#if 1
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
void
ao_radio_test_recv()
{
- ao_radio_recv(0, 34);
+ uint8_t bytes[34];
+ uint8_t b;
+
+ if (ao_radio_recv(bytes, 34)) {
+ if (bytes[33] & 0x80)
+ printf ("CRC OK");
+ else
+ printf ("CRC BAD");
+ printf (" RSSI %d", (int16_t) ((int8_t) bytes[32] >> 1) - 74);
+ for (b = 0; b < 32; b++)
+ printf (" %02x", bytes[b]);
+ printf ("\n");
+ }
}
#endif
ao_radio_configured = 0;
ao_spi_init_cs (AO_CC1120_SPI_CS_PORT, (1 << AO_CC1120_SPI_CS_PIN));
- AO_CC1120_SPI_CS_PORT.bsrr = ((uint32_t) (1 << AO_CC1120_SPI_CS_PIN));
+ AO_CC1120_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC1120_SPI_CS_PIN));
for (i = 0; i < 10000; i++) {
- if ((SPI_2_GPIO.idr & (1 << SPI_2_MISO)) == 0)
+ if ((SPI_2_GPIO->idr & (1 << SPI_2_MISO)) == 0)
break;
}
- AO_CC1120_SPI_CS_PORT.bsrr = (1 << AO_CC1120_SPI_CS_PIN);
+ AO_CC1120_SPI_CS_PORT->bsrr = (1 << AO_CC1120_SPI_CS_PIN);
if (i == 10000)
ao_panic(AO_PANIC_SELF_TEST);
/* Enable the EXTI interrupt for the appropriate pin */
ao_enable_port(AO_CC1120_INT_PORT);
- ao_exti_setup(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, AO_EXTI_MODE_FALLING, ao_radio_tx_isr);
+ ao_exti_setup(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
+ AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
+ ao_radio_tx_isr);
ao_cmd_register(&ao_radio_cmds[0]);
}
#define CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_MASK 3
#define CC1120_PREAMBLE_CFG0 0x0e
+#define CC1120_PREAMBLE_CFG0_PQT_EN 5
+#define CC1120_PREAMBLE_CFG0_PQT_VALID_TIMEOUT 4
+#define CC1120_PREAMBLE_CFG0_PQT 0
+#define CC1120_PREAMBLE_CFG0_PQT_MASK 0xf
+
#define CC1120_FREQ_IF_CFG 0x0f
#define CC1120_IQIC 0x10
#define CC1120_CHAN_BW 0x11
#define CC1120_AGC_CFG1 0x1c
#define CC1120_AGC_CFG0 0x1d
#define CC1120_FIFO_CFG 0x1e
+#define CC1120_FIFO_CFG_CRC_AUTOFLUSH 7
+#define CC1120_FIFO_CFG_FIFO_THR 0
#define CC1120_DEV_ADDR 0x1f
#define CC1120_SETTLING_CFG 0x20
#define CC1120_SETTLING_CFG_FS_AUTOCAL 3
#define CC1120_DIRECT_FIFO 0x3e
#define CC1120_FIFO 0x3f
+#define CC1120_FIFO_SIZE 128
+
/* Extended register space */
#define CC1120_EXTENDED_BIT 0x8000
CC1120_SYNC1, 0xD3, /* Sync Word Configuration [15:8] */\r
CC1120_SYNC0, 0x91, /* Sync Word Configuration [7:0] */\r
\r
- CC1120_SYNC_CFG1, 0x08, /* Sync Word Detection Configuration */\r
+ CC1120_SYNC_CFG1, /* Sync Word Detection Configuration */\r
+ (CC1120_SYNC_CFG1_DEM_CFG_PQT_GATING_ENABLED << CC1120_SYNC_CFG1_DEM_CFG) |\r
+ (0x07 << CC1120_SYNC_CFG1_SYNC_THR),\r
CC1120_SYNC_CFG0,\r
(CC1120_SYNC_CFG0_SYNC_MODE_16_BITS << CC1120_SYNC_CFG0_SYNC_MODE) |\r
(CC1120_SYNC_CFG0_SYNC_NUM_ERROR_2 << CC1120_SYNC_CFG0_SYNC_NUM_ERROR),\r
CC1120_PREAMBLE_CFG1, /* Preamble Length Configuration */\r
(CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_4_BYTES << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |\r
(CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD),\r
- CC1120_PREAMBLE_CFG0, 0x2a, /* */\r
+ CC1120_PREAMBLE_CFG0,\r
+ (1 << CC1120_PREAMBLE_CFG0_PQT_EN) |\r
+ (0x6 << CC1120_PREAMBLE_CFG0_PQT),\r
CC1120_FREQ_IF_CFG, 0x40, /* RX Mixer Frequency Configuration */\r
CC1120_IQIC, 0x46, /* Digital Image Channel Compensation Configuration */\r
CC1120_CHAN_BW, 0x02, /* Channel Filter Configuration */\r
\r
- CC1120_MDMCFG1, 0x46, /* General Modem Parameter Configuration */\r
+ CC1120_MDMCFG1, /* General Modem Parameter Configuration */\r
+ (0 << CC1120_MDMCFG1_CARRIER_SENSE_GATE) |\r
+ (1 << CC1120_MDMCFG1_FIFO_EN) |\r
+ (0 << CC1120_MDMCFG1_MANCHESTER_EN) |\r
+ (0 << CC1120_MDMCFG1_INVERT_DATA_EN) |\r
+ (0 << CC1120_MDMCFG1_COLLISION_DETECT_EN) |\r
+ (CC1120_MDMCFG1_DVGA_GAIN_9 << CC1120_MDMCFG1_DVGA_GAIN) |\r
+ (0 << CC1120_MDMCFG1_SINGLE_ADC_EN),\r
CC1120_MDMCFG0, 0x05, /* General Modem Parameter Configuration */\r
\r
CC1120_AGC_REF, 0x20, /* AGC Reference Level Configuration */\r
CC1120_AGC_CFG2, 0x20, /* AGC Configuration */\r
CC1120_AGC_CFG1, 0xa9, /* AGC Configuration */\r
CC1120_AGC_CFG0, 0xcf, /* AGC Configuration */\r
- CC1120_FIFO_CFG, 0x00, /* FIFO Configuration */\r
+ CC1120_FIFO_CFG, /* FIFO Configuration */\r
+ (0 << CC1120_FIFO_CFG_CRC_AUTOFLUSH) |\r
+ (0x40 << CC1120_FIFO_CFG_FIFO_THR),\r
CC1120_DEV_ADDR, 0x00, /* Device Address Configuration */\r
CC1120_SETTLING_CFG, /* Frequency Synthesizer Calibration and Settling Configuration */\r
(CC1120_SETTLING_CFG_FS_AUTOCAL_IDLE_TO_ON << CC1120_SETTLING_CFG_FS_AUTOCAL) |\r
#if 0\r
CC1120_PKT_CFG2, 0x04, /* Packet Configuration, Reg 2 */\r
CC1120_PKT_CFG1, 0x45, /* Packet Configuration, Reg 1 */\r
-#endif\r
CC1120_PKT_CFG0, 0x00, /* Packet Configuration, Reg 0 */\r
+#endif\r
CC1120_RFEND_CFG1, 0x0f, /* RFEND Configuration, Reg 1 */\r
CC1120_RFEND_CFG0, 0x00, /* RFEND Configuration, Reg 0 */\r
// CC1120_PA_CFG2, 0x3f, /* Power Amplifier Configuration, Reg 2 */\r
- CC1120_PA_CFG2, 0x23, /* Power Amplifier Configuration, Reg 2 */\r
+ CC1120_PA_CFG2, 0x04, /* Power Amplifier Configuration, Reg 2 */\r
CC1120_PA_CFG1, 0x56, /* Power Amplifier Configuration, Reg 1 */\r
CC1120_PA_CFG0, 0x7b, /* Power Amplifier Configuration, Reg 0 */\r
CC1120_PKT_LEN, 0xff, /* Packet Length Configuration */\r
CC1120_MARC_SPARE, 0x00, /* MARC Spare */\r
CC1120_ECG_CFG, 0x00, /* External Clock Frequency Configuration */\r
CC1120_SOFT_TX_DATA_CFG, 0x00, /* Soft TX Data Configuration */\r
- CC1120_EXT_CTRL, 0x01, /* External Control Configuration */\r
+ CC1120_EXT_CTRL, 0x00, /* External Control Configuration */\r
CC1120_RCCAL_FINE, 0x00, /* RC Oscillator Calibration (fine) */\r
CC1120_RCCAL_COARSE, 0x00, /* RC Oscillator Calibration (coarse) */\r
CC1120_RCCAL_OFFSET, 0x00, /* RC Oscillator Calibration Clock Offset */\r
* STM32L definitions and code fragments for AltOS
*/
-#define AO_STACK_SIZE 1024
+#define AO_STACK_SIZE 512
#define AO_LED_TYPE uint16_t
uint32_t *sp; \
asm("mov %0,sp" : "=&r" (sp) ); \
ao_cur_task->sp = (sp); \
- if ((uint8_t *) sp < ao_cur_task->stack) \
+ if ((uint8_t *) sp < &ao_cur_task->stack[0]) \
ao_panic (AO_PANIC_STACK); \
} while (0)
-#define ao_arch_isr_stack() /* nothing */
+#if 0
+#define ao_arch_isr_stack() do { \
+ uint32_t *sp = (uint32_t *) 0x20004000; \
+ asm("mov %0,sp" : "=&r" (sp) ); \
+ } while (0)
+#else
+#define ao_arch_isr_stack()
+#endif
+
#define ao_arch_cpu_idle() do { \
- asm("wfi"); \
+ asm("wfi"); \
} while (0)
#define ao_arch_restore_stack() do { \
#define AO_TIM91011_CLK (2 * AO_PCLK2)
#endif
+#define AO_STM_NVIC_HIGH_PRIORITY 4
+#define AO_STM_NVIC_CLOCK_PRIORITY 6
+#define AO_STM_NVIC_MED_PRIORITY 8
+#define AO_STM_NVIC_LOW_PRIORITY 10
+
void ao_lcd_stm_init(void);
void ao_lcd_font_init(void);
void
ao_serial3_set_speed(uint8_t speed);
-extern uint32_t ao_radio_cal;
+extern const uint32_t ao_radio_cal;
void
ao_adc_init();
#define AO_EXTI_MODE_FALLING 2
#define AO_EXTI_MODE_PULL_UP 4
#define AO_EXTI_MODE_PULL_DOWN 8
+#define AO_EXTI_PRIORITY_LOW 16
+#define AO_EXTI_PRIORITY_MED 0
+#define AO_EXTI_PRIORITY_HIGH 32
void
ao_exti_setup(struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback)());
static void (*ao_exti_callback[16])(void);
-static void
-ao_exti_isr(void) {
- uint32_t pending = stm_exti.pr;
- uint8_t pin;
+uint32_t ao_last_exti;
+
+static void ao_exti_one_isr(uint8_t pin) {
+ uint32_t pending = (ao_last_exti = stm_exti.pr) & (1 << pin);
- /* Clear pending interrupts */
stm_exti.pr = pending;
- for (pin = 0; pin < 16 && pending; pin++) {
- uint32_t mask = (1 << pin);
+ if (pending && ao_exti_callback[pin])
+ (*ao_exti_callback[pin])();
+}
- if (pending & mask) {
- pending &= ~mask;
- if (ao_exti_callback[pin])
- (*ao_exti_callback[pin])();
- }
+static void ao_exti_range_isr(uint8_t first, uint8_t last, uint16_t mask) {
+ uint16_t pending = (ao_last_exti = stm_exti.pr) & mask;
+ uint8_t pin;
+ static uint16_t last_mask;
+ static uint8_t last_pin;
+
+ if (pending == last_mask) {
+ stm_exti.pr = last_mask;
+ (*ao_exti_callback[last_pin])();
+ return;
}
+ stm_exti.pr = pending;
+ for (pin = first; pin <= last; pin++)
+ if ((pending & ((uint32_t) 1 << pin)) && ao_exti_callback[pin]) {
+ last_mask = (1 << pin);
+ last_pin = pin;
+ (*ao_exti_callback[pin])();
+ }
}
-void stm_exti0_isr(void) { ao_exti_isr(); }
-void stm_exti1_isr(void) { ao_exti_isr(); }
-void stm_exti2_isr(void) { ao_exti_isr(); }
-void stm_exti3_isr(void) { ao_exti_isr(); }
-void stm_exti4_isr(void) { ao_exti_isr(); }
-void stm_exti9_5_isr(void) { ao_exti_isr(); }
-void stm_exti15_10_isr(void) { ao_exti_isr(); }
+void stm_exti0_isr(void) { ao_exti_one_isr(0); }
+void stm_exti1_isr(void) { ao_exti_one_isr(1); }
+void stm_exti2_isr(void) { ao_exti_one_isr(2); }
+void stm_exti3_isr(void) { ao_exti_one_isr(3); }
+void stm_exti4_isr(void) { ao_exti_one_isr(4); }
+void stm_exti9_5_isr(void) { ao_exti_range_isr(5, 9, 0x3e0); }
+void stm_exti15_10_isr(void) { ao_exti_range_isr(10, 15, 0xfc00); }
void
ao_exti_setup (struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback)(void)) {
uint32_t mask = 1 << pin;
uint32_t pupdr;
uint8_t irq;
+ uint8_t prio;
ao_exti_callback[pin] = callback;
irq = STM_ISR_EXTI9_5_POS;
else
irq = STM_ISR_EXTI15_10_POS;
- stm_nvic_set_priority(irq, 10);
+
+ /* Set priority */
+ prio = AO_STM_NVIC_MED_PRIORITY;
+ if (mode & AO_EXTI_PRIORITY_LOW)
+ prio = AO_STM_NVIC_LOW_PRIORITY;
+ else if (mode & AO_EXTI_PRIORITY_HIGH)
+ prio = AO_STM_NVIC_HIGH_PRIORITY;
+
+ stm_nvic_set_priority(irq, prio);
stm_nvic_set_enable(irq);
}
void
ao_exti_init(void)
{
- stm_nvic_set_priority(STM_ISR_EXTI1_POS, 10);
- stm_nvic_set_priority(STM_ISR_EXTI2_POS, 10);
- stm_nvic_set_priority(STM_ISR_EXTI3_POS, 10);
- stm_nvic_set_priority(STM_ISR_EXTI4_POS, 10);
- stm_nvic_set_priority(STM_ISR_EXTI9_5_POS, 10);
- stm_nvic_set_priority(STM_ISR_EXTI15_10_POS, 10);
+ stm_nvic_set_priority(STM_ISR_EXTI1_POS, AO_STM_NVIC_MED_PRIORITY);
+ stm_nvic_set_priority(STM_ISR_EXTI2_POS, AO_STM_NVIC_MED_PRIORITY);
+ stm_nvic_set_priority(STM_ISR_EXTI3_POS, AO_STM_NVIC_MED_PRIORITY);
+ stm_nvic_set_priority(STM_ISR_EXTI4_POS, AO_STM_NVIC_MED_PRIORITY);
+ stm_nvic_set_priority(STM_ISR_EXTI9_5_POS, AO_STM_NVIC_MED_PRIORITY);
+ stm_nvic_set_priority(STM_ISR_EXTI15_10_POS, AO_STM_NVIC_MED_PRIORITY);
}
struct stm_spi *stm_spi;
};
-uint8_t ao_spi_mutex[STM_NUM_SPI];
+uint8_t ao_spi_mutex[STM_NUM_SPI];
+uint16_t ao_spi_speed[STM_NUM_SPI];
static const struct ao_spi_stm_info ao_spi_stm_info[STM_NUM_SPI] = {
{
(1 << STM_SPI_CR1_SSI) | /* ... */
(0 << STM_SPI_CR1_LSBFIRST) | /* Big endian */
(1 << STM_SPI_CR1_SPE) | /* Enable SPI unit */
- (STM_SPI_CR1_BR_PCLK_16 << STM_SPI_CR1_BR) | /* baud rate to pclk/4 */
+ (ao_spi_speed[spi_index] << STM_SPI_CR1_BR) | /* baud rate to pclk/4 */
(1 << STM_SPI_CR1_MSTR) |
(0 << STM_SPI_CR1_CPOL) | /* Format 0 */
(0 << STM_SPI_CR1_CPHA));
(0 << STM_SPI_CR2_SSOE) |
(0 << STM_SPI_CR2_TXDMAEN) |
(0 << STM_SPI_CR2_RXDMAEN));
+ ao_spi_speed[spi_index] = AO_SPI_SPEED_FAST;
}
void
ao_timer_init(void)
{
stm_nvic_set_enable(STM_ISR_TIM6_POS);
- stm_nvic_set_priority(STM_ISR_TIM6_POS, 1);
+ stm_nvic_set_priority(STM_ISR_TIM6_POS, AO_STM_NVIC_CLOCK_PRIORITY);
/* Turn on timer 6 */
stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM6EN);
#define DECODE_LEN(input_len) ((input_len) + AO_FEC_PREPARE_EXTRA)
#define EXPAND_LEN(input_len) (ENCODE_LEN(input_len) * 8)
+static uint8_t ao_bit(uint8_t b) {
+ if (b)
+ return 0x00;
+ return 0xff;
+}
+
static int
ao_expand(uint8_t *bits, int bits_len, uint8_t *bytes)
{
for (i = 0; i < bits_len; i++) {
b = bits[i];
for (bit = 7; bit >= 0; bit--)
- *bytes++ = ((b >> bit) & 1) * 0xff;
+ *bytes++ = ao_bit ((b >> bit) & 1);
}
return bits_len * 8;
static uint8_t real_packet[] = {
- 0x00, 0x40, 0x38, 0xcd, 0x38, 0x3d, 0x34, 0xca, 0x31, 0xc3, 0xc1, 0xc6, 0x35, 0xcc, 0x3a, 0x3c,
+ 0x40, 0x38, 0xcd, 0x38, 0x3d, 0x34, 0xca, 0x31, 0xc3, 0xc1, 0xc6, 0x35, 0xcc, 0x3a, 0x3c,
0x3c, 0x3d, 0x3c, 0x37, 0xc5, 0xc1, 0xc0, 0xc1, 0xc1, 0xc3, 0xc0, 0xc1, 0xc6, 0x38, 0x3b, 0xc6,
0xc0, 0xc6, 0x32, 0xc9, 0xc9, 0x34, 0xcf, 0x35, 0xcf, 0x3a, 0x3b, 0xc6, 0xc7, 0x35, 0xcf, 0x36,
0xce, 0x37, 0xc8, 0xc8, 0x3a, 0x3c, 0xc9, 0xc8, 0x3a, 0x3c, 0xcc, 0x32, 0xcd, 0x32, 0xce, 0x32,
};
-void
+int
ao_real_packet(void)
{
uint8_t decode[64];
uint8_t decode_len;
- int off;
+ int ok = 0;
- for (off = 0; off < sizeof (real_packet) - 576; off++) {
- decode_len = ao_fec_decode(real_packet+off, 576, decode, 34, NULL);
+ decode_len = ao_fec_decode(real_packet, 576, decode, 34, NULL);
- if (ao_fec_check_crc(decode, 32)) {
- printf ("match at %d\n", off);
+ if (decode[32] == 0 && decode[33] == 0) {
+ printf ("match\n");
- ao_fec_dump_bytes(decode, decode_len, "Decode");
- }
+ ao_fec_dump_bytes(decode, decode_len, "Decode");
+ ok = 1;
+ } else {
+ printf ("actual packet crc error\n");
}
+ return ok;
}
int
int errors = 0;
int error;
- ao_real_packet(); exit(0);
+ if (!ao_real_packet())
+ errors++;
+
srandom(0);
- for (trial = 0; trial < 10000; trial++) {
+ for (trial = 0; trial < 100000; trial++) {
/* Compute some random data */
original_len = ao_random_data(original, sizeof(original));
transmit_len = ao_expand(encode, encode_len, transmit);
/* Add gaussian noise to the signal */
- receive_errors = ao_fuzz(transmit, transmit_len, receive, 0x30);
+ receive_errors = ao_fuzz(transmit, transmit_len, receive, 0x38);
receive_len = transmit_len;
/* Decode it */
error++;
}
- if (!ao_fec_check_crc(decode, original_len)) {
+ if (decode[original_len] != 0 || decode[original_len+1] != 0) {
printf ("crc mis-match\n");
error++;
}
errors += error;
}
}
+ printf ("%d packets coded\n", trial);
return errors;
}