From 9f6d52c80211f39878e3aa5fb2ae800df6dcaa31 Mon Sep 17 00:00:00 2001 From: "think.overdrive" Date: Mon, 2 Feb 2026 13:38:02 +0100 Subject: [PATCH] initial --- .cargo/config.toml | 41 +++++++++ .gitignore | 5 + Cargo.toml | 49 ++++++++++ build.rs | 28 ++++++ cfg.toml.template | 3 + rust-toolchain.toml | 2 + sdkconfig.defaults | 16 ++++ src/lib.rs | 3 + src/main.rs | 202 ++++++++++++++++++++++++++++++++++++++++ src/modules/display.rs | 204 +++++++++++++++++++++++++++++++++++++++++ src/modules/mod.rs | 2 + src/modules/wifi.rs | 65 +++++++++++++ src/server/http.rs | 47 ++++++++++ src/server/mod.rs | 2 + src/server/template.rs | 21 +++++ src/settings/mod.rs | 1 + src/settings/wifi.rs | 19 ++++ 17 files changed, 710 insertions(+) create mode 100644 .cargo/config.toml create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 build.rs create mode 100644 cfg.toml.template create mode 100644 rust-toolchain.toml create mode 100644 sdkconfig.defaults create mode 100644 src/lib.rs create mode 100644 src/main.rs create mode 100644 src/modules/display.rs create mode 100644 src/modules/mod.rs create mode 100644 src/modules/wifi.rs create mode 100644 src/server/http.rs create mode 100644 src/server/mod.rs create mode 100644 src/server/template.rs create mode 100644 src/settings/mod.rs create mode 100644 src/settings/wifi.rs diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..c4725a3 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,41 @@ +[build] +# Uncomment the relevant target for your chip here (ESP32, ESP32-S2, ESP32-S3 or ESP32-C3) +#target = "xtensa-esp32-espidf" +#target = "xtensa-esp32s2-espidf" +#target = "xtensa-esp32s3-espidf" +target = "riscv32imc-esp-espidf" + +[target.xtensa-esp32-espidf] +linker = "ldproxy" +runner = "espflash --monitor" +#rustflags = ["--cfg", "espidf_time64"] # Extending time_t for ESP IDF 5: https://github.com/esp-rs/rust/issues/110 + +[target.xtensa-esp32s2-espidf] +linker = "ldproxy" +runner = "espflash --monitor" +#rustflags = ["--cfg", "espidf_time64"] # Extending time_t for ESP IDF 5: https://github.com/esp-rs/rust/issues/110 + +[target.xtensa-esp32s3-espidf] +linker = "ldproxy" +runner = "espflash --monitor" +#rustflags = ["--cfg", "espidf_time64"] # Extending time_t for ESP IDF 5: https://github.com/esp-rs/rust/issues/110 + +[target.riscv32imc-esp-espidf] +linker = "ldproxy" +runner = "espflash --monitor" +# Future - necessary for the experimental "native build" of esp-idf-sys with ESP32C3. See also https://github.com/ivmarkov/embuild/issues/16 +# For ESP-IDF 5 add `espidf_time64` and for earlier versions - remove this flag: https://github.com/esp-rs/rust/issues/110 +#rustflags = ["-C", "default-linker-libraries"] +rustflags = ["--cfg", "espidf_time64", "-C", "default-linker-libraries"] + +[unstable] + +build-std = ["std", "panic_abort"] +#build-std-features = ["panic_immediate_abort"] # Required for older ESP-IDF versions without a realpath implementation + +[env] +# Note: these variables are not used when using pio builder (`cargo build --features pio`) +# Builds against ESP-IDF stable (v4.4) +ESP_IDF_VERSION = "release/v5.1" +# Builds against ESP-IDF master (mainline) +#ESP_IDF_VERSION = "master" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b696447 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/.vscode +/.embuild +/target +/Cargo.lock +/cfg.toml diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..8caa6ce --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,49 @@ +[package] +name = "esp32-c3-rust-std" +version = "0.1.0" +authors = ["Gerard CL "] +edition = "2021" +resolver = "2" + +[profile.release] +#opt-level = "s" +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 + +[profile.dev] +debug = true # Symbols are nice and they don't increase the size on Flash +opt-level = "z" + +[features] +default = ["native"] +native = ["esp-idf-sys/native"] + +[dependencies] +esp-idf-sys = { version = "0.36.1", features = ["binstart"] } +esp-idf-svc = { version = "0.51.0", features = ["experimental", "alloc", "std"] } +esp-idf-hal = { version = "0.45.2", features = ["critical-section"]} +ssd1306 = "0.10.0" +display-interface = "0.5.0" +display-interface-i2c = "0.5.0" +display-interface-spi = "0.5.0" +embedded-hal = "1.0.0" +embedded-svc = "0.28.1" +embedded-graphics = "0.8.1" +embedded-graphics-core = "0.4.0" +toml-cfg = { version = "0.2.0" } +anyhow = "=1.0.69" +log = { version = "0.4", features = [] } +heapless = {version = "0.8", features = ["serde"]} +spin = "0.10.0" +#lazy_static = "1.5.0" +# smol = "1.3" + +[build-dependencies] +embuild = { version = "0.33.1", features = ["elf"] } +toml-cfg = { version = "0.2.0" } +anyhow = "1" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..528a24d --- /dev/null +++ b/build.rs @@ -0,0 +1,28 @@ +use std::error::Error; + +#[toml_cfg::toml_config] +pub struct Config { + #[default("")] + wifi_ssid: &'static str, + #[default("")] + wifi_psk: &'static str, +} + +fn main() -> Result<(), Box> { + // Check if the `cfg.toml` file exists and has been filled out. + if !std::path::Path::new("cfg.toml").exists() { + return Err("You need to create a `cfg.toml` file with your Wi-Fi credentials! Start from `cfg.toml.template`.".into()); + } + + // The constant `CONFIG` is auto-generated by `toml_config`. + let app_config = CONFIG; + if app_config.wifi_ssid == "SET_ME" || app_config.wifi_psk == "SET_ME" { + return Err("You need to set the Wi-Fi credentials in `cfg.toml`!".into()); + } + + // Necessary because of this issue: https://github.com/rust-lang/cargo/issues/9641 + embuild::build::CfgArgs::output_propagated("ESP_IDF")?; + embuild::build::LinkArgs::output_propagated("ESP_IDF")?; + + Ok(()) +} diff --git a/cfg.toml.template b/cfg.toml.template new file mode 100644 index 0000000..146d2fd --- /dev/null +++ b/cfg.toml.template @@ -0,0 +1,3 @@ +[esp32-c3-rust-std] +wifi_ssid = "SET_ME" +wifi_psk = "SET_ME" diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..271800c --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" \ No newline at end of file diff --git a/sdkconfig.defaults b/sdkconfig.defaults new file mode 100644 index 0000000..d2bde7a --- /dev/null +++ b/sdkconfig.defaults @@ -0,0 +1,16 @@ +# Rust often needs a bit of an extra main task stack size compared to C (the default is 3K) +CONFIG_ESP_MAIN_TASK_STACK_SIZE=7000 +#CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=4096 + +# Use this to set FreeRTOS kernel tick frequency to 1000 Hz (100 Hz by default). +# This allows to use 1 ms granuality for thread sleeps (10 ms by default). +#CONFIG_FREERTOS_HZ=1000 + +# Workaround for https://github.com/espressif/esp-idf/issues/7631 +#CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=n +#CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=n + +# NAPT demo (router) +#CONFIG_LWIP_L2_TO_L3_COPY=y +#CONFIG_LWIP_IP_FORWARD=y +#CONFIG_LWIP_IPV4_NAPT=y diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..38f5ae8 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,3 @@ +pub mod modules; +pub mod server; +pub mod settings; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..e54ff34 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,202 @@ +use esp_idf_hal::{ + delay::FreeRtos, gpio::{Gpio8, Gpio9, Gpio5, Gpio6}, i2c::{self, I2C0, I2c, I2cConfig, I2cDriver}, peripheral::{Peripheral, PeripheralRef}, prelude::Peripherals, +}; +use esp_idf_svc::{ + eventloop::EspSystemEventLoop, + nvs::EspDefaultNvsPartition, + espnow::{self, EspNow, PeerInfo}, +}; +use esp_idf_sys::{self as _, soc_periph_temperature_sensor_clk_src_t_TEMPERATURE_SENSOR_CLK_SRC_DEFAULT}; +use log::*; +use anyhow::{Error, Result}; +use esp32_c3_rust_std::modules::{display::{DisplayDriver, init_logger}, wifi::WifiDriver}; +use esp32_c3_rust_std::server::http::HttpServer; +const OLED_I2C_ADDRESS: u8 = 0x3C; +const BROADCAST_ADDR: [u8; 6] = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]; + + +fn setup_i2c(i2c_peripheral: I2C0, sda: Gpio5, scl: Gpio6) -> Result, Error> { + use esp_idf_hal::units::Hertz; + let baudrate: Hertz = Hertz(400_000); + let i2c_config: I2cConfig = I2cConfig::new() + .baudrate(baudrate); + + let i2c_driver: I2cDriver = I2cDriver::new( + i2c_peripheral, + sda, + scl, + &i2c_config, + )?; + + Ok(i2c_driver) +} + +use std::env; +use std::sync::mpsc; +use std::thread; +use std::time::Duration; + +enum AppEvent { + EspNowRecv { mac: [u8; 6], data: Vec }, + SendDiscovery +} + +fn main() -> Result<(), Error> { + esp_idf_sys::link_patches(); //Needed for esp32-rs + unsafe { env::set_var("RUST_BACKTRACE", "1");}; + info!("Starting ESP32 C3 setup"); + + let peripherals = Peripherals::take()?; + let sys_loop = EspSystemEventLoop::take()?; + let nvs = EspDefaultNvsPartition::take()?; + //setup OLED + let i2c0 = peripherals.i2c0; + let scl_pin = peripherals.pins.gpio6; + let sda_pin = peripherals.pins.gpio5; + + init_logger(); + let i2c_driver = setup_i2c(i2c0, sda_pin, scl_pin)?; + let mut display_logger = DisplayDriver::new(i2c_driver, OLED_I2C_ADDRESS); + + // wifi module as client + let mut wifi = WifiDriver::new(peripherals.modem, sys_loop, nvs); + wifi.configure(); + wifi.start(); + + // server example for accepting HTTP requests + let mut server = HttpServer::new(); + server.set_handlers(); + info!("HTTP Server accepting connections"); + + //ESPNOW + + //channel for event + let (tx, rx) = mpsc::channel::(); + //espnow + let esp_now = EspNow::take()?; + //esp_now.set_channel(CHANNEL); + //thread receiver + let tx_callback = tx.clone(); + esp_now.register_recv_cb(move |mac, data| + { + let event = AppEvent::EspNowRecv { + mac: *mac.src_addr, + data: data.to_vec() + }; + let _ = tx_callback.send(event); + + })?; + if !esp_now.peer_exists(BROADCAST_ADDR)? { + let broadcast_peer = PeerInfo { + peer_addr: BROADCAST_ADDR, + encrypt: false, + ..Default::default() + }; + esp_now.add_peer(broadcast_peer)?; + info!("Added broadcast peer"); + } + + //thread discover + let tx_timer = tx.clone(); + thread::spawn(move || { + loop { + thread::sleep(Duration::from_secs(5)); + let _ = tx_timer.send(AppEvent::SendDiscovery); + } + + }); + + + let mut wifi_static = wifi.driver.ap_netif().get_ip_info().unwrap(); + // if we reached 10 times, we will print the ip address again + let mut count = 0; + loop { + match rx.recv_timeout(Duration::from_millis(1000)) { + Ok(AppEvent::EspNowRecv { mac, data }) => { + let msg = String::from_utf8_lossy(&data); + info!("RX from {:02X?}", mac); + if !esp_now.peer_exists(mac)? { + info!("New peer connected: {:02X?}", mac); + let new_peer = PeerInfo { + peer_addr: mac, + encrypt: false, + ..Default::default() + }; + if let Ok(_) = esp_now.add_peer(new_peer) { + info!("Added peer: {:02X?}", mac); + let _ = esp_now.send(mac, b"Hello Peer!"); + } + } + } + Ok(AppEvent::SendDiscovery) => { + info!("Sending broadcast discovery message"); + let _ = esp_now.send(BROADCAST_ADDR, b"DISCOVER-ALPHA"); + } + Err(mpsc::RecvTimeoutError::Timeout) => { + let wifi_info: esp_idf_svc::ipv4::IpInfo = wifi.driver.sta_netif().get_ip_info().unwrap(); + if wifi_static != wifi_info || count > 21{ + wifi_static = wifi_info; + info!( + "{:?}", + wifi_info.ip); + info!( + "{:?}", + wifi_info.subnet.gateway); + count = 0; + } + count += 1; + if let Ok(ref mut display_logger) = &mut display_logger{ + display_logger.draw_logs(); + } else { + info!("Failed to draw_logs") + } + + } + Err(mpsc::RecvTimeoutError::Disconnected) => { + info!("Disconnected"); + break; + } + } + + + // let wifi_info: esp_idf_svc::ipv4::IpInfo = wifi.driver.sta_netif().get_ip_info().unwrap(); + // if wifi_static != wifi_info || count > 10{ + // wifi_static = wifi_info; + // info!( + // "{:?}", + // wifi_info.ip + // //wifi.driver.sta_netif().get_ip_info().unwrap() + // ); + // info!( + // "{:?}", + // wifi_info.subnet.gateway + // //wifi.driver.sta_netif().get_ip_info().unwrap() + // ); + // count = 0; + // } + // count += 1; + // // info!( + // // "{:?}", + // // wifi_info.ip + // // //wifi.driver.sta_netif().get_ip_info().unwrap() + // // ); + // // info!( + // // "{:?}", + // // wifi_info.subnet.gateway + // // //wifi.driver.sta_netif().get_ip_info().unwrap() + // // ); + // // if let Some(dns) = wifi_info.dns { + // // info!("{:?}", dns); + // // } + // //display::draw_logs(&mut display); + // if let Ok(ref mut display_logger) = &mut display_logger{ + // display_logger.draw_logs(); + // } else { + // info!("Failed to draw_logs") + // } + // //display_logger.draw_logs(); + // FreeRtos::delay_ms(1000); + // //sleep(Duration::new(2, 0)); + } + Ok(()) +} \ No newline at end of file diff --git a/src/modules/display.rs b/src/modules/display.rs new file mode 100644 index 0000000..3657947 --- /dev/null +++ b/src/modules/display.rs @@ -0,0 +1,204 @@ +use log::{LevelFilter, Metadata, Record, Level}; +use core::fmt::{Debug, Write}; +use spin::Mutex; +use heapless::{String, Vec}; +use embedded_hal::i2c::{ErrorType, I2c}; + +use ssd1306::{ + prelude::*, + I2CDisplayInterface, + Ssd1306, + mode::BufferedGraphicsMode, + rotation::DisplayRotation, +}; + +use embedded_graphics::{ + mono_font::{MonoTextStyle, ascii::{FONT_4X6, FONT_5X7}},//, iso_8859_2::{self, FONT_4X6}}, + pixelcolor::BinaryColor, + prelude::*, + text::{Alignment, Text}, +}; + +const MAX_LOG_LINES: usize = 4; +//const MAX_CHARS_PER_LINE: usize = 128/6; +//const SCROLL_SPEED: u32 = 100; +//const SCROLL_POSITIONS: Mutex<[u32; MAX_LOG_LINES]> = Mutex::new([0u32; MAX_LOG_LINES]); +//const LAST_SCROLL_TIME: Mutex = Mutex::new(0); +const MAX_LINE_LENGTH: usize = 19; +const START_Y_OFFSET: i32 = 8; +static LOG_BUFFER: Mutex, MAX_LOG_LINES>> = Mutex::new(Vec::new()); + +pub type OledDisplay = Ssd1306< + I2CInterface, + DisplaySize128x64, + BufferedGraphicsMode>; + +pub type OledInterface = Ssd1306< + I2CInterface, + //DisplaySize128x64, + //DisplaySize64x32, + DisplaySize128x32, + BufferedGraphicsMode>; + + +pub struct DisplayDriver +where + I: I2c + ErrorType, + ::Error: core::fmt::Debug, + { + display: OledInterface, + } + +impl DisplayDriver +where + I: I2c + ErrorType, + ::Error: core::fmt::Debug, + { + pub fn new(i2c_driver: I, address: u8) -> Result::Error> { + let interface = I2CDisplayInterface::new_custom_address(i2c_driver, address); + log::info!("Driver address: {:?} ", address); + //let interface = I2CDisplayInterface::new(i2c_driver); + let mut display = Ssd1306::new( + interface, + //DisplaySize128x64, + //DisplaySize64x32, + DisplaySize128x32, + DisplayRotation::Rotate0) + .into_buffered_graphics_mode(); + + //display.init().expect("display init failed"); + if let Err(e) = display.init() { + log::error!("Display init failed: {:?}", e); + //return Err(e); + } + display.clear(BinaryColor::Off).expect("display clear failed"); + display.flush().expect("display flush failed"); + + Ok(Self { display }) + } + + pub fn draw_logs(&mut self) { + if let Err(e) = self.display.clear(BinaryColor::Off) { + log::error!("draw error: failed to clear display: {:?}", e); + return; + } + + let buffer = LOG_BUFFER.lock(); + let text_style = MonoTextStyle::new(&FONT_5X7, BinaryColor::On); + //let max_chars = MAX_CHARS_PER_LINE; + + for (i, line) in buffer.iter().enumerate() { + let y = START_Y_OFFSET + (i as i32) * FONT_5X7.character_size.height as i32; + // let substrings = Self::create_scroll_substring(line, max_chars); + + // for (j, substr) in substrings.iter().enumerate() { + // let x = 127 - (j * 6) as i32; // Position each substring horizontally + // if let Err(e) = Text::with_alignment(substr, Point::new(x, y), text_style, Alignment::Right) + // .draw(&mut self.display) { + // log::error!("draw error: failed to draw text: {:?}", e); + // break; + // } + // } + + if let Err(e) = Text::with_alignment(line, Point::new(99, y), text_style, Alignment::Right) + .draw(&mut self.display) { + log::error!("draw error: failed to draw text: {:?}",e); + break; + } + if let Err(e) = self.display.flush() { + log::error!("draw error: failed to flush display: {:?}",e); + } + } + } + fn wrap_text_to_lines(text: &str, max_len: usize) -> Vec, MAX_LOG_LINES> { + let mut lines: Vec, MAX_LOG_LINES> = Vec::, MAX_LOG_LINES>::new(); + let mut current_pos = 0; + while current_pos < text.len() { + let end_pos = (current_pos + max_len).min(text.len()); + let slice = &text[current_pos..end_pos]; + if let Ok(line) = String::try_from(slice) { + if lines.push(line).is_err() { + break; + } + } + current_pos = end_pos; + } + lines + } + fn create_scroll_substring(line: &String, max_chars: usize) -> Vec, 10> { + let mut substrings: Vec, 10> = Vec::, 10>::new(); + + if line.len() <= max_chars { + let mut substr = String::new(); + let _ = write!(&mut substr, "{}", line); + let _ = substrings.push(substr); + return substrings; + } + + //let line_chars: Vec = line.chars().collect(); + let mut extended_line: String = String::new(); + let _ = write!(&mut extended_line, "{} ", line); + let total_chars = extended_line.len(); + for i in 0..(total_chars + max_chars) { + let mut substr = String::new(); + for j in 0..max_chars { + let char_index = (i*j) % total_chars; + if char_index < extended_line.len() { + let ch = extended_line.chars().nth(char_index).unwrap(); + let _ = write!(&mut substr, "{}", ch); + } + } + let _ = substrings.push(substr); + } + substrings + + //let mut line_chars: Vec = Vec::new(); + // for ch in line.chars() { + // if line_chars.push(ch).is_err() { + // break; + // } + // } + // let total_chars = line_chars.len(); + + // for i in 0..(total_chars + max_chars) { + // let mut substr = String::new(); + // for j in 0..max_chars { + // let char_index = (i+ j) % total_chars; + // let _ = write!(&mut substr, "{}", line_chars[char_index]); + // } + // let _ = substrings.push(substr); + // } + // substrings + } + + } + + +pub struct DisplayLogger; + +impl log::Log for DisplayLogger { + fn enabled(&self, metadata: &Metadata) -> bool { + metadata.level() <= Level::Info + } + + fn log(&self, record: &Record) { + if self.enabled(record.metadata()) { + println!("[{}] {}: {}", record.level(), record.target(), record.args()); + let mut line: String = String::new(); + //let _ = write!(&mut line, "[{}] {}", record.level(), record.args()); + let _ = write!(&mut line, "{:?}", record.args()); + + let mut buffer = LOG_BUFFER.lock(); + if buffer.is_full() { + buffer.remove(0); + } + let _ = buffer.push(line); + } + } + + fn flush(&self) {} +} +pub fn init_logger() { + static LOGGER: DisplayLogger = DisplayLogger; + log::set_logger(&LOGGER).map(|()| log::set_max_level(LevelFilter::Info)).unwrap(); +} \ No newline at end of file diff --git a/src/modules/mod.rs b/src/modules/mod.rs new file mode 100644 index 0000000..7e704b8 --- /dev/null +++ b/src/modules/mod.rs @@ -0,0 +1,2 @@ +pub mod wifi; +pub mod display; \ No newline at end of file diff --git a/src/modules/wifi.rs b/src/modules/wifi.rs new file mode 100644 index 0000000..e72d3ad --- /dev/null +++ b/src/modules/wifi.rs @@ -0,0 +1,65 @@ +use embedded_svc::wifi::{ClientConfiguration, Configuration}; +use esp_idf_hal::{modem};//, peripherals::Peripherals}; +use esp_idf_svc::{ + eventloop::{EspEventLoop, System}, + nvs::{EspNvsPartition, NvsDefault}, + wifi::{EspWifi, NonBlocking}, + espnow::{EspNow, PeerInfo, SendStatus, ReceiveInfo, }, +}; +//use heapless::String as HString; +//use std::str::FromStr; +//use crate::{modules::wifi, settings::wifi::WifiConfig}; +use heapless; +use crate::settings::wifi::WIFI_CONFIG; + +pub struct WifiDriver<'a> { + pub driver: EspWifi<'a>, +} +//use esp_idf_hal::modem; +impl WifiDriver<'_> { + pub fn new( + //peripherals: Peripherals, + //esp_idf_hal::peripherals::{Modem}, + mymodem: modem::Modem, + sys_loop: EspEventLoop, + nvs: EspNvsPartition, + ) -> WifiDriver<'static> { + WifiDriver { + driver: EspWifi::new(mymodem, sys_loop, Some(nvs)).unwrap(), + } + } + + pub fn configure(&mut self) { + //let wifi_config = WifiConfig::load_or_default("wifi_config.toml").unwrap(); + //let wifi_config = WifiConfig::Config; + let heapless_ssid_str = heapless::String::<32>::try_from(WIFI_CONFIG.wifi_ssid).expect("SSID too long"); + let heapless_psk_str = heapless::String::<64>::try_from(WIFI_CONFIG.wifi_psk).expect("PSK too long"); + //let wifi_config = WifiConfig::new( + // heapless_ssid_str, + // heapless_psk_str, + //); + self.driver + .set_configuration(&Configuration::Client(ClientConfiguration { + ssid: heapless_ssid_str, + password: heapless_psk_str, + ..Default::default() + })) + .unwrap(); + } + + pub fn start(&mut self) { + self.driver.start().unwrap(); + self.driver.connect().unwrap(); + while !self.driver.is_connected().unwrap() { + let config = self.driver.get_configuration().unwrap(); + println!( + "Waiting for station SSID: {} on Channel #{:?}, with AuthMethod: {}, on BSSID: {:?}", + config.as_client_conf_ref().unwrap().ssid, + config.as_client_conf_ref().unwrap().channel, + config.as_client_conf_ref().unwrap().auth_method, + config.as_client_conf_ref().unwrap().bssid + ) + } + println!("Should be connected now"); + } +} diff --git a/src/server/http.rs b/src/server/http.rs new file mode 100644 index 0000000..505591e --- /dev/null +++ b/src/server/http.rs @@ -0,0 +1,47 @@ +use embedded_svc::{ + http::{Headers, Method}, + io::Write, +}; +use esp_idf_svc::http::server::{Configuration, EspHttpServer}; +use log::info; + +use super::template::render_html; + +pub struct HttpServer<'a> { + server: EspHttpServer<'a>, +} + +impl<'a> HttpServer<'a> { + // Set the HTTP server + pub fn new() -> HttpServer<'a> { + info!("Server creating"); + + HttpServer { + server: EspHttpServer::new(&Configuration::default()).unwrap(), + } + } + + pub fn set_handlers(&mut self) { + info!("Server handlers setup"); + + self.server + .fn_handler("/", Method::Get, move |request| -> Result<(), Box> { + let html = render_html("World Of Hurt"); + let mut response = request.into_ok_response().map_err(|e| Box::new(e) as Box)?; + response.write_all(html.as_bytes()).map_err(|e| Box::new(e) as Box)?; + info!("request for /"); + Ok(()) + }) + .unwrap(); + + self.server + .fn_handler("/host", Method::Get, move |request| -> Result<(), Box> { + let html = render_html(request.host().unwrap_or_default()); + let mut response = request.into_ok_response().map_err(|e| Box::new(e) as Box)?; + response.write_all(html.as_bytes()).map_err(|e| Box::new(e) as Box)?; + info!("request for /host"); + Ok(()) + }) + .unwrap(); + } +} diff --git a/src/server/mod.rs b/src/server/mod.rs new file mode 100644 index 0000000..c8d0bef --- /dev/null +++ b/src/server/mod.rs @@ -0,0 +1,2 @@ +pub mod http; +mod template; diff --git a/src/server/template.rs b/src/server/template.rs new file mode 100644 index 0000000..c085287 --- /dev/null +++ b/src/server/template.rs @@ -0,0 +1,21 @@ +fn templated(content: impl AsRef) -> String { + format!( + r#" + + + + + esp-rs web server + + + {} + + +"#, + content.as_ref() + ) +} + +pub fn render_html(content: impl AsRef) -> String { + templated(format!("Hello {}!", content.as_ref())) +} diff --git a/src/settings/mod.rs b/src/settings/mod.rs new file mode 100644 index 0000000..3b0e25e --- /dev/null +++ b/src/settings/mod.rs @@ -0,0 +1 @@ +pub mod wifi; diff --git a/src/settings/wifi.rs b/src/settings/wifi.rs new file mode 100644 index 0000000..6f6ced4 --- /dev/null +++ b/src/settings/wifi.rs @@ -0,0 +1,19 @@ +#[toml_cfg::toml_config] +#[derive(Default)] +pub struct WifiConfig { + #[default("")] + pub wifi_ssid: &'static str, + #[default("")] + pub wifi_psk: &'static str, +} +// impl WifiConfig { +// pub fn new( +// wifi_ssid: impl Into>, +// wifi_psk: impl Into>, +// ) -> Self { +// Self { +// wifi_ssid: wifi_ssid.into(), +// wifi_psk: wifi_psk.into(), +// } +// } +// } \ No newline at end of file