diff options
-rw-r--r-- | chip/nrf51/build.mk | 1 | ||||
-rw-r--r-- | chip/nrf51/radio_test.c | 184 | ||||
-rw-r--r-- | chip/nrf51/radio_test.h | 41 |
3 files changed, 226 insertions, 0 deletions
diff --git a/chip/nrf51/build.mk b/chip/nrf51/build.mk index 69a2e3ed41..5680f10d91 100644 --- a/chip/nrf51/build.mk +++ b/chip/nrf51/build.mk @@ -14,6 +14,7 @@ chip-y+=gpio.o system.o uart.o chip-y+=jtag.o watchdog.o ppi.o chip-$(CONFIG_BLUETOOTH_LE)+=radio.o bluetooth_le.o +chip-$(CONFIG_BLUETOOTH_LE_RADIO_TEST)+=radio_test.o chip-$(CONFIG_COMMON_TIMER)+=hwtimer.o clock.o chip-$(CONFIG_I2C)+=i2c.o chip-$(HAS_TASK_KEYSCAN)+=keyboard_raw.o diff --git a/chip/nrf51/radio_test.c b/chip/nrf51/radio_test.c new file mode 100644 index 0000000000..bcad7466e9 --- /dev/null +++ b/chip/nrf51/radio_test.c @@ -0,0 +1,184 @@ +/* Copyright 2016 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "bluetooth_le.h" /* chan2freq */ +#include "btle_hci_int.h" +#include "console.h" +#include "radio.h" +#include "radio_test.h" +#include "registers.h" +#include "timer.h" +#include "util.h" + +#define BLE_TEST_TYPE_PRBS9 0 +#define BLE_TEST_TYPE_F0 1 +#define BLE_TEST_TYPE_AA 2 +#define BLE_TEST_TYPE_PRBS15 3 +#define BLE_TEST_TYPE_FF 4 +#define BLE_TEST_TYPE_00 5 +#define BLE_TEST_TYPE_0F 6 +#define BLE_TEST_TYPE_55 7 + +#define BLE_TEST_TYPES_IMPLEMENTED 0xf6 /* No PRBS yet */ + +static struct nrf51_ble_packet_t rx_packet; +static struct nrf51_ble_packet_t tx_packet; +static uint32_t rx_end; + +static int test_in_progress; + +void ble_test_stop(void) +{ + test_in_progress = 0; +} + +static uint32_t prbs_lfsr; +static uint32_t prbs_poly; + +/* + * This is a Galois LFSR, the polynomial is the counterpart of the Fibonacci + * LFSR in the doc. It requires fewer XORs to implement in software. + * This also means that the initial value is different. + */ +static uint8_t prbs_next_byte(void) +{ + int i; + int lsb; + uint8_t rv = 0; + + for (i = 0; i < 8; i++) { + lsb = prbs_lfsr & 1; + rv |= lsb << i; + prbs_lfsr = prbs_lfsr >> 1; + if (lsb) + prbs_lfsr ^= prbs_poly; + } + return rv; +} + +void ble_test_fill_tx_packet(int type, int len) +{ + int i; + + tx_packet.s0 = type & 0xf; + tx_packet.length = len; + + switch (type) { + case BLE_TEST_TYPE_PRBS9: + prbs_lfsr = 0xf; + prbs_poly = 0x108; + for (i = 0; i < len; i++) + tx_packet.payload[i] = prbs_next_byte(); + break; + case BLE_TEST_TYPE_PRBS15: + prbs_lfsr = 0xf; + prbs_poly = 0x6000; + for (i = 0; i < len; i++) + tx_packet.payload[i] = prbs_next_byte(); + break; + case BLE_TEST_TYPE_F0: + memset(tx_packet.payload, 0xF0, len); + break; + case BLE_TEST_TYPE_AA: + memset(tx_packet.payload, 0xAA, len); + break; + case BLE_TEST_TYPE_FF: + memset(tx_packet.payload, 0xFF, len); + break; + case BLE_TEST_TYPE_00: + memset(tx_packet.payload, 0x00, len); + break; + case BLE_TEST_TYPE_0F: + memset(tx_packet.payload, 0x0F, len); + break; + case BLE_TEST_TYPE_55: + memset(tx_packet.payload, 0x55, len); + break; + default: + break; + } +} + +static int ble_test_init(int chan) +{ + int rv = radio_init(BLE_1MBIT); + + if (rv) + return HCI_ERR_Hardware_Failure; + + if (chan > BLE_MAX_TEST_CHANNEL || chan < BLE_MIN_TEST_CHANNEL) + return HCI_ERR_Invalid_HCI_Command_Parameters; + + NRF51_RADIO_CRCCNF = 3 | (1 << 8); /* 3-byte, skip address */ + /* x^24 + x^10 + x^9 + x^6 + x^4 + x^3 + x + 1 */ + /* 0x1_0000_0000_0000_0110_0101_1011 */ + NRF51_RADIO_CRCPOLY = 0x100065B; + NRF51_RADIO_CRCINIT = 0x555555; + + NRF51_RADIO_TXPOWER = NRF51_RADIO_TXPOWER_0_DBM; + + /* The testing address is the inverse of the advertising address. */ + NRF51_RADIO_BASE0 = (~BLE_ADV_ACCESS_ADDRESS) << 8; + + NRF51_RADIO_PREFIX0 = (~BLE_ADV_ACCESS_ADDRESS) >> 24; + + NRF51_RADIO_TXADDRESS = 0; + NRF51_RADIO_RXADDRESSES = 1; + + NRF51_RADIO_PCNF0 = NRF51_RADIO_PCNF0_TEST; + + NRF51_RADIO_PCNF1 = NRF51_RADIO_PCNF1_TEST; + + NRF51_RADIO_FREQUENCY = NRF51_RADIO_FREQUENCY_VAL(2*chan + 2402); + + test_in_progress = 1; + return rv; +} + +int ble_test_rx_init(int chan) +{ + NRF51_RADIO_PACKETPTR = (uint32_t)&rx_packet; + return ble_test_init(chan); +} + +int ble_test_tx_init(int chan, int len, int type) +{ + if (((1 << type) & BLE_TEST_TYPES_IMPLEMENTED) == 0 || + (len < 0 || len > BLE_MAX_TEST_PAYLOAD_OCTETS)) + return HCI_ERR_Invalid_HCI_Command_Parameters; + + ble_test_fill_tx_packet(type, len); + NRF51_RADIO_PACKETPTR = (uint32_t)&tx_packet; + + return ble_test_init(chan); +} + +void ble_test_tx(void) +{ + NRF51_RADIO_END = 0; + NRF51_RADIO_TXEN = 1; +} + +int ble_test_rx(void) +{ + int retries = 100; + + NRF51_RADIO_END = 0; + NRF51_RADIO_RXEN = 1; + + do { + retries--; + if (retries <= 0) { + radio_disable(); + return EC_ERROR_TIMEOUT; + } + usleep(100); + } while (!NRF51_RADIO_END); + + rx_end = get_time().le.lo; + + return EC_SUCCESS; +} + diff --git a/chip/nrf51/radio_test.h b/chip/nrf51/radio_test.h new file mode 100644 index 0000000000..b70a22d69a --- /dev/null +++ b/chip/nrf51/radio_test.h @@ -0,0 +1,41 @@ +/* Copyright 2016 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* + * Radio test interface for NRF51 + * + * These functions implement parts of the Direct Test Mode functionality in + * the Bluetooth Spec. + */ + +#ifndef __NRF51_RADIO_TEST_H +#define __NRF51_RADIO_TEST_H + +#define BLE_MAX_TEST_PAYLOAD_OCTETS 37 +#define BLE_MAX_TEST_CHANNEL 39 +#define BLE_MIN_TEST_CHANNEL 0 + +#define NRF51_RADIO_PCNF0_TEST NRF51_RADIO_PCNF0_ADV + +#define BLE_TEST_WHITEN 0 + +#define NRF51_RADIO_PCNF1_TEST \ + NRF51_RADIO_PCNF1_VAL(BLE_MAX_TEST_PAYLOAD_OCTETS, \ + EXTRA_RECEIVE_BYTES, \ + BLE_ACCESS_ADDRESS_BYTES - 1, \ + BLE_TEST_WHITEN) + +/* + * Prepare the radio for transmitting packets. The value of chan must be + * between 0 and 39 inclusive. The maximum length is 37. + */ + +int ble_test_tx_init(int chan, int type, int len); +int ble_test_rx_init(int chan); +void ble_test_tx(void); +int ble_test_rx(void); +void ble_test_stop(void); + +#endif /* __NRF51_RADIO_TEST_H */ |