diff options
author | Myles Watson <mylesgw@chromium.org> | 2015-03-02 10:46:12 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-08-03 19:40:43 -0700 |
commit | 8c7bdcd5b6037245a6785ece11dc99e115567e70 (patch) | |
tree | 9552812e6c3e339824a5eb3e1bb8981275dd5ead /chip | |
parent | 961f6d2d16c7b1bc5d033364e3c7fc3b30ceaba4 (diff) | |
download | chrome-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')
-rw-r--r-- | chip/nrf51/bluetooth_le.c | 469 | ||||
-rw-r--r-- | chip/nrf51/bluetooth_le.h | 67 | ||||
-rw-r--r-- | chip/nrf51/build.mk | 2 | ||||
-rw-r--r-- | chip/nrf51/registers.h | 51 |
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) |