wireless/bluetooth: decoupling bt_driver_s and bt_buf_s
Signed-off-by: chao.an <anchao@xiaomi.com>
This commit is contained in:
parent
6837d4e1ba
commit
6c69b12000
@ -91,9 +91,10 @@ struct nrf52_sdc_dev_s
|
||||
static void mpsl_assert_handler(const char *const file, const uint32_t line);
|
||||
static void sdc_fault_handler(const char *file, const uint32_t line);
|
||||
|
||||
static int bt_open(FAR const struct bt_driver_s *btdev);
|
||||
static int bt_hci_send(FAR const struct bt_driver_s *btdev,
|
||||
FAR struct bt_buf_s *buf);
|
||||
static int bt_open(FAR struct bt_driver_s *btdev);
|
||||
static int bt_hci_send(FAR struct bt_driver_s *btdev,
|
||||
enum bt_buf_type_e type,
|
||||
FAR void *data, size_t len);
|
||||
|
||||
static void on_hci(void);
|
||||
static void on_hci_worker(void *arg);
|
||||
@ -112,7 +113,7 @@ static void radio_handler(void);
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct bt_driver_s g_bt_driver =
|
||||
static struct bt_driver_s g_bt_driver =
|
||||
{
|
||||
.head_reserve = 0,
|
||||
.open = bt_open,
|
||||
@ -138,7 +139,7 @@ static struct nrf52_sdc_dev_s g_sdc_dev;
|
||||
* Name: bt_open
|
||||
****************************************************************************/
|
||||
|
||||
static int bt_open(FAR const struct bt_driver_s *btdev)
|
||||
static int bt_open(FAR struct bt_driver_s *btdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -147,61 +148,43 @@ static int bt_open(FAR const struct bt_driver_s *btdev)
|
||||
* Name: bt_open
|
||||
****************************************************************************/
|
||||
|
||||
static int bt_hci_send(FAR const struct bt_driver_s *btdev,
|
||||
FAR struct bt_buf_s *buf)
|
||||
static int bt_hci_send(FAR struct bt_driver_s *btdev,
|
||||
enum bt_buf_type_e type,
|
||||
FAR void *data, size_t len)
|
||||
{
|
||||
int ret = OK;
|
||||
int ret = -EIO;
|
||||
|
||||
/* Pass HCI CMD/DATA to SDC */
|
||||
|
||||
if (buf->type == BT_CMD)
|
||||
if (type == BT_CMD || type == BT_ACL_OUT)
|
||||
{
|
||||
struct bt_hci_cmd_hdr_s *cmd = (struct bt_hci_cmd_hdr_s *)buf->data;
|
||||
|
||||
wlinfo("passing CMD %d to softdevice\n", cmd->opcode);
|
||||
wlinfo("passing type %s to softdevice\n",
|
||||
(type == BT_CMD) ? "CMD" : "ACL");
|
||||
|
||||
/* Ensure non-concurrent access to SDC operations */
|
||||
|
||||
nxsem_wait_uninterruptible(&g_sdc_dev.exclsem);
|
||||
|
||||
if (sdc_hci_cmd_put(buf->data) < 0)
|
||||
if (type == BT_CMD)
|
||||
{
|
||||
wlerr("sdc_hci_cmd_put() failed\n");
|
||||
ret = -EIO;
|
||||
ret = sdc_hci_cmd_put(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = sdc_hci_data_put(data);
|
||||
}
|
||||
|
||||
nxsem_post(&g_sdc_dev.exclsem);
|
||||
|
||||
work_queue(LPWORK, &g_sdc_dev.work, on_hci_worker, NULL, 0);
|
||||
}
|
||||
else if (buf->type == BT_ACL_OUT)
|
||||
{
|
||||
wlinfo("passing ACL to softdevice\n");
|
||||
|
||||
/* Ensure non-concurrent access to SDC operations */
|
||||
|
||||
nxsem_wait_uninterruptible(&g_sdc_dev.exclsem);
|
||||
|
||||
if (sdc_hci_data_put(buf->data) < 0)
|
||||
if (ret >= 0)
|
||||
{
|
||||
wlerr("sdc_hci_data_put() failed\n");
|
||||
ret = -EIO;
|
||||
ret = len;
|
||||
|
||||
work_queue(LPWORK, &g_sdc_dev.work, on_hci_worker, NULL, 0);
|
||||
}
|
||||
|
||||
nxsem_post(&g_sdc_dev.exclsem);
|
||||
|
||||
work_queue(LPWORK, &g_sdc_dev.work, on_hci_worker, NULL, 0);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
wlerr("bt_hci_send() failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
return buf->len;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -261,12 +244,11 @@ static void on_hci_worker(void *arg)
|
||||
|
||||
static void on_hci(void)
|
||||
{
|
||||
struct bt_buf_s *outbuf;
|
||||
bool check_again;
|
||||
size_t len;
|
||||
int ret;
|
||||
bool check_again = true;
|
||||
|
||||
while (check_again)
|
||||
do
|
||||
{
|
||||
check_again = false;
|
||||
|
||||
@ -302,13 +284,8 @@ static void on_hci(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
outbuf = bt_buf_alloc(BT_EVT, NULL, BLUETOOTH_H4_HDRLEN);
|
||||
bt_buf_extend(outbuf, len);
|
||||
|
||||
memcpy(outbuf->data, g_sdc_dev.msg_buffer, len);
|
||||
|
||||
bt_hci_receive(outbuf);
|
||||
|
||||
bt_netdev_receive(&g_bt_driver, BT_EVT,
|
||||
g_sdc_dev.msg_buffer, len);
|
||||
check_again = true;
|
||||
}
|
||||
|
||||
@ -326,16 +303,12 @@ static void on_hci(void)
|
||||
|
||||
len = sizeof(*hdr) + hdr->len;
|
||||
|
||||
outbuf = bt_buf_alloc(BT_ACL_IN, NULL, BLUETOOTH_H4_HDRLEN);
|
||||
bt_buf_extend(outbuf, len);
|
||||
|
||||
memcpy(outbuf->data, g_sdc_dev.msg_buffer, len);
|
||||
|
||||
bt_hci_receive(outbuf);
|
||||
|
||||
bt_netdev_receive(&g_bt_driver, BT_ACL_IN,
|
||||
g_sdc_dev.msg_buffer, len);
|
||||
check_again = true;
|
||||
}
|
||||
}
|
||||
while (check_again);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -31,9 +31,13 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <queue.h>
|
||||
|
||||
#include <nuttx/wireless/bluetooth/bt_driver.h>
|
||||
#include <nuttx/nuttx.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/net/bluetooth.h>
|
||||
#include <nuttx/wireless/bluetooth/bt_driver.h>
|
||||
#include <nuttx/wireless/bluetooth/bt_uart.h>
|
||||
|
||||
#include "up_internal.h"
|
||||
#include "up_hcisocket_host.h"
|
||||
@ -42,99 +46,157 @@
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* HCI data types as defined by Linux Kernel */
|
||||
|
||||
#define HCI_COMMAND_PKT 0x01
|
||||
#define HCI_ACLDATA_PKT 0x02
|
||||
#define HCI_SCODATA_PKT 0x03
|
||||
#define HCI_EVENT_PKT 0x04
|
||||
#define HCI_ISODATA_PKT 0x05
|
||||
#define HCI_DIAG_PKT 0xf0
|
||||
#define HCI_VENDOR_PKT 0xff
|
||||
#define BLUETOOTH_RX_FRAMELEN 1024
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct bthcisock_s
|
||||
{
|
||||
FAR struct bt_driver_s drv;
|
||||
int id;
|
||||
int fd;
|
||||
sq_entry_t link;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int bthcisock_send(FAR const struct bt_driver_s *dev,
|
||||
FAR struct bt_buf_s *buf);
|
||||
static int bthcisock_open(FAR const struct bt_driver_s *dev);
|
||||
static int bthcisock_send(FAR struct bt_driver_s *drv,
|
||||
enum bt_buf_type_e type,
|
||||
FAR void *data, size_t len);
|
||||
static int bthcisock_open(FAR struct bt_driver_s *drv);
|
||||
static void bthcisock_close(FAR struct bt_driver_s *drv);
|
||||
static int bthcisock_receive(FAR struct bt_driver_s *drv);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct bt_driver_s g_bt_hcisock =
|
||||
{
|
||||
0, /* head_reserve */
|
||||
bthcisock_open, /* open */
|
||||
bthcisock_send /* send */
|
||||
};
|
||||
|
||||
static int bt_fd = -1; /* Host HCI socket fd */
|
||||
static int host_dev_id = 0; /* Host HCI interface number */
|
||||
|
||||
/* Hold a receive frame buffer here. This allows us to not allocate and free
|
||||
* on every socket read since most of the time there will be no data to
|
||||
* actually process.
|
||||
*/
|
||||
|
||||
struct bt_buf_s *read_buf = NULL;
|
||||
static sq_queue_t g_bthcisock_list;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static int bthcisock_send(FAR const struct bt_driver_s *dev,
|
||||
FAR struct bt_buf_s *buf)
|
||||
static int bthcisock_send(FAR struct bt_driver_s *drv,
|
||||
enum bt_buf_type_e type,
|
||||
FAR void *data, size_t len)
|
||||
{
|
||||
uint8_t *pkt_type = bt_buf_provide(buf, BLUETOOTH_H4_HDRLEN);
|
||||
FAR struct bthcisock_s *dev = (FAR struct bthcisock_s *)drv;
|
||||
FAR char *hdr = (FAR char *)data - drv->head_reserve;
|
||||
int ret;
|
||||
|
||||
switch (buf->type)
|
||||
if (type == BT_CMD)
|
||||
{
|
||||
case BT_CMD:
|
||||
{
|
||||
*pkt_type = HCI_COMMAND_PKT;
|
||||
break;
|
||||
}
|
||||
|
||||
case BT_ACL_OUT:
|
||||
{
|
||||
*pkt_type = HCI_ACLDATA_PKT;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
wlerr("Unexpected HCI packet type %d", buf->type);
|
||||
return buf->len;
|
||||
}
|
||||
*hdr = H4_CMD;
|
||||
}
|
||||
else if (type == BT_ACL_OUT)
|
||||
{
|
||||
*hdr = H4_ACL;
|
||||
}
|
||||
else if (type == BT_ISO_OUT)
|
||||
{
|
||||
*hdr = H4_ISO;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (bthcisock_host_send(bt_fd, buf->data, buf->len) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
ret = bthcisock_host_send(dev->fd, hdr, len + H4_HEADER_SIZE);
|
||||
|
||||
return buf->len;
|
||||
return ret < 0 ? ret : len;
|
||||
}
|
||||
|
||||
static int bthcisock_open(FAR const struct bt_driver_s *dev)
|
||||
static void bthcisock_close(FAR struct bt_driver_s *drv)
|
||||
{
|
||||
int fd = bthcisock_host_open(host_dev_id);
|
||||
if (fd < 0)
|
||||
FAR struct bthcisock_s *dev = (FAR struct bthcisock_s *)drv;
|
||||
|
||||
bthcisock_host_close(dev->fd);
|
||||
dev->fd = -1;
|
||||
}
|
||||
|
||||
static int bthcisock_receive(FAR struct bt_driver_s *drv)
|
||||
{
|
||||
FAR struct bthcisock_s *dev = (FAR struct bthcisock_s *)drv;
|
||||
char data[BLUETOOTH_RX_FRAMELEN];
|
||||
enum bt_buf_type_e type;
|
||||
int ret;
|
||||
|
||||
ret = bthcisock_host_read(dev->fd, data, sizeof(data));
|
||||
if (ret <= 0)
|
||||
{
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bt_fd = fd;
|
||||
if (data[0] == H4_EVT)
|
||||
{
|
||||
type = BT_EVT;
|
||||
}
|
||||
else if (data[0] == H4_ACL)
|
||||
{
|
||||
type = BT_ACL_IN;
|
||||
}
|
||||
else if (data[0] == H4_ISO)
|
||||
{
|
||||
type = BT_ISO_IN;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return bt_netdev_receive(&dev->drv, type,
|
||||
data + H4_HEADER_SIZE,
|
||||
ret - H4_HEADER_SIZE);
|
||||
}
|
||||
|
||||
static int bthcisock_open(FAR struct bt_driver_s *drv)
|
||||
{
|
||||
FAR struct bthcisock_s *dev = (FAR struct bthcisock_s *)drv;
|
||||
int fd;
|
||||
|
||||
fd = bthcisock_host_open(dev->id);
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
return fd;
|
||||
}
|
||||
|
||||
dev->fd = fd;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static FAR struct bthcisock_s *bthcisock_alloc(int dev_id)
|
||||
{
|
||||
/* Register the driver with the Bluetooth stack */
|
||||
|
||||
FAR struct bthcisock_s *dev;
|
||||
FAR struct bt_driver_s *drv;
|
||||
|
||||
dev = (FAR struct bthcisock_s *)kmm_zalloc(sizeof(*dev));
|
||||
if (dev == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev->id = dev_id;
|
||||
dev->fd = -1;
|
||||
drv = &dev->drv;
|
||||
drv->head_reserve = H4_HEADER_SIZE;
|
||||
drv->open = bthcisock_open;
|
||||
drv->send = bthcisock_send;
|
||||
drv->close = bthcisock_close;
|
||||
|
||||
sq_addlast(&dev->link, &g_bthcisock_list);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -156,10 +218,22 @@ static int bthcisock_open(FAR const struct bt_driver_s *dev)
|
||||
|
||||
int bthcisock_register(int dev_id)
|
||||
{
|
||||
/* Register the driver with the Bluetooth stack */
|
||||
FAR struct bthcisock_s *dev;
|
||||
int ret;
|
||||
|
||||
host_dev_id = dev_id;
|
||||
return bt_netdev_register(&g_bt_hcisock);
|
||||
dev = bthcisock_alloc(dev_id);
|
||||
if (dev == NULL)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = bt_netdev_register(&dev->drv);
|
||||
if (ret < 0)
|
||||
{
|
||||
kmm_free(dev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -179,70 +253,17 @@ int bthcisock_register(int dev_id)
|
||||
|
||||
int bthcisock_loop(void)
|
||||
{
|
||||
uint8_t type;
|
||||
int len;
|
||||
FAR struct bthcisock_s *dev;
|
||||
FAR sq_entry_t *entry;
|
||||
|
||||
if (bt_fd < 0)
|
||||
for (entry = sq_peek(&g_bthcisock_list); entry; entry = sq_next(entry))
|
||||
{
|
||||
/* Internal socket has not yet been created */
|
||||
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
if (read_buf == NULL)
|
||||
{
|
||||
/* NOTE: This shared allocation only works because the allocation size
|
||||
* is currently the same for all frame types. If this changes we will
|
||||
* need to allocate for the largest frame or use an intermediate buffer
|
||||
* to copy from
|
||||
*/
|
||||
|
||||
read_buf = bt_buf_alloc(BT_DUMMY, NULL, 0);
|
||||
if (read_buf == NULL)
|
||||
dev = container_of(entry, struct bthcisock_s, link);
|
||||
if (bthcisock_host_avail(dev->fd))
|
||||
{
|
||||
wlerr("ERROR: Failed to allocate buffer\n");
|
||||
return -ENOMEM;
|
||||
bthcisock_receive(&dev->drv);
|
||||
}
|
||||
}
|
||||
|
||||
len = bthcisock_host_read(bt_fd, read_buf->data,
|
||||
BLUETOOTH_MAX_FRAMELEN);
|
||||
if (len < 0)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
type = *(uint8_t *)bt_buf_extend(read_buf, len);
|
||||
bt_buf_consume(read_buf, BLUETOOTH_H4_HDRLEN);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case HCI_EVENT_PKT:
|
||||
{
|
||||
read_buf->type = BT_EVT;
|
||||
break;
|
||||
}
|
||||
|
||||
case HCI_ACLDATA_PKT:
|
||||
{
|
||||
read_buf->type = BT_ACL_IN;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
wlerr("Unknown packet type %d\n", type);
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
bt_hci_receive(read_buf);
|
||||
|
||||
/* Make sure to allocate a new buffer for the next read. Bluetooth
|
||||
* stack will clean up the allocation of this buffer when it has been
|
||||
* handled.
|
||||
*/
|
||||
|
||||
read_buf = NULL;
|
||||
return OK;
|
||||
return 0;
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <nuttx/net/bluetooth.h>
|
||||
#include <nuttx/wireless/bluetooth/bt_hci.h>
|
||||
#include <nuttx/wireless/bluetooth/bt_null.h>
|
||||
#include <nuttx/wireless/bluetooth/bt_driver.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
@ -45,15 +46,16 @@ static void btnull_format_cmdcomplete(FAR struct bt_buf_s *buf,
|
||||
static void btnull_format_bdaddr_rsp(FAR struct bt_buf_s *buf,
|
||||
uint16_t opcode);
|
||||
|
||||
static int btnull_open(FAR const struct bt_driver_s *dev);
|
||||
static int btnull_send(FAR const struct bt_driver_s *dev,
|
||||
FAR struct bt_buf_s *buf);
|
||||
static int btnull_open(FAR struct bt_driver_s *dev);
|
||||
static int btnull_send(FAR struct bt_driver_s *dev,
|
||||
enum bt_buf_type_e type,
|
||||
FAR void *data, size_t len);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct bt_driver_s g_bt_null =
|
||||
static struct bt_driver_s g_bt_null =
|
||||
{
|
||||
0, /* head_reserve */
|
||||
btnull_open, /* open */
|
||||
@ -180,16 +182,17 @@ static void btnull_format_buffersize_rsp(FAR struct bt_buf_s *buf,
|
||||
buf->len = len;
|
||||
}
|
||||
|
||||
static int btnull_send(FAR const struct bt_driver_s *dev,
|
||||
FAR struct bt_buf_s *buf)
|
||||
static int btnull_send(FAR struct bt_driver_s *dev,
|
||||
enum bt_buf_type_e type,
|
||||
FAR void *data, size_t len)
|
||||
{
|
||||
wlinfo("Bit bucket: length %d\n", (int)buf->len);
|
||||
wlinfo("Bit bucket: length %zu\n", len);
|
||||
|
||||
/* Is the Bluetooth stack waiting for an event? */
|
||||
|
||||
if (buf->type == BT_CMD)
|
||||
if (type == BT_CMD)
|
||||
{
|
||||
FAR struct bt_hci_cmd_hdr_s *hdr = (FAR void *)buf->data;
|
||||
FAR struct bt_hci_cmd_hdr_s *hdr = data;
|
||||
FAR struct bt_buf_s *outbuf;
|
||||
uint16_t opcode = hdr->opcode;
|
||||
|
||||
@ -224,13 +227,15 @@ static int btnull_send(FAR const struct bt_driver_s *dev,
|
||||
|
||||
wlinfo("Send CMD complete event\n");
|
||||
|
||||
bt_hci_receive(outbuf);
|
||||
bt_netdev_receive(dev, outbuf->type,
|
||||
outbuf->data, outbuf->len);
|
||||
bt_buf_release(outbuf);
|
||||
}
|
||||
|
||||
return buf->len;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int btnull_open(FAR const struct bt_driver_s *dev)
|
||||
static int btnull_open(FAR struct bt_driver_s *dev)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
@ -51,6 +51,8 @@
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/net/bluetooth.h>
|
||||
|
||||
#include <nuttx/wireless/bluetooth/bt_core.h>
|
||||
#include <nuttx/wireless/bluetooth/bt_hci.h>
|
||||
#include <nuttx/wireless/bluetooth/bt_driver.h>
|
||||
@ -106,99 +108,29 @@ static ssize_t btuart_read(FAR struct btuart_upperhalf_s *upper,
|
||||
return ntotal;
|
||||
}
|
||||
|
||||
static FAR struct bt_buf_s *
|
||||
btuart_evt_recv(FAR struct btuart_upperhalf_s *upper,
|
||||
FAR unsigned int *hdrlen)
|
||||
{
|
||||
FAR struct bt_buf_s *buf;
|
||||
struct bt_hci_evt_hdr_s hdr;
|
||||
ssize_t nread;
|
||||
|
||||
/* We can ignore the return value since we pass buflen == minread */
|
||||
|
||||
nread = btuart_read(upper, (FAR uint8_t *)&hdr,
|
||||
sizeof(struct bt_hci_evt_hdr_s),
|
||||
sizeof(struct bt_hci_evt_hdr_s));
|
||||
|
||||
if (nread != sizeof(struct bt_hci_evt_hdr_s))
|
||||
{
|
||||
wlerr("ERROR: btuart_read returned %ld\n", (long)nread);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = bt_buf_alloc(BT_EVT, NULL, 0);
|
||||
if (buf != NULL)
|
||||
{
|
||||
memcpy(bt_buf_extend(buf, sizeof(struct bt_hci_evt_hdr_s)), &hdr,
|
||||
sizeof(struct bt_hci_evt_hdr_s));
|
||||
}
|
||||
else
|
||||
{
|
||||
wlerr("ERROR: No available event buffers!\n");
|
||||
}
|
||||
|
||||
*hdrlen = hdr.len;
|
||||
|
||||
wlinfo("hdrlen %u\n", hdr.len);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static FAR struct bt_buf_s *
|
||||
btuart_acl_recv(FAR struct btuart_upperhalf_s *upper,
|
||||
FAR unsigned int *hdrlen)
|
||||
{
|
||||
FAR struct bt_buf_s *buf;
|
||||
struct bt_hci_acl_hdr_s hdr;
|
||||
ssize_t nread;
|
||||
|
||||
/* We can ignore the return value since we pass buflen == minread */
|
||||
|
||||
nread = btuart_read(upper, (FAR uint8_t *)&hdr,
|
||||
sizeof(struct bt_hci_acl_hdr_s),
|
||||
sizeof(struct bt_hci_acl_hdr_s));
|
||||
|
||||
if (nread != sizeof(struct bt_hci_acl_hdr_s))
|
||||
{
|
||||
wlerr("ERROR: btuart_read returned %ld\n", (long)nread);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = bt_buf_alloc(BT_ACL_IN, NULL, 0);
|
||||
if (buf != NULL)
|
||||
{
|
||||
memcpy(bt_buf_extend(buf, sizeof(struct bt_hci_acl_hdr_s)), &hdr,
|
||||
sizeof(struct bt_hci_acl_hdr_s));
|
||||
}
|
||||
else
|
||||
{
|
||||
wlerr("ERROR: No available ACL buffers!\n");
|
||||
}
|
||||
|
||||
*hdrlen = BT_LE162HOST(hdr.len);
|
||||
|
||||
wlinfo("hdrlen %u\n", *hdrlen);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void btuart_rxwork(FAR void *arg)
|
||||
{
|
||||
FAR struct btuart_upperhalf_s *upper;
|
||||
FAR const struct btuart_lowerhalf_s *lower;
|
||||
FAR struct bt_buf_s *buf;
|
||||
uint8_t data[BLUETOOTH_MAX_FRAMELEN];
|
||||
enum bt_buf_type_e type;
|
||||
unsigned int hdrlen;
|
||||
int remaining;
|
||||
unsigned int pktlen;
|
||||
ssize_t nread;
|
||||
uint8_t type;
|
||||
union
|
||||
{
|
||||
struct bt_hci_evt_hdr_s evt;
|
||||
struct bt_hci_acl_hdr_s acl;
|
||||
}
|
||||
|
||||
*hdr;
|
||||
|
||||
upper = (FAR struct btuart_upperhalf_s *)arg;
|
||||
DEBUGASSERT(upper != NULL && upper->lower != NULL);
|
||||
lower = upper->lower;
|
||||
|
||||
/* Beginning of a new packet.
|
||||
* Read the first byte to get the packet type.
|
||||
*/
|
||||
|
||||
nread = btuart_read(upper, &type, 1, 0);
|
||||
nread = btuart_read(upper, data, H4_HEADER_SIZE, 0);
|
||||
if (nread != 1)
|
||||
{
|
||||
wlwarn("WARNING: Unable to read H4 packet type: %ld\n",
|
||||
@ -206,65 +138,64 @@ static void btuart_rxwork(FAR void *arg)
|
||||
goto errout_with_busy;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
if (data[0] == H4_EVT)
|
||||
{
|
||||
case H4_EVT:
|
||||
buf = btuart_evt_recv(upper, &hdrlen);
|
||||
break;
|
||||
|
||||
case H4_ACL:
|
||||
buf = btuart_acl_recv(upper, &hdrlen);
|
||||
break;
|
||||
|
||||
default:
|
||||
wlerr("ERROR: Unknown H4 type %u\n", type);
|
||||
goto errout_with_busy;
|
||||
hdrlen = sizeof(struct bt_hci_evt_hdr_s);
|
||||
}
|
||||
|
||||
if (buf == NULL)
|
||||
else if (data[0] == H4_ACL)
|
||||
{
|
||||
/* Failed to allocate a buffer. Drain the Rx data and fail the read. */
|
||||
|
||||
nread = lower->rxdrain(lower);
|
||||
wlwarn("WARNING: Discarded %ld bytes\n", (long)nread);
|
||||
hdrlen = sizeof(struct bt_hci_acl_hdr_s);
|
||||
}
|
||||
else
|
||||
{
|
||||
wlerr("ERROR: Unknown H4 type %u\n", data[0]);
|
||||
goto errout_with_busy;
|
||||
}
|
||||
else if (hdrlen > bt_buf_tailroom(buf))
|
||||
|
||||
nread = btuart_read(upper, data + H4_HEADER_SIZE,
|
||||
hdrlen, hdrlen);
|
||||
if (nread != hdrlen)
|
||||
{
|
||||
wlerr("ERROR: Not enough space in buffer\n");
|
||||
goto errout_with_buf;
|
||||
wlwarn("WARNING: Unable to read H4 packet header: %ld\n",
|
||||
(long)nread);
|
||||
goto errout_with_busy;
|
||||
}
|
||||
|
||||
remaining = hdrlen;
|
||||
wlinfo("Need to get %u bytes\n", remaining);
|
||||
hdr = (void *)(data + H4_HEADER_SIZE);
|
||||
|
||||
while (remaining > 0)
|
||||
if (data[0] == H4_EVT)
|
||||
{
|
||||
nread = btuart_read(upper, bt_buf_tail(buf), remaining, 0);
|
||||
if (nread < 0)
|
||||
{
|
||||
wlerr("ERROR: Read returned error %d\n", (int)nread);
|
||||
goto errout_with_buf;
|
||||
}
|
||||
|
||||
wlinfo("Received %ld bytes\n", (long)nread);
|
||||
|
||||
buf->len += nread;
|
||||
remaining -= nread;
|
||||
pktlen = hdr->evt.len;
|
||||
type = BT_EVT;
|
||||
}
|
||||
else if (data[0] == H4_ACL)
|
||||
{
|
||||
pktlen = hdr->acl.len;
|
||||
type = BT_ACL_IN;
|
||||
}
|
||||
else
|
||||
{
|
||||
wlerr("ERROR: Unknown H4 type %u\n", data[0]);
|
||||
goto errout_with_busy;
|
||||
}
|
||||
|
||||
wlinfo("Full packet received\n");
|
||||
nread = btuart_read(upper, data + H4_HEADER_SIZE + hdrlen,
|
||||
pktlen, pktlen);
|
||||
if (nread != pktlen)
|
||||
{
|
||||
wlwarn("WARNING: Unable to read H4 packet: %ld\n",
|
||||
(long)nread);
|
||||
goto errout_with_busy;
|
||||
}
|
||||
|
||||
/* Pass buffer to the stack */
|
||||
|
||||
BT_DUMP("Received", buf->data, buf->len);
|
||||
BT_DUMP("Received", data, H4_HEADER_SIZE + hdrlen + pktlen);
|
||||
upper->busy = false;
|
||||
bt_hci_receive(buf);
|
||||
bt_netdev_receive(&upper->dev, type, data + H4_HEADER_SIZE,
|
||||
hdrlen + pktlen);
|
||||
return;
|
||||
|
||||
errout_with_buf:
|
||||
bt_buf_release(buf);
|
||||
|
||||
errout_with_busy:
|
||||
upper->busy = false;
|
||||
}
|
||||
@ -293,51 +224,45 @@ static void btuart_rxcallback(FAR const struct btuart_lowerhalf_s *lower,
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
int btuart_send(FAR const struct bt_driver_s *dev, FAR struct bt_buf_s *buf)
|
||||
int btuart_send(FAR struct bt_driver_s *dev,
|
||||
enum bt_buf_type_e type,
|
||||
FAR void *data, size_t len)
|
||||
{
|
||||
FAR uint8_t *hdr = (FAR uint8_t *)data - dev->head_reserve;
|
||||
FAR struct btuart_upperhalf_s *upper;
|
||||
FAR const struct btuart_lowerhalf_s *lower;
|
||||
FAR uint8_t *type;
|
||||
ssize_t ntotal = 0;
|
||||
|
||||
upper = (FAR struct btuart_upperhalf_s *)dev;
|
||||
DEBUGASSERT(upper != NULL && upper->lower != NULL);
|
||||
lower = upper->lower;
|
||||
|
||||
if (bt_buf_headroom(buf) < H4_HEADER_SIZE)
|
||||
if (type == BT_CMD)
|
||||
{
|
||||
*hdr = H4_CMD;
|
||||
}
|
||||
else if (type == BT_ACL_OUT)
|
||||
{
|
||||
*hdr = H4_ACL;
|
||||
}
|
||||
else if (type == BT_ISO_OUT)
|
||||
{
|
||||
*hdr = H4_ISO;
|
||||
}
|
||||
else
|
||||
{
|
||||
wlerr("Not enough headroom in buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
type = bt_buf_provide(buf, H4_HEADER_SIZE);
|
||||
len += H4_HEADER_SIZE;
|
||||
|
||||
switch (buf->type)
|
||||
{
|
||||
case BT_CMD:
|
||||
*type = H4_CMD;
|
||||
break;
|
||||
BT_DUMP("Sending", hdr, len);
|
||||
|
||||
case BT_ACL_OUT:
|
||||
*type = H4_ACL;
|
||||
break;
|
||||
|
||||
case BT_EVT:
|
||||
*type = H4_EVT;
|
||||
break;
|
||||
|
||||
default:
|
||||
wlerr("Unknown buf type %u\n", buf->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
BT_DUMP("Sending", buf->data, buf->len);
|
||||
|
||||
while (ntotal < buf->len)
|
||||
while (ntotal < len)
|
||||
{
|
||||
ssize_t nwritten;
|
||||
|
||||
nwritten = lower->write(lower, buf->data + ntotal, buf->len - ntotal);
|
||||
nwritten = lower->write(lower, hdr + ntotal, len - ntotal);
|
||||
if (nwritten >= 0)
|
||||
{
|
||||
ntotal += nwritten;
|
||||
@ -351,7 +276,7 @@ int btuart_send(FAR const struct bt_driver_s *dev, FAR struct bt_buf_s *buf)
|
||||
return OK;
|
||||
}
|
||||
|
||||
int btuart_open(FAR const struct bt_driver_s *dev)
|
||||
int btuart_open(FAR struct bt_driver_s *dev)
|
||||
{
|
||||
FAR struct btuart_upperhalf_s *upper;
|
||||
FAR const struct btuart_lowerhalf_s *lower;
|
||||
|
@ -94,7 +94,9 @@ struct btuart_upperhalf_s
|
||||
|
||||
/* Generic implementations of HCI UART methods */
|
||||
|
||||
int btuart_send(FAR const struct bt_driver_s *dev, FAR struct bt_buf_s *buf);
|
||||
int btuart_open(FAR const struct bt_driver_s *dev);
|
||||
int btuart_send(FAR struct bt_driver_s *dev,
|
||||
enum bt_buf_type_e type,
|
||||
FAR void *data, size_t len);
|
||||
int btuart_open(FAR struct bt_driver_s *dev);
|
||||
|
||||
#endif /* __DRIVER_WIRELESS_BLUETOOTH_BT_UART_H */
|
||||
|
@ -29,8 +29,6 @@
|
||||
#include <string.h>
|
||||
#include <nuttx/wireless/bluetooth/bt_hci.h>
|
||||
|
||||
#ifdef CONFIG_NET_BLUETOOTH
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
@ -61,6 +59,8 @@
|
||||
#define BLUETOOTH_ADDRCOPY(d,s) memcpy((d),(s),BLUETOOTH_ADDRSIZE)
|
||||
#define BLUETOOTH_ADDRCMP(a,b) (memcmp((a),(b),BLUETOOTH_ADDRSIZE) == 0)
|
||||
|
||||
#ifdef CONFIG_NET_BLUETOOTH
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
@ -49,6 +49,13 @@
|
||||
|
||||
#include <nuttx/wireless/bluetooth/bt_buf.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define bt_netdev_receive(btdev, type, data, len) \
|
||||
(btdev)->receive(btdev, type, data, len)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
@ -61,12 +68,27 @@ struct bt_driver_s
|
||||
|
||||
/* Open the HCI transport */
|
||||
|
||||
CODE int (*open)(FAR const struct bt_driver_s *btdev);
|
||||
CODE int (*open)(FAR struct bt_driver_s *btdev);
|
||||
|
||||
/* Send data to HCI */
|
||||
|
||||
CODE int (*send)(FAR const struct bt_driver_s *btdev,
|
||||
FAR struct bt_buf_s *buf);
|
||||
CODE int (*send)(FAR struct bt_driver_s *btdev,
|
||||
enum bt_buf_type_e type,
|
||||
FAR void *data, size_t len);
|
||||
|
||||
/* Close the HCI transport */
|
||||
|
||||
CODE void (*close)(FAR struct bt_driver_s *btdev);
|
||||
|
||||
/* Filled by register function but called by bt_driver_s */
|
||||
|
||||
CODE int (*receive)(FAR struct bt_driver_s *btdev,
|
||||
enum bt_buf_type_e type,
|
||||
FAR void *data, size_t len);
|
||||
|
||||
/* Filled by register function, shouldn't be touched by bt_driver_s */
|
||||
|
||||
FAR void *priv;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
@ -89,24 +111,6 @@ struct bt_driver_s
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int bt_netdev_register(FAR const struct bt_driver_s *btdev);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bt_hci_receive
|
||||
*
|
||||
* Description:
|
||||
* Called by the Bluetooth low-level driver when new data is received from
|
||||
* the radio. This may be called from the low-level driver and is part of
|
||||
* the driver interface
|
||||
*
|
||||
* Input Parameters:
|
||||
* buf - An instance of the buffer structure providing the received frame.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void bt_hci_receive(FAR struct bt_buf_s *buf);
|
||||
int bt_netdev_register(FAR struct bt_driver_s *btdev);
|
||||
|
||||
#endif /* __INCLUDE_NUTTX_WIRELESS_BLUETOOTH_BT_DRIVER_H */
|
||||
|
@ -992,7 +992,7 @@ static void hci_event(FAR struct bt_buf_s *buf)
|
||||
|
||||
static int hci_tx_kthread(int argc, FAR char *argv[])
|
||||
{
|
||||
FAR const struct bt_driver_s *btdev = g_btdev.btdev;
|
||||
FAR struct bt_driver_s *btdev = g_btdev.btdev;
|
||||
int ret;
|
||||
|
||||
wlinfo("started\n");
|
||||
@ -1487,18 +1487,12 @@ static void cmd_queue_init(void)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int bt_send(FAR const struct bt_driver_s *btdev,
|
||||
int bt_send(FAR struct bt_driver_s *btdev,
|
||||
FAR struct bt_buf_s *buf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Send to driver */
|
||||
|
||||
ret = btdev->send(btdev, buf);
|
||||
|
||||
/* TODO: Hook here to notify hci monitor */
|
||||
|
||||
return ret;
|
||||
return btdev->send(btdev, buf->type, buf->data, buf->len);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -1514,7 +1508,7 @@ int bt_send(FAR const struct bt_driver_s *btdev,
|
||||
|
||||
int bt_initialize(void)
|
||||
{
|
||||
FAR const struct bt_driver_s *btdev = g_btdev.btdev;
|
||||
FAR struct bt_driver_s *btdev = g_btdev.btdev;
|
||||
int ret;
|
||||
|
||||
wlinfo("btdev %p\n", btdev);
|
||||
@ -1564,7 +1558,7 @@ int bt_initialize(void)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int bt_driver_register(FAR const struct bt_driver_s *btdev)
|
||||
int bt_driver_register(FAR struct bt_driver_s *btdev)
|
||||
{
|
||||
DEBUGASSERT(btdev != NULL && btdev->open != NULL && btdev->send != NULL);
|
||||
|
||||
@ -1595,13 +1589,13 @@ int bt_driver_register(FAR const struct bt_driver_s *btdev)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void bt_driver_unregister(FAR const struct bt_driver_s *btdev)
|
||||
void bt_driver_unregister(FAR struct bt_driver_s *btdev)
|
||||
{
|
||||
g_btdev.btdev = NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bt_hci_receive
|
||||
* Name: bt_receive
|
||||
*
|
||||
* Description:
|
||||
* Called by the Bluetooth low-level driver when new data is received from
|
||||
@ -1621,26 +1615,34 @@ 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)
|
||||
int bt_receive(FAR struct bt_driver_s *btdev, enum bt_buf_type_e type,
|
||||
FAR void *data, size_t len)
|
||||
{
|
||||
FAR struct bt_hci_evt_hdr_s *hdr;
|
||||
struct bt_buf_s *buf;
|
||||
int ret;
|
||||
|
||||
wlinfo("buf %p len %u\n", buf, buf->len);
|
||||
wlinfo("data %p len %zu\n", data, len);
|
||||
|
||||
/* Critical command complete/status events use the high priority work
|
||||
* queue.
|
||||
*/
|
||||
|
||||
if (buf->type != BT_ACL_IN)
|
||||
buf = bt_buf_alloc(type, NULL, 0);
|
||||
if (buf == NULL)
|
||||
{
|
||||
if (buf->type != BT_EVT)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(bt_buf_extend(buf, len), data, len);
|
||||
|
||||
if (type != BT_ACL_IN)
|
||||
{
|
||||
if (type != BT_EVT)
|
||||
{
|
||||
wlerr("ERROR: Invalid buf type %u\n", buf->type);
|
||||
bt_buf_release(buf);
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Command Complete/Status events use high priority messages. */
|
||||
@ -1669,7 +1671,7 @@ void bt_hci_receive(FAR struct bt_buf_s *buf)
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1691,6 +1693,8 @@ void bt_hci_receive(FAR struct bt_buf_s *buf)
|
||||
wlerr("ERROR: Failed to schedule LPWORK: %d\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
|
@ -126,7 +126,7 @@ struct bt_dev_s
|
||||
|
||||
/* Registered HCI driver */
|
||||
|
||||
FAR const struct bt_driver_s *btdev;
|
||||
FAR struct bt_driver_s *btdev;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
@ -281,7 +281,7 @@ int bt_initialize(void);
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int bt_driver_register(FAR const struct bt_driver_s *btdev);
|
||||
int bt_driver_register(FAR struct bt_driver_s *btdev);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bt_driver_unregister
|
||||
@ -300,7 +300,7 @@ int bt_driver_register(FAR const struct bt_driver_s *btdev);
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void bt_driver_unregister(FAR const struct bt_driver_s *btdev);
|
||||
void bt_driver_unregister(FAR struct bt_driver_s *btdev);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bt_send
|
||||
@ -318,7 +318,7 @@ void bt_driver_unregister(FAR const struct bt_driver_s *btdev);
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int bt_send(FAR const struct bt_driver_s *btdev,
|
||||
int bt_send(FAR struct bt_driver_s *btdev,
|
||||
FAR struct bt_buf_s *buf);
|
||||
|
||||
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
|
||||
@ -465,4 +465,17 @@ void bt_hci_cb_register(FAR struct bt_hci_cb_s *cb);
|
||||
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bt_receive
|
||||
*
|
||||
* Description:
|
||||
* Called by the Bluetooth low-level driver when new data is received from
|
||||
* the radio. This may be called from the low-level driver and is part of
|
||||
* the driver interface
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int bt_receive(FAR struct bt_driver_s *btdev, enum bt_buf_type_e type,
|
||||
FAR void *data, size_t len);
|
||||
|
||||
#endif /* __WIRELESS_BLUETOOTH_BT_HDICORE_H */
|
||||
|
@ -1271,7 +1271,7 @@ static int btnet_properties(FAR struct radio_driver_s *netdev,
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int bt_netdev_register(FAR const struct bt_driver_s *btdev)
|
||||
int bt_netdev_register(FAR struct bt_driver_s *btdev)
|
||||
{
|
||||
FAR struct btnet_driver_s *priv;
|
||||
FAR struct radio_driver_s *radio;
|
||||
@ -1354,6 +1354,8 @@ int bt_netdev_register(FAR const struct bt_driver_s *btdev)
|
||||
radio->r_req_data = btnet_req_data; /* Enqueue frame for transmission */
|
||||
radio->r_properties = btnet_properties; /* Return radio properties */
|
||||
|
||||
btdev->receive = bt_receive;
|
||||
|
||||
/* Associate the driver in with the Bluetooth stack.
|
||||
*
|
||||
* REVISIT: We will eventually need to remember which Bluetooth device
|
||||
|
Loading…
Reference in New Issue
Block a user