summaryrefslogtreecommitdiff
path: root/chip/nrf51
diff options
context:
space:
mode:
authorMyles Watson <mylesgw@chromium.org>2015-03-02 10:46:12 -0800
committerchrome-bot <chrome-bot@chromium.org>2016-08-03 19:40:43 -0700
commit8c7bdcd5b6037245a6785ece11dc99e115567e70 (patch)
tree9552812e6c3e339824a5eb3e1bb8981275dd5ead /chip/nrf51
parent961f6d2d16c7b1bc5d033364e3c7fc3b30ceaba4 (diff)
downloadchrome-ec-8c7bdcd5b6037245a6785ece11dc99e115567e70.tar.gz
nrf51: Add Bluetooth LE support
RADIO_STATE is broken: remove it. Build on the geneneric radio support to send and receive Bluetooth LE packets. Add macros in registers.h to configure PCNF0 and PCNF1. BUG=None BRANCH=None TEST=Send advertisements with console commands ble_adv type length [interval_us] for example: ble_adv 2 8 Advertisements should be received by other devices The Bluetooth Address has the form C5:A4:A3:A2:A1:A* The device name is a substring of ABCDEFGH... ABCDEFGH @ C5:A4:A3:A2:A1:A2 (name length is 8, type is 2) ABCDEFGH @ C5:A4:A3:A2:A1:A2 (name length is 8, type is 2) ABCDEF @ C5:A4:A3:A2:A1:A6 (name length is 6, type is 6) TEST=Listen for advertisements with console commands ble_adv_scan chan [num] [addr0] for example: ble_scan 37 Example output: BLE packet @ 20000448: type 2, len 33, 5c.f3.70.6b.65.d2 AdvA 20000454: 02 01 08 17 09 43 68 72 2000045c: 6f 6d 65 62 6f 78 20 66 20000464: 6f 72 20 4d 65 65 74 69 2000046c: 6e 46 16 02 01 08 = 2 bytes, Flags, LE and BR capable 17 09 43... = 23 bytes, Name, "Chromebox for Meetings" Change-Id: I2bd3f1d87acb069da0b56c1d7878e7d4fd6a06f3 Signed-off-by: Myles Watson <mylesgw@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/361960 Reviewed-by: Randall Spangler <rspangler@chromium.org> Reviewed-by: Levi Oliver <levio@google.com>
Diffstat (limited to 'chip/nrf51')
-rw-r--r--chip/nrf51/bluetooth_le.c469
-rw-r--r--chip/nrf51/bluetooth_le.h67
-rw-r--r--chip/nrf51/build.mk2
-rw-r--r--chip/nrf51/registers.h51
4 files changed, 585 insertions, 4 deletions
diff --git a/chip/nrf51/bluetooth_le.c b/chip/nrf51/bluetooth_le.c
new file mode 100644
index 0000000000..077f3317f3
--- /dev/null
+++ b/chip/nrf51/bluetooth_le.c
@@ -0,0 +1,469 @@
+/* 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"
+#include "include/bluetooth_le.h"
+#include "console.h"
+#include "radio.h"
+#include "registers.h"
+#include "timer.h"
+#include "util.h"
+
+#define CPUTS(outstr) cputs(CC_BLUETOOTH_LE, outstr)
+#define CPRINTS(format, args...) cprints(CC_BLUETOOTH_LE, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_BLUETOOTH_LE, format, ## args)
+
+static void ble2nrf_packet(struct ble_pdu *ble_p,
+ struct nrf51_ble_packet_t *radio_p)
+{
+ if (ble_p->header_type_adv) {
+ radio_p->s0 = ble_p->header.adv.type & 0xf;
+ radio_p->s0 |= (ble_p->header.adv.txaddr ?
+ 1 << BLE_ADV_HEADER_TXADD_SHIFT : 0);
+ radio_p->s0 |= (ble_p->header.adv.rxaddr ?
+ 1 << BLE_ADV_HEADER_RXADD_SHIFT : 0);
+ radio_p->length = ble_p->header.adv.length & 0x3f; /* 6 bits */
+ } else {
+ radio_p->s0 = ble_p->header.data.llid & 0x3;
+ radio_p->s0 |= (ble_p->header.data.nesn ?
+ 1 << BLE_DATA_HEADER_NESN_SHIFT : 0);
+ radio_p->s0 |= (ble_p->header.data.sn ?
+ 1 << BLE_DATA_HEADER_SN_SHIFT : 0);
+ radio_p->s0 |= (ble_p->header.data.md ?
+ 1 << BLE_DATA_HEADER_MD_SHIFT : 0);
+ radio_p->length = ble_p->header.data.length & 0x1f; /* 5 bits */
+ }
+
+ if (radio_p->length > 0)
+ memcpy(radio_p->payload, ble_p->payload, radio_p->length);
+}
+
+static void nrf2ble_packet(struct ble_pdu *ble_p,
+ struct nrf51_ble_packet_t *radio_p, int type_adv)
+{
+ if (type_adv) {
+ ble_p->header_type_adv = 1;
+ ble_p->header.adv.type = radio_p->s0 & 0xf;
+ ble_p->header.adv.txaddr = (radio_p->s0 &
+ (1 << BLE_ADV_HEADER_TXADD_SHIFT)) != 0;
+ ble_p->header.adv.rxaddr = (radio_p->s0 &
+ (1 << BLE_ADV_HEADER_RXADD_SHIFT)) != 0;
+ /* Length check? 6-37 Bytes */
+ ble_p->header.adv.length = radio_p->length;
+ } else {
+ ble_p->header_type_adv = 0;
+ ble_p->header.data.llid = radio_p->s0 & 0x3;
+ ble_p->header.data.nesn = (radio_p->s0 &
+ (1 << BLE_DATA_HEADER_NESN_SHIFT)) != 0;
+ ble_p->header.data.sn = (radio_p->s0 &
+ (1 << BLE_DATA_HEADER_SN_SHIFT)) != 0;
+ ble_p->header.data.md = (radio_p->s0 &
+ (1 << BLE_DATA_HEADER_MD_SHIFT)) != 0;
+ /* Length check? 0-31 Bytes */
+ ble_p->header.data.length = radio_p->length;
+ }
+
+ if (radio_p->length > 0)
+ memcpy(ble_p->payload, radio_p->payload, radio_p->length);
+}
+
+struct ble_pdu adv_packet;
+struct nrf51_ble_packet_t on_air_packet;
+
+struct ble_pdu rcv_packet;
+
+int ble_radio_init(void)
+{
+ int rv = radio_init(BLE_1MBIT);
+
+ if (rv)
+ return rv;
+
+ NRF51_RADIO_CRCCNF = 3 | NRF51_RADIO_CRCCNF_SKIP_ADDR; /* 3-byte CRC */
+ /* 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;
+
+ 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_ADV;
+
+ NRF51_RADIO_PCNF1 = NRF51_RADIO_PCNF1_ADV;
+
+ return rv;
+}
+
+static struct nrf51_ble_packet_t tx_packet;
+
+static uint32_t tx_end, rsp_end;
+
+void ble_tx(struct ble_pdu *pdu)
+{
+ ble2nrf_packet(pdu, &tx_packet);
+
+ NRF51_RADIO_PACKETPTR = (uint32_t)&tx_packet;
+ NRF51_RADIO_END = NRF51_RADIO_PAYLOAD = NRF51_RADIO_ADDRESS = 0;
+ NRF51_RADIO_TXEN = 1;
+}
+
+static struct nrf51_ble_packet_t rx_packet;
+
+int ble_rx(struct ble_pdu *pdu, int timeout, int adv)
+{
+ uint32_t done;
+
+ NRF51_RADIO_PACKETPTR = (uint32_t)&rx_packet;
+ NRF51_RADIO_END = NRF51_RADIO_PAYLOAD = NRF51_RADIO_ADDRESS = 0;
+ NRF51_RADIO_SHORTS = NRF51_RADIO_SHORTS_READY_START |
+ NRF51_RADIO_SHORTS_END_DISABLE;
+ NRF51_RADIO_RXEN = 1;
+
+ do {
+ if (timeout-- <= 0) {
+ radio_disable();
+ return EC_ERROR_TIMEOUT;
+ }
+ done = NRF51_RADIO_END;
+ } while (!done);
+
+ rsp_end = get_time().le.lo;
+
+ nrf2ble_packet(pdu, &rx_packet, adv);
+
+ return EC_SUCCESS;
+}
+
+/* White list handling */
+int ble_radio_clear_white_list(void)
+{
+ NRF51_RADIO_DACNF = 0;
+ return EC_SUCCESS;
+}
+
+int ble_radio_read_white_list_size(uint8_t *ret_size)
+{
+ int i, size = 0;
+ uint32_t dacnf = NRF51_RADIO_DACNF;
+
+ /* Count the bits that are set */
+ for (i = 0; i < NRF51_RADIO_DACNF_MAX; i++)
+ if (dacnf & NRF51_RADIO_DACNF_ENA(i))
+ size++;
+
+ *ret_size = size;
+
+ return EC_SUCCESS;
+}
+
+int ble_radio_add_device_to_white_list(const uint8_t *addr_ptr, uint8_t rand)
+{
+ uint32_t dacnf = NRF51_RADIO_DACNF;
+ int i;
+ uint32_t aligned;
+
+ /* Check for duplicates using ble_radio_remove_device? */
+
+ /* Find a free entry */
+ for (i = 0; i < NRF51_RADIO_DACNF_MAX &&
+ (dacnf & NRF51_RADIO_DACNF_ENA(i)); i++)
+ ;
+
+ if (i == NRF51_RADIO_DACNF_MAX)
+ return EC_ERROR_OVERFLOW;
+
+ memcpy(&aligned, addr_ptr, 4);
+ NRF51_RADIO_DAB(i) = aligned;
+ memcpy(&aligned, addr_ptr + 4, 2);
+ NRF51_RADIO_DAP(i) = aligned;
+
+ NRF51_RADIO_DACNF = dacnf | NRF51_RADIO_DACNF_ENA(i) |
+ (rand ? NRF51_RADIO_DACNF_TXADD(i) : 0);
+
+ return EC_SUCCESS;
+}
+
+int ble_radio_remove_device_from_white_list(const uint8_t *addr_ptr,
+ uint8_t rand)
+{
+ int i, dacnf = NRF51_RADIO_DACNF;
+
+ /* Find a matching entry */
+ for (i = 0; i < NRF51_RADIO_DACNF_MAX; i++) {
+ uint32_t dab = NRF51_RADIO_DAB(i), dap = NRF51_RADIO_DAP(i);
+
+ if ((dacnf & NRF51_RADIO_DACNF_ENA(i)) && /* Enabled */
+ /* Rand flag matches */
+ (rand == ((dacnf & NRF51_RADIO_DACNF_TXADD(i)) != 0)) &&
+ /* Address matches */
+ (!memcmp(addr_ptr, &dab, 4)) &&
+ (!memcmp(addr_ptr + 4, &dap, 2)))
+ break;
+ }
+
+ if (i == NRF51_RADIO_DACNF_MAX) /* Not found is successfully removed */
+ return EC_SUCCESS;
+
+ NRF51_RADIO_DACNF = dacnf & ~((NRF51_RADIO_DACNF_ENA(i)) |
+ (rand ? NRF51_RADIO_DACNF_TXADD(i) : 0));
+
+ return EC_SUCCESS;
+}
+
+
+int ble_adv_packet(struct ble_pdu *adv_packet, int chan)
+{
+ int done;
+ int rv;
+
+ /* Change channel */
+ NRF51_RADIO_FREQUENCY = NRF51_RADIO_FREQUENCY_VAL(chan2freq(chan));
+ NRF51_RADIO_DATAWHITEIV = chan;
+
+ ble_tx(adv_packet);
+
+ do {
+ done = NRF51_RADIO_END;
+ } while (!done);
+
+ tx_end = get_time().le.lo;
+
+ if (adv_packet->header.adv.type ==
+ BLE_ADV_HEADER_PDU_TYPE_ADV_NONCONN_IND)
+ return EC_SUCCESS;
+
+ rv = ble_rx(&rcv_packet, 16000, 1);
+
+ if (rv != EC_SUCCESS)
+ return rv;
+
+ /* Check for valid responses */
+ switch (rcv_packet.header.adv.type) {
+ case BLE_ADV_HEADER_PDU_TYPE_SCAN_REQ:
+ /* Scan requests are only allowed for ADV_IND and SCAN_IND */
+ if (adv_packet->header.adv.type !=
+ BLE_ADV_HEADER_PDU_TYPE_ADV_IND &&
+ adv_packet->header.adv.type !=
+ BLE_ADV_HEADER_PDU_TYPE_ADV_SCAN_IND)
+ return rv;
+ /* The advertising address needs to match */
+ if (memcmp(&rcv_packet.payload[BLUETOOTH_ADDR_OCTETS],
+ &adv_packet->payload[0], BLUETOOTH_ADDR_OCTETS))
+ return rv;
+ break;
+ case BLE_ADV_HEADER_PDU_TYPE_CONNECT_REQ:
+ /* Connections are only allowed for two types of advertising */
+ if (adv_packet->header.adv.type !=
+ BLE_ADV_HEADER_PDU_TYPE_ADV_IND &&
+ adv_packet->header.adv.type !=
+ BLE_ADV_HEADER_PDU_TYPE_ADV_DIRECT_IND)
+ return rv;
+ /* The advertising address needs to match */
+ if (memcmp(&rcv_packet.payload[BLUETOOTH_ADDR_OCTETS],
+ &adv_packet->payload[0], BLUETOOTH_ADDR_OCTETS))
+ return rv;
+ /* The InitAddr needs to match for Directed advertising */
+ if (adv_packet->header.adv.type ==
+ BLE_ADV_HEADER_PDU_TYPE_ADV_DIRECT_IND &&
+ memcmp(&adv_packet->payload[BLUETOOTH_ADDR_OCTETS],
+ &rcv_packet.payload[0], BLUETOOTH_ADDR_OCTETS))
+ return rv;
+ break;
+ default: /* Unhandled response packet */
+ return rv;
+ break;
+ }
+
+ dump_ble_packet(&rcv_packet);
+ CPRINTF("tx_end %u Response %u\n", tx_end, rsp_end);
+
+ return rv;
+}
+
+int ble_adv_event(struct ble_pdu *adv_packet)
+{
+ int chan;
+ int rv;
+
+ for (chan = 37; chan < 40; chan++) {
+ rv = ble_adv_packet(adv_packet, chan);
+ if (rv != EC_SUCCESS)
+ return rv;
+ }
+
+ return rv;
+}
+
+static void fill_header(struct ble_pdu *adv, int type, int txaddr, int rxaddr)
+{
+ adv->header_type_adv = 1;
+ adv->header.adv.type = type;
+ adv->header.adv.txaddr = txaddr ?
+ BLE_ADV_HEADER_RANDOM_ADDR : BLE_ADV_HEADER_PUBLIC_ADDR;
+ adv->header.adv.rxaddr = rxaddr ?
+ BLE_ADV_HEADER_RANDOM_ADDR : BLE_ADV_HEADER_PUBLIC_ADDR;
+ adv->header.adv.length = 0;
+}
+
+static int fill_payload(uint8_t *payload, uint64_t addr, int name_length)
+{
+ uint8_t *curr;
+
+ curr = pack_adv_addr(payload, addr);
+ curr = pack_adv(curr, name_length, GAP_COMPLETE_NAME,
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs");
+ curr = pack_adv_int(curr, 2, GAP_APPEARANCE,
+ GAP_APPEARANCE_HID_KEYBOARD);
+ curr = pack_adv_int(curr, 1, GAP_FLAGS,
+ GAP_FLAGS_LE_LIM_DISC | GAP_FLAGS_LE_NO_BR_EDR);
+ curr = pack_adv_int(curr, 2, GAP_COMP_16_BIT_UUID,
+ GATT_SERVICE_HID_UUID);
+
+ return curr - payload;
+}
+
+static void fill_packet(struct ble_pdu *adv, uint64_t addr, int type,
+ int name_length)
+{
+ fill_header(adv, type, BLE_ADV_HEADER_RANDOM_ADDR,
+ BLE_ADV_HEADER_PUBLIC_ADDR);
+
+ adv->header.adv.length = fill_payload(adv->payload, addr, name_length);
+}
+
+static int command_ble_adv(int argc, char **argv)
+{
+ int type, length, reps, interval;
+ uint64_t addr;
+ char *e;
+ int i;
+ int rv;
+
+ if (argc < 3 || argc > 5)
+ return EC_ERROR_PARAM_COUNT;
+
+ type = strtoi(argv[1], &e, 0);
+ if (*e || type < 0 || (type > 2 && type != 6))
+ return EC_ERROR_PARAM1;
+
+ length = strtoi(argv[2], &e, 0);
+ if (*e || length > 32)
+ return EC_ERROR_PARAM2;
+
+ if (argc >= 4) {
+ reps = strtoi(argv[3], &e, 0);
+ if (*e || reps < 0)
+ return EC_ERROR_PARAM3;
+ } else {
+ reps = 1;
+ }
+
+ if (argc >= 5) {
+ interval = strtoi(argv[4], &e, 0);
+ if (*e || interval < 0)
+ return EC_ERROR_PARAM4;
+ } else {
+ interval = 100000;
+ }
+
+ if (type == BLE_ADV_HEADER_PDU_TYPE_ADV_DIRECT_IND && length != 12) {
+ length = 12;
+ CPRINTS("type DIRECT needs to have a length of 12");
+ }
+
+ rv = ble_radio_init();
+
+
+ CPRINTS("ADV @%p", &adv_packet);
+
+ ((uint32_t *)&addr)[0] = 0xA3A2A1A0 | type;
+ ((uint32_t *)&addr)[1] = BLE_RANDOM_ADDR_MSBS_STATIC << 8 | 0x5A4;
+
+ fill_packet(&adv_packet, addr, type, length);
+
+ for (i = 0; i < reps; i++) {
+ ble_adv_event(&adv_packet);
+ usleep(interval);
+ }
+
+ return rv;
+}
+DECLARE_CONSOLE_COMMAND(ble_adv, command_ble_adv,
+ "type len [reps] [interval = 100000 (100ms)]",
+ "Send a BLE packet of type type of length len",
+ NULL);
+
+static int command_ble_adv_scan(int argc, char **argv)
+{
+ int chan, packets, i;
+ int addr_lsbyte;
+ char *e;
+ int rv;
+
+ if (argc < 2)
+ return EC_ERROR_PARAM_COUNT;
+
+ chan = strtoi(argv[1], &e, 0);
+ if (*e || chan < 37 || chan > 39)
+ return EC_ERROR_PARAM1;
+
+ chan = strtoi(argv[1], &e, 0);
+ if (*e || chan < 37 || chan > 39)
+ return EC_ERROR_PARAM1;
+
+ if (argc >= 3) {
+ packets = strtoi(argv[2], &e, 0);
+ if (*e || packets < 0)
+ return EC_ERROR_PARAM2;
+ } else {
+ packets = 1;
+ }
+
+ if (argc >= 4) {
+ addr_lsbyte = strtoi(argv[3], &e, 0);
+ if (*e || addr_lsbyte > 255)
+ return EC_ERROR_PARAM3;
+ } else {
+ addr_lsbyte = -1;
+ }
+
+ rv = ble_radio_init();
+
+ /* Change channel */
+ NRF51_RADIO_FREQUENCY = NRF51_RADIO_FREQUENCY_VAL(chan2freq(chan));
+ NRF51_RADIO_DATAWHITEIV = chan;
+
+ CPRINTS("ADV Listen");
+ if (addr_lsbyte != -1)
+ CPRINTS("filtered (%x)\n", addr_lsbyte);
+
+ for (i = 0; i < packets; i++) {
+ rv = ble_rx(&rcv_packet, 1000000, 1);
+
+ if (rv == EC_ERROR_TIMEOUT)
+ continue;
+
+ if (addr_lsbyte == -1 || rcv_packet.payload[0] == addr_lsbyte)
+ dump_ble_packet(&rcv_packet);
+ }
+
+ rv = radio_disable();
+
+ CPRINTS("on_air payload rcvd %p", &rx_packet);
+
+ return rv;
+}
+DECLARE_CONSOLE_COMMAND(ble_scan, command_ble_adv_scan,
+ "chan [num] [addr0]",
+ "Scan for [num] BLE packets on channel chan",
+ NULL);
+
diff --git a/chip/nrf51/bluetooth_le.h b/chip/nrf51/bluetooth_le.h
new file mode 100644
index 0000000000..8a746f39d7
--- /dev/null
+++ b/chip/nrf51/bluetooth_le.h
@@ -0,0 +1,67 @@
+/* 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.
+ */
+
+#ifndef __NRF51_BLUETOOTH_LE_H
+#define __NRF51_BLUETOOTH_LE_H
+
+#include "common.h"
+#include "include/bluetooth_le.h"
+
+#define NRF51_BLE_LENGTH_BITS 8
+#define NRF51_BLE_S0_BYTES 1
+#define NRF51_BLE_S1_BITS 0 /* no s1 field */
+
+#define NRF51_RADIO_PCNF0_ADV NRF51_RADIO_PCNF0_VAL(NRF51_BLE_LENGTH_BITS, \
+ NRF51_BLE_S0_BYTES, \
+ NRF51_BLE_S1_BITS)
+
+#define BLE_ACCESS_ADDRESS_BYTES 4
+#define EXTRA_RECEIVE_BYTES 0
+#define BLE_ADV_WHITEN 1
+
+#define NRF51_RADIO_PCNF1_ADV \
+ NRF51_RADIO_PCNF1_VAL(BLE_MAX_ADV_PAYLOAD_OCTETS, \
+ EXTRA_RECEIVE_BYTES, \
+ BLE_ACCESS_ADDRESS_BYTES - 1, \
+ BLE_ADV_WHITEN)
+
+
+struct nrf51_ble_packet_t {
+ uint8_t s0; /* First byte */
+ uint8_t length; /* Length field */
+ uint8_t payload[BLE_MAX_DATA_PAYLOAD_OCTETS];
+} __packed;
+
+struct nrf51_ble_config_t {
+ uint8_t channel;
+ uint8_t address;
+ uint32_t crc_init;
+};
+
+/* Initialize the nRF51 radio for BLE */
+int ble_radio_init(void);
+
+/* Transmit pdu on the radio */
+void ble_tx(struct ble_pdu *pdu);
+
+/* Receive a packet into pdu if one comes before the timeout */
+int ble_rx(struct ble_pdu *pdu, int timeout, int adv);
+
+/* White list handling */
+
+/* Clear the white list */
+int ble_radio_clear_white_list(void);
+
+/* Read the size of the white list and assign it to ret_size */
+int ble_radio_read_white_list_size(uint8_t *ret_size);
+
+/* Add the device with the address specified by addr_ptr and type */
+int ble_radio_add_device_to_white_list(const uint8_t *addr_ptr, uint8_t type);
+
+/* Remove the device with the address specified by addr_ptr and type */
+int ble_radio_remove_device_from_white_list(const uint8_t *addr_ptr,
+ uint8_t type);
+
+#endif /* __NRF51_BLUETOOTH_LE_H */
diff --git a/chip/nrf51/build.mk b/chip/nrf51/build.mk
index 88509bba3c..69a2e3ed41 100644
--- a/chip/nrf51/build.mk
+++ b/chip/nrf51/build.mk
@@ -13,7 +13,7 @@ CFLAGS_CPU+=-march=armv6-m -mcpu=cortex-m0
chip-y+=gpio.o system.o uart.o
chip-y+=jtag.o watchdog.o ppi.o
-chip-$(CONFIG_BLUETOOTH_LE)+=radio.o
+chip-$(CONFIG_BLUETOOTH_LE)+=radio.o bluetooth_le.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/registers.h b/chip/nrf51/registers.h
index 3f60828fa1..e9d2003f33 100644
--- a/chip/nrf51/registers.h
+++ b/chip/nrf51/registers.h
@@ -232,7 +232,7 @@
#define NRF51_RADIO_TEST REG32(NRF51_RADIO_BASE + 0x540)
#define NRF51_RADIO_TIFS REG32(NRF51_RADIO_BASE + 0x544)
#define NRF51_RADIO_RSSISAMPLE REG32(NRF51_RADIO_BASE + 0x548)
-#define NRF51_RADIO_STATE REG32(NRF51_RADIO_BASE + 0x550)
+/* NRF51_RADIO_STATE (0x550) is Broken (PAN 2.4) */
#define NRF51_RADIO_DATAWHITEIV REG32(NRF51_RADIO_BASE + 0x554)
#define NRF51_RADIO_BCC REG32(NRF51_RADIO_BASE + 0x560)
#define NRF51_RADIO_DAB(n) REG32(NRF51_RADIO_BASE + 0x600 + ((n) * 4))
@@ -251,6 +251,17 @@
#define NRF51_RADIO_SHORTS_ADDRESS_BCSTART 0x040
#define NRF51_RADIO_SHORTS_DISABLED_RSSISTOP 0x100
+/* For RADIO.INTEN bits */
+#define NRF51_RADIO_READY_BIT 0
+#define NRF51_RADIO_ADDRESS_BIT 1
+#define NRF51_RADIO_PAYLOAD_BIT 2
+#define NRF51_RADIO_END_BIT 3
+#define NRF51_RADIO_DISABLED_BIT 4
+#define NRF51_RADIO_DEVMATCH_BIT 5
+#define NRF51_RADIO_DEVMISS_BIT 6
+#define NRF51_RADIO_RSSIEND_BIT 7
+#define NRF51_RADIO_BCMATCH_BIT 10
+
/* CRC Status */
#define NRF51_RADIO_CRCSTATUS_OK 0x1
@@ -269,18 +280,50 @@
/* TX Mode */
#define NRF51_RADIO_MODE_BLE_1MBIT 0x03
-/* PCNF0 Packet Configuration */
+/*
+ * PCNF0 and PCNF1 Packet Configuration
+ *
+ * The radio unpacks the packet for you according to these settings.
+ *
+ * The on-air format is:
+ *
+ * |_Preamble_|___Base___|_Prefix_|___S0____|_Length_,_S1_|__Payload__|___|
+ * 0 <ba_bytes> <1 byte><s0_bytes> <1 byte> <max_bytes> <extra>
+ *
+ * The in-memory format is
+ *
+ * uint8_t s0[s0_bytes];
+ * uint8_t length;
+ * uint8_t s1;
+ * uint8_t payload[max_bytes];
+ *
+ * lf_bits is how many bits to store in length
+ * s1_bits is how many bits to store in s1
+ *
+ * If any one of these lengths are set to zero, the field is omitted in memory.
+ */
+
#define NRF51_RADIO_PCNF0_LFLEN_SHIFT 0
#define NRF51_RADIO_PCNF0_S0LEN_SHIFT 8
#define NRF51_RADIO_PCNF0_S1LEN_SHIFT 16
-/* PCNF1 Packet Configuration */
+#define NRF51_RADIO_PCNF0_VAL(lf_bits, s0_bytes, s1_bits) \
+ ((lf_bits) << NRF51_RADIO_PCNF0_LFLEN_SHIFT | \
+ (s0_bytes) << NRF51_RADIO_PCNF0_S0LEN_SHIFT | \
+ (s1_bits) << NRF51_RADIO_PCNF0_S1LEN_SHIFT)
+
#define NRF51_RADIO_PCNF1_MAXLEN_SHIFT 0
#define NRF51_RADIO_PCNF1_STATLEN_SHIFT 8
#define NRF51_RADIO_PCNF1_BALEN_SHIFT 16
#define NRF51_RADIO_PCNF1_ENDIAN_BIG 0x1000000
#define NRF51_RADIO_PCNF1_WHITEEN 0x2000000
+#define NRF51_RADIO_PCNF1_VAL(max_bytes, extra_bytes, ba_bytes, whiten) \
+ ((max_bytes) << NRF51_RADIO_PCNF1_MAXLEN_SHIFT | \
+ (extra_bytes) << NRF51_RADIO_PCNF1_STATLEN_SHIFT | \
+ (ba_bytes) << NRF51_RADIO_PCNF1_BALEN_SHIFT | \
+ ((whiten) ? NRF51_RADIO_PCNF1_WHITEEN : 0))
+
/* PREFIX0 */
#define NRF51_RADIO_PREFIX0_AP0_SHIFT 0
#define NRF51_RADIO_PREFIX0_AP1_SHIFT 8
@@ -313,7 +356,9 @@
/* DACNF */
#define NRF51_RADIO_DACNF_ENA(n) (1 << (n))
+#define NRF51_RADIO_DACNF_MAX 8
#define NRF51_RADIO_DACNF_TXADD(n) (1 << ((n)+8))
+#define NRF51_RADIO_TXADD_MAX 8
/* OVERRIDE4 */
#define NRF51_RADIO_OVERRIDE_EN (1 << 31)