-
Notifications
You must be signed in to change notification settings - Fork 0
Idea for single core HCI optimization
Single core device implementing both host and controller part, needs to implement HCI communication originally designed for wired connection. This adds a lot of redundancy and inefficiency both in memory usage and performance.
A good place to inspect to review how the host interface the controller is the file hci_core.c
.
Some observations are:
- Despite the fact that the HCI is inherently asynchronous, most of the call are synchronous and uses
bt_hci_cmd_send_sync
- We can consider as a (typical?) example of synchronous call, the function hci_le_read_phy
static int hci_le_read_phy(struct bt_conn *conn)
{
struct bt_hci_cp_le_read_phy *cp;
struct bt_hci_rp_le_read_phy *rp;
struct net_buf *buf, *rsp;
int err;
buf = bt_hci_cmd_create(BT_HCI_OP_LE_READ_PHY, sizeof(*cp));
if (!buf) {
return -ENOBUFS;
}
cp = net_buf_add(buf, sizeof(*cp));
cp->handle = sys_cpu_to_le16(conn->handle);
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_PHY, buf, &rsp);
if (err) {
return err;
}
rp = (void *)rsp->data;
conn->le.phy.tx_phy = bt_get_phy(rp->tx_phy);
conn->le.phy.rx_phy = bt_get_phy(rp->rx_phy);
net_buf_unref(rsp);
return 0;
}
The steps performed are the following:
- call
bt_hci_cmd_create
to allocate buffer and check success - add space for parameters via
net_buf_add_mem
, if any - fill parameters taking care of endianess (weird for a single core!), if any
- call
bt_hci_cmd_send_sync
returning error and possible reply
A possible generalization of this method could be to define a controller API for each controller command as follow:
int hci_op_le_read_phy(struct bt_hci_cp_le_set_phy *cp, struct bt_hci_rp_le_set_phy *rp);
, standard naming convention to be defined.
This kind of API should be used to handle both single host+controller as well as separated host and controller.
Example of implementation for separated host and controller.
int hci_op_le_read_phy(struct bt_hci_cp_le_set_phy *cp, struct bt_hci_rp_le_set_phy *rp)
{
buf = bt_hci_cmd_create();
// copy param from cp to buf
bt_fill_cmd_params(buf, cp);
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_PHY, buf, &rsp);
bt_fill_rsp_params(buf, rp);
return rp->status; # extracted from response
}
Example of implementation for single core host and controller.
int hci_op_le_read_phy(struct bt_hci_cp_le_set_phy *cp, struct bt_hci_rp_le_set_phy *rp)
{
// Call matching API in the controller library (typically provided by SoC), after rearranging parameters ?
// If we consider Zephyr controller, the call can be as follow
return le_read_phy(cp, rp); // Indeed this is not that simple since net buf are used, need to be reviewed
}
- cp and rp parameters have dynamic allocation via net_buf, with the new proposal the caller should define them in its own stack.
- Related to previous point, how variable length params are treated ? E.g.
bt_hci_cp_host_num_completed_packets
, are always last param with zero size array[0]
? - when reply is present, is it possible to ignore it passing rsp=NULL ? Is it a useful use case ?
- list asynchronous cases by checking calls to
bt_hci_cmd_send
and define a strategy for them. - do we need to do something regarding events ?
- What about acl,iso traffic ?
- What about classic bluetooth (EDR), anything to do ?