summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMyles Watson <mylesgw@chromium.org>2015-02-02 14:45:15 -0800
committerchrome-bot <chrome-bot@chromium.org>2016-08-03 19:40:45 -0700
commitfc55bb5026a86fffc54a291c16b22ccfb5d4b2c0 (patch)
treee6338a7131d0afa7d5c14e2a3ebe02b9096e2720
parent8c7bdcd5b6037245a6785ece11dc99e115567e70 (diff)
downloadchrome-ec-fc55bb5026a86fffc54a291c16b22ccfb5d4b2c0.tar.gz
nrf51: Add Bluetooth LE test code for the radio
Implement support for Direct Test Modet packets. BUG=None BRANCH=None CQ-DEPEND=CL:361960 TEST=use hci commands to send and receive test packets. Change-Id: Idc12812fb88319ba6f8aad4396a175e3299211b8 Signed-off-by: Myles Watson <mylesgw@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/362143 Reviewed-by: Randall Spangler <rspangler@chromium.org> Reviewed-by: Levi Oliver <levio@google.com>
-rw-r--r--chip/nrf51/build.mk1
-rw-r--r--chip/nrf51/radio_test.c184
-rw-r--r--chip/nrf51/radio_test.h41
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 */