mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-27 12:20:56 +00:00

* Start scheduler on preempt init, remove deinit * Static-allocate the main task context * taskless idle * Remove the need for an idle task
224 lines
6.5 KiB
Rust
224 lines
6.5 KiB
Rust
//! WiFi and BLE COEXistence example
|
|
//!
|
|
//! - set SSID and PASSWORD env variable
|
|
//! - gets an ip address via DHCP
|
|
//! - performs an HTTP get request to some "random" server
|
|
//! - does BLE advertising (you cannot connect to it - it's just not implemented in the example)
|
|
//!
|
|
//! Note: On ESP32-C2 and ESP32-C3 you need a wifi-heap size of 70000, on
|
|
//! ESP32-C6 you need 80000 and a tx_queue_size of 10
|
|
|
|
#![no_std]
|
|
#![no_main]
|
|
|
|
use core::net::Ipv4Addr;
|
|
|
|
use bleps::{
|
|
Ble,
|
|
HciConnector,
|
|
ad_structure::{
|
|
AdStructure,
|
|
BR_EDR_NOT_SUPPORTED,
|
|
LE_GENERAL_DISCOVERABLE,
|
|
create_advertising_data,
|
|
},
|
|
att::Uuid,
|
|
};
|
|
use blocking_network_stack::Stack;
|
|
use embedded_io::*;
|
|
use esp_alloc as _;
|
|
use esp_backtrace as _;
|
|
use esp_hal::{
|
|
clock::CpuClock,
|
|
main,
|
|
rng::Rng,
|
|
time::{self, Duration},
|
|
timer::timg::TimerGroup,
|
|
};
|
|
use esp_println::{print, println};
|
|
use esp_radio::{
|
|
ble::controller::BleConnector,
|
|
wifi::{ClientConfig, Config},
|
|
};
|
|
use smoltcp::{
|
|
iface::{SocketSet, SocketStorage},
|
|
wire::{DhcpOption, IpAddress},
|
|
};
|
|
|
|
esp_bootloader_esp_idf::esp_app_desc!();
|
|
|
|
const SSID: &str = env!("SSID");
|
|
const PASSWORD: &str = env!("PASSWORD");
|
|
|
|
#[main]
|
|
fn main() -> ! {
|
|
esp_println::logger::init_logger_from_env();
|
|
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
|
|
let peripherals = esp_hal::init(config);
|
|
|
|
// COEX needs more RAM - add some more
|
|
#[cfg(feature = "esp32")]
|
|
{
|
|
esp_alloc::heap_allocator!(#[unsafe(link_section = ".dram2_uninit")] size: 96 * 1024);
|
|
esp_alloc::heap_allocator!(size: 24 * 1024);
|
|
}
|
|
#[cfg(not(feature = "esp32"))]
|
|
{
|
|
esp_alloc::heap_allocator!(#[unsafe(link_section = ".dram2_uninit")] size: 64 * 1024);
|
|
esp_alloc::heap_allocator!(size: 64 * 1024);
|
|
}
|
|
|
|
let timg0 = TimerGroup::new(peripherals.TIMG0);
|
|
esp_preempt::start(timg0.timer0);
|
|
|
|
let esp_radio_ctrl = esp_radio::init().unwrap();
|
|
|
|
let now = || time::Instant::now().duration_since_epoch().as_millis();
|
|
|
|
// initializing Bluetooth first results in a more stable WiFi connection on
|
|
// ESP32
|
|
let connector = BleConnector::new(&esp_radio_ctrl, peripherals.BT);
|
|
let hci = HciConnector::new(connector, now);
|
|
let mut ble = Ble::new(&hci);
|
|
|
|
println!("{:?}", ble.init());
|
|
println!("{:?}", ble.cmd_set_le_advertising_parameters());
|
|
println!(
|
|
"{:?}",
|
|
ble.cmd_set_le_advertising_data(
|
|
create_advertising_data(&[
|
|
AdStructure::Flags(LE_GENERAL_DISCOVERABLE | BR_EDR_NOT_SUPPORTED),
|
|
AdStructure::ServiceUuids16(&[Uuid::Uuid16(0x1809)]),
|
|
AdStructure::CompleteLocalName(esp_hal::chip!()),
|
|
])
|
|
.unwrap()
|
|
)
|
|
);
|
|
println!("{:?}", ble.cmd_set_le_advertise_enable(true));
|
|
|
|
println!("started advertising");
|
|
|
|
let (mut controller, interfaces) =
|
|
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI).unwrap();
|
|
|
|
let mut device = interfaces.sta;
|
|
let iface = create_interface(&mut device);
|
|
|
|
controller
|
|
.set_power_saving(esp_radio::wifi::PowerSaveMode::None)
|
|
.unwrap();
|
|
|
|
let mut socket_set_entries: [SocketStorage; 3] = Default::default();
|
|
let mut socket_set = SocketSet::new(&mut socket_set_entries[..]);
|
|
let mut dhcp_socket = smoltcp::socket::dhcpv4::Socket::new();
|
|
// we can set a hostname here (or add other DHCP options)
|
|
dhcp_socket.set_outgoing_options(&[DhcpOption {
|
|
kind: 12,
|
|
data: b"esp-radio",
|
|
}]);
|
|
socket_set.add(dhcp_socket);
|
|
|
|
let rng = Rng::new();
|
|
let stack = Stack::new(iface, device, socket_set, now, rng.random());
|
|
|
|
let client_config = Config::Client(
|
|
ClientConfig::default()
|
|
.with_ssid(SSID.into())
|
|
.with_password(PASSWORD.into()),
|
|
);
|
|
|
|
let res = controller.set_config(&client_config);
|
|
println!("wifi_set_configuration returned {:?}", res);
|
|
|
|
controller.start().unwrap();
|
|
println!("is wifi started: {:?}", controller.is_started());
|
|
println!("{:?}", controller.capabilities());
|
|
println!("wifi_connect {:?}", controller.connect());
|
|
|
|
// wait to get connected
|
|
println!("Wait to get connected");
|
|
loop {
|
|
match controller.is_connected() {
|
|
Ok(true) => break,
|
|
Ok(false) => {}
|
|
Err(err) => {
|
|
println!("{:?}", err);
|
|
loop {}
|
|
}
|
|
}
|
|
}
|
|
println!("{:?}", controller.is_connected());
|
|
|
|
// wait for getting an ip address
|
|
println!("Wait to get an ip address");
|
|
loop {
|
|
stack.work();
|
|
|
|
if stack.is_iface_up() {
|
|
println!("got ip {:?}", stack.get_ip_info());
|
|
break;
|
|
}
|
|
}
|
|
|
|
println!("Start busy loop on main");
|
|
|
|
let mut rx_buffer = [0u8; 128];
|
|
let mut tx_buffer = [0u8; 128];
|
|
let mut socket = stack.get_socket(&mut rx_buffer, &mut tx_buffer);
|
|
|
|
loop {
|
|
println!("Making HTTP request");
|
|
socket.work();
|
|
|
|
socket
|
|
.open(IpAddress::Ipv4(Ipv4Addr::new(142, 250, 185, 115)), 80)
|
|
.unwrap();
|
|
|
|
socket
|
|
.write(b"GET / HTTP/1.0\r\nHost: www.mobile-j.de\r\n\r\n")
|
|
.unwrap();
|
|
socket.flush().unwrap();
|
|
|
|
let deadline = time::Instant::now() + Duration::from_secs(20);
|
|
let mut buffer = [0u8; 128];
|
|
while let Ok(len) = socket.read(&mut buffer) {
|
|
let to_print = unsafe { core::str::from_utf8_unchecked(&buffer[..len]) };
|
|
print!("{}", to_print);
|
|
|
|
if time::Instant::now() > deadline {
|
|
println!("Timeout");
|
|
break;
|
|
}
|
|
}
|
|
println!();
|
|
|
|
socket.disconnect();
|
|
|
|
let deadline = time::Instant::now() + Duration::from_secs(5);
|
|
while time::Instant::now() < deadline {
|
|
socket.work();
|
|
}
|
|
}
|
|
}
|
|
|
|
// some smoltcp boilerplate
|
|
fn timestamp() -> smoltcp::time::Instant {
|
|
smoltcp::time::Instant::from_micros(
|
|
esp_hal::time::Instant::now()
|
|
.duration_since_epoch()
|
|
.as_micros() as i64,
|
|
)
|
|
}
|
|
|
|
pub fn create_interface(device: &mut esp_radio::wifi::WifiDevice) -> smoltcp::iface::Interface {
|
|
// users could create multiple instances but since they only have one WifiDevice
|
|
// they probably can't do anything bad with that
|
|
smoltcp::iface::Interface::new(
|
|
smoltcp::iface::Config::new(smoltcp::wire::HardwareAddress::Ethernet(
|
|
smoltcp::wire::EthernetAddress::from_bytes(&device.mac_address()),
|
|
)),
|
|
device,
|
|
timestamp(),
|
|
)
|
|
}
|