bluetooth: Add support for HCI RAW channel; make host layer optional
This commit is contained in:
parent
1080d3f411
commit
5386f972fa
15 changed files with 551 additions and 37 deletions
|
@ -90,3 +90,4 @@ NXSYMBOLS(tcsetattr)
|
|||
NXSYMBOLS(unlink)
|
||||
NXSYMBOLS(usleep)
|
||||
NXSYMBOLS(write)
|
||||
NXSYMBOLS(sendmsg)
|
||||
|
|
|
@ -120,6 +120,8 @@ static int bthcisock_send(FAR const struct bt_driver_s *dev,
|
|||
return -1;
|
||||
}
|
||||
|
||||
bt_buf_release(buf);
|
||||
|
||||
return buf->len;
|
||||
}
|
||||
|
||||
|
@ -197,7 +199,7 @@ int bthcisock_loop()
|
|||
* to copy from
|
||||
*/
|
||||
|
||||
read_buf = bt_buf_alloc(BT_DUMMY, NULL, 0);
|
||||
read_buf = bt_buf_alloc(BT_DUMMY, NULL, BLUETOOTH_H4_HDRLEN);
|
||||
if (read_buf == NULL)
|
||||
{
|
||||
wlerr("ERROR: Failed to allocate buffer\n");
|
||||
|
|
|
@ -74,6 +74,9 @@
|
|||
* is made, the first unused channel for the relevant bdaddr will be
|
||||
* allocated and may be discovered using the getsockname(2) call.
|
||||
*
|
||||
* BTPROTO_NONE
|
||||
* This is to be used internally to indicate unconfigured protocol. Not
|
||||
* to be used on sockets by user.
|
||||
*/
|
||||
|
||||
#define BTPROTO_L2CAP 0
|
||||
|
@ -84,6 +87,7 @@
|
|||
#define BTPROTO_CMTP 5
|
||||
#define BTPROTO_HIDP 6
|
||||
#define BTPROTO_AVDTP 7
|
||||
#define BTPROTO_NONE 255
|
||||
|
||||
/* HCI socket options (SOL_HCI, see include/sys/socket.h):
|
||||
*
|
||||
|
@ -242,6 +246,19 @@
|
|||
#define BT_PSM_OTS 0x0025 /* Object Transfer Service (OTS),
|
||||
* Bluetooth SIG */
|
||||
|
||||
/* Channels for a BTPROTO_HCI socket */
|
||||
|
||||
#define HCI_CHANNEL_RAW 0x0
|
||||
#define HCI_CHANNEL_USER 0x1
|
||||
|
||||
/* Packets types send over the network layer for BTPROTO_HCI */
|
||||
|
||||
#define HCI_COMMAND_PKT 0x01
|
||||
#define HCI_ACLDATA_PKT 0x02
|
||||
#define HCI_SCODATA_PKT 0x03
|
||||
#define HCI_EVENT_PKT 0x04
|
||||
#define HCI_VENDOR_PKT 0xff
|
||||
|
||||
/****************************************************************************
|
||||
* Public Type Definitions
|
||||
****************************************************************************/
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
|
||||
struct bluetooth_frame_meta_s
|
||||
{
|
||||
uint8_t bm_proto; /* Protocol */
|
||||
bt_addr_t bm_raddr; /* Connected remote address */
|
||||
uint8_t bm_channel; /* Connection channel */
|
||||
};
|
||||
|
|
|
@ -97,6 +97,7 @@ struct bluetooth_conn_s
|
|||
#if CONFIG_NET_BLUETOOTH_BACKLOG > 0
|
||||
uint8_t bc_backlog; /* Number of frames in RX queue */
|
||||
#endif
|
||||
uint8_t bc_proto; /* Protocol */
|
||||
|
||||
/* Queue of incoming packets */
|
||||
|
||||
|
|
|
@ -105,8 +105,16 @@ void bluetooth_conn_initialize(void)
|
|||
dq_init(&g_free_bluetooth_connections);
|
||||
dq_init(&g_active_bluetooth_connections);
|
||||
|
||||
/* Mark connections as uninitialized */
|
||||
|
||||
memset(g_bluetooth_connections, 0, sizeof(g_bluetooth_connections));
|
||||
|
||||
for (i = 0; i < CONFIG_NET_BLUETOOTH_NCONNS; i++)
|
||||
{
|
||||
/* Indicate a connection unbound with BTPROTO_NONE */
|
||||
|
||||
g_bluetooth_connections[i].bc_proto = BTPROTO_NONE;
|
||||
|
||||
/* Link each pre-allocated connection structure into the free list. */
|
||||
|
||||
dq_addlast(&g_bluetooth_connections[i].bc_node,
|
||||
|
@ -192,6 +200,11 @@ void bluetooth_conn_free(FAR struct bluetooth_conn_s *conn)
|
|||
/* Free the connection */
|
||||
|
||||
dq_addlast(&conn->bc_node, &g_free_bluetooth_connections);
|
||||
|
||||
/* Mark as unbound */
|
||||
|
||||
conn->bc_proto = BTPROTO_NONE;
|
||||
|
||||
net_unlock();
|
||||
}
|
||||
|
||||
|
@ -214,21 +227,52 @@ FAR struct bluetooth_conn_s *
|
|||
|
||||
DEBUGASSERT(meta != NULL);
|
||||
|
||||
for (conn = (FAR struct bluetooth_conn_s *)g_active_bluetooth_connections.head;
|
||||
for (conn =
|
||||
(FAR struct bluetooth_conn_s *)g_active_bluetooth_connections.head;
|
||||
conn != NULL;
|
||||
conn = (FAR struct bluetooth_conn_s *)conn->bc_node.flink)
|
||||
{
|
||||
/* Does the destination address match the bound address of the socket. */
|
||||
/* match protocol and channel first */
|
||||
|
||||
if ((BLUETOOTH_ADDRCMP(&conn->bc_raddr, &meta->bm_raddr) ||
|
||||
BLUETOOTH_ADDRCMP(&conn->bc_raddr, &g_any_addr)) &&
|
||||
(meta->bm_channel == conn->bc_channel ||
|
||||
BT_CHANNEL_ANY == conn->bc_channel))
|
||||
if (meta->bm_proto != conn->bc_proto ||
|
||||
meta->bm_channel != conn->bc_channel)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (meta->bm_proto)
|
||||
{
|
||||
/* For BTPROTO_HCI, the socket will not be connected but only
|
||||
* bound, thus we match for the device directly
|
||||
*/
|
||||
|
||||
case BTPROTO_HCI:
|
||||
|
||||
/* TODO: handle when multiple devices supported, need to add ID
|
||||
* to meta and conn structures
|
||||
*/
|
||||
|
||||
goto stop;
|
||||
|
||||
break;
|
||||
|
||||
/* For BTPROTO_L2CAP, the destination address must match the
|
||||
* bound address of the socket
|
||||
*/
|
||||
|
||||
case BTPROTO_L2CAP:
|
||||
if ((BLUETOOTH_ADDRCMP(&conn->bc_raddr, &meta->bm_raddr) ||
|
||||
BLUETOOTH_ADDRCMP(&conn->bc_raddr, &g_any_addr)) &&
|
||||
(meta->bm_channel == conn->bc_channel))
|
||||
{
|
||||
goto stop;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stop:
|
||||
return conn;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ struct bluetooth_sendto_s
|
|||
FAR struct socket *is_sock; /* Points to the parent socket structure */
|
||||
FAR struct devif_callback_s *is_cb; /* Reference to callback instance */
|
||||
bt_addr_t is_destaddr; /* Frame destination address */
|
||||
uint8_t is_channel; /* Frame destination channel */
|
||||
uint16_t is_channel; /* Frame destination channel */
|
||||
sem_t is_sem; /* Used to wake up the waiting thread */
|
||||
FAR const uint8_t *is_buffer; /* User buffer of data to send */
|
||||
size_t is_buflen; /* Number of bytes in the is_buffer */
|
||||
|
@ -117,6 +117,7 @@ static uint16_t bluetooth_sendto_eventhandler(FAR struct net_driver_s *dev,
|
|||
|
||||
BLUETOOTH_ADDRCOPY(&meta.bm_raddr, &pstate->is_destaddr);
|
||||
meta.bm_channel = pstate->is_channel;
|
||||
meta.bm_proto = pstate->is_sock->s_proto;
|
||||
|
||||
/* Get the Bluetooth MAC header length */
|
||||
|
||||
|
@ -235,7 +236,6 @@ ssize_t psock_bluetooth_sendto(FAR struct socket *psock, FAR const void *buf,
|
|||
FAR const struct sockaddr *to,
|
||||
socklen_t tolen)
|
||||
{
|
||||
FAR struct sockaddr_l2 *destaddr;
|
||||
FAR struct radio_driver_s *radio;
|
||||
FAR struct bluetooth_conn_s *conn;
|
||||
struct bluetooth_sendto_s state;
|
||||
|
@ -262,11 +262,32 @@ ssize_t psock_bluetooth_sendto(FAR struct socket *psock, FAR const void *buf,
|
|||
|
||||
/* Get the device driver that will service this transfer */
|
||||
|
||||
if (psock->s_proto == BTPROTO_L2CAP)
|
||||
{
|
||||
radio = bluetooth_find_device(conn, &conn->bc_laddr);
|
||||
if (radio == NULL)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
else if (psock->s_proto == BTPROTO_HCI)
|
||||
{
|
||||
/* TODO: should actually look among BT devices */
|
||||
|
||||
radio =
|
||||
(FAR struct radio_driver_s *)netdev_findbyindex(conn->bc_ldev + 1);
|
||||
|
||||
DEBUGASSERT(radio->r_dev.d_lltype == NET_LL_BLUETOOTH);
|
||||
|
||||
if (radio == NULL)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Perform the send operation */
|
||||
|
||||
|
@ -290,9 +311,22 @@ ssize_t psock_bluetooth_sendto(FAR struct socket *psock, FAR const void *buf,
|
|||
|
||||
/* Copy the destination address */
|
||||
|
||||
destaddr = (FAR struct sockaddr_l2 *)to;
|
||||
if (psock->s_proto == BTPROTO_L2CAP)
|
||||
{
|
||||
FAR struct sockaddr_l2 *destaddr = (FAR struct sockaddr_l2 *)to;
|
||||
memcpy(&state.is_destaddr, &destaddr->l2_bdaddr,
|
||||
sizeof(bt_addr_t));
|
||||
}
|
||||
else if (psock->s_proto == BTPROTO_HCI)
|
||||
{
|
||||
FAR struct sockaddr_hci *destaddr = (FAR struct sockaddr_hci *)to;
|
||||
state.is_channel = destaddr->hci_channel;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -EOPNOTSUPP;
|
||||
goto err_with_net;
|
||||
}
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
|
@ -348,6 +382,12 @@ ssize_t psock_bluetooth_sendto(FAR struct socket *psock, FAR const void *buf,
|
|||
/* Return the number of bytes actually sent */
|
||||
|
||||
return state.is_sent;
|
||||
|
||||
err_with_net:
|
||||
nxsem_destroy(&state.is_sem);
|
||||
net_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NET_BLUETOOTH */
|
||||
|
|
|
@ -294,6 +294,7 @@ static int bluetooth_connect(FAR struct socket *psock,
|
|||
btaddr = (FAR struct sockaddr_l2 *)addr;
|
||||
memcpy(&conn->bc_raddr, &btaddr->l2_bdaddr, sizeof(bt_addr_t));
|
||||
conn->bc_channel = btaddr->l2_cid;
|
||||
conn->bc_proto = psock->s_proto;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -485,6 +486,8 @@ static int bluetooth_l2cap_bind(FAR struct socket *psock,
|
|||
|
||||
conn = (FAR struct bluetooth_conn_s *)psock->s_conn;
|
||||
|
||||
conn->bc_proto = psock->s_proto;
|
||||
|
||||
/* Find the device associated with the requested address */
|
||||
|
||||
radio = bluetooth_find_device(conn, &iaddr->l2_bdaddr);
|
||||
|
@ -549,6 +552,7 @@ static int bluetooth_hci_bind(FAR struct socket *psock,
|
|||
|
||||
conn = (FAR struct bluetooth_conn_s *)psock->s_conn;
|
||||
|
||||
conn->bc_proto = psock->s_proto;
|
||||
conn->bc_channel = hciaddr->hci_channel;
|
||||
conn->bc_ldev = hciaddr->hci_dev;
|
||||
|
||||
|
@ -766,6 +770,7 @@ static ssize_t bluetooth_send(FAR struct socket *psock, FAR const void *buf,
|
|||
size_t len, int flags)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
DEBUGASSERT(psock != NULL || buf != NULL);
|
||||
|
||||
/* Only SOCK_RAW is supported */
|
||||
|
@ -871,7 +876,7 @@ static ssize_t bluetooth_hci_send(FAR struct socket *psock,
|
|||
FAR const void *buf,
|
||||
size_t len, int flags)
|
||||
{
|
||||
#warning Missing logic
|
||||
/* We only support sendto() for HCI sockets */
|
||||
|
||||
return -EPFNOSUPPORT;
|
||||
}
|
||||
|
@ -905,9 +910,9 @@ static ssize_t bluetooth_sendto(FAR struct socket *psock,
|
|||
{
|
||||
ssize_t ret;
|
||||
|
||||
/* Only SOCK_RAW on L2CAP is supported */
|
||||
/* Only SOCK_RAW is supported */
|
||||
|
||||
if (psock->s_type == SOCK_RAW && psock->s_proto == BTPROTO_L2CAP)
|
||||
if (psock->s_type == SOCK_RAW)
|
||||
{
|
||||
/* Raw packet send */
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ ssize_t psock_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
|
|||
return -EBADF;
|
||||
}
|
||||
|
||||
/* Let logic specific to this address family handle the sendfrom()
|
||||
/* Let logic specific to this address family handle the sendmsg()
|
||||
* operation.
|
||||
*/
|
||||
|
||||
|
|
|
@ -48,12 +48,19 @@ menuconfig WIRELESS_BLUETOOTH
|
|||
---help---
|
||||
This option enables Bluetooth Low Energy support.
|
||||
|
||||
NOTE: This selection is marked EXPERIMENTAL. It is incomplete and,
|
||||
hence, untested. It still lacks any low-level Bluetooth drivers and
|
||||
is missing the network interface driver.
|
||||
|
||||
if WIRELESS_BLUETOOTH
|
||||
|
||||
menuconfig WIRELESS_BLUETOOTH_HOST
|
||||
bool "BLE Host Layer"
|
||||
default y
|
||||
---help---
|
||||
This enables support for BLE host layer implementation. This can be
|
||||
used to interface to a BLE controller via HCI protocol (either to a local
|
||||
BLE link-layer or to an external device over HCI UART).
|
||||
|
||||
if WIRELESS_BLUETOOTH_HOST
|
||||
endif # WIRELESS_BLUETOOTH_HOST
|
||||
|
||||
config BLUETOOTH_MAX_CONN
|
||||
int "Maximum number of simultaneous connections"
|
||||
default 1
|
||||
|
|
|
@ -37,10 +37,18 @@ ifeq ($(CONFIG_WIRELESS_BLUETOOTH),y)
|
|||
|
||||
# Include Bluetooth support
|
||||
|
||||
CSRCS += bt_atomic.c bt_att.c bt_buf.c bt_conn.c bt_gatt.c bt_hcicore.c
|
||||
CSRCS += bt_ioctl.c bt_keys.c bt_l2cap.c bt_netdev.c bt_queue.c bt_smp.c
|
||||
CSRCS += bt_buf.c bt_netdev.c bt_queue.c bt_hcicore.c
|
||||
|
||||
ifeq ($(CONFIG_WIRELESS_BLUETOOTH_HOST),y)
|
||||
|
||||
# Host-layer
|
||||
|
||||
CSRCS += bt_atomic.c bt_att.c bt_conn.c bt_gatt.c
|
||||
CSRCS += bt_ioctl.c bt_keys.c bt_l2cap.c bt_smp.c
|
||||
CSRCS += bt_uuid.c
|
||||
|
||||
endif
|
||||
|
||||
DEPPATH += --dep-path bluetooth
|
||||
VPATH += :bluetooth
|
||||
CFLAGS += ${shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)wireless$(DELIM)bluetooth}
|
||||
|
|
|
@ -388,9 +388,11 @@ FAR struct bt_buf_s *bt_buf_alloc(enum bt_buf_type_e type,
|
|||
|
||||
void bt_buf_release(FAR struct bt_buf_s *buf)
|
||||
{
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
enum bt_buf_type_e type;
|
||||
irqstate_t flags;
|
||||
uint16_t handle;
|
||||
#endif
|
||||
irqstate_t flags;
|
||||
|
||||
wlinfo("buf %p ref %u type %d\n", buf, buf->ref, buf->type);
|
||||
|
||||
|
@ -400,8 +402,10 @@ void bt_buf_release(FAR struct bt_buf_s *buf)
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
handle = buf->u.acl.handle;
|
||||
type = buf->type;
|
||||
#endif
|
||||
|
||||
/* Free the contained frame and return the container to the correct memory
|
||||
* pool.
|
||||
|
@ -460,6 +464,7 @@ void bt_buf_release(FAR struct bt_buf_s *buf)
|
|||
|
||||
wlinfo("Buffer freed: %p\n", buf);
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
if (type == BT_ACL_IN)
|
||||
{
|
||||
FAR struct bt_hci_cp_host_num_completed_packets_s *cp;
|
||||
|
@ -484,6 +489,7 @@ void bt_buf_release(FAR struct bt_buf_s *buf)
|
|||
|
||||
bt_hci_cmd_send(BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS, buf);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -100,8 +100,12 @@ struct bt_dev_s g_btdev;
|
|||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
static FAR struct bt_conn_cb_s *g_callback_list;
|
||||
static bt_le_scan_cb_t *g_scan_dev_found_cb;
|
||||
#else
|
||||
static struct bt_hci_cb_s *g_hci_cb;
|
||||
#endif
|
||||
|
||||
/* Lists of pending received messages. One for low priority input that is
|
||||
* processed on the low priority work queue and one for high priority
|
||||
|
@ -229,6 +233,7 @@ static FAR struct bt_buf_s *
|
|||
return buf;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
static void bt_connected(FAR struct bt_conn_s *conn)
|
||||
{
|
||||
FAR struct bt_conn_cb_s *cb;
|
||||
|
@ -982,6 +987,7 @@ static void hci_event(FAR struct bt_buf_s *buf)
|
|||
|
||||
bt_buf_release(buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: hci_tx_kthread
|
||||
|
@ -1075,6 +1081,7 @@ static void hci_rx_work(FAR void *arg)
|
|||
|
||||
/* TODO: Hook monitor callback */
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
switch (buf->type)
|
||||
{
|
||||
case BT_ACL_IN:
|
||||
|
@ -1090,6 +1097,9 @@ static void hci_rx_work(FAR void *arg)
|
|||
bt_buf_release(buf);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
g_hci_cb->received(buf, g_hci_cb->context);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1131,6 +1141,7 @@ static void priority_rx_work(FAR void *arg)
|
|||
continue;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
bt_buf_consume(buf, sizeof(struct bt_hci_evt_hdr_s));
|
||||
|
||||
switch (hdr->evt)
|
||||
|
@ -1151,11 +1162,15 @@ static void priority_rx_work(FAR void *arg)
|
|||
wlerr("Unknown event 0x%02x\n", hdr->evt);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
UNUSED(hdr);
|
||||
|
||||
bt_buf_release(buf);
|
||||
g_hci_cb->received(buf, g_hci_cb->context);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
static void read_local_features_complete(FAR struct bt_buf_s *buf)
|
||||
{
|
||||
FAR struct bt_hci_rp_read_local_features_s *rp = (FAR void *)buf->data;
|
||||
|
@ -1433,6 +1448,7 @@ static int hci_initialize(void)
|
|||
nxsem_init(&g_btdev.le_pkts_sem, 0, g_btdev.le_pkts);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* threads, fifos and semaphores initialization */
|
||||
|
||||
|
@ -1496,6 +1512,7 @@ int bt_initialize(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
ret = hci_initialize();
|
||||
if (ret < 0)
|
||||
{
|
||||
|
@ -1503,7 +1520,10 @@ int bt_initialize(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
return bt_l2cap_init();
|
||||
ret = bt_l2cap_init();
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -1582,6 +1602,8 @@ void bt_driver_unregister(FAR const struct bt_driver_s *btdev)
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* TODO: rename to bt_receive? */
|
||||
|
||||
void bt_hci_receive(FAR struct bt_buf_s *buf)
|
||||
{
|
||||
FAR struct bt_hci_evt_hdr_s *hdr;
|
||||
|
@ -1652,6 +1674,8 @@ void bt_hci_receive(FAR struct bt_buf_s *buf)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bt_hci_cmd_create
|
||||
*
|
||||
|
@ -2143,3 +2167,27 @@ FAR const char *bt_addr_le_str(FAR const bt_addr_le_t *addr)
|
|||
return str;
|
||||
}
|
||||
#endif /* CONFIG_DEBUG_WIRELESS_ERROR */
|
||||
|
||||
#else
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bt_hci_cb_register
|
||||
*
|
||||
* Description:
|
||||
* Register callbacks to handle RAW HCI packets
|
||||
*
|
||||
* Input Parameters:
|
||||
* cb - Instance of the callback structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void bt_hci_cb_register(FAR struct bt_hci_cb_s *cb)
|
||||
{
|
||||
g_hci_cb = cb;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -76,6 +76,7 @@ struct bt_dev_s
|
|||
|
||||
bt_addr_t bdaddr;
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
/* Controller version & manufacturer information */
|
||||
|
||||
uint8_t hci_version;
|
||||
|
@ -104,6 +105,7 @@ struct bt_dev_s
|
|||
uint8_t le_pkts;
|
||||
uint16_t le_mtu;
|
||||
sem_t le_pkts_sem;
|
||||
#endif
|
||||
|
||||
/* Number of commands controller can accept */
|
||||
|
||||
|
@ -127,6 +129,7 @@ struct bt_dev_s
|
|||
FAR const struct bt_driver_s *btdev;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
/* Connection callback structure */
|
||||
|
||||
struct bt_conn_s; /* Forward reference */
|
||||
|
@ -138,7 +141,18 @@ struct bt_conn_cb_s
|
|||
CODE void (*connected)(FAR struct bt_conn_s *conn, FAR void *context);
|
||||
CODE void (*disconnected)(FAR struct bt_conn_s *conn, FAR void *context);
|
||||
};
|
||||
#else
|
||||
/* RAW HCI packets callbacks */
|
||||
|
||||
struct bt_hci_cb_s
|
||||
{
|
||||
FAR void *context;
|
||||
|
||||
CODE void (*received)(FAR struct bt_buf_s *buf, FAR void *context);
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
/****************************************************************************
|
||||
* Name: bt_le_scan_cb_t
|
||||
*
|
||||
|
@ -160,6 +174,7 @@ struct bt_conn_cb_s
|
|||
typedef CODE void bt_le_scan_cb_t(FAR const bt_addr_le_t *addr, int8_t rssi,
|
||||
uint8_t adv_type,
|
||||
FAR const uint8_t *adv_data, uint8_t len);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
|
@ -171,6 +186,7 @@ extern struct bt_dev_s g_btdev;
|
|||
* Inline Functions
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
static inline int bt_addr_cmp(FAR const bt_addr_t *a, FAR const bt_addr_t *b)
|
||||
{
|
||||
return memcmp(a, b, sizeof(*a));
|
||||
|
@ -231,6 +247,8 @@ static inline bool bt_addr_le_is_identity(FAR const bt_addr_le_t *addr)
|
|||
|
||||
struct bt_eir_s; /* Forward reference */
|
||||
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bt_initialize
|
||||
*
|
||||
|
@ -284,6 +302,7 @@ int bt_driver_register(FAR const struct bt_driver_s *btdev);
|
|||
|
||||
void bt_driver_unregister(FAR const struct bt_driver_s *btdev);
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
/****************************************************************************
|
||||
* Name: bt_hci_cmd_create
|
||||
*
|
||||
|
@ -409,5 +428,24 @@ int bt_le_scan_update(void);
|
|||
****************************************************************************/
|
||||
|
||||
void bt_conn_cb_register(FAR struct bt_conn_cb_s *cb);
|
||||
#else
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bt_hci_cb_register
|
||||
*
|
||||
* Description:
|
||||
* Register callbacks to handle RAW HCI packets
|
||||
*
|
||||
* Input Parameters:
|
||||
* cb - Instance of the callback structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void bt_hci_cb_register(FAR struct bt_hci_cb_s *cb);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __WIRELESS_BLUETOOTH_BT_HDICORE_H */
|
||||
|
|
|
@ -63,10 +63,15 @@
|
|||
#include <nuttx/net/bluetooth.h>
|
||||
#include <nuttx/net/sixlowpan.h>
|
||||
#include <nuttx/wireless/bluetooth/bt_core.h>
|
||||
#include <netpacket/bluetooth.h>
|
||||
|
||||
#include "bt_hcicore.h"
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
#include "bt_l2cap.h"
|
||||
#include "bt_conn.h"
|
||||
#endif
|
||||
|
||||
#include "bt_ioctl.h"
|
||||
|
||||
#if defined(CONFIG_NET_6LOWPAN) || defined(CONFIG_NET_BLUETOOTH)
|
||||
|
@ -125,8 +130,13 @@ struct btnet_driver_s
|
|||
bool bd_bifup; /* true:ifup false:ifdown */
|
||||
struct wdog_s bd_txpoll; /* TX poll timer */
|
||||
struct work_s bd_pollwork; /* Defer poll work to the work queue */
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
struct bt_conn_cb_s bd_hcicb; /* HCI connection status callbacks */
|
||||
struct bt_l2cap_chan_s bd_l2capcb; /* L2CAP status callbacks */
|
||||
#else
|
||||
struct bt_hci_cb_s bd_hcicb; /* HCI RAW packet callbacks */
|
||||
#endif
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -140,6 +150,7 @@ static inline void btnet_netmask(FAR struct net_driver_s *netdev);
|
|||
|
||||
/* Bluetooth callback functions *********************************************/
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
/* L2CAP callbacks */
|
||||
|
||||
static void btnet_l2cap_connected(FAR struct bt_conn_s *conn,
|
||||
|
@ -157,6 +168,9 @@ static void btnet_hci_connected(FAR struct bt_conn_s *conn,
|
|||
FAR void *context);
|
||||
static void btnet_hci_disconnected(FAR struct bt_conn_s *conn,
|
||||
FAR void *context);
|
||||
#else
|
||||
static void btnet_hci_received(FAR struct bt_buf_s *buf, FAR void *context);
|
||||
#endif
|
||||
|
||||
/* Network interface support ************************************************/
|
||||
|
||||
|
@ -187,6 +201,16 @@ static int btnet_req_data(FAR struct radio_driver_s *netdev,
|
|||
static int btnet_properties(FAR struct radio_driver_s *netdev,
|
||||
FAR struct radiodev_properties_s *properties);
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
static int btnet_req_l2cap_data(FAR struct btnet_driver_s *priv,
|
||||
FAR struct bluetooth_frame_meta_s *meta,
|
||||
FAR struct iob_s *framelist);
|
||||
#endif
|
||||
|
||||
static int btnet_req_hci_data(FAR struct btnet_driver_s *priv,
|
||||
FAR struct bluetooth_frame_meta_s *meta,
|
||||
FAR struct iob_s *framelist);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
@ -276,6 +300,7 @@ static inline void btnet_netmask(FAR struct net_driver_s *netdev)
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
/****************************************************************************
|
||||
* Name: btnet_hci_connect/disconnect/encrypt_change
|
||||
*
|
||||
|
@ -475,6 +500,126 @@ static void btnet_hci_disconnected(FAR struct bt_conn_s *conn,
|
|||
wlinfo("Disconnected\n");
|
||||
#warning Missing logic
|
||||
}
|
||||
#else
|
||||
|
||||
/****************************************************************************
|
||||
* Name: btnet_hci_received
|
||||
*
|
||||
* Description:
|
||||
* This callback is called from the RX queue handling when an HCI
|
||||
* packet is received from controller.
|
||||
*
|
||||
* Input Parameters:
|
||||
* buf - The packet
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* No assumption should be made about the thread of execution that these
|
||||
* are called from
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void btnet_hci_received(FAR struct bt_buf_s *buf, FAR void *context)
|
||||
{
|
||||
FAR struct btnet_driver_s *priv;
|
||||
FAR struct iob_s *frame;
|
||||
struct bluetooth_frame_meta_s meta;
|
||||
int ret = -ENODEV;
|
||||
|
||||
wlinfo("Received frame\n");
|
||||
|
||||
DEBUGASSERT(buf != NULL && buf->frame != NULL);
|
||||
|
||||
/* Detach the IOB frame from the buffer structure */
|
||||
|
||||
frame = buf->frame;
|
||||
buf->frame = NULL;
|
||||
|
||||
/* Ignore the frame if the network is not up */
|
||||
|
||||
priv = (FAR struct btnet_driver_s *)context;
|
||||
if (!priv->bd_bifup)
|
||||
{
|
||||
wlwarn("WARNING: Dropped... Network is down\n");
|
||||
goto drop;
|
||||
}
|
||||
|
||||
/* Make sure that the size/offset data matches the buffer structure data. */
|
||||
|
||||
DEBUGASSERT(frame->io_offset == BLUETOOTH_H4_HDRLEN);
|
||||
|
||||
/* Rearrange IOB to consider H4 header */
|
||||
|
||||
frame->io_len = buf->len + frame->io_offset;
|
||||
frame->io_pktlen = buf->len + frame->io_offset;
|
||||
frame->io_offset = 0;
|
||||
|
||||
DEBUGASSERT(frame->io_len <= CONFIG_IOB_BUFSIZE);
|
||||
|
||||
/* Write H4 header */
|
||||
|
||||
switch (buf->type)
|
||||
{
|
||||
case BT_EVT:
|
||||
frame->io_data[0] = HCI_EVENT_PKT;
|
||||
break;
|
||||
case BT_ACL_IN:
|
||||
frame->io_data[0] = HCI_ACLDATA_PKT;
|
||||
break;
|
||||
default:
|
||||
wlerr("Bad HCI type: %i\n", buf->type);
|
||||
goto drop;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Construct the frame meta data.
|
||||
*/
|
||||
|
||||
meta.bm_channel = HCI_CHANNEL_RAW;
|
||||
meta.bm_proto = BTPROTO_HCI;
|
||||
|
||||
/* Transfer the frame to the network logic */
|
||||
|
||||
net_lock();
|
||||
|
||||
#ifdef CONFIG_NET_BLUETOOTH
|
||||
/* Invoke the PF_BLUETOOTH tap first. If the frame matches
|
||||
* with a connected PF_BLUETOOTH socket, it will take the
|
||||
* frame and return success.
|
||||
*/
|
||||
|
||||
ret = bluetooth_input(&priv->bd_dev, frame, (FAR void *)&meta);
|
||||
#endif
|
||||
|
||||
drop:
|
||||
|
||||
/* Handle errors */
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
iob_free(frame, IOBUSER_WIRELESS_BLUETOOTH);
|
||||
|
||||
/* Increment statistics */
|
||||
|
||||
NETDEV_RXDROPPED(&priv->bd_dev.r_dev);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Increment statistics */
|
||||
|
||||
NETDEV_RXPACKETS(&priv->bd_dev.r_dev);
|
||||
NETDEV_RXIPV6(&priv->bd_dev.r_dev);
|
||||
}
|
||||
|
||||
/* Release our reference on the buffer */
|
||||
|
||||
bt_buf_release(buf);
|
||||
net_unlock();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: btnet_txpoll_callback
|
||||
|
@ -852,7 +997,26 @@ static int btnet_rmmac(FAR struct net_driver_s *netdev,
|
|||
static int btnet_get_mhrlen(FAR struct radio_driver_s *netdev,
|
||||
FAR const void *meta)
|
||||
{
|
||||
/* Always report the maximum frame length. */
|
||||
const struct bluetooth_frame_meta_s *btmeta = meta;
|
||||
|
||||
if (btmeta->bm_proto == BTPROTO_HCI)
|
||||
{
|
||||
/* the net device only requires the H4 header, the rest is already
|
||||
* part of the packet
|
||||
*/
|
||||
|
||||
return BLUETOOTH_H4_HDRLEN;
|
||||
}
|
||||
else if (btmeta->bm_proto == BTPROTO_L2CAP)
|
||||
{
|
||||
/* Report the complete header size, since H4 + ACL + L2CAP header
|
||||
* will not be part of the packet
|
||||
*/
|
||||
|
||||
/* TODO: correct? */
|
||||
|
||||
return BLUETOOTH_MAX_HDRLEN;
|
||||
}
|
||||
|
||||
return BLUETOOTH_MAX_HDRLEN;
|
||||
}
|
||||
|
@ -880,10 +1044,6 @@ static int btnet_req_data(FAR struct radio_driver_s *netdev,
|
|||
{
|
||||
FAR struct btnet_driver_s *priv;
|
||||
FAR struct bluetooth_frame_meta_s *btmeta;
|
||||
FAR struct bt_conn_s *conn;
|
||||
FAR struct bt_buf_s *buf;
|
||||
FAR struct iob_s *iob;
|
||||
bt_addr_le_t peer;
|
||||
|
||||
wlinfo("Received framelist\n");
|
||||
DEBUGASSERT(priv != NULL && meta != NULL && framelist != NULL);
|
||||
|
@ -891,6 +1051,52 @@ static int btnet_req_data(FAR struct radio_driver_s *netdev,
|
|||
priv = (FAR struct btnet_driver_s *)netdev;
|
||||
btmeta = (FAR struct bluetooth_frame_meta_s *)meta;
|
||||
|
||||
if (btmeta->bm_proto == BTPROTO_HCI)
|
||||
{
|
||||
return btnet_req_hci_data(priv, btmeta, framelist);
|
||||
}
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
else if (btmeta->bm_proto == BTPROTO_L2CAP)
|
||||
{
|
||||
return btnet_req_l2cap_data(priv, btmeta, framelist);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
/****************************************************************************
|
||||
* Name: btnet_req_l2cap_data
|
||||
*
|
||||
* Description:
|
||||
* Requests the transfer of a list of L2CAP frames to the MAC.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - Bluetooth network device
|
||||
* btmeta - Bluetooth frame metadata
|
||||
* framelist - Head of a list of L2CAP frames to be transferred.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) returned on success; a negated errno value is returned on
|
||||
* any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int btnet_req_l2cap_data(FAR struct btnet_driver_s *priv,
|
||||
FAR struct bluetooth_frame_meta_s *btmeta,
|
||||
FAR struct iob_s *framelist)
|
||||
{
|
||||
FAR struct bt_conn_s *conn;
|
||||
bt_addr_le_t peer;
|
||||
FAR struct iob_s *iob;
|
||||
FAR struct bt_buf_s *buf;
|
||||
UNUSED(priv);
|
||||
|
||||
/* Create a connection structure for this peer if one does not already
|
||||
* exist.
|
||||
*
|
||||
|
@ -945,7 +1151,84 @@ static int btnet_req_data(FAR struct radio_driver_s *netdev,
|
|||
NETDEV_TXDONE(&priv->bd_dev.r_dev);
|
||||
}
|
||||
|
||||
UNUSED(priv);
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: btnet_req_hci_data
|
||||
*
|
||||
* Description:
|
||||
* Requests the transfer of a list of HCI frames to the MAC.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - Bluetooth network device
|
||||
* btmeta - Bluetooth frame metadata
|
||||
* framelist - Head of a list of HCI frames to be transferred.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) returned on success; a negated errno value is returned on
|
||||
* any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int btnet_req_hci_data(FAR struct btnet_driver_s *priv,
|
||||
FAR struct bluetooth_frame_meta_s *meta,
|
||||
FAR struct iob_s *framelist)
|
||||
{
|
||||
FAR struct iob_s *iob;
|
||||
FAR struct bt_buf_s *buf;
|
||||
|
||||
/* Add the incoming list of frames to the MAC's outgoing queue */
|
||||
|
||||
for (iob = framelist; iob != NULL; iob = framelist)
|
||||
{
|
||||
/* Increment statistics */
|
||||
|
||||
NETDEV_TXPACKETS(&priv->bd_dev.r_dev);
|
||||
|
||||
/* Remove the IOB from the queue */
|
||||
|
||||
framelist = iob->io_flink;
|
||||
iob->io_flink = NULL;
|
||||
|
||||
DEBUGASSERT(iob->io_offset == BLUETOOTH_H4_HDRLEN &&
|
||||
iob->io_len >= BLUETOOTH_H4_HDRLEN);
|
||||
|
||||
/* Allocate a buffer to contain the IOB */
|
||||
|
||||
switch (iob->io_data[iob->io_offset])
|
||||
{
|
||||
case HCI_ACLDATA_PKT:
|
||||
iob->io_offset += 1;
|
||||
buf = bt_buf_alloc(BT_ACL_OUT, iob, 0);
|
||||
break;
|
||||
case HCI_COMMAND_PKT:
|
||||
iob->io_offset += 1;
|
||||
buf = bt_buf_alloc(BT_CMD, iob, 0);
|
||||
break;
|
||||
case HCI_EVENT_PKT:
|
||||
iob->io_offset += 1;
|
||||
buf = bt_buf_alloc(BT_EVT, iob, 0);
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
if (buf == NULL)
|
||||
{
|
||||
wlerr("ERROR: Failed to allocate buffer container\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
g_btdev.btdev->send(g_btdev.btdev, buf);
|
||||
|
||||
/* Transfer the frame to the Bluetooth stack. */
|
||||
|
||||
NETDEV_TXDONE(&priv->bd_dev.r_dev);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -1009,8 +1292,13 @@ int bt_netdev_register(FAR const struct bt_driver_s *btdev)
|
|||
FAR struct btnet_driver_s *priv;
|
||||
FAR struct radio_driver_s *radio;
|
||||
FAR struct net_driver_s *netdev;
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
FAR struct bt_conn_cb_s *hcicb;
|
||||
FAR struct bt_l2cap_chan_s *l2capcb;
|
||||
#else
|
||||
FAR struct bt_hci_cb_s *hcicb;
|
||||
#endif
|
||||
int ret;
|
||||
|
||||
/* Get the interface structure associated with this interface number. */
|
||||
|
@ -1035,13 +1323,14 @@ int bt_netdev_register(FAR const struct bt_driver_s *btdev)
|
|||
netdev->d_addmac = btnet_addmac; /* Add multicast MAC address */
|
||||
netdev->d_rmmac = btnet_rmmac; /* Remove multicast MAC address */
|
||||
#endif
|
||||
#ifdef CONFIG_NETDEV_IOCTL
|
||||
#if defined(CONFIG_NETDEV_IOCTL) && defined(CONFIG_WIRELESS_BLUETOOTH_HOST)
|
||||
netdev->d_ioctl = btnet_ioctl; /* Handle network IOCTL commands */
|
||||
#endif
|
||||
netdev->d_private = priv; /* Used to recover private state from netdev */
|
||||
|
||||
/* Connection status change callbacks */
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
hcicb = &priv->bd_hcicb;
|
||||
hcicb->context = priv;
|
||||
hcicb->connected = btnet_hci_connected;
|
||||
|
@ -1059,6 +1348,13 @@ int bt_netdev_register(FAR const struct bt_driver_s *btdev)
|
|||
l2capcb->receive = btnet_l2cap_receive;
|
||||
|
||||
bt_l2cap_chan_default(l2capcb);
|
||||
#else
|
||||
hcicb = &priv->bd_hcicb;
|
||||
hcicb->context = priv;
|
||||
hcicb->received = btnet_hci_received;
|
||||
|
||||
bt_hci_cb_register(hcicb);
|
||||
#endif
|
||||
|
||||
/* Setup a locking semaphore for exclusive device driver access */
|
||||
|
||||
|
|
Loading…
Reference in a new issue