Skip to content

Commit

Permalink
Update serial example to work
Browse files Browse the repository at this point in the history
* Add embedded example using uart with flow control
* Use tokio for std example
* Update adapter to be able to process incoming packets even as outgoing
  are sent
  • Loading branch information
lulf committed Mar 20, 2024
1 parent 191299d commit 3d89126
Show file tree
Hide file tree
Showing 13 changed files with 387 additions and 313 deletions.
12 changes: 12 additions & 0 deletions examples/embedded-io-hci/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
runner = "probe-rs run --chip nRF52833_xxAA"

[build]
# Pick ONE of these compilation targets
# target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
# target = "thumbv7m-none-eabi" # Cortex-M3
# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU)
target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)

[env]
DEFMT_LOG = "info"
41 changes: 41 additions & 0 deletions examples/embedded-io-hci/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[package]
name = "serial-hci"
version = "0.1.0"
edition = "2021"

[dependencies]
embassy-executor = { version = "0.5", default-features = false, features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers", "executor-interrupt"] }
embassy-time = { version = "0.3.0", default-features = false, features = ["defmt", "defmt-timestamp-uptime"] }
embassy-nrf = { version = "0.1.0", default-features = false, features = ["defmt", "nrf52833", "time-driver-rtc1", "gpiote", "unstable-pac", "rt"] }
embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
embedded-io = { version = "0.6.1", features = ["defmt-03"] }
embassy-sync = { version = "0.5.0", features = ["defmt"] }
embassy-futures = "0.1.1"
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7.0"
static_cell = "2"
defmt = "0.3"
defmt-rtt = "0.4.0"

panic-probe = { version = "0.3", features = ["print-defmt"] }

bt-hci = { version = "0.1.0", default-features = false, features = ["defmt"] }
trouble-host = { version = "0.1.0", path = "../../host", features = ["defmt"] }

[patch.crates-io]
bt-hci = { git = "https://github.com/alexmoon/bt-hci.git", branch = "serial-controller" }
embassy-executor = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" }
embassy-time = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" }
embassy-nrf = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" }
embassy-sync = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" }
embassy-futures = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" }
#
#embassy-executor = { path = "../../../embassy/embassy-executor" }
#embassy-time = { path = "../../../embassy/embassy-time"}
#embassy-nrf = { path = "../../../embassy/embassy-nrf"}
#embassy-sync = { path = "../../../embassy/embassy-sync"}
#embassy-futures = { path = "../../../embassy/embassy-futures"}
#bt-hci = { path = "../../../bt-hci" }

[profile.release]
debug = 2
35 changes: 35 additions & 0 deletions examples/embedded-io-hci/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//! This build script copies the `memory.x` file from the crate root into
//! a directory where the linker can always find it at build time.
//! For many projects this is optional, as the linker always searches the
//! project root directory -- wherever `Cargo.toml` is. However, if you
//! are using a workspace or have a more complicated build setup, this
//! build script becomes required. Additionally, by requesting that
//! Cargo re-run the build script whenever `memory.x` is changed,
//! updating `memory.x` ensures a rebuild of the application with the
//! new memory settings.
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

fn main() {
// Put `memory.x` in our output directory and ensure it's
// on the linker search path.
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
File::create(out.join("memory.x"))
.unwrap()
.write_all(include_bytes!("memory.x"))
.unwrap();
println!("cargo:rustc-link-search={}", out.display());

// By default, Cargo will re-run a build script whenever
// any file in the project changes. By specifying `memory.x`
// here, we ensure the build script is only re-run when
// `memory.x` is changed.
println!("cargo:rerun-if-changed=memory.x");

println!("cargo:rustc-link-arg-bins=--nmagic");
println!("cargo:rustc-link-arg-bins=-Tlink.x");
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
}
7 changes: 7 additions & 0 deletions examples/embedded-io-hci/memory.x
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
MEMORY
{
/* NOTE 1 K = 1 KiBi = 1024 bytes */
/* These values correspond to the NRF52840 */
FLASH : ORIGIN = 0x00000000, LENGTH = 512K
RAM : ORIGIN = 0x20000000, LENGTH = 128K
}
132 changes: 132 additions & 0 deletions examples/embedded-io-hci/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]

use bt_hci::cmd::SyncCmd;
use bt_hci::param::BdAddr;
use bt_hci::serial::SerialController;
use defmt::{error, info, unwrap};
use embassy_executor::Spawner;
use embassy_futures::join::join3;
use embassy_nrf::peripherals;
use embassy_nrf::{bind_interrupts, pac};
use embassy_nrf::{buffered_uarte, uarte};
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
use embassy_time::{Duration, Timer};
use static_cell::StaticCell;
use trouble_host::{
adapter::{Adapter, HostResources},
advertise::{AdStructure, AdvertiseConfig, BR_EDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE},
attribute::{AttributeTable, CharacteristicProp, Service, Uuid},
PacketQos,
};

use {defmt_rtt as _, panic_probe as _};

bind_interrupts!(struct Irqs {
UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;
});

#[embassy_executor::main]
async fn main(_s: Spawner) {
let p = embassy_nrf::init(Default::default());

let uart_tx = p.P0_01;
let uart_rx = p.P0_17;
let uart_cts = p.P0_13;
let uart_rts = p.P1_02;

let mut config = uarte::Config::default();
config.parity = uarte::Parity::EXCLUDED;
config.baudrate = uarte::Baudrate::BAUD115200;

let mut tx_buffer = [0u8; 4096];
let mut rx_buffer = [0u8; 4096];

let mut u = buffered_uarte::BufferedUarte::new_with_rtscts(
p.UARTE0,
p.TIMER0,
p.PPI_CH0,
p.PPI_CH1,
p.PPI_GROUP0,
Irqs,
uart_rx,
uart_tx,
uart_cts,
uart_rts,
config,
&mut rx_buffer,
&mut tx_buffer,
);

let (reader, writer) = u.split();

let controller: SerialController<NoopRawMutex, _, _, 10> = SerialController::new(reader, writer);
static HOST_RESOURCES: StaticCell<HostResources<NoopRawMutex, 4, 32, 27>> = StaticCell::new();
let host_resources = HOST_RESOURCES.init(HostResources::new(PacketQos::None));

let adapter: Adapter<'_, NoopRawMutex, _, 2, 4, 1, 1> = Adapter::new(controller, host_resources);
let config = AdvertiseConfig {
params: None,
data: &[
AdStructure::Flags(LE_GENERAL_DISCOVERABLE | BR_EDR_NOT_SUPPORTED),
AdStructure::ServiceUuids16(&[Uuid::Uuid16([0x0f, 0x18])]),
AdStructure::CompleteLocalName("Trouble"),
],
};

let mut table: AttributeTable<'_, NoopRawMutex, 10> = AttributeTable::new();

// Generic Access Service (mandatory)
let id = b"Trouble";
let appearance = [0x80, 0x07];
let mut bat_level = [0; 1];
let handle = {
let mut svc = table.add_service(Service::new(0x1800));
let _ = svc.add_characteristic_ro(0x2a00, id);
let _ = svc.add_characteristic_ro(0x2a01, &appearance[..]);
drop(svc);

// Generic attribute service (mandatory)
table.add_service(Service::new(0x1801));

// Battery service
let mut svc = table.add_service(Service::new(0x180f));

svc.add_characteristic(
0x2a19,
&[CharacteristicProp::Read, CharacteristicProp::Notify],
&mut bat_level,
)
};

let server = adapter.gatt_server(&table);

info!("Starting advertising and GATT service");
let _ = join3(
adapter.run(),
async {
loop {
match server.next().await {
Ok(event) => {
info!("Gatt event: {:?}", event);
}
Err(e) => {
error!("Error processing GATT events: {:?}", e);
}
}
}
},
async {
let conn = adapter.advertise(&config).await.unwrap();
// Keep connection alive
let mut tick: u8 = 0;
loop {
Timer::after(Duration::from_secs(10)).await;
tick += 1;
server.notify(handle, &conn, &[tick]).await.unwrap();
}
},
)
.await;
}
19 changes: 9 additions & 10 deletions examples/serial-hci/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,22 @@ env_logger = "0.10.0"
log = "0.4"
crossterm = "0.27.0"
rand_core = { version = "0.6.4", features = ["std"] }
embassy-executor = { version = "0.5.0", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] }
embedded-io-adapters = { version = "0.6.1", features = ["futures-03"] }
# embassy-executor = { version = "0.5.0", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] }
embedded-io-adapters = { version = "0.6.1", features = ["tokio-1"] }
embedded-io-async = { version = "0.6.1" }
embassy-time = { version = "0.3.0", features = ["log", "std", ] }
embassy-sync = { version = "0.5.0", features = ["log"] }
critical-section = { version = "1.1", features = ["std"] }
embassy-futures = { version = "0.1" }
nix = "0.26.2"
async-io = "1.6.0"
static_cell = "2"
futures = { version = "0.3.17" }
tokio = { version = "1", features = ["full"] }
tokio-serial = "5.4"

bt-hci = { version = "0.1.0", default-features = false } #features = ["log"] }
trouble-host = { version = "0.1.0", path = "../../host" } #, features = ["log"] }
bt-hci = { version = "0.1.0", default-features = false, features = ["log"] }
trouble-host = { version = "0.1.0", path = "../../host", features = ["log"] }

[patch.crates-io]
bt-hci = { git = "https://github.com/alexmoon/bt-hci.git", branch = "main" }
bt-hci = { git = "https://github.com/alexmoon/bt-hci.git", branch = "serial-controller" }
embassy-sync = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" }
embassy-time = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" }
embassy-executor = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" }
#embassy-executor = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" }
#bt-hci = { path = "../../../bt-hci" }
Loading

0 comments on commit 3d89126

Please sign in to comment.