From b5f26fb3626c974093e70196836a5520babfac33 Mon Sep 17 00:00:00 2001 From: Daniel Bulant Date: Tue, 12 May 2026 14:10:04 +0200 Subject: [PATCH] basic working esp --- esp32/src/bin/scan.rs | 2 +- esp32/src/input.rs | 28 +++++----- esp32/src/main.rs | 115 ++++++++++++++++++++++++++++++++---------- esp32/src/net.rs | 92 +++++++++++++++++++++++++-------- esp32/src/screen.rs | 35 ++++++++----- 5 files changed, 194 insertions(+), 78 deletions(-) diff --git a/esp32/src/bin/scan.rs b/esp32/src/bin/scan.rs index 1377a1f..b59c1d2 100644 --- a/esp32/src/bin/scan.rs +++ b/esp32/src/bin/scan.rs @@ -46,7 +46,7 @@ async fn main(_spawner: Spawner) -> ! { loop { println!("Scan"); - let scan_config = ScanConfig::default().with_max(10); + let scan_config = ScanConfig::default().with_max(20); let result = controller.scan_async(&scan_config).await.unwrap(); for ap in result { println!("{:?}", ap); diff --git a/esp32/src/input.rs b/esp32/src/input.rs index 1aa1853..8be575d 100644 --- a/esp32/src/input.rs +++ b/esp32/src/input.rs @@ -3,7 +3,7 @@ use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, channel::Channe use embassy_time::{Duration, Timer}; use esp_hal::gpio::Input; use esp_hal::i2c::master::{Config, I2c}; -use esp_hal::peripherals::{GPIO4, GPIO5, I2C0}; +use esp_hal::peripherals::{GPIO21, GPIO22, I2C0}; use esp_hal::time::Rate; use esp_println::println; @@ -15,17 +15,20 @@ pub static ANGLE: Mutex = Mutex::new(0); pub struct RotationConfig { pub i2c0: I2C0<'static>, - pub scl: GPIO5<'static>, - pub sda: GPIO4<'static>, + pub scl: GPIO22<'static>, + pub sda: GPIO21<'static>, } #[embassy_executor::task] pub async fn rotation_read_task(config: RotationConfig) { - let i2c = I2c::new(config.i2c0, Config::default().with_frequency(Rate::from_khz(400))) - .unwrap() - .with_sda(config.sda) - .with_scl(config.scl) - .into_async(); + let i2c = I2c::new( + config.i2c0, + Config::default().with_frequency(Rate::from_khz(400)), + ) + .unwrap() + .with_sda(config.sda) + .with_scl(config.scl) + .into_async(); let mut as5600 = As5600::new(i2c); loop { @@ -43,14 +46,7 @@ pub async fn rotation_read_task(config: RotationConfig) { let mut value = wheel.value; let mut accumulated = wheel.accumulated; let precision = crate::WHEEL_PRECISION; - apply_wheel_delta( - &mut value, - min, - max, - &mut accumulated, - diff, - precision, - ); + apply_wheel_delta(&mut value, min, max, &mut accumulated, diff, precision); wheel.value = value; wheel.accumulated = accumulated; } diff --git a/esp32/src/main.rs b/esp32/src/main.rs index 2c7c49c..34ad5e7 100644 --- a/esp32/src/main.rs +++ b/esp32/src/main.rs @@ -8,10 +8,13 @@ use embassy_net::tcp::{TcpReader, TcpWriter}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::mutex::Mutex; use embassy_sync::signal::Signal; +use embassy_time::Timer; use embedded_io::Write; use esp_backtrace as _; use esp_hal::{ gpio::{Input, InputConfig as GpioInputConfig, Pin, Pull}, + interrupt::software::SoftwareInterruptControl, + timer::timg::TimerGroup, }; use esp_println::println; use owned_str::OwnedStr; @@ -62,7 +65,8 @@ static WHEEL_VALUE: Mutex = Mutex::new(Wheel }); #[panic_handler] -fn panic(_: &core::panic::PanicInfo) -> ! { +fn panic(info: &core::panic::PanicInfo) -> ! { + println!("PANIC! {:?}", info); loop {} } @@ -109,7 +113,10 @@ pub async fn tcp_read_loop(mut read: TcpReader<'_>) { if key == "rangeMin" || key == "rangeMax" { match q_type { QuestionType::Choice => {} - QuestionType::Numeric { ref mut min, ref mut max } => { + QuestionType::Numeric { + ref mut min, + ref mut max, + } => { if key == "rangeMin" { *min = value.parse().unwrap(); future_wheel.min = *min; @@ -221,42 +228,98 @@ pub async fn main_loop() { } } +esp_bootloader_esp_idf::esp_app_desc!(); + #[esp_rtos::main] async fn main(spawner: Spawner) -> ! { - let p = esp_hal::init(esp_hal::Config::default().with_cpu_clock(esp_hal::clock::CpuClock::max())); + let p = + esp_hal::init(esp_hal::Config::default().with_cpu_clock(esp_hal::clock::CpuClock::max())); + + println!("Booting"); + let timg0 = TimerGroup::new(p.TIMG0); + let sw_int = SoftwareInterruptControl::new(p.SW_INTERRUPT); + esp_rtos::start(timg0.timer0, sw_int.software_interrupt0); esp_alloc::heap_allocator!(size: 64 * 1024); let lcd = screen::LcdPins { - rs: p.GPIO10, - e: p.GPIO11, - d4: p.GPIO12, - d5: p.GPIO13, - d6: p.GPIO14, - d7: p.GPIO15, + rs: p.GPIO4, + e: p.GPIO16, + d4: p.GPIO17, + d5: p.GPIO18, + d6: p.GPIO19, + d7: p.GPIO23, }; spawner.spawn(screen::lcd_display_task(screen::LcdConfig { pins: lcd }).expect("spawn lcd")); - spawner.spawn(input::rotation_read_task(input::RotationConfig { - i2c0: p.I2C0, - scl: p.GPIO5, - sda: p.GPIO4, - }).expect("spawn rotation")); + spawner.spawn( + input::rotation_read_task(input::RotationConfig { + i2c0: p.I2C0, + scl: p.GPIO22, + sda: p.GPIO21, + }) + .expect("spawn rotation"), + ); - spawner.spawn(input::button_task(Input::new(p.GPIO18.degrade(), GpioInputConfig::default().with_pull(Pull::Up)), 1).expect("spawn btn1")); - spawner.spawn(input::button_task(Input::new(p.GPIO19.degrade(), GpioInputConfig::default().with_pull(Pull::Up)), 2).expect("spawn btn2")); - spawner.spawn(input::button_task(Input::new(p.GPIO20.degrade(), GpioInputConfig::default().with_pull(Pull::Up)), 3).expect("spawn btn3")); - spawner.spawn(input::button_task(Input::new(p.GPIO21.degrade(), GpioInputConfig::default().with_pull(Pull::Up)), 4).expect("spawn btn4")); + spawner.spawn( + input::button_task( + Input::new( + p.GPIO26.degrade(), + GpioInputConfig::default().with_pull(Pull::Up), + ), + 1, + ) + .expect("spawn btn1"), + ); + spawner.spawn( + input::button_task( + Input::new( + p.GPIO25.degrade(), + GpioInputConfig::default().with_pull(Pull::Up), + ), + 2, + ) + .expect("spawn btn2"), + ); + spawner.spawn( + input::button_task( + Input::new( + p.GPIO33.degrade(), + GpioInputConfig::default().with_pull(Pull::Up), + ), + 3, + ) + .expect("spawn btn3"), + ); + spawner.spawn( + input::button_task( + Input::new( + p.GPIO32.degrade(), + GpioInputConfig::default().with_pull(Pull::Up), + ), + 4, + ) + .expect("spawn btn4"), + ); - spawner.spawn(net::network_setup_task(spawner, net::NetworkConfig { - wifi: p.WIFI, - wifi_network: WIFI_NETWORK, - wifi_password: WIFI_PASSWORD, - target_ip: TARGET_IP, - target_port: TARGET_PORT, - }).expect("spawn net")); + spawner.spawn( + net::network_setup_task( + spawner, + net::NetworkConfig { + wifi: p.WIFI, + wifi_network: WIFI_NETWORK, + wifi_password: WIFI_PASSWORD, + target_ip: TARGET_IP, + target_port: TARGET_PORT, + }, + ) + .expect("spawn net"), + ); + + println!("Init done"); loop { - embassy_time::Timer::after_millis(1000).await; + Timer::after_millis(1000).await; + // println!("Looping"); } } diff --git a/esp32/src/net.rs b/esp32/src/net.rs index 58943f7..000c0ce 100644 --- a/esp32/src/net.rs +++ b/esp32/src/net.rs @@ -3,13 +3,14 @@ use core::str::FromStr; use embassy_futures::join::join; use embassy_net::tcp::TcpSocket; -use embassy_time::Duration; +use embassy_time::{Duration, Timer}; use esp_hal::peripherals::WIFI; use esp_hal::rng::Rng; use esp_println::println; -use esp_radio::wifi::{scan::ScanConfig, Config, ControllerConfig}; use esp_radio::wifi::sta::StationConfig; +use esp_radio::wifi::{Config, ControllerConfig, scan::ScanConfig}; +use crate::{WIFI_NETWORK, WIFI_PASSWORD}; use crate::{buffer::wait_for_config, tcp_read_loop, tcp_write_loop}; pub struct NetworkConfig<'a> { @@ -21,12 +22,17 @@ pub struct NetworkConfig<'a> { } #[embassy_executor::task] -async fn net_task(mut runner: embassy_net::Runner<'static, esp_radio::wifi::Interface<'static>>) -> ! { +async fn net_task( + mut runner: embassy_net::Runner<'static, esp_radio::wifi::Interface<'static>>, +) -> ! { runner.run().await } #[embassy_executor::task] -pub async fn network_setup_task(spawner: embassy_executor::Spawner, config: NetworkConfig<'static>) { +pub async fn network_setup_task( + spawner: embassy_executor::Spawner, + config: NetworkConfig<'static>, +) { let wifi_config = Config::Station( StationConfig::default() .with_ssid(config.wifi_network) @@ -41,6 +47,10 @@ pub async fn network_setup_task(spawner: embassy_executor::Spawner, config: Netw .unwrap(); println!("Wifi configured and started!"); + controller + .set_power_saving(esp_radio::wifi::PowerSaveMode::None) + .unwrap(); + let wifi_interface = interfaces.station; let net_config = embassy_net::Config::dhcpv4(Default::default()); let rng = Rng::new(); @@ -54,28 +64,68 @@ pub async fn network_setup_task(spawner: embassy_executor::Spawner, config: Netw ); spawner.spawn(net_task(runner).expect("spawn net task")); - println!("Scan"); - let scan_config = ScanConfig::default().with_max(10); - let result = controller.scan_async(&scan_config).await.unwrap(); - for ap in result { - println!("{:?}", ap); + loop { + println!("Scan"); + let scan_config = ScanConfig::default().with_max(10); + let result = controller.scan_async(&scan_config).await.unwrap(); + for ap in result { + println!( + "- {} (CH {} Strength {})", + ap.ssid.as_str(), + ap.channel, + ap.signal_strength + ); + } + + println!("Scan ended"); + + if let Err(e) = controller.set_config(&Config::Station( + StationConfig::default() + // .with_auth_method(esp_radio::wifi::AuthenticationMethod::Wpa2Wpa3Personal) + .with_ssid(WIFI_NETWORK) + .with_password(WIFI_PASSWORD.into()), + )) { + println!("Connection error: {:?}", e); + Timer::after_millis(1000).await; + continue; + } + + if let Err(e) = controller.connect_async().await { + println!("Connect error: {:?}", e); + Timer::after_millis(1000).await; + continue; + } + + println!("Configured"); + + stack.wait_config_up().await; + + break; } - stack.wait_config_up().await; + println!("Waiting for DHCP"); + let cfg = wait_for_config(stack).await; let local_addr = cfg.address.address(); println!("IP address: {:?}", local_addr); - let host_addr = embassy_net::Ipv4Address::from_str(config.target_ip).unwrap(); - let mut rx_buffer = [0; 4096]; - let mut tx_buffer = [0; 4096]; - let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); - socket.set_timeout(Some(Duration::from_secs(10))); - socket.set_keep_alive(Some(Duration::from_secs(1))); - if let Err(e) = socket.connect(SocketAddrV4::new(host_addr, config.target_port)).await { - println!("tcp connect error: {:?}", e); - } + loop { + let host_addr = embassy_net::Ipv4Address::from_str(config.target_ip).unwrap(); + let mut rx_buffer = [0; 4096]; + let mut tx_buffer = [0; 4096]; + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); + socket.set_timeout(Some(Duration::from_secs(10))); + socket.set_keep_alive(Some(Duration::from_secs(1))); + if let Err(e) = socket + .connect(SocketAddrV4::new(host_addr, config.target_port)) + .await + { + println!("tcp connect error: {:?}", e); + Timer::after_millis(1000).await; + continue; + } - let (read, write) = socket.split(); - join(tcp_read_loop(read), tcp_write_loop(write)).await; + let (read, write) = socket.split(); + join(tcp_read_loop(read), tcp_write_loop(write)).await; + } } diff --git a/esp32/src/screen.rs b/esp32/src/screen.rs index 2e5793e..37818cb 100644 --- a/esp32/src/screen.rs +++ b/esp32/src/screen.rs @@ -1,19 +1,16 @@ -use core::convert::Infallible; - use ag_lcd::LcdDisplay; use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex, signal::Signal}; use embassy_time::{Delay, Timer}; use esp_hal::gpio::{Level, Output, OutputConfig}; -use esp_hal::peripherals::{GPIO10, GPIO11, GPIO12, GPIO13, GPIO14, GPIO15}; -use ufmt::uWrite; +use esp_hal::peripherals::{GPIO4, GPIO16, GPIO17, GPIO18, GPIO19, GPIO23}; pub struct LcdPins { - pub rs: GPIO10<'static>, - pub e: GPIO11<'static>, - pub d4: GPIO12<'static>, - pub d5: GPIO13<'static>, - pub d6: GPIO14<'static>, - pub d7: GPIO15<'static>, + pub rs: GPIO4<'static>, + pub e: GPIO16<'static>, + pub d4: GPIO17<'static>, + pub d5: GPIO18<'static>, + pub d6: GPIO19<'static>, + pub d7: GPIO23<'static>, } pub struct LcdConfig { @@ -32,7 +29,8 @@ pub async fn overwrite_lcd(line1: &str, line2: &str) { } pub fn stack_resources() -> &'static mut embassy_net::StackResources<5> { - static RESOURCES: static_cell::StaticCell> = static_cell::StaticCell::new(); + static RESOURCES: static_cell::StaticCell> = + static_cell::StaticCell::new(); RESOURCES.init(embassy_net::StackResources::new()) } @@ -53,7 +51,10 @@ impl ScreenBuffer { } pub static SCREEN_BUFFER: Mutex = Mutex::new(ScreenBuffer { - line1: [0; 16], line1_ptr: 0, line2: [0; 16], line2_ptr: 0, + line1: [0; 16], + line1_ptr: 0, + line2: [0; 16], + line2_ptr: 0, }); static LCD_UPDATE: Signal = Signal::new(); @@ -76,14 +77,20 @@ pub async fn lcd_display_task(config: LcdConfig) { .with_cursor(ag_lcd::Cursor::On) .with_lines(ag_lcd::Lines::TwoLines) .build(); + lcd.set_blink(ag_lcd::Blink::Off); + lcd.set_cursor(ag_lcd::Cursor::Off); loop { LCD_UPDATE.wait().await; let buffer = SCREEN_BUFFER.lock().await; lcd.clear(); - for byte in &buffer.line1 { lcd.write(*byte); } + for byte in &buffer.line1 { + lcd.write(*byte); + } lcd.set_position(0, 1); - for byte in &buffer.line2 { lcd.write(*byte); } + for byte in &buffer.line2 { + lcd.write(*byte); + } Timer::after_millis(20).await; } }