Skip to content

Commit

Permalink
refactor: remove C from HostResources
Browse files Browse the repository at this point in the history
* Refactor API to remove C: Controller from HostResources
* Remove Clone + Copy on Stack and use it to hold the BleHost
* Remove all 'internal' lifetime of elements within channels. Guarantee
  their lifetime in types that is handed ownership of elements from
channels.
* Simplify packet pool, removing the QoS flag.

Issue #252
  • Loading branch information
lulf committed Jan 20, 2025
1 parent 0d179c7 commit 2e2e415
Show file tree
Hide file tree
Showing 24 changed files with 508 additions and 712 deletions.
8 changes: 3 additions & 5 deletions examples/apps/src/ble_advertise_multiple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,9 @@ where
let address: Address = Address::random([0xff, 0x8f, 0x1a, 0x05, 0xe4, 0xff]);
info!("Our address = {:?}", address);

let mut resources: HostResources<C, CONNECTIONS_MAX, L2CAP_CHANNELS_MAX, L2CAP_MTU> =
HostResources::new(PacketQos::None);
let (_, mut peripheral, _, mut runner) = trouble_host::new(controller, &mut resources)
.set_random_address(address)
.build();
let mut resources: HostResources<CONNECTIONS_MAX, L2CAP_CHANNELS_MAX, L2CAP_MTU> = HostResources::new();
let stack = trouble_host::new(controller, &mut resources).set_random_address(address);
let (mut peripheral, _, mut runner) = stack.build();

let mut adv_data = [0; 31];
let len = AdStructure::encode_slice(
Expand Down
10 changes: 4 additions & 6 deletions examples/apps/src/ble_bas_central.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,9 @@ where
let address: Address = Address::random([0xff, 0x8f, 0x1b, 0x05, 0xe4, 0xff]);
info!("Our address = {:?}", address);

let mut resources: HostResources<C, CONNECTIONS_MAX, L2CAP_CHANNELS_MAX, L2CAP_MTU> =
HostResources::new(PacketQos::None);
let (stack, _, mut central, mut runner) = trouble_host::new(controller, &mut resources)
.set_random_address(address)
.build();
let mut resources: HostResources<CONNECTIONS_MAX, L2CAP_CHANNELS_MAX, L2CAP_MTU> = HostResources::new();
let stack = trouble_host::new(controller, &mut resources).set_random_address(address);
let (_, mut central, mut runner) = stack.build();

// NOTE: Modify this to match the address of the peripheral you want to connect to.
// Currently it matches the address used by the peripheral examples
Expand All @@ -42,7 +40,7 @@ where
let conn = central.connect(&config).await.unwrap();
info!("Connected, creating gatt client");

let client = GattClient::<C, 10, 24>::new(stack, &conn).await.unwrap();
let client = GattClient::<C, 10, 24>::new(&stack, &conn).await.unwrap();

let _ = join(client.task(), async {
info!("Looking for battery service");
Expand Down
12 changes: 5 additions & 7 deletions examples/apps/src/ble_bas_peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,9 @@ where
let address: Address = Address::random([0xff, 0x8f, 0x1a, 0x05, 0xe4, 0xff]);
info!("Our address = {:?}", address);

let mut resources: HostResources<C, CONNECTIONS_MAX, L2CAP_CHANNELS_MAX, L2CAP_MTU> =
HostResources::new(PacketQos::None);
let (stack, mut peripheral, _, runner) = trouble_host::new(controller, &mut resources)
.set_random_address(address)
.build();
let mut resources: HostResources<CONNECTIONS_MAX, L2CAP_CHANNELS_MAX, L2CAP_MTU> = HostResources::new();
let stack = trouble_host::new(controller, &mut resources).set_random_address(address);
let (mut peripheral, _, runner) = stack.build();

info!("Starting advertising and GATT service");
let server = Server::new_with_config(GapConfig::Peripheral(PeripheralConfig {
Expand All @@ -57,7 +55,7 @@ where
Ok(conn) => {
// set up tasks when the connection is established to a central, so they don't run when no one is connected.
let a = gatt_events_task(&server, &conn);
let b = custom_task(&server, &conn, stack);
let b = custom_task(&server, &conn, &stack);
// run until any task ends (usually because the connection has been closed),
// then return to advertising state.
select(a, b).await;
Expand Down Expand Up @@ -176,7 +174,7 @@ async fn advertise<'a, C: Controller>(
/// This task will notify the connected central of a counter value every 2 seconds.
/// It will also read the RSSI value every 2 seconds.
/// and will stop when the connection is closed by the central or an error occurs.
async fn custom_task<C: Controller>(server: &Server<'_>, conn: &Connection<'_>, stack: Stack<'_, C>) {
async fn custom_task<C: Controller>(server: &Server<'_>, conn: &Connection<'_>, stack: &Stack<'_, C>) {
let mut tick: u8 = 0;
let level = server.battery_service.level;
loop {
Expand Down
15 changes: 6 additions & 9 deletions examples/apps/src/ble_l2cap_central.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,9 @@ where
let address: Address = Address::random([0xff, 0x8f, 0x1b, 0x05, 0xe4, 0xff]);
info!("Our address = {:?}", address);

let mut resources: HostResources<C, CONNECTIONS_MAX, L2CAP_CHANNELS_MAX, L2CAP_MTU> =
HostResources::new(PacketQos::None);

let (stack, _, mut central, mut runner) = trouble_host::new(controller, &mut resources)
.set_random_address(address)
.build();
let mut resources: HostResources<CONNECTIONS_MAX, L2CAP_CHANNELS_MAX, L2CAP_MTU> = HostResources::new();
let stack = trouble_host::new(controller, &mut resources).set_random_address(address);
let (_, mut central, mut runner) = stack.build();

// NOTE: Modify this to match the address of the peripheral you want to connect to.
// Currently it matches the address used by the peripheral examples
Expand All @@ -42,18 +39,18 @@ where
let conn = central.connect(&config).await.unwrap();
info!("Connected, creating l2cap channel");
const PAYLOAD_LEN: usize = 27;
let mut ch1 = L2capChannel::create(stack, &conn, 0x2349, &Default::default())
let mut ch1 = L2capChannel::create(&stack, &conn, 0x2349, &Default::default())
.await
.unwrap();
info!("New l2cap channel created, sending some data!");
for i in 0..10 {
let tx = [i; PAYLOAD_LEN];
ch1.send::<_, PAYLOAD_LEN>(stack, &tx).await.unwrap();
ch1.send::<_, PAYLOAD_LEN>(&stack, &tx).await.unwrap();
}
info!("Sent data, waiting for them to be sent back");
let mut rx = [0; PAYLOAD_LEN];
for i in 0..10 {
let len = ch1.receive(stack, &mut rx).await.unwrap();
let len = ch1.receive(&stack, &mut rx).await.unwrap();
assert_eq!(len, rx.len());
assert_eq!(rx, [i; PAYLOAD_LEN]);
}
Expand Down
15 changes: 6 additions & 9 deletions examples/apps/src/ble_l2cap_peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,13 @@ pub async fn run<C, const L2CAP_MTU: usize>(controller: C)
where
C: Controller,
{
let mut resources: HostResources<C, CONNECTIONS_MAX, L2CAP_CHANNELS_MAX, L2CAP_MTU> =
HostResources::new(PacketQos::None);

// Hardcoded peripheral address
let address: Address = Address::random([0xff, 0x8f, 0x1a, 0x05, 0xe4, 0xff]);
info!("Our address = {:?}", address);

let (stack, mut peripheral, _, mut runner) = trouble_host::new(controller, &mut resources)
.set_random_address(address)
.build();
let mut resources: HostResources<CONNECTIONS_MAX, L2CAP_CHANNELS_MAX, L2CAP_MTU> = HostResources::new();
let stack = trouble_host::new(controller, &mut resources).set_random_address(address);
let (mut peripheral, _, mut runner) = stack.build();

let mut adv_data = [0; 31];
AdStructure::encode_slice(
Expand Down Expand Up @@ -50,7 +47,7 @@ where

info!("Connection established");

let mut ch1 = L2capChannel::accept(stack, &conn, &[0x2349], &Default::default())
let mut ch1 = L2capChannel::accept(&stack, &conn, &[0x2349], &Default::default())
.await
.unwrap();

Expand All @@ -60,7 +57,7 @@ where
const PAYLOAD_LEN: usize = 27;
let mut rx = [0; PAYLOAD_LEN];
for i in 0..10 {
let len = ch1.receive(stack, &mut rx).await.unwrap();
let len = ch1.receive(&stack, &mut rx).await.unwrap();
assert_eq!(len, rx.len());
assert_eq!(rx, [i; PAYLOAD_LEN]);
}
Expand All @@ -69,7 +66,7 @@ where
Timer::after(Duration::from_secs(1)).await;
for i in 0..10 {
let tx = [i; PAYLOAD_LEN];
ch1.send::<_, PAYLOAD_LEN>(stack, &tx).await.unwrap();
ch1.send::<_, PAYLOAD_LEN>(&stack, &tx).await.unwrap();
}
info!("L2CAP data echoed");

Expand Down
13 changes: 6 additions & 7 deletions examples/tests/tests/ble_l2cap_central.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,9 @@ async fn run_l2cap_central_test(labels: &[(&str, &str)], firmware: &str) {
let peripheral = tokio::task::spawn_local(async move {
let controller_peripheral = serial::create_controller(&peripheral).await;

let mut resources: HostResources<serial::Controller, 2, 4, 27> = HostResources::new(PacketQos::None);
let (stack, mut peripheral, _central, mut runner) = trouble_host::new(controller_peripheral, &mut resources)
.set_random_address(peripheral_address)
.build();
let mut resources: HostResources<2, 4, 27> = HostResources::new();
let stack = trouble_host::new(controller_peripheral, &mut resources).set_random_address(peripheral_address);
let (mut peripheral, _central, mut runner) = stack.build();

select! {
r = runner.run() => {
Expand Down Expand Up @@ -79,23 +78,23 @@ async fn run_l2cap_central_test(labels: &[(&str, &str)], firmware: &str) {
let conn = acceptor.accept().await?;
println!("[peripheral] connected");

let mut ch1 = L2capChannel::accept(stack, &conn, &[0x2349], &Default::default()).await?;
let mut ch1 = L2capChannel::accept(&stack, &conn, &[0x2349], &Default::default()).await?;

println!("[peripheral] channel created");

const PAYLOAD_LEN: usize = 27;
// Size of payload we're expecting
let mut rx = [0; PAYLOAD_LEN];
for i in 0..10 {
let len = ch1.receive(stack, &mut rx).await?;
let len = ch1.receive(&stack, &mut rx).await?;
assert_eq!(len, rx.len());
assert_eq!(rx, [i; PAYLOAD_LEN]);
}
println!("[peripheral] data received");

for i in 0..10 {
let tx = [i; PAYLOAD_LEN];
ch1.send::<_, PAYLOAD_LEN>(stack, &tx).await?;
ch1.send::<_, PAYLOAD_LEN>(&stack, &tx).await?;
}
println!("[peripheral] data sent");
token.cancel();
Expand Down
12 changes: 6 additions & 6 deletions examples/tests/tests/ble_l2cap_peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ async fn run_l2cap_peripheral_test(labels: &[(&str, &str)], firmware: &str) {
let peripheral_address: Address = Address::random([0xff, 0x8f, 0x1a, 0x05, 0xe4, 0xff]);
let central = tokio::task::spawn_local(async move {
let controller_central = serial::create_controller(&central).await;
let mut resources: HostResources<serial::Controller, 2, 4, 27> = HostResources::new(PacketQos::None);
let (stack, _peripheral, mut central, mut runner) =
trouble_host::new(controller_central, &mut resources).build();
let mut resources: HostResources<2, 4, 27> = HostResources::new();
let stack = trouble_host::new(controller_central, &mut resources);
let (_peripheral, mut central, mut runner) = stack.build();
select! {
r = runner.run() => {
r
Expand All @@ -67,16 +67,16 @@ async fn run_l2cap_peripheral_test(labels: &[(&str, &str)], firmware: &str) {
let conn = central.connect(&config).await.unwrap();
log::info!("[central] connected");
const PAYLOAD_LEN: usize = 27;
let mut ch1 = L2capChannel::create(stack, &conn, 0x2349, &Default::default()).await?;
let mut ch1 = L2capChannel::create(&stack, &conn, 0x2349, &Default::default()).await?;
log::info!("[central] channel created");
for i in 0..10 {
let tx = [i; PAYLOAD_LEN];
ch1.send::<_, PAYLOAD_LEN>(stack, &tx).await?;
ch1.send::<_, PAYLOAD_LEN>(&stack, &tx).await?;
}
log::info!("[central] data sent");
let mut rx = [0; PAYLOAD_LEN];
for i in 0..10 {
let len = ch1.receive(stack, &mut rx).await?;
let len = ch1.receive(&stack, &mut rx).await?;
assert_eq!(len, rx.len());
assert_eq!(rx, [i; PAYLOAD_LEN]);
}
Expand Down
74 changes: 13 additions & 61 deletions host/src/central.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
//! Functionality for the BLE central role.
use crate::connection::{ConnectConfig, Connection};
use crate::connection::{ConnectConfig, Connection, PhySet};
use crate::{BleHostError, Error, Stack};
use bt_hci::cmd::le::{LeAddDeviceToFilterAcceptList, LeClearFilterAcceptList, LeCreateConn, LeExtCreateConn};
use bt_hci::controller::{Controller, ControllerCmdAsync, ControllerCmdSync};
use bt_hci::param::{AddrKind, BdAddr, InitiatingPhy, LeConnRole, PhyParams};
#[cfg(feature = "controller-host-flow-control")]
use bt_hci::param::{ConnHandleCompletedPackets, ControllerToHostFlowControl};
use embassy_futures::select::{select, Either};
use embassy_time::Duration;

/// A type implementing the BLE central role.
pub struct Central<'d, C: Controller> {
pub(crate) stack: Stack<'d, C>,
pub struct Central<'stack, C: Controller> {
pub(crate) stack: &'stack Stack<'stack, C>,
}

impl<'d, C: Controller> Central<'d, C> {
pub(crate) fn new(stack: Stack<'d, C>) -> Self {
impl<'stack, C: Controller> Central<'stack, C> {
pub(crate) fn new(stack: &'stack Stack<'stack, C>) -> Self {
Self { stack }
}

/// Attempt to create a connection with the provided config.
pub async fn connect(&mut self, config: &ConnectConfig<'_>) -> Result<Connection<'d>, BleHostError<C::Error>>
pub async fn connect(&mut self, config: &ConnectConfig<'_>) -> Result<Connection<'stack>, BleHostError<C::Error>>
where
C: ControllerCmdSync<LeClearFilterAcceptList>
+ ControllerCmdSync<LeAddDeviceToFilterAcceptList>
Expand All @@ -30,7 +29,7 @@ impl<'d, C: Controller> Central<'d, C> {
return Err(Error::InvalidValue.into());
}

let host = self.stack.host;
let host = &self.stack.host;
let _drop = crate::host::OnDrop::new(|| {
host.connect_command_state.cancel(true);
});
Expand Down Expand Up @@ -70,7 +69,10 @@ impl<'d, C: Controller> Central<'d, C> {
}

/// Attempt to create a connection with the provided config.
pub async fn connect_ext(&mut self, config: &ConnectConfig<'_>) -> Result<Connection<'d>, BleHostError<C::Error>>
pub async fn connect_ext(
&mut self,
config: &ConnectConfig<'_>,
) -> Result<Connection<'stack>, BleHostError<C::Error>>
where
C: ControllerCmdSync<LeClearFilterAcceptList>
+ ControllerCmdSync<LeAddDeviceToFilterAcceptList>
Expand All @@ -80,7 +82,7 @@ impl<'d, C: Controller> Central<'d, C> {
return Err(Error::InvalidValue.into());
}

let host = self.stack.host;
let host = &self.stack.host;
// Ensure no other connect ongoing.
let _drop = crate::host::OnDrop::new(|| {
host.connect_command_state.cancel(true);
Expand Down Expand Up @@ -133,7 +135,7 @@ impl<'d, C: Controller> Central<'d, C> {
where
C: ControllerCmdSync<LeClearFilterAcceptList> + ControllerCmdSync<LeAddDeviceToFilterAcceptList>,
{
let host = self.stack.host;
let host = &self.stack.host;
host.command(LeClearFilterAcceptList::new()).await?;
for entry in filter_accept_list {
host.command(LeAddDeviceToFilterAcceptList::new(entry.0, *entry.1))
Expand All @@ -160,53 +162,3 @@ pub(crate) fn create_phy_params<P: Copy>(phy: P, phys: PhySet) -> PhyParams<P> {
};
phy_params
}

/// Scanner configuration.
pub struct ScanConfig<'d> {
/// Active scanning.
pub active: bool,
/// List of addresses to accept.
pub filter_accept_list: &'d [(AddrKind, &'d BdAddr)],
/// PHYs to scan on.
pub phys: PhySet,
/// Scan interval.
pub interval: Duration,
/// Scan window.
pub window: Duration,
/// Scan timeout.
pub timeout: Duration,
}

impl Default for ScanConfig<'_> {
fn default() -> Self {
Self {
active: true,
filter_accept_list: &[],
phys: PhySet::M1,
interval: Duration::from_secs(1),
window: Duration::from_secs(1),
timeout: Duration::from_secs(0),
}
}
}

/// PHYs to scan on.
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Eq, PartialEq, Copy, Clone)]
#[repr(u8)]
pub enum PhySet {
/// 1Mbps phy
M1 = 1,
/// 2Mbps phy
M2 = 2,
/// 1Mbps + 2Mbps phys
M1M2 = 3,
/// Coded phy (125kbps, S=8)
Coded = 4,
/// 1Mbps and Coded phys
M1Coded = 5,
/// 2Mbps and Coded phys
M2Coded = 6,
/// 1Mbps, 2Mbps and Coded phys
M1M2Coded = 7,
}
Loading

0 comments on commit 2e2e415

Please sign in to comment.