Bluetooth: Controller: Refactor HCI files
As part of the effort to consolidate the BLE Controller's HCI layer, the following files have been renamed: * hci.h -> hci_internal.h: contains the HCI API to be used by the driver * main.c -> hci_driver.c: Implement bt_driver and includes initialization and glue code Jira: ZEP-726 Change-Id: Ica8b3e114da42a766a1b14ce59558cacd899a1a7 Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
This commit is contained in:
parent
eeccdaca05
commit
496b02b54a
4 changed files with 22 additions and 24 deletions
|
@ -1,400 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <nanokernel.h>
|
||||
#include <arch/cpu.h>
|
||||
|
||||
#include <board.h>
|
||||
#include <init.h>
|
||||
#include <uart.h>
|
||||
#include <misc/util.h>
|
||||
#include <misc/stack.h>
|
||||
#include <misc/byteorder.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <bluetooth/bluetooth.h>
|
||||
#include <bluetooth/log.h>
|
||||
#include <bluetooth/hci.h>
|
||||
#include <bluetooth/driver.h>
|
||||
|
||||
#include "util/defines.h"
|
||||
#include "util/work.h"
|
||||
#include "hal/clock.h"
|
||||
#include "hal/rand.h"
|
||||
#include "hal/ccm.h"
|
||||
#include "hal/radio.h"
|
||||
#include "ll/ticker.h"
|
||||
#include "ll/ctrl_internal.h"
|
||||
#include "hci/hci.h"
|
||||
|
||||
#include "hal/debug.h"
|
||||
|
||||
#if !defined(CONFIG_BLUETOOTH_DEBUG_DRIVER)
|
||||
#undef BT_DBG
|
||||
#define BT_DBG(fmt, ...)
|
||||
#endif
|
||||
|
||||
#define HCI_CMD 0x01
|
||||
#define HCI_ACL 0x02
|
||||
#define HCI_SCO 0x03
|
||||
#define HCI_EVT 0x04
|
||||
|
||||
static uint8_t ALIGNED(4) _rand_context[3 + 4 + 1];
|
||||
static uint8_t ALIGNED(4) _ticker_nodes[RADIO_TICKER_NODES][TICKER_NODE_T_SIZE];
|
||||
static uint8_t ALIGNED(4) _ticker_users[RADIO_TICKER_USERS][TICKER_USER_T_SIZE];
|
||||
static uint8_t ALIGNED(4) _ticker_user_ops[RADIO_TICKER_USER_OPS]
|
||||
[TICKER_USER_OP_T_SIZE];
|
||||
static uint8_t ALIGNED(4) _radio[LL_MEM_TOTAL];
|
||||
|
||||
static struct nano_sem nano_sem_native_recv;
|
||||
static BT_STACK_NOINIT(native_recv_fiber_stack,
|
||||
CONFIG_BLUETOOTH_CONTROLLER_RX_STACK_SIZE);
|
||||
|
||||
void radio_active_callback(uint8_t active)
|
||||
{
|
||||
}
|
||||
|
||||
void radio_event_callback(void)
|
||||
{
|
||||
nano_isr_sem_give(&nano_sem_native_recv);
|
||||
}
|
||||
|
||||
static void power_clock_nrf5_isr(void *arg)
|
||||
{
|
||||
power_clock_isr();
|
||||
}
|
||||
|
||||
static void radio_nrf5_isr(void *arg)
|
||||
{
|
||||
radio_isr();
|
||||
}
|
||||
|
||||
static void rtc0_nrf5_isr(void *arg)
|
||||
{
|
||||
uint32_t compare0, compare1;
|
||||
|
||||
/* store interested events */
|
||||
compare0 = NRF_RTC0->EVENTS_COMPARE[0];
|
||||
compare1 = NRF_RTC0->EVENTS_COMPARE[1];
|
||||
|
||||
/* On compare0 run ticker worker instance0 */
|
||||
if (compare0) {
|
||||
NRF_RTC0->EVENTS_COMPARE[0] = 0;
|
||||
|
||||
ticker_trigger(0);
|
||||
}
|
||||
|
||||
/* On compare1 run ticker worker instance1 */
|
||||
if (compare1) {
|
||||
NRF_RTC0->EVENTS_COMPARE[1] = 0;
|
||||
|
||||
ticker_trigger(1);
|
||||
}
|
||||
|
||||
work_run(RTC0_IRQn);
|
||||
}
|
||||
|
||||
static void rng_nrf5_isr(void *arg)
|
||||
{
|
||||
rng_isr();
|
||||
}
|
||||
|
||||
static void swi4_nrf5_isr(void *arg)
|
||||
{
|
||||
work_run(NRF52_IRQ_SWI4_EGU4_IRQn);
|
||||
}
|
||||
|
||||
static void swi5_nrf5_isr(void *arg)
|
||||
{
|
||||
work_run(NRF52_IRQ_SWI5_EGU5_IRQn);
|
||||
}
|
||||
|
||||
static struct net_buf *native_evt_recv(uint8_t *remaining, uint8_t **in)
|
||||
{
|
||||
struct bt_hci_evt_hdr hdr;
|
||||
struct net_buf *buf;
|
||||
|
||||
/* TODO: check available length */
|
||||
memcpy(&hdr, *in, sizeof(hdr));
|
||||
*in += sizeof(hdr);
|
||||
|
||||
*remaining = hdr.len;
|
||||
|
||||
buf = bt_buf_get_evt(0);
|
||||
if (buf) {
|
||||
memcpy(net_buf_add(buf, sizeof(hdr)), &hdr, sizeof(hdr));
|
||||
} else {
|
||||
BT_ERR("No available event buffers!");
|
||||
}
|
||||
|
||||
BT_DBG("len %u", hdr.len);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static struct net_buf *native_acl_recv(uint8_t *remaining, uint8_t **in)
|
||||
{
|
||||
struct bt_hci_acl_hdr hdr;
|
||||
struct net_buf *buf;
|
||||
|
||||
/* TODO: check available length */
|
||||
memcpy(&hdr, *in, sizeof(hdr));
|
||||
*in += sizeof(hdr);
|
||||
|
||||
buf = bt_buf_get_acl();
|
||||
if (buf) {
|
||||
memcpy(net_buf_add(buf, sizeof(hdr)), &hdr, sizeof(hdr));
|
||||
} else {
|
||||
BT_ERR("No available ACL buffers!");
|
||||
}
|
||||
|
||||
*remaining = sys_le16_to_cpu(hdr.len);
|
||||
|
||||
BT_DBG("len %u", *remaining);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int native_recv(uint8_t remaining, uint8_t *in)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
uint8_t type;
|
||||
|
||||
type = *in++;
|
||||
|
||||
switch (type) {
|
||||
case HCI_EVT:
|
||||
buf = native_evt_recv(&remaining, &in);
|
||||
break;
|
||||
case HCI_ACL:
|
||||
buf = native_acl_recv(&remaining, &in);
|
||||
break;
|
||||
default:
|
||||
BT_ERR("Unknown HCI type %u", type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
BT_DBG("remaining %u bytes", remaining);
|
||||
|
||||
if (buf && remaining > net_buf_tailroom(buf)) {
|
||||
BT_ERR("Not enough space in buffer");
|
||||
net_buf_unref(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
if (buf) {
|
||||
memcpy(net_buf_tail(buf), in, remaining);
|
||||
buf->len += remaining;
|
||||
|
||||
BT_DBG("bt_recv");
|
||||
|
||||
bt_recv(buf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void native_recv_fiber(int unused0, int unused1)
|
||||
{
|
||||
while (1) {
|
||||
uint16_t handle;
|
||||
uint8_t num_cmplt;
|
||||
struct radio_pdu_node_rx *radio_pdu_node_rx;
|
||||
|
||||
while ((num_cmplt =
|
||||
radio_rx_get(&radio_pdu_node_rx, &handle))) {
|
||||
uint8_t len;
|
||||
uint8_t *buf;
|
||||
int retval;
|
||||
|
||||
hci_encode_num_cmplt(handle, num_cmplt, &len, &buf);
|
||||
BT_ASSERT(len);
|
||||
|
||||
retval = native_recv(len, buf);
|
||||
BT_ASSERT(!retval);
|
||||
|
||||
fiber_yield();
|
||||
}
|
||||
|
||||
if (radio_pdu_node_rx) {
|
||||
uint8_t len;
|
||||
uint8_t *buf;
|
||||
int retval;
|
||||
|
||||
hci_encode((uint8_t *)radio_pdu_node_rx, &len, &buf);
|
||||
|
||||
/* Not all radio_rx_get are translated to HCI!,
|
||||
* hence just dequeue.
|
||||
*/
|
||||
if (len) {
|
||||
retval = native_recv(len, buf);
|
||||
BT_ASSERT(!retval);
|
||||
}
|
||||
|
||||
radio_rx_dequeue();
|
||||
radio_rx_fc_set(radio_pdu_node_rx->hdr.handle, 0);
|
||||
radio_pdu_node_rx->hdr.onion.next = 0;
|
||||
radio_rx_mem_release(&radio_pdu_node_rx);
|
||||
|
||||
fiber_yield();
|
||||
} else {
|
||||
nano_fiber_sem_take(&nano_sem_native_recv,
|
||||
TICKS_UNLIMITED);
|
||||
}
|
||||
|
||||
stack_analyze("native recv fiber stack",
|
||||
native_recv_fiber_stack,
|
||||
sizeof(native_recv_fiber_stack));
|
||||
}
|
||||
}
|
||||
|
||||
static int native_send(struct net_buf *buf)
|
||||
{
|
||||
extern void hci_handle(uint8_t x, uint8_t *len, uint8_t **out);
|
||||
uint8_t type;
|
||||
uint8_t remaining;
|
||||
uint8_t *in;
|
||||
|
||||
BT_DBG("enter");
|
||||
|
||||
remaining = 0;
|
||||
|
||||
type = bt_buf_get_type(buf);
|
||||
switch (type) {
|
||||
case BT_BUF_ACL_OUT:
|
||||
hci_handle(HCI_ACL, &remaining, &in);
|
||||
break;
|
||||
case BT_BUF_CMD:
|
||||
hci_handle(HCI_CMD, &remaining, &in);
|
||||
break;
|
||||
default:
|
||||
BT_ERR("Unknown HCI type %u", type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (remaining || !buf->len) {
|
||||
BT_ERR("Empty or Len greater than expected");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (buf->len) {
|
||||
while (buf->len - 1) {
|
||||
hci_handle(net_buf_pull_u8(buf), &remaining, &in);
|
||||
}
|
||||
|
||||
if (remaining) {
|
||||
BT_ERR("Len greater than expected");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hci_handle(net_buf_pull_u8(buf), &remaining, &in);
|
||||
|
||||
BT_DBG("hci_handle returned %u bytes", remaining);
|
||||
|
||||
if (remaining) {
|
||||
int retval;
|
||||
|
||||
retval = native_recv(remaining, in);
|
||||
if (retval) {
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
net_buf_unref(buf);
|
||||
|
||||
BT_DBG("exit");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int native_open(void)
|
||||
{
|
||||
uint32_t retval;
|
||||
|
||||
clock_k32src_start(1);
|
||||
|
||||
_ticker_users[RADIO_TICKER_USER_ID_WORKER][0] =
|
||||
RADIO_TICKER_USER_WORKER_OPS;
|
||||
_ticker_users[RADIO_TICKER_USER_ID_JOB][0] =
|
||||
RADIO_TICKER_USER_JOB_OPS;
|
||||
_ticker_users[RADIO_TICKER_USER_ID_APP][0] =
|
||||
RADIO_TICKER_USER_APP_OPS;
|
||||
|
||||
ticker_init(RADIO_TICKER_INSTANCE_ID_RADIO, RADIO_TICKER_NODES,
|
||||
&_ticker_nodes[0]
|
||||
, RADIO_TICKER_USERS, &_ticker_users[0]
|
||||
, RADIO_TICKER_USER_OPS, &_ticker_user_ops[0]
|
||||
);
|
||||
|
||||
rand_init(_rand_context, sizeof(_rand_context));
|
||||
|
||||
retval = radio_init(7, /* 20ppm = 7 ... 250ppm = 1, 500ppm = 0 */
|
||||
RADIO_CONNECTION_CONTEXT_MAX,
|
||||
RADIO_PACKET_COUNT_RX_MAX,
|
||||
RADIO_PACKET_COUNT_TX_MAX,
|
||||
RADIO_LL_LENGTH_OCTETS_RX_MAX, &_radio[0],
|
||||
sizeof(_radio)
|
||||
);
|
||||
if (retval) {
|
||||
BT_ERR("Required RAM size: %d, supplied: %u.", retval,
|
||||
sizeof(_radio));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
IRQ_CONNECT(NRF52_IRQ_POWER_CLOCK_IRQn, 2, power_clock_nrf5_isr, 0, 0);
|
||||
IRQ_CONNECT(NRF52_IRQ_RADIO_IRQn, 0, radio_nrf5_isr, 0, 0);
|
||||
IRQ_CONNECT(NRF52_IRQ_RTC0_IRQn, 0, rtc0_nrf5_isr, 0, 0);
|
||||
IRQ_CONNECT(NRF52_IRQ_RNG_IRQn, 2, rng_nrf5_isr, 0, 0);
|
||||
IRQ_CONNECT(NRF52_IRQ_SWI4_EGU4_IRQn, 0, swi4_nrf5_isr, 0, 0);
|
||||
IRQ_CONNECT(NRF52_IRQ_SWI5_EGU5_IRQn, 2, swi5_nrf5_isr, 0, 0);
|
||||
irq_enable(NRF52_IRQ_POWER_CLOCK_IRQn);
|
||||
irq_enable(NRF52_IRQ_RADIO_IRQn);
|
||||
irq_enable(NRF52_IRQ_RTC0_IRQn);
|
||||
irq_enable(NRF52_IRQ_RNG_IRQn);
|
||||
irq_enable(NRF52_IRQ_SWI4_EGU4_IRQn);
|
||||
irq_enable(NRF52_IRQ_SWI5_EGU5_IRQn);
|
||||
|
||||
nano_sem_init(&nano_sem_native_recv);
|
||||
fiber_start(native_recv_fiber_stack, sizeof(native_recv_fiber_stack),
|
||||
(nano_fiber_entry_t)native_recv_fiber, 0, 0, 7, 0);
|
||||
|
||||
BT_DBG("Success.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bt_driver drv = {
|
||||
.name = "Controller",
|
||||
.bus = BT_DRIVER_BUS_VIRTUAL,
|
||||
.open = native_open,
|
||||
.send = native_send,
|
||||
};
|
||||
|
||||
static int _native_init(struct device *unused)
|
||||
{
|
||||
ARG_UNUSED(unused);
|
||||
|
||||
bt_driver_register(&drv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SYS_INIT(_native_init, NANOKERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
|
Loading…
Add table
Add a link
Reference in a new issue