summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMyles Watson <mylesgw@chromium.org>2015-02-02 14:44:27 -0800
committerchrome-bot <chrome-bot@chromium.org>2016-08-08 01:48:43 -0700
commit9ee1b4a767daaf23b278c9f33b0fe30bf9d91adf (patch)
treebbcce34eeaaecbd2de74636c526d33226a8bc828
parent73701c46370cd562d311feeb80b2de8ea696935c (diff)
downloadchrome-ec-9ee1b4a767daaf23b278c9f33b0fe30bf9d91adf.tar.gz
btle: Add common link layer code
BUG=None BRANCH=None TEST=make BOARD=hadoken Add a task that is responsible for the state of the link layer. Change-Id: Ifc79bf1e4c57f5de448ab05b3a8d3a1aca5a58e2 Signed-off-by: Myles Watson <mylesgw@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/362144 Commit-Ready: Dan Shi <dshi@google.com> Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--board/hadoken/board.h1
-rw-r--r--board/hadoken/ec.tasklist1
-rw-r--r--common/btle_ll.c552
-rw-r--r--common/build.mk1
-rw-r--r--include/bluetooth_le.h2
-rw-r--r--include/bluetooth_le_ll.h120
-rw-r--r--include/config.h3
-rw-r--r--include/console_channel.inc3
8 files changed, 682 insertions, 1 deletions
diff --git a/board/hadoken/board.h b/board/hadoken/board.h
index 6e696a480c..ddbe81c4d2 100644
--- a/board/hadoken/board.h
+++ b/board/hadoken/board.h
@@ -28,6 +28,7 @@
#define CONFIG_BLUETOOTH_LE
#define CONFIG_BLUETOOTH_LE_STACK
#define CONFIG_BLUETOOTH_LE_RADIO_TEST
+#define CONFIG_BLUETOOTH_LL_DEBUG
#include "gpio_signal.h"
diff --git a/board/hadoken/ec.tasklist b/board/hadoken/ec.tasklist
index 684f22b716..3c5b72d44b 100644
--- a/board/hadoken/ec.tasklist
+++ b/board/hadoken/ec.tasklist
@@ -17,4 +17,5 @@
#define CONFIG_TASK_LIST \
TASK_ALWAYS(HOOKS, hook_task, NULL, LARGER_TASK_STACK_SIZE) \
TASK_ALWAYS(CONSOLE, console_task, NULL, TASK_STACK_SIZE) \
+ TASK_ALWAYS(BLE_LL, bluetooth_ll_task, NULL, TASK_STACK_SIZE)
diff --git a/common/btle_ll.c b/common/btle_ll.c
new file mode 100644
index 0000000000..9ee052dac0
--- /dev/null
+++ b/common/btle_ll.c
@@ -0,0 +1,552 @@
+/* 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_ll.h"
+#include "bluetooth_le.h"
+#include "btle_hci_int.h"
+#include "util.h"
+#include "console.h"
+#include "radio.h"
+#include "radio_test.h"
+#include "task.h"
+#include "timer.h"
+
+#ifdef CONFIG_BLUETOOTH_LL_DEBUG
+
+#define CPUTS(outstr) cputs(CC_BLUETOOTH_LL, outstr)
+#define CPRINTS(format, args...) cprints(CC_BLUETOOTH_LL, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_BLUETOOTH_LL, format, ## args)
+
+#else /* CONFIG_BLUETOOTH_LL_DEBUG */
+
+#define CPUTS(outstr)
+#define CPRINTS(format, args...)
+#define CPRINTF(format, args...)
+
+#endif /* CONFIG_BLUETOOTH_LL_DEBUG */
+
+/* Link Layer */
+
+enum ll_state_t ll_state = UNINITIALIZED;
+
+static struct hciLeSetAdvParams ll_adv_params;
+static struct hciLeSetScanParams ll_scan_params;
+static int ll_adv_interval_us;
+static int ll_adv_timeout_us;
+
+static struct ble_pdu ll_adv_pdu;
+static struct ble_pdu ll_scan_rsp_pdu;
+
+int ll_power;
+
+static uint64_t ll_random_address = 0xC5BADBADBAD1; /* Uninitialized */
+static uint64_t ll_public_address = 0xC5BADBADBADF; /* Uninitialized */
+static uint8_t ll_channel_map[5] = {0xff, 0xff, 0xff, 0xff, 0x1f};
+
+static uint8_t ll_filter_duplicates;
+
+int ll_pseudo_rand(int max_plus_one)
+{
+ static uint32_t lfsr = 0x55555;
+ int lsb = lfsr & 1;
+
+ lfsr = lfsr >> 1;
+ if (lsb)
+ lfsr ^= 0x80020003; /* Bits 32, 22, 2, 1 */
+ return lfsr % max_plus_one;
+}
+
+uint8_t ll_set_tx_power(uint8_t *params)
+{
+ /* Add checking */
+ ll_power = params[0];
+ return HCI_SUCCESS;
+}
+
+uint8_t ll_read_tx_power(void)
+{
+ return ll_power;
+}
+
+/* LE Information */
+uint8_t ll_read_buffer_size(uint8_t *return_params)
+{
+ return_params[0] = LL_MAX_DATA_PACKET_LENGTH & 0xff;
+ return_params[1] = (LL_MAX_DATA_PACKET_LENGTH >> 8) & 0xff;
+ return_params[2] = LL_MAX_DATA_PACKETS;
+ return HCI_SUCCESS;
+}
+
+uint8_t ll_read_local_supported_features(uint8_t *return_params)
+{
+ uint64_t supported_features = LL_SUPPORTED_FEATURES;
+
+ memcpy(return_params, &supported_features, sizeof(supported_features));
+ return HCI_SUCCESS;
+}
+
+uint8_t ll_read_supported_states(uint8_t *return_params)
+{
+ uint64_t supported_states = LL_SUPPORTED_STATES;
+
+ memcpy(return_params, &supported_states, sizeof(supported_states));
+ return HCI_SUCCESS;
+}
+
+uint8_t ll_set_host_channel_classification(uint8_t *params)
+{
+ memcpy(ll_channel_map, params, sizeof(ll_channel_map));
+ return HCI_SUCCESS;
+}
+
+/* Advertising */
+uint8_t ll_set_scan_response_data(uint8_t *params)
+{
+ if (params[0] > BLE_MAX_ADV_PAYLOAD_OCTETS)
+ return HCI_ERR_Invalid_HCI_Command_Parameters;
+
+ if (ll_state == ADVERTISING)
+ return HCI_ERR_Controller_Busy;
+
+ memcpy(&ll_scan_rsp_pdu.payload[BLUETOOTH_ADDR_OCTETS], &params[1],
+ params[0]);
+ ll_scan_rsp_pdu.header.adv.length = params[0] + BLUETOOTH_ADDR_OCTETS;
+
+ return HCI_SUCCESS;
+}
+
+uint8_t ll_set_adv_data(uint8_t *params)
+{
+ if (params[0] > BLE_MAX_ADV_PAYLOAD_OCTETS)
+ return HCI_ERR_Invalid_HCI_Command_Parameters;
+
+ if (ll_state == ADVERTISING)
+ return HCI_ERR_Controller_Busy;
+
+ /* Skip the address */
+ memcpy(&ll_adv_pdu.payload[BLUETOOTH_ADDR_OCTETS], &params[1],
+ params[0]);
+ ll_adv_pdu.header.adv.length = params[0] + BLUETOOTH_ADDR_OCTETS;
+
+ return HCI_SUCCESS;
+}
+
+uint8_t ll_reset(void)
+{
+ ll_state = UNINITIALIZED;
+ radio_disable();
+
+ ble_radio_clear_white_list();
+
+ return HCI_SUCCESS;
+}
+
+static uint8_t ll_state_change_request(enum ll_state_t next_state)
+{
+ /* Initialize the radio if it hasn't been initialized */
+ if (ll_state == UNINITIALIZED) {
+ if (ble_radio_init() != EC_SUCCESS)
+ return HCI_ERR_Hardware_Failure;
+ ll_state = STANDBY;
+ }
+
+ /* Only change states when the link layer is in STANDBY */
+ if (next_state != STANDBY && ll_state != STANDBY)
+ return HCI_ERR_Controller_Busy;
+
+ ll_state = next_state;
+
+ return HCI_SUCCESS;
+}
+
+uint8_t ll_set_advertising_enable(uint8_t *params)
+{
+ uint8_t rv;
+
+ if (params[0]) {
+ rv = ll_state_change_request(ADVERTISING);
+ if (rv == HCI_SUCCESS)
+ task_wake(TASK_ID_BLE_LL);
+ } else {
+ rv = ll_state_change_request(STANDBY);
+ }
+
+ return rv;
+}
+
+uint8_t ll_set_scan_enable(uint8_t *params)
+{
+ uint8_t rv;
+
+ if (params[0]) {
+ ll_filter_duplicates = params[1];
+ rv = ll_state_change_request(SCANNING);
+ if (rv == HCI_SUCCESS)
+ task_wake(TASK_ID_BLE_LL);
+ } else {
+ rv = ll_state_change_request(STANDBY);
+ }
+
+ return HCI_SUCCESS;
+}
+
+/* White List */
+uint8_t ll_clear_white_list(void)
+{
+ if (ble_radio_clear_white_list() == EC_SUCCESS)
+ return HCI_SUCCESS;
+ else
+ return HCI_ERR_Hardware_Failure;
+}
+
+uint8_t ll_read_white_list_size(uint8_t *return_params)
+{
+ if (ble_radio_read_white_list_size(return_params) == EC_SUCCESS)
+ return HCI_SUCCESS;
+ else
+ return HCI_ERR_Hardware_Failure;
+}
+
+uint8_t ll_add_device_to_white_list(uint8_t *params)
+{
+ if (ble_radio_add_device_to_white_list(&params[1], params[0]) ==
+ EC_SUCCESS)
+ return HCI_SUCCESS;
+ else
+ return HCI_ERR_Host_Rejected_Due_To_Limited_Resources;
+}
+
+uint8_t ll_remove_device_from_white_list(uint8_t *params)
+{
+ if (ble_radio_remove_device_from_white_list(&params[1], params[0]) ==
+ EC_SUCCESS)
+ return HCI_SUCCESS;
+ else
+ return HCI_ERR_Hardware_Failure;
+}
+
+/* Connections */
+uint8_t ll_read_remote_used_features(uint8_t *params)
+{
+ uint16_t handle = params[0] | (((uint16_t)params[1]) << 8);
+
+ CPRINTS("Read remote used features for handle %d", handle);
+ /* Check handle */
+ return HCI_SUCCESS;
+}
+
+/* RF PHY Testing */
+static int ll_test_packets;
+
+uint8_t ll_receiver_test(uint8_t *params)
+{
+ int rv;
+
+ ll_test_packets = 0;
+
+ /* See if the link layer is busy */
+ rv = ll_state_change_request(TEST_RX);
+ if (rv)
+ return rv;
+
+ rv = ble_test_rx_init(params[0]);
+ if (rv)
+ return rv;
+
+ CPRINTS("Start Rx test");
+ task_wake(TASK_ID_BLE_LL);
+
+ return HCI_SUCCESS;
+}
+
+uint8_t ll_transmitter_test(uint8_t *params)
+{
+ int rv;
+
+ ll_test_packets = 0;
+
+ /* See if the link layer is busy */
+ rv = ll_state_change_request(TEST_TX);
+ if (rv)
+ return rv;
+
+ rv = ble_test_tx_init(params[0], params[1], params[2]);
+ if (rv)
+ return rv;
+
+ CPRINTS("Start Tx test");
+ task_wake(TASK_ID_BLE_LL);
+
+ return HCI_SUCCESS;
+}
+
+uint8_t ll_test_end(uint8_t *return_params)
+{
+ CPRINTS("End (%d packets)", ll_test_packets);
+
+ ble_test_stop();
+
+ if (ll_state == TEST_RX) {
+ return_params[0] = ll_test_packets & 0xff;
+ return_params[1] = (ll_test_packets >> 8);
+ ll_test_packets = 0;
+ } else {
+ return_params[0] = 0;
+ return_params[1] = 0;
+ ll_test_packets = 0;
+ }
+ return ll_reset();
+}
+
+uint8_t ll_set_random_address(uint8_t *params)
+{
+ /* No checking. The host should know the rules. */
+ memcpy(&ll_random_address, params,
+ sizeof(struct hciLeSetRandomAddress));
+ return HCI_SUCCESS;
+}
+
+uint8_t ll_set_scan_params(uint8_t *params)
+{
+ if (ll_state == SCANNING)
+ return HCI_ERR_Controller_Busy;
+
+ memcpy(&ll_scan_params, params, sizeof(struct hciLeSetScanParams));
+
+ return HCI_SUCCESS;
+}
+
+uint8_t ll_set_advertising_params(uint8_t *params)
+{
+ if (ll_state == ADVERTISING)
+ return HCI_ERR_Controller_Busy;
+
+ memcpy(&ll_adv_params, params, sizeof(struct hciLeSetAdvParams));
+
+ switch (ll_adv_params.advType) {
+ case BLE_ADV_HEADER_PDU_TYPE_ADV_NONCONN_IND:
+ case BLE_ADV_HEADER_PDU_TYPE_ADV_SCAN_IND:
+ if (ll_adv_params.advIntervalMin <
+ (100000 / LL_ADV_INTERVAL_UNIT_US)) /* 100ms */
+ return HCI_ERR_Invalid_HCI_Command_Parameters;
+ /* Fall through */
+ case BLE_ADV_HEADER_PDU_TYPE_ADV_IND:
+ if (ll_adv_params.advIntervalMin > ll_adv_params.advIntervalMax)
+ return HCI_ERR_Invalid_HCI_Command_Parameters;
+ if (ll_adv_params.advIntervalMin <
+ (20000 / LL_ADV_INTERVAL_UNIT_US) || /* 20ms */
+ ll_adv_params.advIntervalMax >
+ (10240000 / LL_ADV_INTERVAL_UNIT_US)) /* 10.24s */
+ return HCI_ERR_Invalid_HCI_Command_Parameters;
+ ll_adv_interval_us = (((ll_adv_params.advIntervalMin +
+ ll_adv_params.advIntervalMax) / 2) *
+ LL_ADV_INTERVAL_UNIT_US);
+ /* Don't time out */
+ ll_adv_timeout_us = -1;
+ break;
+ case BLE_ADV_HEADER_PDU_TYPE_ADV_DIRECT_IND:
+ ll_adv_interval_us = LL_ADV_DIRECT_INTERVAL_US;
+ ll_adv_timeout_us = LL_ADV_DIRECT_TIMEOUT_US;
+ break;
+ default:
+ return HCI_ERR_Invalid_HCI_Command_Parameters;
+ }
+
+ /* Initialize the ADV PDU */
+ ll_adv_pdu.header_type_adv = 1;
+ ll_adv_pdu.header.adv.type = ll_adv_params.advType;
+ ll_adv_pdu.header.adv.txaddr = ll_adv_params.useRandomAddress;
+
+ if (ll_adv_params.useRandomAddress)
+ memcpy(ll_adv_pdu.payload, &ll_random_address,
+ BLUETOOTH_ADDR_OCTETS);
+ else
+ memcpy(ll_adv_pdu.payload, &ll_public_address,
+ BLUETOOTH_ADDR_OCTETS);
+
+ if (ll_adv_params.advType == BLE_ADV_HEADER_PDU_TYPE_ADV_DIRECT_IND) {
+ ll_adv_pdu.header.adv.rxaddr =
+ ll_adv_params.directRandomAddress;
+ memcpy(&ll_adv_pdu.payload[BLUETOOTH_ADDR_OCTETS],
+ ll_adv_params.directAddr,
+ sizeof(ll_adv_params.directAddr));
+ ll_adv_pdu.header.adv.length = 12;
+ } else {
+ ll_adv_pdu.header.adv.rxaddr = 0;
+ }
+
+ /* All other types get data from SetAdvertisingData */
+
+ /* Initialize the Scan Rsp PDU */
+ ll_scan_rsp_pdu.header_type_adv = 1;
+ ll_scan_rsp_pdu.header.adv.type = BLE_ADV_HEADER_PDU_TYPE_SCAN_RSP;
+ ll_scan_rsp_pdu.header.adv.txaddr = ll_adv_params.useRandomAddress;
+
+ if (ll_adv_params.useRandomAddress)
+ memcpy(ll_scan_rsp_pdu.payload, &ll_random_address,
+ BLUETOOTH_ADDR_OCTETS);
+ else
+ memcpy(ll_scan_rsp_pdu.payload, &ll_public_address,
+ BLUETOOTH_ADDR_OCTETS);
+
+ ll_scan_rsp_pdu.header.adv.rxaddr = 0;
+
+ return HCI_SUCCESS;
+}
+
+static uint32_t tx_end, rsp_end, tx_rsp_end;
+struct ble_pdu ll_rcv_packet;
+
+int ble_ll_adv(int chan)
+{
+ int rv;
+
+ ble_tx(&ll_adv_pdu);
+
+ while (!RADIO_DONE)
+ ;
+
+ tx_end = get_time().le.lo;
+
+ if (ll_adv_pdu.header.adv.type ==
+ BLE_ADV_HEADER_PDU_TYPE_ADV_NONCONN_IND)
+ return rv;
+
+ rv = ble_rx(&ll_rcv_packet, 16000, 1);
+
+ if (rv != EC_SUCCESS)
+ return rv;
+
+ while (!RADIO_DONE)
+ ;
+
+ tx_rsp_end = get_time().le.lo;
+
+ /* Check for valid responses */
+ switch (ll_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 ((ll_adv_pdu.header.adv.type !=
+ BLE_ADV_HEADER_PDU_TYPE_ADV_IND &&
+ ll_adv_pdu.header.adv.type !=
+ BLE_ADV_HEADER_PDU_TYPE_ADV_SCAN_IND) ||
+ /* The advertising address needs to match */
+ (memcmp(&ll_rcv_packet.payload[BLUETOOTH_ADDR_OCTETS],
+ &ll_adv_pdu.payload[0], BLUETOOTH_ADDR_OCTETS))) {
+ /* Don't send the scan response */
+ radio_disable();
+ return rv;
+ }
+ break;
+ case BLE_ADV_HEADER_PDU_TYPE_CONNECT_REQ:
+ /* Don't send a scan response */
+ radio_disable();
+ /* Connecting is only allowed for ADV_IND and ADV_DIRECT_IND */
+ if (ll_adv_pdu.header.adv.type !=
+ BLE_ADV_HEADER_PDU_TYPE_ADV_IND &&
+ ll_adv_pdu.header.adv.type !=
+ BLE_ADV_HEADER_PDU_TYPE_ADV_DIRECT_IND)
+ return rv;
+ /* The advertising address needs to match */
+ if (memcmp(&ll_rcv_packet.payload[BLUETOOTH_ADDR_OCTETS],
+ &ll_adv_pdu.payload[0], BLUETOOTH_ADDR_OCTETS))
+ return rv;
+ /* The InitAddr address needs to match for ADV_DIRECT_IND */
+ if (ll_adv_pdu.header.adv.type ==
+ BLE_ADV_HEADER_PDU_TYPE_ADV_DIRECT_IND &&
+ memcmp(&ll_adv_pdu.payload[BLUETOOTH_ADDR_OCTETS],
+ &ll_rcv_packet.payload[0], BLUETOOTH_ADDR_OCTETS))
+ return rv;
+ break;
+ default: /* Unhandled response packet */
+ radio_disable();
+ return rv;
+ break;
+ }
+
+ dump_ble_packet(&ll_rcv_packet);
+ CPRINTF("ADV %u Response %u %u\n", tx_end, rsp_end, tx_rsp_end);
+
+ return rv;
+}
+
+int ble_ll_adv_event(void)
+{
+ int chan_idx;
+ int rv;
+
+ for (chan_idx = 0; chan_idx < 3; chan_idx++) {
+ if (ll_adv_params.advChannelMap & (1 << chan_idx)) {
+ rv = ble_ll_adv(chan_idx + 37);
+ if (rv != EC_SUCCESS)
+ return rv;
+ }
+ }
+
+ return rv;
+}
+
+static int ll_adv_events;
+static timestamp_t deadline;
+static uint32_t start, end;
+
+void bluetooth_ll_task(void)
+{
+ CPRINTS("LL task init");
+
+ while (1) {
+ switch (ll_state) {
+ case ADVERTISING:
+
+ if (deadline.val == 0) {
+ CPRINTS("ADV @%p", &ll_adv_pdu);
+ deadline.val = get_time().val +
+ (uint32_t)ll_adv_timeout_us;
+ ll_adv_events = 0;
+ }
+
+ ble_ll_adv_event();
+ ll_adv_events++;
+
+ /* sleep for 0-10ms */
+ usleep(ll_adv_interval_us + ll_pseudo_rand(10000));
+
+ if (get_time().val > deadline.val) {
+ deadline.val = 0;
+ ll_state = STANDBY;
+ break;
+ }
+ break;
+ case STANDBY:
+ CPRINTS("Standby %d events", ll_adv_events);
+ ll_adv_events = 0;
+ task_wait_event(-1);
+ break;
+ case TEST_RX:
+ if (ble_test_rx() == HCI_SUCCESS)
+ ll_test_packets++;
+ /* Packets come every 625us, sleep to save power */
+ usleep(300);
+ break;
+ case TEST_TX:
+ start = get_time().le.lo;
+ ble_test_tx();
+ ll_test_packets++;
+ end = get_time().le.lo;
+ usleep(625 - 82 - (end-start)); /* 625us */
+ break;
+ case UNINITIALIZED:
+ ll_adv_events = 0;
+ deadline.val = 0;
+ task_wait_event(-1);
+ break;
+ default:
+ CPRINTS("Unhandled State ll_state = %d", ll_state);
+ ll_state = UNINITIALIZED;
+ task_wait_event(-1);
+ }
+ }
+}
+
diff --git a/common/build.mk b/common/build.mk
index 9a11df345d..09700021ec 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -26,6 +26,7 @@ common-$(CONFIG_BATTERY_BQ27541)+=battery.o
common-$(CONFIG_BATTERY_BQ27621)+=battery.o
common-$(CONFIG_BATTERY_SMART)+=battery.o
common-$(CONFIG_BLUETOOTH_LE)+=bluetooth_le.o
+common-$(CONFIG_BLUETOOTH_LE_STACK)+= btle_ll.o
common-$(CONFIG_BUTTON_COUNT)+=button.o
common-$(CONFIG_CAPSENSE)+=capsense.o
common-$(CONFIG_CASE_CLOSED_DEBUG)+=case_closed_debug.o
diff --git a/include/bluetooth_le.h b/include/bluetooth_le.h
index 65be0d0fbd..814e3673fc 100644
--- a/include/bluetooth_le.h
+++ b/include/bluetooth_le.h
@@ -364,7 +364,7 @@ void fill_remapping_table(struct remapping_table *rt, uint8_t map[5],
void ble_tx(struct ble_pdu *pdu);
-int ble_ll_rx(struct ble_pdu *pdu, int timeout, int adv);
+int ble_rx(struct ble_pdu *pdu, int timeout, int adv);
int ble_radio_init(void);
diff --git a/include/bluetooth_le_ll.h b/include/bluetooth_le_ll.h
new file mode 100644
index 0000000000..14520f1139
--- /dev/null
+++ b/include/bluetooth_le_ll.h
@@ -0,0 +1,120 @@
+/* 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 "common.h"
+#include "btle_hci_int.h"
+
+enum ll_state_t {
+ UNINITIALIZED,
+ STANDBY,
+ SCANNING,
+ ADVERTISING,
+ INITIATING,
+ CONNECTION,
+ TEST_RX,
+ TEST_TX,
+};
+
+#define LL_ADV_INTERVAL_UNIT_US 625
+#define LL_ADV_TIMEOUT_UNIT_US 1000000
+
+#define LL_ADV_DIRECT_INTERVAL_US 3750 /* 3.75 ms */
+#define LL_ADV_DIRECT_TIMEOUT_US 1280000 /* 1.28 s */
+
+#define LL_MAX_DATA_PACKET_LENGTH 27
+#define LL_MAX_DATA_PACKETS 4
+
+#define LL_MAX_BUFFER_SIZE (LL_MAX_DATA_PACKET_LENGTH * LL_MAX_DATA_PACKETS)
+
+#define LL_SUPPORTED_FEATURES (HCI_LE_FTR_ENCRYPTION | \
+ HCI_LE_FTR_CONNECTION_PARAMETERS_REQUEST | \
+ HCI_LE_FTR_EXTENDED_REJECT_INDICATION | \
+ HCI_LE_FTR_SLAVE_INITIATED_FEATURES_EXCHANGE)
+
+#define LL_SUPPORTED_STATES (HCI_LE_STATE_NONCON_ADV | \
+ HCI_LE_STATE_SCANNABLE_ADV | \
+ HCI_LE_STATE_CONNECTABLE_ADV | \
+ HCI_LE_STATE_DIRECT_ADV | \
+ HCI_LE_STATE_PASSIVE_SCAN | \
+ HCI_LE_STATE_ACTIVE_SCAN | \
+ HCI_LE_STATE_INITIATE | \
+ HCI_LE_STATE_SLAVE)
+
+/*
+ * 4.6.1 LE Encryption
+ * A controller that supports LE Encryption shall support the following sections
+ * within this document:
+ * - LL_ENC_REQ (Section 2.4.2.4)
+ * - LL_ENC_RSP (Section 2.4.2.5)
+ * - LL_START_ENC_REQ (Section 2.4.2.6)
+ * - LL_START_ENC_RSP (Section 2.4.2.7)
+ * - LL_PAUSE_ENC_REQ (Section 2.4.2.11)
+ * - LL_PAUSE_ENC_RSP (Section 2.4.2.12)
+ * - Encryption Start Procedure (Section 5.1.3.1)
+ * - Encryption Pause Procedure (Section 5.1.3.2)
+ */
+
+/*Link Layer Control PDU Opcodes */
+#define LL_CONNECTION_UPDATE_REQ 0x00
+#define LL_CHANNEL_MAP_REQ 0x01
+#define LL_TERMINATE_IND 0x02
+#define LL_ENC_REQ 0x03
+#define LL_ENC_RSP 0x04
+#define LL_START_ENC_REQ 0x05
+#define LL_START_ENC_RSP 0x06
+#define LL_UNKNOWN_RSP 0x07
+#define LL_FEATURE_REQ 0x08
+#define LL_FEATURE_RSP 0x09
+#define LL_PAUSE_ENC_REQ 0x0A
+#define LL_PAUSE_ENC_RSP 0x0B
+#define LL_VERSION_IND 0x0C
+#define LL_REJECT_IND 0x0D
+#define LL_SLAVE_FEATURE_REQ 0x0E
+#define LL_CONNECTION_PARAM_REQ 0x0F
+#define LL_CONNECTION_PARAM_RSP 0x10
+#define LL_REJECT_IND_EXT 0x11
+#define LL_PING_REQ 0x12
+#define LL_PING_RSP 0x13
+
+uint8_t ll_reset(void);
+
+uint8_t ll_set_tx_power(uint8_t *params);
+
+
+/* LE Information */
+uint8_t ll_read_buffer_size(uint8_t *return_params);
+uint8_t ll_read_local_supported_features(uint8_t *return_params);
+uint8_t ll_read_supported_states(uint8_t *return_params);
+uint8_t ll_set_host_channel_classification(uint8_t *params);
+
+/* Advertising */
+uint8_t ll_set_advertising_params(uint8_t *params);
+uint8_t ll_read_tx_power(void);
+uint8_t ll_set_adv_data(uint8_t *params);
+uint8_t ll_set_scan_response_data(uint8_t *params);
+uint8_t ll_set_advertising_enable(uint8_t *params);
+
+uint8_t ll_set_random_address(uint8_t *params);
+
+/* Scanning */
+uint8_t ll_set_scan_enable(uint8_t *params);
+uint8_t ll_set_scan_params(uint8_t *params);
+
+/* White List */
+uint8_t ll_clear_white_list(void);
+uint8_t ll_read_white_list_size(uint8_t *return_params);
+uint8_t ll_add_device_to_white_list(uint8_t *params);
+uint8_t ll_remove_device_from_white_list(uint8_t *params);
+
+/* Connections */
+uint8_t ll_read_remote_used_features(uint8_t *params);
+
+/* RF Phy Testing */
+uint8_t ll_receiver_test(uint8_t *params);
+uint8_t ll_transmitter_test(uint8_t *params);
+uint8_t ll_test_end(uint8_t *return_params);
+
+void ll_ble_test_rx(void);
+void ll_ble_test_rx(void);
diff --git a/include/config.h b/include/config.h
index 182d56ba78..7180757350 100644
--- a/include/config.h
+++ b/include/config.h
@@ -262,6 +262,9 @@
/* Include support for the HCI and link layers for Bluetooth LE */
#undef CONFIG_BLUETOOTH_LE_STACK
+/* Include debugging support for the Bluetooth link layer */
+#undef CONFIG_BLUETOOTH_LL_DEBUG
+
/* Boot header storage offset. */
#undef CONFIG_BOOT_HEADER_STORAGE_OFF
diff --git a/include/console_channel.inc b/include/console_channel.inc
index 4faeff5281..ab733bd49b 100644
--- a/include/console_channel.inc
+++ b/include/console_channel.inc
@@ -9,7 +9,10 @@ CONSOLE_CHANNEL(CC_COMMAND, "command")
CONSOLE_CHANNEL(CC_ACCEL, "accel")
#ifdef CONFIG_BLUETOOTH_LE
CONSOLE_CHANNEL(CC_BLUETOOTH_LE, "bluetooth_le")
+#ifdef CONFIG_BLUETOOTH_LL_DEBUG
+CONSOLE_CHANNEL(CC_BLUETOOTH_LL, "bluetooth_ll")
#endif
+#endif /* CONFIG_BLUETOOTH_LE */
#ifdef CONFIG_EXTENSION_COMMAND
CONSOLE_CHANNEL(CC_EXTENSION, "extension")
#endif