BLE Host - flow control.

X-Original-Commit: 1fb89fd97abe73c06e7e360d838e2b2c4f01d0cb
This commit is contained in:
Christopher Collins
2018-01-14 23:44:29 -08:00
parent 2f3362372e
commit efaad20099
16 changed files with 547 additions and 39 deletions
+1
View File
@@ -1021,6 +1021,7 @@ ble_gap_conn_broken(uint16_t conn_handle, int reason)
ble_sm_connection_broken(conn_handle);
ble_gatts_connection_broken(conn_handle);
ble_gattc_connection_broken(conn_handle);
ble_hs_flow_connection_broken(conn_handle);;
ble_hs_atomic_conn_delete(conn_handle);
+45 -7
View File
@@ -149,13 +149,14 @@ ble_hs_is_parent_task(void)
os_sched_get_current_task() == ble_hs_parent_task;
}
/**
* Locks the BLE host mutex. Nested locks allowed.
*/
void
ble_hs_lock(void)
ble_hs_lock_nested(void)
{
int rc;
BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
#if MYNEWT_VAL(BLE_HS_DEBUG)
if (!os_started()) {
ble_hs_dbg_mutex_locked = 1;
@@ -167,14 +168,16 @@ ble_hs_lock(void)
BLE_HS_DBG_ASSERT_EVAL(rc == 0 || rc == OS_NOT_STARTED);
}
/**
* Unlocks the BLE host mutex. Nested locks allowed.
*/
void
ble_hs_unlock(void)
ble_hs_unlock_nested(void)
{
int rc;
#if MYNEWT_VAL(BLE_HS_DEBUG)
if (!os_started()) {
BLE_HS_DBG_ASSERT(ble_hs_dbg_mutex_locked);
ble_hs_dbg_mutex_locked = 0;
return;
}
@@ -184,6 +187,37 @@ ble_hs_unlock(void)
BLE_HS_DBG_ASSERT_EVAL(rc == 0 || rc == OS_NOT_STARTED);
}
/**
* Locks the BLE host mutex. Nested locks not allowed.
*/
void
ble_hs_lock(void)
{
BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
#if MYNEWT_VAL(BLE_HS_DEBUG)
if (!os_started()) {
BLE_HS_DBG_ASSERT(!ble_hs_dbg_mutex_locked);
}
#endif
ble_hs_lock_nested();
}
/**
* Unlocks the BLE host mutex. Nested locks not allowed.
*/
void
ble_hs_unlock(void)
{
#if MYNEWT_VAL(BLE_HS_DEBUG)
if (!os_started()) {
BLE_HS_DBG_ASSERT(ble_hs_dbg_mutex_locked);
}
#endif
ble_hs_unlock_nested();
}
void
ble_hs_process_rx_data_queue(void)
{
@@ -214,8 +248,7 @@ ble_hs_wakeup_tx_conn(struct ble_hs_conn *conn)
/* Controller is at capacity. This packet will be the first to
* get transmitted next time around.
*/
STAILQ_INSERT_HEAD(&conn->bhc_tx_q, OS_MBUF_PKTHDR(om),
omp_next);
STAILQ_INSERT_HEAD(&conn->bhc_tx_q, OS_MBUF_PKTHDR(om), omp_next);
return BLE_HS_EAGAIN;
}
}
@@ -579,6 +612,11 @@ ble_hs_rx_data(struct os_mbuf *om, void *arg)
{
int rc;
/* If flow control is enabled, mark this packet with its corresponding
* connection handle.
*/
ble_hs_flow_fill_acl_usrhdr(om);
rc = os_mqueue_put(&ble_hs_rx_q, ble_hs_evq, om);
if (rc != 0) {
os_mbuf_free_chain(om);
+8
View File
@@ -65,6 +65,14 @@ struct ble_hs_conn {
*/
uint16_t bhc_outstanding_pkts;
#if MYNEWT_VAL(BLE_HS_FLOW_CTRL)
/**
* Count of packets received over this connection that have been processed
* and freed.
*/
uint16_t bhc_completed_pkts;
#endif
/** Queue of outgoing packets that could not be sent. */
STAILQ_HEAD(, os_mbuf_pkthdr) bhc_tx_q;
+240
View File
@@ -0,0 +1,240 @@
#include "syscfg/syscfg.h"
#include "nimble/ble_hci_trans.h"
#include "ble_hs_priv.h"
#if MYNEWT_VAL(BLE_HS_FLOW_CTRL)
#define BLE_HS_FLOW_ITVL_TICKS \
(MYNEWT_VAL(BLE_HS_FLOW_CTRL_ITVL) * OS_TICKS_PER_SEC / 1000)
/**
* The number of freed buffers since the most-recent
* number-of-completed-packets event was sent. This is used to determine if an
* immediate event transmission is required.
*/
static uint16_t ble_hs_flow_num_completed_pkts;
/** Periodically sends number-of-completed-packets events. */
static struct os_callout ble_hs_flow_timer;
static os_event_fn ble_hs_flow_event_cb;
static struct os_event ble_hs_flow_ev = {
.ev_cb = ble_hs_flow_event_cb,
};
static int
ble_hs_flow_tx_num_comp_pkts(void)
{
uint8_t buf[
BLE_HCI_HOST_NUM_COMP_PKTS_HDR_LEN +
BLE_HCI_HOST_NUM_COMP_PKTS_ENT_LEN
];
struct hci_host_num_comp_pkts_entry entry;
struct ble_hs_conn *conn;
int rc;
BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
/* For each connection with completed packets, send a separate
* host-number-of-completed-packets command.
*/
for (conn = ble_hs_conn_first();
conn != NULL;
conn = SLIST_NEXT(conn, bhc_next)) {
if (conn->bhc_completed_pkts > 0) {
/* Only specify one connection per command. */
buf[0] = 1;
/* Append entry for this connection. */
entry.conn_handle = conn->bhc_handle;
entry.num_pkts = conn->bhc_completed_pkts;
rc = ble_hs_hci_cmd_build_host_num_comp_pkts_entry(
&entry,
buf + BLE_HCI_HOST_NUM_COMP_PKTS_HDR_LEN,
sizeof buf - BLE_HCI_HOST_NUM_COMP_PKTS_HDR_LEN);
BLE_HS_DBG_ASSERT(rc == 0);
conn->bhc_completed_pkts = 0;
/* The host-number-of-completed-packets command does not elicit a
* response from the controller, so don't use the normal blocking
* HCI API when sending it.
*/
rc = ble_hs_hci_cmd_send_buf(
BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND,
BLE_HCI_OCF_CB_HOST_NUM_COMP_PKTS),
buf, off);
if (rc != 0) {
return rc;
}
}
}
return 0;
}
static void
ble_hs_flow_event_cb(struct os_event *ev)
{
int rc;
ble_hs_lock();
if (ble_hs_flow_num_completed_pkts > 0) {
rc = ble_hs_flow_tx_num_comp_pkts();
if (rc != 0) {
ble_hs_sched_reset(rc);
}
ble_hs_flow_num_completed_pkts = 0;
}
ble_hs_unlock();
}
static void
ble_hs_flow_inc_completed_pkts(struct ble_hs_conn *conn)
{
uint16_t num_free;
int rc;
BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
conn->bhc_completed_pkts++;
ble_hs_flow_num_completed_pkts++;
if (ble_hs_flow_num_completed_pkts > MYNEWT_VAL(BLE_ACL_BUF_COUNT)) {
ble_hs_sched_reset(BLE_HS_ECONTROLLER);
return;
}
/* If the number of free buffers is at or below the configured threshold,
* send an immediate number-of-copmleted-packets event.
*/
num_free = MYNEWT_VAL(BLE_ACL_BUF_COUNT) - ble_hs_flow_num_completed_pkts;
if (num_free <= MYNEWT_VAL(BLE_HS_FLOW_CTRL_THRESH)) {
os_eventq_put(ble_hs_evq_get(), &ble_hs_flow_ev);
os_callout_stop(&ble_hs_flow_timer);
} else if (ble_hs_flow_num_completed_pkts == 1) {
rc = os_callout_reset(&ble_hs_flow_timer, BLE_HS_FLOW_ITVL_TICKS);
BLE_HS_DBG_ASSERT_EVAL(rc == 0);
}
}
static os_error_t
ble_hs_flow_acl_free(struct os_mempool_ext *mpe, void *data, void *arg)
{
struct ble_hs_conn *conn;
const struct os_mbuf *om;
uint16_t conn_handle;
int rc;
om = data;
/* An ACL data packet must be a single mbuf, and it must contain the
* corresponding connection handle in its user header.
*/
assert(OS_MBUF_IS_PKTHDR(om));
assert(OS_MBUF_USRHDR_LEN(om) >= sizeof conn_handle);
/* Copy the connection handle out of the mbuf. */
memcpy(&conn_handle, OS_MBUF_USRHDR(om), sizeof conn_handle);
/* Free the mbuf back to its pool. */
rc = os_memblock_put_from_cb(&mpe->mpe_mp, data);
if (rc != 0) {
return rc;
}
/* Allow nested locks - there are too many places where acl buffers can get
* freed.
*/
ble_hs_lock_nested();
conn = ble_hs_conn_find(conn_handle);
if (conn != NULL) {
ble_hs_flow_inc_completed_pkts(conn);
}
ble_hs_unlock_nested();
return 0;
}
#endif /* MYNEWT_VAL(BLE_HS_FLOW_CTRL) */
void
ble_hs_flow_connection_broken(uint16_t conn_handle)
{
#if MYNEWT_VAL(BLE_HS_FLOW_CTRL) && \
MYNEWT_VAL(BLE_HS_FLOW_CTRL_TX_ON_DISCONNECT)
ble_hs_lock();
ble_hs_flow_tx_num_comp_pkts();
ble_hs_unlock();
#endif
}
/**
* Fills the user header of an incoming data packet. On function return, the
* header contains the connection handle associated with the sender.
*
* If flow control is disabled, this function is a no-op.
*/
void
ble_hs_flow_fill_acl_usrhdr(struct os_mbuf *om)
{
#if MYNEWT_VAL(BLE_HS_FLOW_CTRL)
const struct hci_data_hdr *hdr;
uint16_t *conn_handle;
BLE_HS_DBG_ASSERT(OS_MBUF_USRHDR_LEN(om) >= sizeof *conn_handle);
conn_handle = OS_MBUF_USRHDR(om);
hdr = (void *)om->om_data;
*conn_handle = BLE_HCI_DATA_HANDLE(hdr->hdh_handle_pb_bc);
#endif
}
/**
* Sends the HCI commands to the controller required for enabling host flow
* control.
*
* If flow control is disabled, this function is a no-op.
*/
int
ble_hs_flow_startup(void)
{
#if MYNEWT_VAL(BLE_HS_FLOW_CTRL)
struct hci_host_buf_size buf_size_cmd;
int rc;
/* Assume failure. */
ble_hci_trans_set_acl_free_cb(NULL, NULL);
os_callout_stop(&ble_hs_flow_timer);
rc = ble_hs_hci_cmd_tx_set_ctlr_to_host_fc(BLE_HCI_CTLR_TO_HOST_FC_ACL);
if (rc != 0) {
return rc;
}
buf_size_cmd = (struct hci_host_buf_size) {
.acl_pkt_len = MYNEWT_VAL(BLE_ACL_BUF_SIZE),
.num_acl_pkts = MYNEWT_VAL(BLE_ACL_BUF_COUNT),
};
rc = ble_hs_hci_cmd_tx_host_buf_size(&buf_size_cmd);
if (rc != 0) {
ble_hs_hci_cmd_tx_set_ctlr_to_host_fc(BLE_HCI_CTLR_TO_HOST_FC_OFF);
return rc;
}
/* Flow control successfully enabled. */
ble_hs_flow_num_completed_pkts = 0;
ble_hci_trans_set_acl_free_cb(ble_hs_flow_acl_free, NULL);
os_callout_init(&ble_hs_flow_timer, ble_hs_evq_get(),
ble_hs_flow_event_cb, NULL);
#endif
return 0;
}
+36
View File
@@ -0,0 +1,36 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef H_BLE_HS_FLOW_PRIV_
#define H_BLE_HS_FLOW_PRIV_
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
void ble_hs_flow_connection_broken(uint16_t conn_handle);
void ble_hs_flow_fill_acl_usrhdr(struct os_mbuf *om);
int ble_hs_flow_startup(void);
#ifdef __cplusplus
}
#endif
#endif
+46 -1
View File
@@ -66,7 +66,7 @@ ble_hs_hci_cmd_write_hdr(uint8_t ogf, uint16_t ocf, uint8_t len, void *buf)
u8ptr[2] = len;
}
int
static int
ble_hs_hci_cmd_send(uint16_t opcode, uint8_t len, const void *cmddata)
{
uint8_t *buf;
@@ -532,6 +532,51 @@ ble_hs_hci_cmd_reset(void)
0, NULL);
}
/** Set controller to host flow control (OGF 0x03, OCF 0x0031). */
int
ble_hs_hci_cmd_tx_set_ctlr_to_host_fc(uint8_t fc_enable)
{
if (fc_enable > BLE_HCI_CTLR_TO_HOST_FC_BOTH) {
return BLE_HS_EINVAL;
}
return ble_hs_hci_cmd_tx_empty_ack(
BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND,
BLE_HCI_OCF_CB_SET_CTLR_TO_HOST_FC),
&fc_enable, 1);
}
/* Host buffer size (OGF 0x03, OCF 0x0033). */
int
ble_hs_hci_cmd_tx_host_buf_size(const struct hci_host_buf_size *cmd)
{
uint8_t buf[BLE_HCI_HOST_BUF_SIZE_LEN];
put_le16(buf + 0, cmd->acl_pkt_len);
buf[2] = cmd->sync_pkt_len;
put_le16(buf + 3, cmd->num_acl_pkts);
put_le16(buf + 5, cmd->num_sync_pkts);
return ble_hs_hci_cmd_tx_empty_ack(
BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_HOST_BUF_SIZE),
buf, sizeof buf);
}
/* Host number of completed packets (OGF 0x03, OCF 0x0035). */
int
ble_hs_hci_cmd_build_host_num_comp_pkts_entry(
const struct hci_host_num_comp_pkts_entry *entry,
uint8_t *dst, int dst_len)
{
if (dst_len < BLE_HCI_HOST_NUM_COMP_PKTS_ENT_LEN) {
return BLE_HS_EMSGSIZE;
}
put_le16(dst + 0, entry->conn_handle);
put_le16(dst + 2, entry->num_pkts);
return 0;
}
/**
* Read the transmit power level used for LE advertising channel packets.
+5 -2
View File
@@ -99,8 +99,6 @@ int ble_hs_hci_evt_process(uint8_t *data);
uint16_t ble_hs_hci_util_opcode_join(uint8_t ogf, uint16_t ocf);
void ble_hs_hci_cmd_write_hdr(uint8_t ogf, uint16_t ocf, uint8_t len,
void *buf);
int ble_hs_hci_cmd_send(uint16_t opcode, uint8_t len,
const void *cmddata);
int ble_hs_hci_cmd_send_buf(uint16_t opcode, void *buf, uint8_t buf_len);
void ble_hs_hci_cmd_build_set_event_mask(uint64_t event_mask,
uint8_t *dst, int dst_len);
@@ -142,6 +140,11 @@ int ble_hs_hci_cmd_build_le_add_to_whitelist(const uint8_t *addr,
uint8_t addr_type,
uint8_t *dst, int dst_len);
int ble_hs_hci_cmd_reset(void);
int ble_hs_hci_cmd_tx_set_ctlr_to_host_fc(uint8_t fc_enable);
int ble_hs_hci_cmd_tx_host_buf_size(const struct hci_host_buf_size *cmd);
int ble_hs_hci_cmd_build_host_num_comp_pkts_entry(
const struct hci_host_num_comp_pkts_entry *entry,
uint8_t *dst, int dst_len);
int ble_hs_hci_cmd_read_adv_pwr(void);
int ble_hs_hci_cmd_le_create_conn_cancel(void);
int ble_hs_hci_cmd_build_le_conn_update(const struct hci_conn_update *hcu,
+3
View File
@@ -39,6 +39,7 @@
#include "ble_l2cap_coc_priv.h"
#include "ble_sm_priv.h"
#include "ble_hs_adv_priv.h"
#include "ble_hs_flow_priv.h"
#include "ble_hs_pvcy_priv.h"
#include "ble_hs_id_priv.h"
#include "ble_uuid_priv.h"
@@ -117,6 +118,8 @@ int ble_hs_misc_restore_irks(void);
int ble_hs_locked_by_cur_task(void);
int ble_hs_is_parent_task(void);
void ble_hs_lock_nested(void);
void ble_hs_unlock_nested(void);
void ble_hs_lock(void);
void ble_hs_unlock(void);
void ble_hs_hw_error(uint8_t hw_code);
+3
View File
@@ -280,5 +280,8 @@ ble_hs_startup_go(void)
ble_hs_pvcy_set_our_irk(NULL);
/* If flow control is enabled, configure the controller to use it. */
ble_hs_flow_startup();
return 0;
}
+29
View File
@@ -374,5 +374,34 @@ syscfg.defs:
that have been enabled in the stack, such as GATT support.
value: 0
# Flow control settings.
BLE_HS_FLOW_CTRL:
description: >
Whether to enable host-side flow control. This should only be
enabled in host-only setups (i.e., not combined-host-controller).
value: 0
BLE_HS_FLOW_CTRL_ITVL:
description: >
The interval, in milliseconds, that the host should provide
number-of-completed-packets updates to the controller.
value: 1000
BLE_HS_FLOW_CTRL_THRESH:
description: >
If the number of data buffers available to the controller falls to
this number, immediately send a number-of-completed-packets event.
The free buffer count is calculated as follows:
(total-acl-bufs - bufs-freed-since-last-num-completed-event).
value: 2
BLE_HS_FLOW_CTRL_TX_ON_DISCONNECT:
description: >
If enabled, the host will immediately transmit a
host-number-of-completed-packets command whenever a connection
terminates. This behavior is not required by the standard, but is
a necessary workaround when interfacing with some controllers.
value: 0
syscfg.vals.BLE_MESH:
BLE_SM_SC: 1
+3
View File
@@ -150,6 +150,9 @@ struct ble_mbuf_hdr
#define BLE_MBUF_MEMBLOCK_OVERHEAD \
(sizeof(struct os_mbuf) + BLE_MBUF_PKTHDR_OVERHEAD)
/* Length of host user header. Only contains the peer's connection handle. */
#define BLE_MBUF_HS_HDR_LEN (2)
#define BLE_DEV_ADDR_LEN (6)
extern uint8_t g_dev_addr[BLE_DEV_ADDR_LEN];
extern uint8_t g_random_addr[BLE_DEV_ADDR_LEN];
+15
View File
@@ -21,6 +21,8 @@
#define H_HCI_TRANSPORT_
#include <inttypes.h>
#include "os/os_mempool.h"
#ifdef __cplusplus
extern "C" {
#endif
@@ -125,6 +127,19 @@ uint8_t *ble_hci_trans_buf_alloc(int type);
*/
void ble_hci_trans_buf_free(uint8_t *buf);
/**
* Configures a callback to get executed whenever an ACL data packet is freed.
* The function is called immediately before the free occurs.
*
* @param cb The callback to configure.
* @param arg An optional argument to pass to the callback.
*
* @return 0 on success;
* BLE_ERR_UNSUPPORTED if the transport does not
* support this operation.
*/
int ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg);
/**
* Configures the HCI transport to operate with a controller. The transport
* will execute specified callbacks upon receiving HCI packets from the host.
+35
View File
@@ -70,6 +70,9 @@ extern "C" {
#define BLE_HCI_OCF_CB_SET_EVENT_MASK (0x0001)
#define BLE_HCI_OCF_CB_RESET (0x0003)
#define BLE_HCI_OCF_CB_READ_TX_PWR (0x002D)
#define BLE_HCI_OCF_CB_SET_CTLR_TO_HOST_FC (0x0031)
#define BLE_HCI_OCF_CB_HOST_BUF_SIZE (0x0033)
#define BLE_HCI_OCF_CB_HOST_NUM_COMP_PKTS (0x0035)
#define BLE_HCI_OCF_CB_SET_EVENT_MASK2 (0x0063)
#define BLE_HCI_OCF_CB_RD_AUTH_PYLD_TMO (0x007B)
#define BLE_HCI_OCF_CB_WR_AUTH_PYLD_TMO (0x007C)
@@ -173,6 +176,21 @@ extern "C" {
/* --- Set event mask (OGF 0x03, OCF 0x0001 --- */
#define BLE_HCI_SET_EVENT_MASK_LEN (8)
/* --- Set controller to host flow control (OGF 0x03, OCF 0x0031) --- */
#define BLE_HCI_CTLR_TO_HOST_FC_LEN (1)
#define BLE_HCI_CTLR_TO_HOST_FC_OFF (0)
#define BLE_HCI_CTLR_TO_HOST_FC_ACL (1)
#define BLE_HCI_CTLR_TO_HOST_FC_SYNC (2)
#define BLE_HCI_CTLR_TO_HOST_FC_BOTH (3)
/* --- Host buffer size (OGF 0x03, OCF 0x0033) --- */
#define BLE_HCI_HOST_BUF_SIZE_LEN (7)
/* --- Host number of completed packets (OGF 0x03, OCF 0x0035) --- */
#define BLE_HCI_HOST_NUM_COMP_PKTS_HDR_LEN (1)
#define BLE_HCI_HOST_NUM_COMP_PKTS_ENT_LEN (4)
/* --- Read BD_ADDR (OGF 0x04, OCF 0x0009 --- */
#define BLE_HCI_IP_RD_BD_ADDR_ACK_PARAM_LEN (6)
@@ -785,6 +803,23 @@ extern "C" {
#define BLE_HCI_LE_ENH_CONN_COMPLETE_LEN (31)
/*--- Shared data structures ---*/
/* Host buffer size (OGF=0x03, OCF=0x0033) */
struct hci_host_buf_size
{
uint16_t acl_pkt_len;
uint8_t sync_pkt_len;
uint16_t num_acl_pkts;
uint16_t num_sync_pkts;
};
/* Host number of completed packets (OGF=0x03, OCF=0x0035) */
struct hci_host_num_comp_pkts_entry
{
uint16_t conn_handle;
uint16_t num_pkts;
};
/* Read local version information (OGF=0x0004, OCF=0x0001) */
struct hci_loc_ver_info
{
+32 -15
View File
@@ -100,7 +100,7 @@ static struct os_mempool ble_hci_emspi_pkt_pool;
static void *ble_hci_emspi_pkt_buf;
static struct os_mbuf_pool ble_hci_emspi_acl_mbuf_pool;
static struct os_mempool ble_hci_emspi_acl_pool;
static struct os_mempool_ext ble_hci_emspi_acl_pool;
static void *ble_hci_emspi_acl_buf;
static void
@@ -269,15 +269,15 @@ done:
static struct os_mbuf *
ble_hci_trans_acl_buf_alloc(void)
{
struct os_mbuf *m;
uint8_t usrhdr_len;
/*
* XXX: note that for host only there would be no need to allocate
* a user header. Address this later.
*/
m = os_mbuf_get_pkthdr(&ble_hci_emspi_acl_mbuf_pool,
sizeof(struct ble_mbuf_hdr));
return m;
#if MYNEWT_VAL(BLE_HS_FLOW_CTRL)
usrhdr_len = BLE_MBUF_HS_HDR_LEN;
#else
usrhdr_len = 0;
#endif
return os_mbuf_get_pkthdr(&ble_hci_emspi_acl_mbuf_pool, usrhdr_len);
}
/**
@@ -767,6 +767,22 @@ ble_hci_trans_buf_free(uint8_t *buf)
}
}
/**
* Configures a callback to get executed whenever an ACL data packet is freed.
* The function is called in lieu of actually freeing the packet.
*
* @param cb The callback to configure.
*
* @return 0 on success.
*/
int
ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg)
{
ble_hci_emspi_acl_pool.mpe_put_cb = cb;
ble_hci_emspi_acl_pool.mpe_put_arg = arg;
return 0;
}
/**
* Resets the HCI UART transport to a clean state. Frees all buffers and
* reconfigures the UART.
@@ -865,15 +881,16 @@ ble_hci_emspi_init(void)
BLE_MBUF_MEMBLOCK_OVERHEAD +
BLE_HCI_DATA_HDR_SZ;
acl_block_size = OS_ALIGN(acl_block_size, OS_ALIGNMENT);
rc = mem_malloc_mempool(&ble_hci_emspi_acl_pool,
MYNEWT_VAL(BLE_ACL_BUF_COUNT),
acl_block_size,
"ble_hci_emspi_acl_pool",
&ble_hci_emspi_acl_buf);
rc = mem_malloc_mempool_ext(&ble_hci_emspi_acl_pool,
MYNEWT_VAL(BLE_ACL_BUF_COUNT),
acl_block_size,
"ble_hci_emspi_acl_pool",
&ble_hci_emspi_acl_buf);
SYSINIT_PANIC_ASSERT(rc == 0);
rc = os_mbuf_pool_init(&ble_hci_emspi_acl_mbuf_pool,
&ble_hci_emspi_acl_pool, acl_block_size,
&ble_hci_emspi_acl_pool.mpe_mp,
acl_block_size,
MYNEWT_VAL(BLE_ACL_BUF_COUNT));
SYSINIT_PANIC_ASSERT(rc == 0);
+10
View File
@@ -168,6 +168,16 @@ ble_hci_trans_buf_free(uint8_t *buf)
}
}
/**
* Unsupported; the RAM transport does not have a dedicated ACL data packet
* pool.
*/
int
ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg)
{
return BLE_ERR_UNSUPPORTED;
}
static void
ble_hci_ram_free_mem(void)
{
+36 -14
View File
@@ -93,7 +93,7 @@ static struct os_mempool ble_hci_uart_pkt_pool;
static void *ble_hci_uart_pkt_buf;
static struct os_mbuf_pool ble_hci_uart_acl_mbuf_pool;
static struct os_mempool ble_hci_uart_acl_pool;
static struct os_mempool_ext ble_hci_uart_acl_pool;
static void *ble_hci_uart_acl_buf;
/**
@@ -165,13 +165,17 @@ static struct os_mbuf *
ble_hci_trans_acl_buf_alloc(void)
{
struct os_mbuf *m;
uint8_t usrhdr_len;
/*
* XXX: note that for host only there would be no need to allocate
* a user header. Address this later.
*/
m = os_mbuf_get_pkthdr(&ble_hci_uart_acl_mbuf_pool,
sizeof(struct ble_mbuf_hdr));
#if MYNEWT_VAL(BLE_DEVICE)
usrhdr_len = sizeof(struct ble_mbuf_hdr);
#elif MYNEWT_VAL(BLE_HS_FLOW_CTRL)
usrhdr_len = BLE_MBUF_HS_HDR_LEN;
#else
usrhdr_len = 0;
#endif
m = os_mbuf_get_pkthdr(&ble_hci_uart_acl_mbuf_pool, usrhdr_len);
return m;
}
@@ -949,6 +953,22 @@ ble_hci_trans_buf_free(uint8_t *buf)
}
}
/**
* Configures a callback to get executed whenever an ACL data packet is freed.
* The function is called in lieu of actually freeing the packet.
*
* @param cb The callback to configure.
*
* @return 0 on success.
*/
int
ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg)
{
ble_hci_uart_acl_pool.mpe_put_cb = cb;
ble_hci_uart_acl_pool.mpe_put_arg = arg;
return 0;
}
/**
* Resets the HCI UART transport to a clean state. Frees all buffers and
* reconfigures the UART.
@@ -1020,15 +1040,17 @@ ble_hci_uart_init(void)
acl_block_size = acl_data_length + BLE_MBUF_MEMBLOCK_OVERHEAD +
BLE_HCI_DATA_HDR_SZ;
acl_block_size = OS_ALIGN(acl_block_size, OS_ALIGNMENT);
rc = mem_malloc_mempool(&ble_hci_uart_acl_pool,
MYNEWT_VAL(BLE_ACL_BUF_COUNT),
acl_block_size,
"ble_hci_uart_acl_pool",
&ble_hci_uart_acl_buf);
rc = mem_malloc_mempool_ext(&ble_hci_emspi_acl_pool,
MYNEWT_VAL(BLE_ACL_BUF_COUNT),
acl_block_size,
"ble_hci_uart_acl_pool",
&ble_hci_uart_acl_buf);
SYSINIT_PANIC_ASSERT(rc == 0);
rc = os_mbuf_pool_init(&ble_hci_uart_acl_mbuf_pool, &ble_hci_uart_acl_pool,
acl_block_size, MYNEWT_VAL(BLE_ACL_BUF_COUNT));
rc = os_mbuf_pool_init(&ble_hci_uart_acl_mbuf_pool,
&ble_hci_uart_acl_pool.mpe_mp,
acl_block_size,
MYNEWT_VAL(BLE_ACL_BUF_COUNT));
SYSINIT_PANIC_ASSERT(rc == 0);
/*