nimble/transport: Add ISO support

This adds support for HCI ISO Data packets to UART H4, nRF5340 IPC and
native transport.

The default ISO buffers count is set to 0 as it will disable ISO support
by default.
This commit is contained in:
Andrzej Kaczmarek
2023-06-09 09:49:11 +02:00
parent 6349d771d5
commit ca043593a9
13 changed files with 223 additions and 0 deletions
@@ -31,11 +31,13 @@
typedef void *(hci_h4_alloc_cmd)(void);
typedef void *(hci_h4_alloc_evt)(int);
typedef struct os_mbuf *(hci_h4_alloc_acl)(void);
typedef struct os_mbuf *(hci_h4_alloc_iso)(void);
struct hci_h4_allocators {
hci_h4_alloc_cmd *cmd;
hci_h4_alloc_acl *acl;
hci_h4_alloc_evt *evt;
hci_h4_alloc_iso *iso;
};
extern const struct hci_h4_allocators hci_h4_allocs_from_ll;
@@ -39,6 +39,7 @@ const struct hci_h4_allocators hci_h4_allocs_from_ll = {
const struct hci_h4_allocators hci_h4_allocs_from_hs = {
.cmd = ble_transport_alloc_cmd,
.acl = ble_transport_alloc_acl_from_hs,
.iso = ble_transport_alloc_iso_from_hs,
};
struct hci_h4_input_buffer {
@@ -58,6 +59,7 @@ hci_h4_frame_start(struct hci_h4_sm *rxs, uint8_t pkt_type)
rxs->min_len = 3;
break;
case HCI_H4_ACL:
case HCI_H4_ISO:
rxs->min_len = 4;
break;
case HCI_H4_EVT:
@@ -159,6 +161,16 @@ hci_h4_sm_w4_header(struct hci_h4_sm *h4sm, struct hci_h4_input_buffer *ib)
h4sm->exp_len = h4sm->hdr[1] + 2;
break;
case HCI_H4_ISO:
assert(h4sm->allocs && h4sm->allocs->iso);
h4sm->om = h4sm->allocs->iso();
if (!h4sm->om) {
return -1;
}
os_mbuf_append(h4sm->om, h4sm->hdr, h4sm->len);
h4sm->exp_len = (get_le16(&h4sm->hdr[2]) & 0x7fff) + 4;
break;
default:
assert(0);
break;
@@ -185,6 +197,7 @@ hci_h4_sm_w4_payload(struct hci_h4_sm *h4sm,
}
break;
case HCI_H4_ACL:
case HCI_H4_ISO:
assert(h4sm->om);
mbuf_len = OS_MBUF_PKTLEN(h4sm->om);
@@ -230,6 +243,7 @@ hci_h4_sm_completed(struct hci_h4_sm *h4sm)
}
break;
case HCI_H4_ACL:
case HCI_H4_ISO:
if (h4sm->om) {
assert(h4sm->frame_cb);
rc = h4sm->frame_cb(h4sm->pkt_type, h4sm->om);
@@ -27,6 +27,7 @@
#define HCI_IPC_TYPE_EVT 0x04
#define HCI_IPC_TYPE_EVT_DISCARDABLE 0x05
#define HCI_IPC_TYPE_EVT_IN_CMD 0x06
#define HCI_IPC_TYPE_ISO 0x07
struct __attribute__((packed)) hci_ipc_hdr {
uint8_t type;
@@ -58,6 +58,13 @@ hci_ipc_alloc(struct hci_ipc_sm *sm)
sm->buf = ble_transport_alloc_cmd();
break;
#endif
case HCI_IPC_TYPE_ISO:
#if MYNEWT_VAL(BLE_CONTROLLER)
sm->om = ble_transport_alloc_iso_from_hs();
#else
sm->om = ble_transport_alloc_iso_from_ll();
#endif
break;
default:
assert(0);
break;
@@ -102,6 +109,13 @@ hci_ipc_frame(struct hci_ipc_sm *sm)
ble_transport_to_hs_evt(sm->buf);
break;
#endif
case HCI_IPC_TYPE_ISO:
#if MYNEWT_VAL(BLE_CONTROLLER)
ble_transport_to_ll_iso(sm->om);
#else
ble_transport_to_hs_iso(sm->om);
#endif
break;
default:
assert(0);
break;
@@ -161,6 +175,7 @@ hci_ipc_copy_to_buf(struct hci_ipc_sm *sm, const uint8_t *buf, uint16_t len)
memcpy(sm->buf + sm->buf_len, buf, len);
break;
case HCI_IPC_TYPE_ACL:
case HCI_IPC_TYPE_ISO:
rc = os_mbuf_append(sm->om, buf, len);
assert(rc == 0);
break;
@@ -39,7 +39,9 @@ void ble_transport_init(void);
void *ble_transport_alloc_cmd(void);
void *ble_transport_alloc_evt(int discardable);
struct os_mbuf *ble_transport_alloc_acl_from_hs(void);
struct os_mbuf *ble_transport_alloc_iso_from_hs(void);
struct os_mbuf *ble_transport_alloc_acl_from_ll(void);
struct os_mbuf *ble_transport_alloc_iso_from_ll(void);
/* Generic deallocator for cmd/evt buffers */
void ble_transport_free(void *buf);
@@ -50,8 +52,10 @@ int ble_transport_register_put_acl_from_ll_cb(os_mempool_put_fn *cb);
/* Send data to hs/ll side */
int ble_transport_to_ll_cmd(void *buf);
int ble_transport_to_ll_acl(struct os_mbuf *om);
int ble_transport_to_ll_iso(struct os_mbuf *om);
int ble_transport_to_hs_evt(void *buf);
int ble_transport_to_hs_acl(struct os_mbuf *om);
int ble_transport_to_hs_iso(struct os_mbuf *om);
#ifdef __cplusplus
}
@@ -59,6 +59,12 @@ ble_transport_to_ll_acl(struct os_mbuf *om)
return ble_transport_to_ll_acl_impl(om);
}
static inline int
ble_transport_to_ll_iso(struct os_mbuf *om)
{
return ble_transport_to_ll_iso_impl(om);
}
static inline int
ble_transport_to_hs_evt(void *buf)
{
@@ -70,6 +76,12 @@ ble_transport_to_hs_acl(struct os_mbuf *om)
{
return ble_transport_to_hs_acl_impl(om);
}
static inline int
ble_transport_to_hs_iso(struct os_mbuf *om)
{
return ble_transport_to_hs_iso_impl(om);
}
#endif /* BLE_MONITOR */
#ifdef __cplusplus
@@ -31,8 +31,10 @@ extern void ble_transport_hs_init(void);
/* APIs to be implemented by HS/LL side of transports */
extern int ble_transport_to_ll_cmd_impl(void *buf);
extern int ble_transport_to_ll_acl_impl(struct os_mbuf *om);
extern int ble_transport_to_ll_iso_impl(struct os_mbuf *om);
extern int ble_transport_to_hs_evt_impl(void *buf);
extern int ble_transport_to_hs_acl_impl(struct os_mbuf *om);
extern int ble_transport_to_hs_iso_impl(struct os_mbuf *om);
#ifdef __cplusplus
}
@@ -63,6 +63,35 @@ nrf5340_ble_hci_acl_tx(struct os_mbuf *om)
return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0;
}
#if !MYNEWT_VAL(BLE_CONTROLLER)
static int
nrf5340_ble_hci_iso_tx(struct os_mbuf *om)
{
struct hci_ipc_hdr hdr;
struct os_mbuf *x;
int rc;
hdr.type = HCI_IPC_TYPE_ISO;
hdr.length = 4 + get_le16(&om->om_data[2]);
rc = ipc_nrf5340_write(IPC_TX_CHANNEL, &hdr, sizeof(hdr), false);
if (rc == 0) {
x = om;
while (x) {
rc = ipc_nrf5340_write(IPC_TX_CHANNEL, x->om_data, x->om_len, true);
if (rc < 0) {
break;
}
x = SLIST_NEXT(x, om_next);
}
}
os_mbuf_free_chain(om);
return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0;
}
#endif
static void
nrf5340_ble_hci_trans_rx(int channel, void *user_data)
{
@@ -149,6 +178,12 @@ ble_transport_to_ll_acl_impl(struct os_mbuf *om)
return nrf5340_ble_hci_acl_tx(om);
}
int
ble_transport_to_ll_iso_impl(struct os_mbuf *om)
{
return nrf5340_ble_hci_iso_tx(om);
}
void
ble_transport_ll_init(void)
{
+16
View File
@@ -509,6 +509,14 @@ ble_transport_to_ll_acl(struct os_mbuf *om)
return ble_transport_to_ll_acl_impl(om);
}
int
ble_transport_to_ll_iso(struct os_mbuf *om)
{
ble_monitor_send_om(BLE_MONITOR_OPCODE_ISO_TX_PKT, om);
return ble_transport_to_ll_iso_impl(om);
}
int
ble_transport_to_hs_acl(struct os_mbuf *om)
{
@@ -528,4 +536,12 @@ ble_transport_to_hs_evt(void *buf)
return ble_transport_to_hs_evt_impl(buf);
}
int
ble_transport_to_hs_iso(struct os_mbuf *om)
{
ble_monitor_send_om(BLE_MONITOR_OPCODE_ISO_RX_PKT, om);
return ble_transport_to_hs_iso_impl(om);
}
#endif /* MYNEWT_VAL(BLE_MONITOR_RTT) || MYNEWT_VAL(BLE_MONITOR_UART) */
+2
View File
@@ -38,6 +38,8 @@ extern "C" {
#define BLE_MONITOR_OPCODE_VENDOR_DIAG 11
#define BLE_MONITOR_OPCODE_SYSTEM_NOTE 12
#define BLE_MONITOR_OPCODE_USER_LOGGING 13
#define BLE_MONITOR_OPCODE_ISO_TX_PKT 18
#define BLE_MONITOR_OPCODE_ISO_RX_PKT 19
#define BLE_MONITOR_EXTHDR_COMMAND_DROPS 1
#define BLE_MONITOR_EXTHDR_EVENT_DROPS 2
+69
View File
@@ -49,18 +49,26 @@
#if MYNEWT_VAL_CHOICE(BLE_TRANSPORT_LL, native) && \
MYNEWT_VAL_CHOICE(BLE_TRANSPORT_HS, native)
#define POOL_ACL_COUNT (0)
#define POOL_ISO_COUNT (0)
#elif !MYNEWT_VAL_CHOICE(BLE_TRANSPORT_LL, native) && \
!MYNEWT_VAL_CHOICE(BLE_TRANSPORT_HS, native)
#define POOL_ACL_COUNT ((MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_HS_COUNT)) + \
(MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT)))
#define POOL_ISO_COUNT ((MYNEWT_VAL(BLE_TRANSPORT_ISO_FROM_HS_COUNT)) + \
(MYNEWT_VAL(BLE_TRANSPORT_ISO_FROM_LL_COUNT)))
#elif MYNEWT_VAL_CHOICE(BLE_TRANSPORT_LL, native)
#define POOL_ACL_COUNT (MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_HS_COUNT))
#define POOL_ISO_COUNT (MYNEWT_VAL(BLE_TRANSPORT_ISO_FROM_HS_COUNT))
#else
#define POOL_ACL_COUNT (MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT))
#define POOL_ISO_COUNT (MYNEWT_VAL(BLE_TRANSPORT_ISO_FROM_LL_COUNT))
#endif
#define POOL_ACL_SIZE (OS_ALIGN( MYNEWT_VAL(BLE_TRANSPORT_ACL_SIZE) + \
BLE_MBUF_MEMBLOCK_OVERHEAD + \
BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT))
#define POOL_ISO_SIZE (OS_ALIGN(MYNEWT_VAL(BLE_TRANSPORT_ISO_SIZE) + \
BLE_MBUF_MEMBLOCK_OVERHEAD + \
BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT))
static uint8_t pool_cmd_buf[ OS_MEMPOOL_BYTES(POOL_CMD_COUNT, POOL_CMD_SIZE) ];
static struct os_mempool pool_cmd;
@@ -77,6 +85,12 @@ static struct os_mempool_ext pool_acl;
static struct os_mbuf_pool mpool_acl;
#endif
#if POOL_ISO_COUNT > 0
static uint8_t pool_iso_buf[ OS_MEMPOOL_BYTES(POOL_ISO_COUNT, POOL_ISO_SIZE) ];
static struct os_mempool_ext pool_iso;
static struct os_mbuf_pool mpool_iso;
#endif
static os_mempool_put_fn *transport_put_acl_from_ll_cb;
void *
@@ -159,6 +173,32 @@ ble_transport_alloc_acl_from_hs(void)
#endif
}
struct os_mbuf *
ble_transport_alloc_iso_from_hs(void)
{
#if POOL_ISO_COUNT > 0
struct os_mbuf *om;
struct os_mbuf_pkthdr *pkthdr;
uint16_t usrhdr_len;
#if MYNEWT_VAL_CHOICE(BLE_TRANSPORT_LL, native)
usrhdr_len = sizeof(struct ble_mbuf_hdr);
#else
usrhdr_len = 0;
#endif
om = os_mbuf_get_pkthdr(&mpool_iso, usrhdr_len);
if (om) {
pkthdr = OS_MBUF_PKTHDR(om);
pkthdr->omp_flags = OMP_FLAG_FROM_HS;
}
return om;
#else
return NULL;
#endif
}
struct os_mbuf *
ble_transport_alloc_acl_from_ll(void)
{
@@ -178,6 +218,25 @@ ble_transport_alloc_acl_from_ll(void)
#endif
}
struct os_mbuf *
ble_transport_alloc_iso_from_ll(void)
{
#if POOL_ISO_COUNT > 0
struct os_mbuf *om;
struct os_mbuf_pkthdr *pkthdr;
om = os_mbuf_get_pkthdr(&mpool_iso, 0);
if (om) {
pkthdr = OS_MBUF_PKTHDR(om);
pkthdr->omp_flags = OMP_FLAG_FROM_LL;
}
return om;
#else
return NULL;
#endif
}
void
ble_transport_free(void *buf)
{
@@ -278,6 +337,16 @@ ble_transport_init(void)
pool_acl.mpe_put_cb = ble_transport_acl_put;
#endif
#if POOL_ISO_COUNT > 0
rc = os_mempool_ext_init(&pool_iso, POOL_ISO_COUNT, POOL_ISO_SIZE,
pool_iso_buf, "transport_pool_iso");
SYSINIT_PANIC_ASSERT(rc == 0);
rc = os_mbuf_pool_init(&mpool_iso, &pool_iso.mpe_mp,
POOL_ISO_SIZE, POOL_ISO_COUNT);
SYSINIT_PANIC_ASSERT(rc == 0);
#endif
}
int
+21
View File
@@ -58,6 +58,16 @@ syscfg.defs:
BLE_TRANSPORT_ACL_SIZE:
description: Size of each buffer in ACL pool.
value: 251
BLE_TRANSPORT_ISO_COUNT:
description: >
Number of ISO buffers available in transport. This determines
number of buffers used by host/controller for flow control.
Buffers pool is allocated for each non-native transport side
selected, unless overriden by BLE_TRANSPORT_ISO_FROM_[HS|LL]_COUNT.
value: 10
BLE_TRANSPORT_ISO_SIZE:
description: Size of each buffer in ISO pool.
value: 300
BLE_TRANSPORT_EVT_COUNT:
description: >
Number of event buffers available in transport.
@@ -88,6 +98,17 @@ syscfg.defs:
of ACL buffers available for controller.
value: MYNEWT_VAL(BLE_TRANSPORT_ACL_COUNT)
BLE_TRANSPORT_ISO_FROM_HS_COUNT:
description: >
Overrides BLE_TRANSPORT_ISO_COUNT on host side, i.e. number
of ISO buffers available for host.
value: MYNEWT_VAL(BLE_TRANSPORT_ISO_COUNT)
BLE_TRANSPORT_ISO_FROM_LL_COUNT:
description: >
Overrides BLE_TRANSPORT_ISO_COUNT on controller side, i.e. number
of ISO buffers available for controller.
value: MYNEWT_VAL(BLE_TRANSPORT_ISO_COUNT)
# import monitor and defunct settings from separate file to reduce clutter in main file
$import:
- "@apache-mynewt-nimble/nimble/transport/syscfg.monitor.yml"
+30
View File
@@ -61,6 +61,8 @@ hci_uart_frame_cb(uint8_t pkt_type, void *data)
return ble_transport_to_ll_cmd(data);
case HCI_H4_ACL:
return ble_transport_to_ll_acl(data);
case HCI_H4_ISO:
return ble_transport_to_ll_iso(data);
default:
assert(0);
break;
@@ -227,6 +229,34 @@ ble_transport_to_hs_acl_impl(struct os_mbuf *om)
return 0;
}
int
ble_transport_to_hs_iso_impl(struct os_mbuf *om)
{
struct hci_uart_tx *txe;
os_sr_t sr;
txe = os_memblock_get(&pool_tx_q);
if (!txe) {
assert(0);
return -ENOMEM;
}
txe->type = HCI_H4_ISO;
txe->sent_type = 0;
txe->len = OS_MBUF_PKTLEN(om);
txe->idx = 0;
txe->buf = NULL;
txe->om = om;
OS_ENTER_CRITICAL(sr);
STAILQ_INSERT_TAIL(&tx_q, txe, tx_q_next);
OS_EXIT_CRITICAL(sr);
hal_uart_start_tx(MYNEWT_VAL(BLE_TRANSPORT_UART_PORT));
return 0;
}
void
ble_transport_hs_init(void)
{