commit ae0393cd4883468187b2715645c03f080eb9f049
parent 35c7d34b8dfd997093a7158d5a82abac8166f41c
Author: Daniel Barlow <dan@telent.net>
Date: Tue, 23 Dec 2025 16:51:10 +0000
rearrange as workspace of crates
I would rather like to be able to write tests for the complicated
bits, but using "cargo test" with the esp32 tolchain/libraries
is beyond my skill level if it's even possible. Hence we now have
an ecu-portable crate for stuff that can be built using plain old Rust
(e.g. x86_64 with std) and an ecu-esp32 crate for the rest of it
Diffstat:
13 files changed, 480 insertions(+), 400 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -290,12 +290,13 @@ dependencies = [
]
[[package]]
-name = "eculogical"
+name = "ecu-esp32"
version = "0.1.0"
dependencies = [
"bleps",
"bt-hci",
"dns-protocol",
+ "ecu_portable",
"embassy-executor",
"embassy-futures",
"embassy-net",
@@ -317,6 +318,10 @@ dependencies = [
]
[[package]]
+name = "ecu_portable"
+version = "0.1.0"
+
+[[package]]
name = "embassy-embedded-hal"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
@@ -1,87 +1,3 @@
-[package]
-edition = "2024"
-name = "eculogical"
-rust-version = "1.88"
-version = "0.1.0"
-
-
-[dependencies]
-esp-hal = { version = "1.0.0", features = ["esp32c3", "log-04", "unstable"] }
-
-esp-rtos = { version = "0.2.0", features = [
- "esp-alloc",
- "esp-radio",
- "esp32c3",
- "log-04",
- "embassy",
-] }
-
-esp-bootloader-esp-idf = { version = "0.4.0", features = ["esp32c3", "log-04"] }
-log = "0.4.27"
-
-bleps = { git = "https://github.com/bjoernQ/bleps", package = "bleps", rev = "a5148d8ae679e021b78f53fd33afb8bb35d0b62e", features = [
- "async",
- "macros",
-] }
-esp-alloc = "0.9.0"
-bt-hci = { version = "0.6.0" }
-embassy-executor = { version = "0.9.1", features = [] }
-embassy-time = { version = "0.5.0", features = [] }
-embedded-io = { version = "0.7.1", features = [] }
-embedded-io-async = { version = "0.7.0", features = [] }
-esp-backtrace = { version = "0.18.1", features = [
- "esp32c3",
- "panic-handler",
- "println",
-] }
-esp-println = { version = "0.16.1", features = ["esp32c3", "log-04"] }
-esp-radio = { version = "0.17.0", features = [
- "ble",
- "esp-alloc",
- "esp32c3",
- "log-04",
- "unstable",
- "wifi",
- "smoltcp"
-] }
-
-smoltcp = { version = "0.12.0", default-features = false, features = [
- "medium-ethernet",
- "socket-raw",
- "proto-dhcpv4",
- "proto-ipv4"
-] }
-
-
-embassy-futures = "0.1.1"
-embassy-sync = { version = "0.7" }
-
-static_cell = "2"
-trouble-host = { version = "0.5.0", features = [
- "peripheral", "gatt", "default-packet-pool-mtu-255",
- "derive", "scan",
-] }
-embassy-net = { version = "0.7.1", features = [
- "medium-ethernet", "proto-ipv4", "tcp", "dhcpv4", "udp",
- "dns", "mdns", "multicast"
-] }
-
-dns-protocol = { version = "0.1.2", default-features = false, features = [
- # no "std" feature
-] }
-
-
-
-[profile.dev]
-# Rust debug is too slow.
-# For debug builds always builds with some optimization
-opt-level = "s"
-
-[profile.release]
-codegen-units = 1 # LLVM can perform better optimizations using a single thread
-debug = 2
-debug-assertions = false
-incremental = false
-lto = 'fat'
-opt-level = 's'
-overflow-checks = false
+[workspace]
+resolver = "3"
+members = ["ecu-esp32", "ecu-portable"]
diff --git a/ecu-esp32/Cargo.toml b/ecu-esp32/Cargo.toml
@@ -0,0 +1,89 @@
+[package]
+edition = "2024"
+name = "ecu-esp32"
+rust-version = "1.88"
+version = "0.1.0"
+
+
+[dependencies]
+ecu_portable = { path = "../ecu-portable" }
+
+esp-hal = { version = "1.0.0", features = ["esp32c3", "log-04", "unstable"] }
+
+esp-rtos = { version = "0.2.0", features = [
+ "esp-alloc",
+ "esp-radio",
+ "esp32c3",
+ "log-04",
+ "embassy",
+] }
+
+esp-bootloader-esp-idf = { version = "0.4.0", features = ["esp32c3", "log-04"] }
+log = "0.4.27"
+
+bleps = { git = "https://github.com/bjoernQ/bleps", package = "bleps", rev = "a5148d8ae679e021b78f53fd33afb8bb35d0b62e", features = [
+ "async",
+ "macros",
+] }
+esp-alloc = "0.9.0"
+bt-hci = { version = "0.6.0" }
+embassy-executor = { version = "0.9.1", features = [] }
+embassy-time = { version = "0.5.0", features = [] }
+embedded-io = { version = "0.7.1", features = [] }
+embedded-io-async = { version = "0.7.0", features = [] }
+esp-backtrace = { version = "0.18.1", features = [
+ "esp32c3",
+ "panic-handler",
+ "println",
+] }
+esp-println = { version = "0.16.1", features = ["esp32c3", "log-04"] }
+esp-radio = { version = "0.17.0", features = [
+ "ble",
+ "esp-alloc",
+ "esp32c3",
+ "log-04",
+ "unstable",
+ "wifi",
+ "smoltcp"
+] }
+
+smoltcp = { version = "0.12.0", default-features = false, features = [
+ "medium-ethernet",
+ "socket-raw",
+ "proto-dhcpv4",
+ "proto-ipv4"
+] }
+
+
+embassy-futures = "0.1.1"
+embassy-sync = { version = "0.7" }
+
+static_cell = "2"
+trouble-host = { version = "0.5.0", features = [
+ "peripheral", "gatt", "default-packet-pool-mtu-255",
+ "derive", "scan",
+] }
+embassy-net = { version = "0.7.1", features = [
+ "medium-ethernet", "proto-ipv4", "tcp", "dhcpv4", "udp",
+ "dns", "mdns", "multicast"
+] }
+
+dns-protocol = { version = "0.1.2", default-features = false, features = [
+ # no "std" feature
+] }
+
+
+
+[profile.dev]
+# Rust debug is too slow.
+# For debug builds always builds with some optimization
+opt-level = "s"
+
+[profile.release]
+codegen-units = 1 # LLVM can perform better optimizations using a single thread
+debug = 2
+debug-assertions = false
+incremental = false
+lto = 'fat'
+opt-level = 's'
+overflow-checks = false
diff --git a/build.rs b/ecu-esp32/build.rs
diff --git a/rust-toolchain.toml b/ecu-esp32/rust-toolchain.toml
diff --git a/src/ecu.rs b/ecu-esp32/src/ecu.rs
diff --git a/src/main.rs b/ecu-esp32/src/main.rs
diff --git a/src/wibble.rs b/ecu-esp32/src/wibble.rs
diff --git a/ecu-esp32/src/wifi.rs b/ecu-esp32/src/wifi.rs
@@ -0,0 +1,322 @@
+//! Set SSID and PASSWORD env variable before running this example.
+//!
+//! This gets an ip address via DHCP and advertises it with mdns
+
+
+use embassy_executor::Spawner;
+use embassy_net::{
+ Runner,
+ StackResources,
+ udp::{PacketMetadata, UdpSocket, UdpMetadata},
+ IpAddress,
+ IpEndpoint
+};
+
+use embassy_time::{Duration, Timer};
+use esp_alloc as _;
+use esp_backtrace as _;
+use esp_hal::{
+ rng::Rng,
+};
+use esp_println::println;
+use esp_radio::{
+ Controller,
+ wifi::{
+ ClientConfig,
+ ModeConfig,
+ ScanConfig,
+ WifiController,
+ WifiDevice,
+ WifiEvent,
+ WifiStaState,
+ },
+};
+
+use log::info;
+
+
+use dns_protocol::{Message, Question,
+ MessageType,
+ Label,
+ ResourceRecord, ResourceType, Flags};
+
+// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html
+macro_rules! mk_static {
+ ($t:ty,$val:expr) => {{
+ static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new();
+ #[deny(unused_attributes)]
+ let x = STATIC_CELL.uninit().write(($val));
+ x
+ }};
+}
+
+const SSID: &str = env!("SSID");
+const PASSWORD: &str = env!("PASSWORD");
+
+const MDNS_IP: IpAddress = IpAddress::v4(224, 0, 0, 251);
+const MDNS_PORT: u16 = 5353;
+const MDNS_ENDPOINT: IpEndpoint = IpEndpoint::new(MDNS_IP, MDNS_PORT);
+
+const CACHE_FLUSH : u16 = 1<<15;
+
+
+// RFC: "Multicast DNS responses MUST NOT contain any questions in the
+// Question Section. ". However, responses to "legacy" queries (port != 5353)
+// should have a question section just like traditional DNS
+
+async fn send_advert(sock: &UdpSocket<'_>,
+ id: u16,
+ endpoint: IpEndpoint,
+ question: Option<&Question<'_>>,
+ my_address: &[u8]) {
+
+ let questions = match question {
+ Some(q) =>&mut [*q][..],
+ None => &mut [][..]
+ };
+
+ let mut buf : [u8; 32] = [0; 32];
+
+ info!("ptr data bytes: {:?}",
+ ecu_portable::ptr_data(
+ &["myname", "_keihin", "_udp"],
+ &mut buf)
+ );
+
+ // FIXME for legacy unicast response max ttl is 10s
+
+ let mut answer = [
+ ResourceRecord::new(
+ "eculogical.local",
+ ResourceType::A,
+ 1 | CACHE_FLUSH,
+ 120, // ttl
+ &my_address
+ )
+ ];
+
+ let mut flags = Flags::new();
+ flags.set_qr(MessageType::Reply);
+ flags.set_authoritative(true);
+
+ let advert_message = Message::new(
+ id,
+ flags,
+ questions,
+ &mut answer,
+ &mut [],
+ &mut []);
+
+ let mut data_buf = [0; 4096];
+ // Serialize the message into the buffer
+ assert!(advert_message.space_needed() <= data_buf.len());
+
+ log::info!("ready to send to {:?}", endpoint);
+
+ match advert_message.write(&mut data_buf) {
+ Result::Ok(len) => {
+ log::info!("sock.send: {:?}", sock.send_to(&data_buf[..len], endpoint).await);
+ },
+ Result::Err(err) => {
+ log::error!("message.write {:?}", err);
+ }
+ }
+}
+
+async fn send_responses(sock: &UdpSocket<'_>,
+ my_address: &[u8],
+ message: &Message<'_,'_>,
+ meta: &UdpMetadata) {
+
+ let my_hostname = Label::from("eculogical.local");
+ let q_id = message.id();
+
+ // for each relevant question we want to add RRs (as answers
+ // or additional) to the reply packet. I'm uncertain whether
+ // it's ok to do this for legacy queries but they probably
+ // don't have multiple questions anyway
+ for q in message.questions() {
+ log::info!("question {:?} {:?} {:?} flags {:?} from {:?}",
+ q.name(), q.ty(), q.class(),
+ message.flags().raw(),
+ meta.endpoint);
+ if q.name().eq(&my_hostname) {
+ if meta.endpoint.port == 5353 {
+ send_advert(&sock, q_id, MDNS_ENDPOINT, None, &my_address).await;
+ } else if (q.class() & 0x8000) != 0 {
+ log::info!("unicast");
+ send_advert(&sock, q_id, meta.endpoint, None, &my_address).await;
+ } else {
+ // legacy unicast, send questions
+ send_advert(&sock, q_id, meta.endpoint, Some(q), &my_address).await;
+ }
+ log::info!("IT ME");
+ }
+ }
+}
+
+pub async fn start_wifi(spawner: &Spawner,
+ wifi_peripheral: esp_hal::peripherals::WIFI<'static>) -> ! {
+
+
+ let esp_radio_ctrl = &*mk_static!(Controller<'static>, esp_radio::init().unwrap());
+
+ let (controller, interfaces) =
+ esp_radio::wifi::new(esp_radio_ctrl, wifi_peripheral, Default::default()).unwrap();
+
+ let wifi_interface = interfaces.sta;
+
+ let config = embassy_net::Config::dhcpv4(Default::default());
+
+ let rng = Rng::new();
+ let seed = (rng.random() as u64) << 32 | rng.random() as u64;
+
+ // Init network stack
+ let (stack, runner) = embassy_net::new(
+ wifi_interface,
+ config,
+ mk_static!(StackResources<3>, StackResources::<3>::new()),
+ seed,
+ );
+
+ spawner.spawn(connection(controller)).ok();
+ spawner.spawn(net_task(runner)).ok();
+
+ let mut rx_buffer = [0; 4096];
+ let mut tx_buffer = [0; 4096];
+ let my_address;
+
+ loop {
+ if stack.is_link_up() {
+ break;
+ }
+ Timer::after(Duration::from_millis(500)).await;
+ }
+
+ println!("Waiting to get IP address...");
+ loop {
+ if let Some(config) = stack.config_v4() {
+ println!("Got IP: {}", config.address);
+ my_address = config.address.address().octets();
+ break;
+ }
+ Timer::after(Duration::from_millis(500)).await;
+ }
+
+ let mut rx_meta = [PacketMetadata::EMPTY; 512];
+ let mut tx_meta = [PacketMetadata::EMPTY; 512];
+ let mut sock = UdpSocket::new(
+ stack,
+ &mut rx_meta,
+ &mut rx_buffer,
+ &mut tx_meta,
+ &mut tx_buffer,
+ );
+ sock.set_hop_limit(Some(1));
+
+ log::info!("sock.bind(5353) res: {:?}", sock.bind(MDNS_PORT));
+ log::info!(
+ "multicast_res: {:?}",
+ stack.join_multicast_group(MDNS_IP)
+ );
+
+
+ send_advert(&sock, rng.random() as u16, MDNS_ENDPOINT, None, &my_address).await;
+
+ let mut data_buf = [0; 4096];
+
+ loop {
+ if sock.may_recv() {
+ let mut questions = [Question::default(); 16];
+ let mut answers = [ResourceRecord::default(); 16];
+ let mut authorities = [ResourceRecord::default(); 16];
+ let mut addl = [ResourceRecord::default(); 16];
+
+ let res = sock.recv_from(&mut data_buf).await;
+ if let Ok((n, meta)) = res {
+ log::info!("received packet len {n}");
+ let message = Message::read(
+ &data_buf[..n],
+ &mut questions,
+ &mut answers,
+ &mut authorities,
+ &mut addl,
+ );
+
+ match message {
+ Result::Ok(message) => {
+ send_responses(&sock, &my_address, &message, &meta).await;
+ },
+ Result::Err(err) => {
+ log::error!("parsing dns message: {:?}", err);
+ }
+ }
+ }
+ }
+
+ Timer::after(Duration::from_millis(80)).await;
+ }
+
+ // _ = stack.leave_multicast_group(MDNS_IP);
+ // sock.close();
+ // drop(sock);
+
+ // loop {
+ // Timer::after(Duration::from_millis(1_000)).await;
+ // log::info!("bump");
+ // }
+
+}
+
+#[embassy_executor::task]
+async fn connection(mut controller: WifiController<'static>) {
+ println!("start connection task");
+ println!("Device capabilities: {:?}", controller.capabilities());
+ loop {
+ match esp_radio::wifi::sta_state() {
+ WifiStaState::Connected => {
+ // wait until we're no longer connected
+ controller
+ .wait_for_event(WifiEvent::StaDisconnected)
+ .await;
+ Timer::after(Duration::from_millis(5000)).await
+ }
+ _ => {}
+ }
+ if !matches!(controller.is_started(), Ok(true)) {
+ let station_config = ModeConfig::Client(
+ ClientConfig::default()
+ .with_ssid(SSID.into())
+ .with_password(PASSWORD.into()),
+ );
+ controller.set_config(&station_config).unwrap();
+ println!("Starting wifi");
+ controller.start_async().await.unwrap();
+ println!("Wifi started!");
+
+ println!("Scan");
+ let scan_config = ScanConfig::default().with_max(10);
+ let result = controller
+ .scan_with_config_async(scan_config)
+ .await
+ .unwrap();
+ for ap in result {
+ println!("{:?}", ap);
+ }
+ }
+ println!("About to connect...");
+
+ match controller.connect_async().await {
+ Ok(_) => println!("Wifi connected!"),
+ Err(e) => {
+ println!("Failed to connect to wifi: {e:?}");
+ Timer::after(Duration::from_millis(5000)).await
+ }
+ }
+ }
+}
+
+#[embassy_executor::task]
+async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) {
+ runner.run().await
+}
diff --git a/ecu-portable/Cargo.toml b/ecu-portable/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "ecu_portable"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
diff --git a/ecu-portable/src/lib.rs b/ecu-portable/src/lib.rs
@@ -0,0 +1,41 @@
+#![no_std]
+
+use core::iter::Iterator;
+
+pub fn ptr_data<'b>(labels : &[&str], buf : &'b mut[u8]) -> &'b mut [u8] {
+ let mut offset = 0;
+ for l in labels.iter() {
+ buf[offset] = l.len() as u8;
+ for (i, &item) in l.as_bytes().iter().enumerate() {
+ buf[offset + 1 + i] = item;
+ }
+ offset = offset + l.len() + 1;
+ }
+ &mut buf[..offset]
+}
+
+
+#[cfg(test)]
+mod tests {
+ extern crate std;
+ use super::*;
+
+ #[test]
+ fn test_ptr_data() {
+ let mut buf : [u8; 32] = [0; 32];
+ assert_eq!(ptr_data(&["hello"], &mut buf),
+ [5, 104, 101, 108, 108, 111]);
+
+ assert_eq!(ptr_data(&[], &mut buf),
+ []);
+
+ assert_eq!(ptr_data(&["hello", "world"], &mut buf),
+ [5, 104, 101, 108, 108, 111,
+ 5, 119, 111, 114, 108, 100]);
+
+ assert_eq!(ptr_data(&["hello", "cool", "world"], &mut buf),
+ [5, 104, 101, 108, 108, 111,
+ 4, 99, 111, 111, 108,
+ 5, 119, 111, 114, 108, 100]);
+ }
+}
diff --git a/notes.md b/notes.md
@@ -1,3 +1,16 @@
+# Building
+
+The repo is split into two crates in a cargo workspace: code in
+ecu-portable can be built and run using the native compiler, hence is
+unit-testable, and code in ecu-esp32 depends on all the esp32 gubbins
+so you can test it only by running it.
+
+```
+ cargo test -p ecu-portable --target x86_64-unknown-linux-gnu
+ SSID=my-wifi PASSWORD="my-wifi-password" cargo run --release
+```
+
+
# Resources
https://github.com/aeaphichart/HondaECU-1
diff --git a/src/wifi.rs b/src/wifi.rs
@@ -1,312 +0,0 @@
-//! Set SSID and PASSWORD env variable before running this example.
-//!
-//! This gets an ip address via DHCP and advertises it with mdns
-
-
-use embassy_executor::Spawner;
-use embassy_net::{
- Runner,
- StackResources,
- udp::{PacketMetadata, UdpSocket, UdpMetadata},
- IpAddress,
- IpEndpoint
-};
-
-use embassy_time::{Duration, Timer};
-use esp_alloc as _;
-use esp_backtrace as _;
-use esp_hal::{
- rng::Rng,
-};
-use esp_println::println;
-use esp_radio::{
- Controller,
- wifi::{
- ClientConfig,
- ModeConfig,
- ScanConfig,
- WifiController,
- WifiDevice,
- WifiEvent,
- WifiStaState,
- },
-};
-
-
-use dns_protocol::{Message, Question,
- MessageType,
- Label,
- ResourceRecord, ResourceType, Flags};
-
-// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html
-macro_rules! mk_static {
- ($t:ty,$val:expr) => {{
- static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new();
- #[deny(unused_attributes)]
- let x = STATIC_CELL.uninit().write(($val));
- x
- }};
-}
-
-const SSID: &str = env!("SSID");
-const PASSWORD: &str = env!("PASSWORD");
-
-const MDNS_IP: IpAddress = IpAddress::v4(224, 0, 0, 251);
-const MDNS_PORT: u16 = 5353;
-const MDNS_ENDPOINT: IpEndpoint = IpEndpoint::new(MDNS_IP, MDNS_PORT);
-
-const CACHE_FLUSH : u16 = 1<<15;
-
-
-// RFC: "Multicast DNS responses MUST NOT contain any questions in the
-// Question Section. ". However, responses to "legacy" queries (port != 5353)
-// should have a question section just like traditional DNS
-
-async fn send_advert(sock: &UdpSocket<'_>,
- id: u16,
- endpoint: IpEndpoint,
- question: Option<&Question<'_>>,
- my_address: &[u8]) {
-
- let questions = match question {
- Some(q) =>&mut [*q][..],
- None => &mut [][..]
- };
-
- // FIXME for legacy unicast response max ttl is 10s
-
- let mut answer = [
- ResourceRecord::new(
- "eculogical.local",
- ResourceType::A,
- 1 | CACHE_FLUSH,
- 120, // ttl
- &my_address
- )
- ];
-
- let mut flags = Flags::new();
- flags.set_qr(MessageType::Reply);
- flags.set_authoritative(true);
-
- let advert_message = Message::new(
- id,
- flags,
- questions,
- &mut answer,
- &mut [],
- &mut []);
-
- let mut data_buf = [0; 4096];
- // Serialize the message into the buffer
- assert!(advert_message.space_needed() <= data_buf.len());
-
- log::info!("ready to send to {:?}", endpoint);
-
- match advert_message.write(&mut data_buf) {
- Result::Ok(len) => {
- log::info!("sock.send: {:?}", sock.send_to(&data_buf[..len], endpoint).await);
- },
- Result::Err(err) => {
- log::error!("message.write {:?}", err);
- }
- }
-}
-
-async fn send_responses(sock: &UdpSocket<'_>,
- my_address: &[u8],
- message: &Message<'_,'_>,
- meta: &UdpMetadata) {
-
- let my_hostname = Label::from("eculogical.local");
- let q_id = message.id();
-
- // for each relevant question we want to add RRs (as answers
- // or additional) to the reply packet. I'm uncertain whether
- // it's ok to do this for legacy queries but they probably
- // don't have multiple questions anyway
- for q in message.questions() {
- log::info!("question {:?} {:?} {:?} flags {:?} from {:?}",
- q.name(), q.ty(), q.class(),
- message.flags().raw(),
- meta.endpoint);
- if q.name().eq(&my_hostname) {
- if meta.endpoint.port == 5353 {
- send_advert(&sock, q_id, MDNS_ENDPOINT, None, &my_address).await;
- } else if (q.class() & 0x8000) != 0 {
- log::info!("unicast");
- send_advert(&sock, q_id, meta.endpoint, None, &my_address).await;
- } else {
- // legacy unicast, send questions
- send_advert(&sock, q_id, meta.endpoint, Some(q), &my_address).await;
- }
- log::info!("IT ME");
- }
- }
-}
-
-pub async fn start_wifi(spawner: &Spawner,
- wifi_peripheral: esp_hal::peripherals::WIFI<'static>) -> ! {
-
-
- let esp_radio_ctrl = &*mk_static!(Controller<'static>, esp_radio::init().unwrap());
-
- let (controller, interfaces) =
- esp_radio::wifi::new(esp_radio_ctrl, wifi_peripheral, Default::default()).unwrap();
-
- let wifi_interface = interfaces.sta;
-
- let config = embassy_net::Config::dhcpv4(Default::default());
-
- let rng = Rng::new();
- let seed = (rng.random() as u64) << 32 | rng.random() as u64;
-
- // Init network stack
- let (stack, runner) = embassy_net::new(
- wifi_interface,
- config,
- mk_static!(StackResources<3>, StackResources::<3>::new()),
- seed,
- );
-
- spawner.spawn(connection(controller)).ok();
- spawner.spawn(net_task(runner)).ok();
-
- let mut rx_buffer = [0; 4096];
- let mut tx_buffer = [0; 4096];
- let my_address;
-
- loop {
- if stack.is_link_up() {
- break;
- }
- Timer::after(Duration::from_millis(500)).await;
- }
-
- println!("Waiting to get IP address...");
- loop {
- if let Some(config) = stack.config_v4() {
- println!("Got IP: {}", config.address);
- my_address = config.address.address().octets();
- break;
- }
- Timer::after(Duration::from_millis(500)).await;
- }
-
- let mut rx_meta = [PacketMetadata::EMPTY; 512];
- let mut tx_meta = [PacketMetadata::EMPTY; 512];
- let mut sock = UdpSocket::new(
- stack,
- &mut rx_meta,
- &mut rx_buffer,
- &mut tx_meta,
- &mut tx_buffer,
- );
- sock.set_hop_limit(Some(1));
-
- log::info!("sock.bind(5353) res: {:?}", sock.bind(MDNS_PORT));
- log::info!(
- "multicast_res: {:?}",
- stack.join_multicast_group(MDNS_IP)
- );
-
-
- send_advert(&sock, rng.random() as u16, MDNS_ENDPOINT, None, &my_address).await;
-
- let mut data_buf = [0; 4096];
-
- loop {
- if sock.may_recv() {
- let mut questions = [Question::default(); 16];
- let mut answers = [ResourceRecord::default(); 16];
- let mut authorities = [ResourceRecord::default(); 16];
- let mut addl = [ResourceRecord::default(); 16];
-
- let res = sock.recv_from(&mut data_buf).await;
- if let Ok((n, meta)) = res {
- log::info!("received packet len {n}");
- let message = Message::read(
- &data_buf[..n],
- &mut questions,
- &mut answers,
- &mut authorities,
- &mut addl,
- );
-
- match message {
- Result::Ok(message) => {
- send_responses(&sock, &my_address, &message, &meta).await;
- },
- Result::Err(err) => {
- log::error!("parsing dns message: {:?}", err);
- }
- }
- }
- }
-
- Timer::after(Duration::from_millis(80)).await;
- }
-
- // _ = stack.leave_multicast_group(MDNS_IP);
- // sock.close();
- // drop(sock);
-
- // loop {
- // Timer::after(Duration::from_millis(1_000)).await;
- // log::info!("bump");
- // }
-
-}
-
-#[embassy_executor::task]
-async fn connection(mut controller: WifiController<'static>) {
- println!("start connection task");
- println!("Device capabilities: {:?}", controller.capabilities());
- loop {
- match esp_radio::wifi::sta_state() {
- WifiStaState::Connected => {
- // wait until we're no longer connected
- controller
- .wait_for_event(WifiEvent::StaDisconnected)
- .await;
- Timer::after(Duration::from_millis(5000)).await
- }
- _ => {}
- }
- if !matches!(controller.is_started(), Ok(true)) {
- let station_config = ModeConfig::Client(
- ClientConfig::default()
- .with_ssid(SSID.into())
- .with_password(PASSWORD.into()),
- );
- controller.set_config(&station_config).unwrap();
- println!("Starting wifi");
- controller.start_async().await.unwrap();
- println!("Wifi started!");
-
- println!("Scan");
- let scan_config = ScanConfig::default().with_max(10);
- let result = controller
- .scan_with_config_async(scan_config)
- .await
- .unwrap();
- for ap in result {
- println!("{:?}", ap);
- }
- }
- println!("About to connect...");
-
- match controller.connect_async().await {
- Ok(_) => println!("Wifi connected!"),
- Err(e) => {
- println!("Failed to connect to wifi: {e:?}");
- Timer::after(Duration::from_millis(5000)).await
- }
- }
- }
-}
-
-#[embassy_executor::task]
-async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) {
- runner.run().await
-}