altitude.h
altitude-pa.h
+ao_whiten.h
vpath make-altitude util
vpath make-altitude-pa util
vpath make-kalman util
+vpath make-whiten util
vpath kalman.5c kalman
vpath kalman_filter.5c kalman
vpath load_csv.5c kalman
all-recursive: all-local
-all-local: altitude.h altitude-pa.h ao_kalman.h
+all-local: altitude.h altitude-pa.h ao_kalman.h ao_whiten.h
altitude.h: make-altitude
nickle $< > $@
ao_kalman.h: make-kalman kalman.5c kalman_filter.5c load_csv.5c matrix.5c
bash $< kalman > $@
+ao_whiten.h: make-whiten
+ nickle $< > $@
+
clean-local:
rm -f altitude.h ao_kalman.h
#include <ao.h>
#include <ao_cc1120.h>
#include <ao_exti.h>
+#include <ao_fec.h>
uint8_t ao_radio_wake;
uint8_t ao_radio_mutex;
return ao_radio_marc_status() == CC1120_MARC_STATUS1_RX_FINISHED;
}
+static void
+ao_radio_start_tx(void)
+{
+ ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG);
+ ao_exti_enable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
+ ao_radio_strobe(CC1120_STX);
+}
+
void
ao_radio_rdf(uint8_t len)
{
int i;
ao_radio_get(len);
- ao_radio_abort = 0;
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_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG);
-
ao_radio_fifo_write_fixed(ao_radio_rdf_value, len);
- ao_radio_reg_write(CC1120_PKT_LEN, len);
-
- ao_exti_enable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
-
- ao_radio_strobe(CC1120_STX);
+ ao_radio_start_tx();
cli();
while (!ao_radio_wake && !ao_radio_abort)
void
ao_radio_send(void *d, uint8_t size)
{
- uint8_t marc_status;
-
+ uint8_t marc_status;
+ static uint8_t prepare[128];
+ uint8_t prepare_len;
+ static uint8_t encode[256];
+ uint8_t encode_len;
+ static uint8_t interleave[256];
+ uint8_t interleave_len;
+
+ ao_fec_dump_bytes(d, size, "Input");
+
+#if 1
+ prepare_len = ao_fec_prepare(d, size, prepare);
+ ao_fec_dump_bytes(prepare, prepare_len, "Prepare");
+
+ ao_fec_whiten(prepare, prepare_len, prepare);
+ ao_fec_dump_bytes(prepare, prepare_len, "Whiten");
+
+ encode_len = ao_fec_encode(prepare, prepare_len, encode);
+ ao_fec_dump_bytes(encode, encode_len, "Encode");
+
+ interleave_len = ao_fec_interleave(encode, encode_len, interleave);
+ ao_fec_dump_bytes(interleave, interleave_len, "Interleave");
+ ao_radio_get(interleave_len);
+ ao_radio_fifo_write(interleave, interleave_len);
+#else
ao_radio_get(size);
- ao_radio_wake = 0;
ao_radio_fifo_write(d, size);
- ao_exti_enable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
- ao_radio_strobe(CC1120_STX);
+#endif
+
+ ao_radio_wake = 0;
+
+ ao_radio_start_tx();
+
cli();
- for (;;) {
- if (ao_radio_wake) {
- marc_status = ao_radio_marc_status();
- if (marc_status != CC1120_MARC_STATUS1_NO_FAILURE)
- break;
- ao_radio_wake = 0;
- }
+ while (!ao_radio_wake && !ao_radio_abort)
ao_sleep(&ao_radio_wake);
- }
sei();
+ if (!ao_radio_tx_done())
+ ao_radio_idle();
ao_radio_put();
}
cli();
for (;;) {
if (ao_radio_abort)
+
break;
if (ao_radio_wake) {
marc_status = ao_radio_marc_status();
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, ((1 << CC1120_PKT_CFG1_WHITE_DATA) |
+ 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)),
for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
ao_radio_reg_write(radio_setup[i], radio_setup[i+1]);
- /* Enable marc status interrupt on gpio 2 pin */
- ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_MARC_MCU_WAKEUP);
-
ao_radio_set_packet();
ao_config_get();
ao_radio_rdf(RDF_PACKET_LEN);
}
+static void ao_radio_packet(void) {
+ static uint8_t packet[] = {
+#if 1
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+#else
+ 3, 1, 2, 3
+#endif
+ };
+
+ ao_radio_send(packet, sizeof (packet));
+}
+
#endif
static const struct ao_cmds ao_radio_cmds[] = {
#if CC1120_DEBUG
{ ao_radio_show, "R\0Show CC1120 status" },
{ ao_radio_beep, "b\0Emit an RDF beacon" },
+ { ao_radio_packet, "p\0Send a test packet" },
#endif
{ 0, NULL }
};
*\r
***************************************************************/\r
\r
- CC1120_SYNC3, 0x93, /* Sync Word Configuration [31:24] */\r
- CC1120_SYNC2, 0x0b, /* Sync Word Configuration [23:16] */\r
- CC1120_SYNC1, 0x51, /* Sync Word Configuration [15:8] */\r
- CC1120_SYNC0, 0xde, /* Sync Word Configuration [7:0] */\r
+ CC1120_SYNC3, 0xD3, /* Sync Word Configuration [31:24] */\r
+ CC1120_SYNC2, 0x91, /* Sync Word Configuration [23:16] */\r
+ 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_CFG0, 0x17, /* Sync Word Length Configuration */\r
-#if 0\r
- CC1120_DEVIATION_M, 0x50, /* Frequency Deviation Configuration */\r
- CC1120_MODCFG_DEV_E, 0x0d, /* Modulation Format and Frequency Deviation Configuration */\r
-#endif\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_DCFILT_CFG, 0x1c, /* Digital DC Removal Configuration */\r
- CC1120_PREAMBLE_CFG1, 0x18, /* Preamble Length Configuration */\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_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_MDMCFG0, 0x05, /* General Modem Parameter Configuration */\r
-#if 0\r
- CC1120_DRATE2, 0x93, /* Data Rate Configuration Exponent and Mantissa [19:16] */\r
- CC1120_DRATE1, 0xa4, /* Data Rate Configuration Mantissa [15:8] */\r
- CC1120_DRATE0, 0x00, /* Data Rate Configuration Mantissa [7:0] */\r
-#endif\r
+\r
CC1120_AGC_REF, 0x20, /* AGC Reference Level Configuration */\r
CC1120_AGC_CS_THR, 0x19, /* Carrier Sense Threshold Configuration */\r
CC1120_AGC_GAIN_ADJUST, 0x00, /* RSSI Offset Configuration */\r
--- /dev/null
+/*
+ * Copyright © 2012 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_FEC_H_
+#define _AO_FEC_H_
+
+#include <stdint.h>
+
+#define AO_FEC_CRC_INIT 0xffff
+#define AO_FEC_TRELLIS_TERMINATOR 0x0b
+#define AO_FEC_PREPARE_EXTRA 4
+
+void
+ao_fec_dump_bytes(uint8_t *bytes, uint8_t len, char *name);
+
+uint16_t
+ao_fec_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
+ */
+uint8_t
+ao_fec_whiten(uint8_t *in, uint8_t len, uint8_t *out);
+
+/*
+ * Encode data. 'out' must be len*2 bytes long
+ */
+uint8_t
+ao_fec_encode(uint8_t *in, uint8_t len, uint8_t *out);
+
+/*
+ * Interleave data. 'out' must be 'len' bytes long
+ */
+uint8_t
+ao_fec_interleave(uint8_t *in, uint8_t len, uint8_t *out);
+
+#endif /* _AO_FEC_H_ */
--- /dev/null
+/*
+ * Copyright © 2012 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_fec.h>
+#include <stdio.h>
+
+void
+ao_fec_dump_bytes(uint8_t *bytes, uint8_t len, char *name)
+{
+ uint8_t i;
+
+ printf ("%s (%d):", name, len);
+ for (i = 0; i < len; i++) {
+ if ((i & 7) == 0)
+ printf ("\n\t%02x:", i);
+ printf(" %02x", bytes[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;
+}
+
+uint16_t
+ao_fec_crc(uint8_t *bytes, uint8_t len)
+{
+ uint16_t crc = AO_FEC_CRC_INIT;
+
+ while (len--)
+ crc = crc_byte(*bytes++, crc);
+ return crc;
+}
+
+uint8_t
+ao_fec_prepare(uint8_t *in, uint8_t len, uint8_t *out)
+{
+ uint16_t crc = ao_fec_crc (in, len);
+ uint8_t i;
+ uint8_t num_fec;
+
+ /* Copy data */
+ for (i = 0; i < len; i++)
+ out[i] = in[i];
+
+ /* Append CRC */
+ out[i++] = crc >> 8;
+ out[i++] = crc;
+
+ /* Append FEC -- 1 byte if odd, two bytes if even */
+ num_fec = 2 - (i & 1);
+ while (num_fec--)
+ out[i++] = AO_FEC_TRELLIS_TERMINATOR;
+ return i;
+}
+
+static const uint8_t whiten[] = {
+#include "ao_whiten.h"
+};
+
+uint8_t
+ao_fec_whiten(uint8_t *in, uint8_t len, uint8_t *out)
+{
+ const uint8_t *w = whiten;
+
+ while (len--)
+ *out++ = *in++ ^ *w++;
+}
+
+static const uint8_t ao_fec_encode_table[16] = {
+ 0, 3, 1, 2,
+ 3, 0, 2, 1,
+ 3, 0, 2, 1,
+ 0, 3, 1, 2
+};
+
+uint8_t
+ao_fec_encode(uint8_t *in, uint8_t len, uint8_t *out)
+{
+ uint16_t fec = 0, output;
+ uint8_t byte, bit;
+
+ for (byte = 0; byte < len; byte++) {
+ fec = (fec & 0x700) | in[byte];
+ output = 0;
+ for (bit = 0; bit < 8; bit++) {
+ output = output << 2 | ao_fec_encode_table[fec >> 7];
+ fec = (fec << 1) & 0x7ff;
+ }
+ out[byte * 2] = output >> 8;
+ out[byte * 2 + 1] = output;
+ }
+ return len * 2;
+}
+
+uint8_t
+ao_fec_interleave(uint8_t *in, uint8_t len, uint8_t *out)
+{
+ 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 |= (in[i + (~j & 0x3)] >> (2 * ((j & 0xc) >> 2))) & 0x03;
+ }
+ out[i+0] = interleaved >> 24;
+ out[i+1] = interleaved >> 16;
+ out[i+2] = interleaved >> 8;
+ out[i+3] = interleaved;
+ }
+ return len;
+}
ao_ms5607.h \
ao_hmc5883.h \
ao_mpu6000.h \
+ ao_cc1120_CC1120.h \
+ ao_whiten.h \
stm32l.h
#
ao_dma_stm.c \
ao_spi_stm.c \
ao_cc1120.c \
+ ao_fec_tx.c \
ao_ms5607.c \
ao_adc_stm.c \
ao_beep_stm.c \
vpath % ..:../core:../drivers:../util
-PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_flight_test_noisy_accel ao_gps_test ao_gps_test_skytraq ao_convert_test ao_convert_pa_test
+PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_flight_test_noisy_accel ao_gps_test ao_gps_test_skytraq ao_convert_test ao_convert_pa_test ao_fec_tx_test
KALMAN=make-kalman
cc $(CFLAGS) -o $@ $<
ao_kalman.h: $(KALMAN)
- (cd .. && make ao_kalman.h)
\ No newline at end of file
+ (cd .. && make ao_kalman.h)
+
+ao_fec_tx_test: ao_fec_tx_test.c ao_fec_tx.c
+ cc $(CFLAGS) -o $@ ao_fec_tx_test.c ../drivers/ao_fec_tx.c
--- /dev/null
+/*
+ * Copyright © 2012 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_fec.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int
+main(int argc, char **argv)
+{
+ uint8_t input[4] = { 3, 1, 2, 3 };
+ uint8_t prepare[sizeof(input) + AO_FEC_PREPARE_EXTRA];
+ uint8_t encode[sizeof(prepare) * 2];
+ uint8_t interleave[sizeof(encode)];
+ uint8_t prepare_len;
+ uint8_t encode_len;
+ uint8_t interleave_len;
+
+ ao_fec_dump_bytes(input, sizeof(input), "Input");
+
+ prepare_len = ao_fec_prepare(input, sizeof (input), prepare);
+
+ ao_fec_dump_bytes(prepare, prepare_len, "Prepare");
+
+ encode_len = ao_fec_encode(prepare, prepare_len, encode);
+
+ ao_fec_dump_bytes(encode, encode_len, "Encode");
+
+ interleave_len = ao_fec_interleave(encode, encode_len, interleave);
+
+ ao_fec_dump_bytes(interleave, interleave_len, "Interleave");
+}
+
--- /dev/null
+/*
+ * Copyright © 2012 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.
+ */
+
+/* Generate the data whitening array used by the CC11* radios */
+
+int pn9 = 0x1ff;
+
+void
+pn9_step() {
+ pn9 = (pn9 >> 1) | (((pn9 ^ (pn9 >> 5)) & 1) << 8);
+}
+
+int val()
+{
+ int ret = pn9 & 0xff;
+
+ for (int i = 0; i < 8; i++)
+ pn9_step();
+ return ret;
+}
+
+for (int i = 0; i < 128; i++)
+ printf (" /* %3d */ 0x%02x,\n", i + 1, val());