Skip to content

Commit

Permalink
feat: add scanner example
Browse files Browse the repository at this point in the history
* Refactor scanner again to avoid buffer copies
* Add ble scanner example
  • Loading branch information
lulf committed Jan 27, 2025
1 parent f73481f commit 88a1303
Show file tree
Hide file tree
Showing 13 changed files with 186 additions and 327 deletions.
3 changes: 2 additions & 1 deletion examples/apps/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ edition = "2021"
license = "MIT OR Apache-2.0"

[dependencies]
trouble-host = { path = "../../host", features = ["derive"] }
trouble-host = { path = "../../host", features = ["derive", "scan"] }
bt-hci = { version = "0.2" }
embassy-executor = { version = "0.7.0" }
embassy-futures = "0.1.1"
Expand All @@ -14,6 +14,7 @@ embassy-time = "0.4"
embedded-hal = "1.0"
static_cell = "2"
embedded-io = "0.6"
heapless = "0.8"

defmt = { version = "0.3", optional = true }
log = { version = "0.4", optional = true }
Expand Down
5 changes: 3 additions & 2 deletions examples/apps/src/ble_bas_peripheral.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use embassy_futures::{join::join, select::select};
use embassy_futures::join::join;
use embassy_futures::select::select;
use embassy_time::Timer;
use trouble_host::prelude::*;

Expand Down Expand Up @@ -77,7 +78,7 @@ where
///
/// If you didn't require this to be generic for your application, you could statically spawn this with i.e.
///
/// ```rust [ignore]
/// ```rust,ignore
///
/// #[embassy_executor::task]
/// async fn ble_task(mut runner: Runner<'static, SoftdeviceController<'static>>) {
Expand Down
65 changes: 65 additions & 0 deletions examples/apps/src/ble_scanner.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use bt_hci::cmd::le::LeSetScanParams;
use bt_hci::controller::ControllerCmdSync;
use core::cell::RefCell;
use embassy_futures::join::join;
use embassy_time::{Duration, Timer};
use heapless::Deque;
use trouble_host::prelude::*;

/// Max number of connections
const CONNECTIONS_MAX: usize = 1;
const L2CAP_CHANNELS_MAX: usize = 1;
const L2CAP_MTU: usize = 27;

pub async fn run<C>(controller: C)
where
C: Controller + ControllerCmdSync<LeSetScanParams>,
{
// Using a fixed "random" address can be useful for testing. In real scenarios, one would
// use e.g. the MAC 6 byte array as the address (how to get that varies by the platform).
let address: Address = Address::random([0xff, 0x8f, 0x1b, 0x05, 0xe4, 0xff]);

info!("Our address = {:?}", address);
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 Host {
central, mut runner, ..
} = stack.build();

let printer = Printer {
seen: RefCell::new(Deque::new()),
};
let mut scanner = Scanner::new(central);
let _ = join(runner.run_with_handler(&printer), async {
let mut config = ScanConfig::default();
config.active = true;
config.phys = PhySet::M1;
config.interval = Duration::from_secs(1);
config.window = Duration::from_secs(1);
let mut _session = scanner.scan(&config).await.unwrap();
// Scan forever
loop {
Timer::after(Duration::from_secs(1)).await;
}
})
.await;
}

struct Printer {
seen: RefCell<Deque<BdAddr, 128>>,
}

impl EventHandler for Printer {
fn on_adv_reports(&self, mut it: LeAdvReportsIter<'_>) {
let mut seen = self.seen.borrow_mut();
while let Some(Ok(report)) = it.next() {
if seen.iter().find(|b| b.raw() == report.addr.raw()).is_none() {
info!("discovered: {:?}", report.addr);
if seen.is_full() {
seen.pop_front();
}
seen.push_back(report.addr).unwrap();
}
}
}
}
1 change: 1 addition & 0 deletions examples/apps/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ pub mod ble_bas_central;
pub mod ble_bas_peripheral;
pub mod ble_l2cap_central;
pub mod ble_l2cap_peripheral;
pub mod ble_scanner;
43 changes: 1 addition & 42 deletions examples/esp32/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion examples/nrf-sdc/.cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ runner = "probe-rs run --chip nRF52840_xxAA"
target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)

[env]
DEFMT_LOG = "trace"
DEFMT_LOG = "trouble_host=trace,info"
23 changes: 1 addition & 22 deletions examples/nrf-sdc/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

72 changes: 72 additions & 0 deletions examples/nrf-sdc/src/bin/ble_scanner.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#![no_std]
#![no_main]

use defmt::unwrap;
use embassy_executor::Spawner;
use embassy_nrf::peripherals::RNG;
use embassy_nrf::{bind_interrupts, rng};
use embassy_time::{Duration, Timer};
use nrf_sdc::mpsl::MultiprotocolServiceLayer;
use nrf_sdc::{self as sdc, mpsl};
use static_cell::StaticCell;
use trouble_example_apps::ble_scanner;
use {defmt_rtt as _, panic_probe as _};

bind_interrupts!(struct Irqs {
RNG => rng::InterruptHandler<RNG>;
EGU0_SWI0 => nrf_sdc::mpsl::LowPrioInterruptHandler;
CLOCK_POWER => nrf_sdc::mpsl::ClockInterruptHandler;
RADIO => nrf_sdc::mpsl::HighPrioInterruptHandler;
TIMER0 => nrf_sdc::mpsl::HighPrioInterruptHandler;
RTC0 => nrf_sdc::mpsl::HighPrioInterruptHandler;
});

#[embassy_executor::task]
async fn mpsl_task(mpsl: &'static MultiprotocolServiceLayer<'static>) -> ! {
mpsl.run().await
}

fn build_sdc<'d, const N: usize>(
p: nrf_sdc::Peripherals<'d>,
rng: &'d mut rng::Rng<RNG>,
mpsl: &'d MultiprotocolServiceLayer,
mem: &'d mut sdc::Mem<N>,
) -> Result<nrf_sdc::SoftdeviceController<'d>, nrf_sdc::Error> {
sdc::Builder::new()?
.support_scan()?
.support_ext_scan()?
.support_central()?
.support_ext_central()?
.central_count(1)?
.build(p, rng, mpsl, mem)
}

#[embassy_executor::main]
async fn main(spawner: Spawner) {
let p = embassy_nrf::init(Default::default());
let mpsl_p = mpsl::Peripherals::new(p.RTC0, p.TIMER0, p.TEMP, p.PPI_CH19, p.PPI_CH30, p.PPI_CH31);
let lfclk_cfg = mpsl::raw::mpsl_clock_lfclk_cfg_t {
source: mpsl::raw::MPSL_CLOCK_LF_SRC_RC as u8,
rc_ctiv: mpsl::raw::MPSL_RECOMMENDED_RC_CTIV as u8,
rc_temp_ctiv: mpsl::raw::MPSL_RECOMMENDED_RC_TEMP_CTIV as u8,
accuracy_ppm: mpsl::raw::MPSL_DEFAULT_CLOCK_ACCURACY_PPM as u16,
skip_wait_lfclk_started: mpsl::raw::MPSL_DEFAULT_SKIP_WAIT_LFCLK_STARTED != 0,
};
static MPSL: StaticCell<MultiprotocolServiceLayer> = StaticCell::new();
let mpsl = MPSL.init(unwrap!(mpsl::MultiprotocolServiceLayer::new(mpsl_p, Irqs, lfclk_cfg)));
spawner.must_spawn(mpsl_task(&*mpsl));

let sdc_p = sdc::Peripherals::new(
p.PPI_CH17, p.PPI_CH18, p.PPI_CH20, p.PPI_CH21, p.PPI_CH22, p.PPI_CH23, p.PPI_CH24, p.PPI_CH25, p.PPI_CH26,
p.PPI_CH27, p.PPI_CH28, p.PPI_CH29,
);

let mut rng = rng::Rng::new(p.RNG, Irqs);

let mut sdc_mem = sdc::Mem::<2712>::new();
let sdc = unwrap!(build_sdc(sdc_p, &mut rng, mpsl, &mut sdc_mem));

Timer::after(Duration::from_millis(200)).await;

ble_scanner::run(sdc).await;
}
29 changes: 4 additions & 25 deletions examples/rp-pico-w/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 88a1303

Please sign in to comment.