Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Firmware] Implement BLE on esp32 #201

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions firmware/Cargo.lock

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

62 changes: 9 additions & 53 deletions firmware/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,7 @@ rust-version.workspace = true


[features]
default = [
"mcu-esp32c3",
"imu-stubbed",
"log-rtt",
"net-wifi",
"fusion-stubbed",
]
default = ["mcu-esp32c3", "imu-stubbed", "log-rtt", "net-ble", "fusion-stubbed"]
# default = [
# "mcu-nrf52840",
# "imu-stubbed",
Expand All @@ -32,35 +26,10 @@ default = [
# default = ["mcu-esp32", "imu-stubbed", "log-uart", "net-stubbed", "fusion-stubbed"]

# Supported microcontrollers
mcu-esp32 = [
"_mcu-f-esp32",
"dep:esp32-hal",
"defmt_esp_println/esp32",
"esp-backtrace/esp32",
"xtensa-lx/esp32",
"esp-wifi/esp32",
]
mcu-esp32c3 = [
"_mcu-f-esp32",
"dep:esp32c3-hal",
"defmt_esp_println/esp32c3",
"esp-backtrace/esp32c3",
"dep:riscv",
"esp-wifi/esp32c3",
]
mcu-nrf52840 = [
"_mcu-f-nrf52",
"embassy-nrf/nrf52840",
"dep:embassy-usb",
"nrf-softdevice/nrf52840",
"dep:nrf52840-pac",
]
mcu-nrf52832 = [
"_mcu-f-nrf52",
"embassy-nrf/nrf52832",
"nrf-softdevice/nrf52832",
"dep:nrf52832-pac",
]
mcu-esp32 = ["_mcu-f-esp32", "dep:esp32-hal", "defmt_esp_println/esp32", "esp-backtrace/esp32", "xtensa-lx/esp32", "esp-wifi/esp32"]
mcu-esp32c3 = ["_mcu-f-esp32", "dep:esp32c3-hal", "defmt_esp_println/esp32c3", "esp-backtrace/esp32c3", "dep:riscv", "esp-wifi/esp32c3"]
mcu-nrf52840 = ["_mcu-f-nrf52", "embassy-nrf/nrf52840", "dep:embassy-usb", "nrf-softdevice/nrf52840", "dep:nrf52840-pac"]
mcu-nrf52832 = ["_mcu-f-nrf52", "embassy-nrf/nrf52832", "nrf-softdevice/nrf52832", "dep:nrf52832-pac"]

# Wi-fi dependencies
net-wifi = ["esp-wifi?/wifi"] # use wifi
Expand Down Expand Up @@ -93,23 +62,9 @@ nrf-boot-s140 = ["nrf-softdevice/s140"] # use softdevice 140
# All features with underscores are internal only, should not be used by other crates,
# and are not covered under semver guarantees.
# nrf52 family
_mcu-f-nrf52 = [
"dep:cortex-m",
"dep:cortex-m-rt",
"dep:alloc-cortex-m",
"embassy-nrf/time-driver-rtc1",
"embassy-executor/integrated-timers",
"dep:defmt-bbq",
]

_mcu-f-esp32 = [
"dep:esp-alloc",
"dep:embedded-svc",
"dep:embassy-net",
"dep:smoltcp",
"dep:bleps",
"dep:bleps-macros",
]
_mcu-f-nrf52 = ["dep:cortex-m", "dep:cortex-m-rt", "dep:alloc-cortex-m", "embassy-nrf/time-driver-rtc1", "embassy-executor/integrated-timers", "dep:defmt-bbq"]

_mcu-f-esp32 = ["dep:esp-alloc", "dep:embedded-svc", "dep:embassy-net", "dep:smoltcp", "dep:bleps", "dep:bleps-macros"]

[dependencies]
# mcu-esp32 stuff
Expand Down Expand Up @@ -219,6 +174,7 @@ firmware_protocol = { path = "../networking/firmware_protocol", features = [
] }
paste = "1.0"
load-dotenv = "0.1"
heapless = { version = "0.7", default-features = false }

[build-dependencies]
feature_utils = "0.0.0"
Expand Down
99 changes: 65 additions & 34 deletions firmware/src/networking/ble/esp.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use core::num::Wrapping;

use bleps::{
ad_structure::{
create_advertising_data, AdStructure, BR_EDR_NOT_SUPPORTED,
Expand All @@ -6,14 +8,15 @@ use bleps::{
attribute_server::AttributeServer,
Ble, HciConnector,
};
use defmt::{debug, error, trace, warn};
use defmt::{debug, error, warn};
use embassy_futures::yield_now;
use esp_wifi::{self, ble::controller::BleConnector, current_millis};
use firmware_protocol::{CbPacket, Packet, SbPacket};

use crate::aliases::ඞ::NetConcrete;
use crate::networking::Packets;

pub async fn network_task(_packets: &Packets, _net: NetConcrete) -> ! {
pub async fn network_task(packets: &Packets, _net: NetConcrete) -> ! {
// HCI is the host-controller interface, which lets the MCU communicate to the BLE hardware through a standard
// command interface
let connector = BleConnector {};
Expand All @@ -39,49 +42,77 @@ pub async fn network_task(_packets: &Packets, _net: NetConcrete) -> ! {
ble.cmd_set_le_advertise_enable(true)
.expect("Failed to start advertising");

let mut rf = || &b"Hello Bare-Metal BLE"[..];
let mut wf = |offset: u16, data: &[u8]| {
trace!("RECEIVED: {} {=[u8]:a}", offset, data);
let mut sb_packet: Option<Packet<SbPacket>> = None;
let mut cb_packet: Option<Packet<CbPacket>> = None;
let mut sb_buf = [0; 512];

let mut sb_callback = || {
if let Some(packet) = sb_packet {
let nbytes = packet.serialize_into(&mut sb_buf).unwrap();
let data = &sb_buf[..nbytes];

debug!("SEND: {=[u8]}", data);
sb_packet = None;
data
} else {
warn!("Data wasn't ready when we did work.");
&[]
}
};
let mut cb_callback = |offset: u16, data: &[u8]| {
debug!("RECV: {} {=[u8]}", offset, data);

// let mut wf2 = |offset: u16, data: &[u8]| {
// trace!("RECEIVED: {} {=[u8]:a}", offset, data);
// };
//
// let mut rf3 = || &b"Hola!"[..];
// let mut wf3 = |offset: u16, data: &[u8]| {
// trace!("RECEIVED: Offset {}, data {=[u8]:a}", offset, data);
// };
if cb_packet.is_some() {
panic!("This shouldn't have been possible!::<Packet> We are about to drop data.");
}

use bleps_macros::gatt;
let Ok(packet) = Packet::deserialize_from(data) else {
warn!("Discarding bogus packet");
return;
};
cb_packet = Some(packet);
};

gatt!([service {
bleps_macros::gatt!([service {
uuid: "133712e0-2354-11eb-9f10-fbc30a62cf38",
characteristics: [
characteristic {
uuid: "13370000-2354-11eb-9f10-fbc30a62cf38",
read: rf,
write: wf,
},
// characteristic {
// uuid: "13371111-2354-11eb-9f10-fbc30a62cf38",
// write: wf2,
// },
// characteristic {
// name: "my_characteristic",
// uuid: "13372222-2354-11eb-9f10-fbc30a62cf38",
// notify: true,
// read: rf3,
// write: wf3,
// },
],
characteristics: [characteristic {
uuid: "13370000-2354-11eb-9f10-fbc30a62cf38",
read: sb_callback,
write: cb_callback,
},],
},]);

let mut srv = AttributeServer::new(&mut ble, &mut gatt_attributes);

let mut tx_seq = 0;
let mut rx_seq = 0;
debug!("Starting BLE loop");
loop {
yield_now().await;
// First we *must* handle any clientbound data, BEFORE doing work. Otherwise we may
// experience data loss.
if let Some(packet) = cb_packet {
let (rx_seq_new, packet) = packet.split();
if rx_seq_new <= rx_seq {
warn!(
"Out of order packet received: {}, we are at {} ({})",
rx_seq_new,
rx_seq,
defmt::Debug2Format(&packet)
);
} else {
packets.clientbound.send(packet).await;
rx_seq = rx_seq_new;
}
cb_packet = None;
}

// Next, we load up the next packet.
// TODO: Switch to debug assert or remove.
assert!(sb_packet.is_none(), "This shouldn't be possible");
sb_packet = Some(Packet::new(tx_seq, packets.serverbound.recv().await));
tx_seq += 1;

// Next, we will retrieve the next data to send the server.
use bleps::attribute_server::WorkResult;
match srv.do_work() {
Ok(WorkResult::DidWork) => {}
Expand Down