commit 18e9f86c36378aa80d5e576c3e120b2f0c0f61ea Author: Thomas Klaehn Date: Sat Feb 8 08:48:24 2025 +0100 Initial commit Signed-off-by: Thomas Klaehn diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..16d902e --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,28 @@ +[build] +target = "riscv32imc-esp-espidf" + +[target.riscv32imc-esp-espidf] +linker = "ldproxy" +runner = "espflash flash --monitor" +# Future - necessary for the experimental "native build" of esp-idf-sys with ESP32C3 +# See also https://github.com/ivmarkov/embuild/issues/16 +rustflags = ["--cfg", "espidf_time64"] + +[unstable] +build-std = ["std", "panic_abort"] + +[env] +# Enables the esp-idf-sys "native" build feature (`cargo build --features native`) to build against ESP-IDF (v5.3.2) +ESP_IDF_VERSION = { value = "tag:v5.3.2" } + +# These configurations will pick up your custom "sdkconfig.release", "sdkconfig.debug" or "sdkconfig.defaults[.*]" files +# that you might put in the root of the project +# The easiest way to generate a full "sdkconfig[.release|debug]" configuration (as opposed to manually enabling only the necessary flags via "sdkconfig.defaults[.*]" +# is by running "cargo pio espidf menuconfig" (that is, if using the pio builder) +#ESP_IDF_SDKCONFIG = { value = "./sdkconfig.release", relative = true } +#ESP_IDF_SDKCONFIG = { value = "./sdkconfig.debug", relative = true } +ESP_IDF_SDKCONFIG_DEFAULTS = { value = "./sdkconfig.defaults", relative = true } +# ESP-IDF will be installed in ~/.espressif so it can be reused across the different examples. +# See also https://github.com/esp-rs/esp-idf-sys/blob/master/BUILD-OPTIONS.md#esp_idf_tools_install_dir-esp_idf_tools_install_dir +ESP_IDF_TOOLS_INSTALL_DIR = { value = "global" } + diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..10aa2a5 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,79 @@ +# Base image +FROM debian:bookworm-slim +ENV DEBIAN_FRONTEND=noninteractive +ENV LC_ALL=C.UTF-8 +ENV LANG=C.UTF-8 + +# Arguments +ARG CONTAINER_USER=esp +ARG CONTAINER_GROUP=esp +ARG NIGHTLY_VERSION=nightly-2024-06-30 +ARG ESP_IDF_VERSION=v5.2.2 +ARG ESP_BOARD=esp32c3 + +# Install dependencies +RUN apt-get update \ + && apt-get install -y git wget flex bison gperf python3 python3-pip python3-venv \ + cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0 \ + llvm-dev libclang-dev clang pkg-config unzip libusb-1.0-0 \ + libpython3-all-dev python3-virtualenv curl \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* /tmp/library-scripts + +# Set users +RUN adduser --disabled-password --gecos "" ${CONTAINER_USER} +RUN adduser ${CONTAINER_USER} root +USER ${CONTAINER_USER} +WORKDIR /home/${CONTAINER_USER} + +# Install rustup +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- \ + --default-toolchain ${NIGHTLY_VERSION} -y --profile minimal \ + --component rust-src,clippy,rustfmt + +# Update envs +ENV PATH=${PATH}:$HOME/.cargo/bin + +# Install extra crates +RUN ARCH=$($HOME/.cargo/bin/rustup show | grep "Default host" | sed -e 's/.* //') && \ + curl -L "https://github.com/esp-rs/espflash/releases/latest/download/cargo-espflash-${ARCH}.zip" -o "${HOME}/.cargo/bin/cargo-espflash.zip" && \ + unzip "${HOME}/.cargo/bin/cargo-espflash.zip" -d "${HOME}/.cargo/bin/" && \ + rm "${HOME}/.cargo/bin/cargo-espflash.zip" && \ + chmod u+x "${HOME}/.cargo/bin/cargo-espflash" && \ + curl -L "https://github.com/esp-rs/espflash/releases/latest/download/espflash-${ARCH}.zip" -o "${HOME}/.cargo/bin/espflash.zip" && \ + unzip "${HOME}/.cargo/bin/espflash.zip" -d "${HOME}/.cargo/bin/" && \ + rm "${HOME}/.cargo/bin/espflash.zip" && \ + chmod u+x "${HOME}/.cargo/bin/espflash" && \ + curl -L "https://github.com/esp-rs/esp-web-flash-server/releases/latest/download/web-flash-${ARCH}.zip" -o "${HOME}/.cargo/bin/web-flash.zip" && \ + unzip "${HOME}/.cargo/bin/web-flash.zip" -d "${HOME}/.cargo/bin/" && \ + rm "${HOME}/.cargo/bin/web-flash.zip" && \ + chmod u+x "${HOME}/.cargo/bin/web-flash" && \ + curl -L "https://github.com/esp-rs/embuild/releases/latest/download/ldproxy-${ARCH}.zip" -o "${HOME}/.cargo/bin/ldproxy.zip" && \ + unzip "${HOME}/.cargo/bin/ldproxy.zip" -d "${HOME}/.cargo/bin/" && \ + rm "${HOME}/.cargo/bin/ldproxy.zip" && \ + chmod u+x "${HOME}/.cargo/bin/ldproxy" && \ + GENERATE_VERSION=$(git ls-remote --refs --sort="version:refname" --tags "https://github.com/cargo-generate/cargo-generate" | cut -d/ -f3- | tail -n1) && \ + GENERATE_URL="https://github.com/cargo-generate/cargo-generate/releases/latest/download/cargo-generate-${GENERATE_VERSION}-${ARCH}.tar.gz" && \ + curl -L "${GENERATE_URL}" -o "${HOME}/.cargo/bin/cargo-generate.tar.gz" && \ + tar xf "${HOME}/.cargo/bin/cargo-generate.tar.gz" -C "${HOME}/.cargo/bin/" && \ + rm "${HOME}/.cargo/bin/cargo-generate.tar.gz" && \ + chmod u+x "${HOME}/.cargo/bin/cargo-generate" + +# Install esp-idf +RUN mkdir -p ${HOME}/.espressif/frameworks/ \ + && git clone --branch ${ESP_IDF_VERSION} -q --depth 1 --shallow-submodules \ + --recursive https://github.com/espressif/esp-idf.git \ + ${HOME}/.espressif/frameworks/esp-idf \ + && python3 ${HOME}/.espressif/frameworks/esp-idf/tools/idf_tools.py install cmake \ + && ${HOME}/.espressif/frameworks/esp-idf/install.sh ${ESP_BOARD} \ + && rm -rf .espressif/dist \ + && rm -rf .espressif/frameworks/esp-idf/docs \ + && rm -rf .espressif/frameworks/esp-idf/examples \ + && rm -rf .espressif/frameworks/esp-idf/tools/esp_app_trace \ + && rm -rf .espressif/frameworks/esp-idf/tools/test_idf_size + +# Activate ESP environment +ENV IDF_TOOLS_PATH=${HOME}/.espressif +RUN echo "source ${HOME}/.espressif/frameworks/esp-idf/export.sh > /dev/null 2>&1" >> ~/.bashrc + +CMD "/bin/bash" diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100755 index 0000000..7a09006 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,51 @@ +{ + "name": "espressif-training", + // Comment the image and use the build property to build the image from the + // Dockerfile instead of downloading it from https://hub.docker.com/r/espressif/rust-std-training + // "image": "docker.io/espressif/rust-std-training", + "build": { + "dockerfile": "Dockerfile", + "args": { + "NIGHTLY_VERSION": "nightly-2025-01-01" + } + }, + // Privileged container in order to access /dev + "privileged": true, + // Mount USB devices (debug probes, UART interfaces, ...) + "mounts": [ + "source=/dev/bus/usb/,target=/dev/bus/usb/,type=bind" + ], + "runArgs": [ + "--device=/dev/ttyACM0" + ], + "customizations": { + "vscode": { + "settings": { + "editor.formatOnPaste": true, + "editor.formatOnSave": true, + "editor.formatOnSaveMode": "modifications", + "editor.formatOnType": true, + "lldb.executable": "/usr/bin/lldb", + "files.watcherExclude": { + "**/target/**": true + }, + "rust-analyzer.checkOnSave.command": "clippy", + "[rust]": { + "editor.defaultFormatter": "rust-lang.rust-analyzer" + } + }, + "extensions": [ + "rust-lang.rust-analyzer", + "tamasfe.even-better-toml", + "vadimcn.vscode-lldb", + "serayuzgur.crates", + "mutantdino.resourcemonitor", + "yzhang.markdown-all-in-one", + "Wokwi.wokwi-vscode" + ] + } + }, + "remoteUser": "esp", + "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached", + "workspaceFolder": "/workspace" +} diff --git a/.devcontainer/test.sh b/.devcontainer/test.sh new file mode 100644 index 0000000..71d40da --- /dev/null +++ b/.devcontainer/test.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +set -ef + +echo "Compiling $1" + +cd /home/esp/workspace/$1 + +if [ -f cfg.toml.example ]; then + # Rename file to cfg.toml + cp cfg.toml.example cfg.toml + # Replace defaults + sed -i 's/wifi_ssid = "FBI Surveillance Van"/wifi_ssid = "Wokwi-GUEST"/g' cfg.toml + sed -i 's/wifi_psk = "hunter2"/wifi_psk = ""/g' cfg.toml + sed -i 's/mqtt_user = "horse"/mqtt_user = "user"/g' cfg.toml + sed -i 's/mqtt_pass = "CorrectHorseBatteryStaple"/mqtt_pass = "pass"/g' cfg.toml + sed -i 's/mqtt_host = "yourpc.local"/mqtt_host = "host"/g' cfg.toml +fi + +$HOME/.cargo/bin/cargo clean +$HOME/.cargo/bin/cargo build + +# Check examples +if [[ "$1" == advanced/button-interrupt ]]; then + $HOME/.cargo/bin/cargo build --example solution + $HOME/.cargo/bin/cargo build --example solution_led + # Simulate with Wokwi + sed -i 's/^[[:space:]]*firmware[[:space:]]*=[[:space:]]*["'"'"']\([^"'"'"']*\)["'"'"']\([[:space:]]*\)$/\nfirmware = "target\/riscv32imc-esp-espidf\/debug\/examples\/solution"/' wokwi.toml +fi + +if [[ "$1" == advanced/i2c-sensor-reading ]]; then + $HOME/.cargo/bin/cargo build --example part_1 + $HOME/.cargo/bin/cargo build --example part_2 +fi + +if [[ "$1" == intro/http-client ]]; then + $HOME/.cargo/bin/cargo build --example http_client + $HOME/.cargo/bin/cargo build --example https_client + # Simulate with Wokwi + sed -i 's/^[[:space:]]*firmware[[:space:]]*=[[:space:]]*["'"'"']\([^"'"'"']*\)["'"'"']\([[:space:]]*\)$/\nfirmware = "target\/riscv32imc-esp-espidf\/debug\/examples\/http_client"/' wokwi.toml +fi + +if [[ "$1" == intro/http-server ]]; then + $HOME/.cargo/bin/cargo build --example http_server +fi + +if [[ "$1" == intro/mqtt/exercise ]]; then + $HOME/.cargo/bin/cargo build --example solution_publ_rcv + $HOME/.cargo/bin/cargo build --example solution_publ +fi diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ecd5a24 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +.vscode +.idea +target +Cargo.lock +cfg.toml +__pycache__ +.DS_Store +.embuild/ +.vale +.vale.ini +components_esp32c3.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..2c53ec4 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "hardware-check" +version = "0.1.0" +authors = [ + "Anatol Ulrich ", + "Sergio Gasquez ", +] +edition = "2021" +resolver = "2" + +[[bin]] +name = "hardware-check" +harness = false # We can't use the default rust libtest harness for a crosscompile target + +[profile.release] +opt-level = "s" + +[profile.dev] +debug = true # Symbols are nice and they don't increase the size on Flash +opt-level = "z" + +[dependencies] +anyhow = "=1.0.95" +esp-idf-svc = "=0.50.1" +log = "=0.4.22" +rgb-led = { path = "lib/rgb-led" } +toml-cfg = "=0.1.3" +wifi = { path = "lib/wifi" } + +[build-dependencies] +embuild = "=0.33.0" +toml-cfg = "=0.1.3" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..8c39435 --- /dev/null +++ b/build.rs @@ -0,0 +1,22 @@ +#[toml_cfg::toml_config] +pub struct Config { + #[default("")] + wifi_ssid: &'static str, + #[default("")] + wifi_psk: &'static str, +} + +fn main() { + // Check if the `cfg.toml` file exists and has been filled out. + if !std::path::Path::new("cfg.toml").exists() { + panic!("You need to create a `cfg.toml` file with your Wi-Fi credentials! Use `cfg.toml.example` as a template."); + } + + // The constant `CONFIG` is auto-generated by `toml_config`. + let app_config = CONFIG; + if app_config.wifi_ssid == "FBI Surveillance Van" || app_config.wifi_psk == "hunter2" { + panic!("You need to set the Wi-Fi credentials in `cfg.toml`!"); + } + + embuild::espidf::sysenv::output(); +} diff --git a/lib/rgb-led/.cargo/config.toml b/lib/rgb-led/.cargo/config.toml new file mode 100644 index 0000000..3fafebc --- /dev/null +++ b/lib/rgb-led/.cargo/config.toml @@ -0,0 +1,28 @@ +[build] +target = "riscv32imc-esp-espidf" + +[target.riscv32imc-esp-espidf] +linker = "ldproxy" +runner = "espflash flash --monitor" +# Future - necessary for the experimental "native build" of esp-idf-sys with ESP32C3 +# See also https://github.com/ivmarkov/embuild/issues/16 +rustflags = ["--cfg", "espidf_time64"] + +[unstable] +build-std = ["panic_abort", "std"] + +[env] +# Enables the esp-idf-sys "native" build feature (`cargo build --features native`) to build against ESP-IDF (v5.3.2) +ESP_IDF_VERSION = { value = "tag:v5.3.2" } + +# These configurations will pick up your custom "sdkconfig.release", "sdkconfig.debug" or "sdkconfig.defaults[.*]" files +# that you might put in the root of the project +# The easiest way to generate a full "sdkconfig[.release|debug]" configuration (as opposed to manually enabling only the necessary flags via "sdkconfig.defaults[.*]" +# is by running "cargo pio espidf menuconfig" (that is, if using the pio builder) +#ESP_IDF_SDKCONFIG = { value = "./sdkconfig.release", relative = true } +#ESP_IDF_SDKCONFIG = { value = "./sdkconfig.debug", relative = true } +ESP_IDF_SDKCONFIG_DEFAULTS = { value = "./sdkconfig.defaults", relative = true } +# ESP-IDF will be installed in ~/.espressif so it can be reused across the different examples. +# See also https://github.com/esp-rs/esp-idf-sys/blob/master/BUILD-OPTIONS.md#esp_idf_tools_install_dir-esp_idf_tools_install_dir +ESP_IDF_TOOLS_INSTALL_DIR = { value = "global" } + diff --git a/lib/rgb-led/.gitignore b/lib/rgb-led/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/lib/rgb-led/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/lib/rgb-led/Cargo.toml b/lib/rgb-led/Cargo.toml new file mode 100644 index 0000000..69d1914 --- /dev/null +++ b/lib/rgb-led/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "rgb-led" +version = "0.1.0" +edition = "2021" +authors = ["Sergio Gasquez "] + +[dependencies] +anyhow = "=1.0.95" +esp-idf-svc = "=0.50.1" +esp-idf-hal ={ version = "=0.45.0", features = ["rmt-legacy"] } +log = "=0.4.22" +rgb = "0.8.29" + +[build-dependencies] +embuild = "=0.33.0" diff --git a/lib/rgb-led/build.rs b/lib/rgb-led/build.rs new file mode 100644 index 0000000..112ec3f --- /dev/null +++ b/lib/rgb-led/build.rs @@ -0,0 +1,3 @@ +fn main() { + embuild::espidf::sysenv::output(); +} diff --git a/lib/rgb-led/examples/ws2812.rs b/lib/rgb-led/examples/ws2812.rs new file mode 100644 index 0000000..1f65c37 --- /dev/null +++ b/lib/rgb-led/examples/ws2812.rs @@ -0,0 +1,27 @@ +use anyhow::Result; +use esp_idf_svc::hal::{delay::FreeRtos, peripherals::Peripherals}; +use log::info; +use rgb_led::WS2812RMT; + +fn main() -> Result<()> { + esp_idf_svc::sys::link_patches(); + esp_idf_svc::log::EspLogger::initialize_default(); + + let peripherals = Peripherals::take().unwrap(); + // Onboard RGB LED pin + // Rust ESP Board gpio2, ESP32-C3-DevKitC-02 gpio8 + let led = peripherals.pins.gpio2; + let channel = peripherals.rmt.channel0; + let mut ws2812 = WS2812RMT::new(led, channel)?; + loop { + info!("Red!"); + ws2812.set_pixel(rgb::RGB8::new(255, 0, 0))?; + FreeRtos::delay_ms(1000); + info!("Green!"); + ws2812.set_pixel(rgb::RGB8::new(0, 255, 0))?; + FreeRtos::delay_ms(1000); + info!("Blue!"); + ws2812.set_pixel(rgb::RGB8::new(0, 0, 255))?; + FreeRtos::delay_ms(1000); + } +} diff --git a/lib/rgb-led/rust-toolchain.toml b/lib/rgb-led/rust-toolchain.toml new file mode 100644 index 0000000..3116971 --- /dev/null +++ b/lib/rgb-led/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "nightly-2025-01-01" +components = ["rust-src"] diff --git a/lib/rgb-led/src/lib.rs b/lib/rgb-led/src/lib.rs new file mode 100644 index 0000000..34ed1c3 --- /dev/null +++ b/lib/rgb-led/src/lib.rs @@ -0,0 +1,48 @@ +use anyhow::Result; +use core::time::Duration; +use esp_idf_hal::{ + gpio::OutputPin, + peripheral::Peripheral, + rmt::{config::TransmitConfig, FixedLengthSignal, PinState, Pulse, RmtChannel, TxRmtDriver}, +}; + +pub use rgb::RGB8; + +pub struct WS2812RMT<'a> { + tx_rtm_driver: TxRmtDriver<'a>, +} + +impl<'d> WS2812RMT<'d> { + // Rust ESP Board gpio2, ESP32-C3-DevKitC-02 gpio8 + pub fn new( + led: impl Peripheral

+ 'd, + channel: impl Peripheral

+ 'd, + ) -> Result { + let config = TransmitConfig::new().clock_divider(2); + let tx = TxRmtDriver::new(channel, led, &config)?; + Ok(Self { tx_rtm_driver: tx }) + } + + pub fn set_pixel(&mut self, rgb: RGB8) -> Result<()> { + let color: u32 = ((rgb.g as u32) << 16) | ((rgb.r as u32) << 8) | rgb.b as u32; + let ticks_hz = self.tx_rtm_driver.counter_clock()?; + let t0h = Pulse::new_with_duration(ticks_hz, PinState::High, &ns(350))?; + let t0l = Pulse::new_with_duration(ticks_hz, PinState::Low, &ns(800))?; + let t1h = Pulse::new_with_duration(ticks_hz, PinState::High, &ns(700))?; + let t1l = Pulse::new_with_duration(ticks_hz, PinState::Low, &ns(600))?; + let mut signal = FixedLengthSignal::<24>::new(); + for i in (0..24).rev() { + let p = 2_u32.pow(i); + let bit = p & color != 0; + let (high_pulse, low_pulse) = if bit { (t1h, t1l) } else { (t0h, t0l) }; + signal.set(23 - i as usize, &(high_pulse, low_pulse))?; + } + self.tx_rtm_driver.start_blocking(&signal)?; + + Ok(()) + } +} + +fn ns(nanos: u64) -> Duration { + Duration::from_nanos(nanos) +} diff --git a/lib/wifi/.cargo/config.toml b/lib/wifi/.cargo/config.toml new file mode 100644 index 0000000..3fafebc --- /dev/null +++ b/lib/wifi/.cargo/config.toml @@ -0,0 +1,28 @@ +[build] +target = "riscv32imc-esp-espidf" + +[target.riscv32imc-esp-espidf] +linker = "ldproxy" +runner = "espflash flash --monitor" +# Future - necessary for the experimental "native build" of esp-idf-sys with ESP32C3 +# See also https://github.com/ivmarkov/embuild/issues/16 +rustflags = ["--cfg", "espidf_time64"] + +[unstable] +build-std = ["panic_abort", "std"] + +[env] +# Enables the esp-idf-sys "native" build feature (`cargo build --features native`) to build against ESP-IDF (v5.3.2) +ESP_IDF_VERSION = { value = "tag:v5.3.2" } + +# These configurations will pick up your custom "sdkconfig.release", "sdkconfig.debug" or "sdkconfig.defaults[.*]" files +# that you might put in the root of the project +# The easiest way to generate a full "sdkconfig[.release|debug]" configuration (as opposed to manually enabling only the necessary flags via "sdkconfig.defaults[.*]" +# is by running "cargo pio espidf menuconfig" (that is, if using the pio builder) +#ESP_IDF_SDKCONFIG = { value = "./sdkconfig.release", relative = true } +#ESP_IDF_SDKCONFIG = { value = "./sdkconfig.debug", relative = true } +ESP_IDF_SDKCONFIG_DEFAULTS = { value = "./sdkconfig.defaults", relative = true } +# ESP-IDF will be installed in ~/.espressif so it can be reused across the different examples. +# See also https://github.com/esp-rs/esp-idf-sys/blob/master/BUILD-OPTIONS.md#esp_idf_tools_install_dir-esp_idf_tools_install_dir +ESP_IDF_TOOLS_INSTALL_DIR = { value = "global" } + diff --git a/lib/wifi/.gitignore b/lib/wifi/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/lib/wifi/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/lib/wifi/Cargo.toml b/lib/wifi/Cargo.toml new file mode 100644 index 0000000..30d81dc --- /dev/null +++ b/lib/wifi/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "wifi" +version = "0.1.0" +edition = "2021" +authors = ["Sergio Gasquez "] + +[dependencies] +anyhow = "=1.0.95" +esp-idf-svc = "=0.50.1" +log = "=0.4.22" + +[build-dependencies] +embuild = "=0.33.0" + +[dev-dependencies] +toml-cfg = "=0.1.3" diff --git a/lib/wifi/build.rs b/lib/wifi/build.rs new file mode 100644 index 0000000..112ec3f --- /dev/null +++ b/lib/wifi/build.rs @@ -0,0 +1,3 @@ +fn main() { + embuild::espidf::sysenv::output(); +} diff --git a/lib/wifi/cfg.toml.example b/lib/wifi/cfg.toml.example new file mode 100644 index 0000000..a5ea911 --- /dev/null +++ b/lib/wifi/cfg.toml.example @@ -0,0 +1,3 @@ +[wifi] +wifi_ssid = "FBI Surveillance Van" +wifi_psk = "hunter2" diff --git a/lib/wifi/examples/wifi.rs b/lib/wifi/examples/wifi.rs new file mode 100644 index 0000000..d9d607f --- /dev/null +++ b/lib/wifi/examples/wifi.rs @@ -0,0 +1,40 @@ +use anyhow::{bail, Result}; +use esp_idf_svc::{eventloop::EspSystemEventLoop, hal::prelude::Peripherals}; +use wifi::wifi; + +/// This configuration is picked up at compile time by `build.rs` from the +/// file `cfg.toml`. +#[toml_cfg::toml_config] +pub struct Config { + #[default("")] + wifi_ssid: &'static str, + #[default("")] + wifi_psk: &'static str, +} + +fn main() -> Result<()> { + esp_idf_svc::sys::link_patches(); + esp_idf_svc::log::EspLogger::initialize_default(); + + let peripherals = Peripherals::take().unwrap(); + let sysloop = EspSystemEventLoop::take()?; + + let app_config = CONFIG; + // Connect to the Wi-Fi network + let _wifi = match wifi( + app_config.wifi_ssid, + app_config.wifi_psk, + peripherals.modem, + sysloop, + ) { + Ok(inner) => { + println!("Connected to Wi-Fi network!"); + inner + } + Err(err) => { + // Red! + bail!("Could not connect to Wi-Fi network: {:?}", err) + } + }; + Ok(()) +} diff --git a/lib/wifi/rust-toolchain.toml b/lib/wifi/rust-toolchain.toml new file mode 100644 index 0000000..3116971 --- /dev/null +++ b/lib/wifi/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "nightly-2025-01-01" +components = ["rust-src"] diff --git a/lib/wifi/sdkconfig.defaults b/lib/wifi/sdkconfig.defaults new file mode 100644 index 0000000..8923886 --- /dev/null +++ b/lib/wifi/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_ESP_MAIN_TASK_STACK_SIZE=20000 +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=4096 diff --git a/lib/wifi/src/lib.rs b/lib/wifi/src/lib.rs new file mode 100644 index 0000000..8debbf3 --- /dev/null +++ b/lib/wifi/src/lib.rs @@ -0,0 +1,78 @@ +use anyhow::{bail, Result}; +use esp_idf_svc::{ + eventloop::EspSystemEventLoop, + hal::peripheral, + wifi::{AuthMethod, BlockingWifi, ClientConfiguration, Configuration, EspWifi}, +}; +use log::info; + +pub fn wifi( + ssid: &str, + pass: &str, + modem: impl peripheral::Peripheral

+ 'static, + sysloop: EspSystemEventLoop, +) -> Result>> { + let mut auth_method = AuthMethod::WPA2Personal; + if ssid.is_empty() { + bail!("Missing WiFi name") + } + if pass.is_empty() { + auth_method = AuthMethod::None; + info!("Wifi password is empty"); + } + let mut esp_wifi = EspWifi::new(modem, sysloop.clone(), None)?; + + let mut wifi = BlockingWifi::wrap(&mut esp_wifi, sysloop)?; + + wifi.set_configuration(&Configuration::Client(ClientConfiguration::default()))?; + + info!("Starting wifi..."); + + wifi.start()?; + + info!("Scanning..."); + + let ap_infos = wifi.scan()?; + + let ours = ap_infos.into_iter().find(|a| a.ssid == ssid); + + let channel = if let Some(ours) = ours { + info!( + "Found configured access point {} on channel {}", + ssid, ours.channel + ); + Some(ours.channel) + } else { + info!( + "Configured access point {} not found during scanning, will go with unknown channel", + ssid + ); + None + }; + + wifi.set_configuration(&Configuration::Client(ClientConfiguration { + ssid: ssid + .try_into() + .expect("Could not parse the given SSID into WiFi config"), + password: pass + .try_into() + .expect("Could not parse the given password into WiFi config"), + channel, + auth_method, + ..Default::default() + }))?; + + info!("Connecting wifi..."); + + wifi.connect()?; + + info!("Waiting for DHCP lease..."); + + wifi.wait_netif_up()?; + + let ip_info = wifi.wifi().sta_netif().get_ip_info()?; + + info!("Wifi DHCP info: {:?}", ip_info); + + Ok(Box::new(esp_wifi)) +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..3116971 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "nightly-2025-01-01" +components = ["rust-src"] diff --git a/scripts/jtag-host.sh b/scripts/jtag-host.sh new file mode 100755 index 0000000..b9a1841 --- /dev/null +++ b/scripts/jtag-host.sh @@ -0,0 +1,10 @@ +#! /bin/sh + +git clone https://github.com/espressif/openocd-esp32.git + +install -m 0644 openocd-esp32/contrib/60-openocd.rules /etc/udev/rules.d + +rm -rf openocd-esp32/ + +udevadm control -R +udevadm trigger \ No newline at end of file diff --git a/sdkconfig.defaults b/sdkconfig.defaults new file mode 100644 index 0000000..8923886 --- /dev/null +++ b/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_ESP_MAIN_TASK_STACK_SIZE=20000 +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=4096 diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..0939990 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,68 @@ +use anyhow::{bail, Result}; +use esp_idf_svc::eventloop::EspSystemEventLoop; +use esp_idf_svc::hal::prelude::Peripherals; +use log::info; +use rgb_led::{RGB8, WS2812RMT}; +use wifi::wifi; + +/// This configuration is picked up at compile time by `build.rs` from the +/// file `cfg.toml`. +#[toml_cfg::toml_config] +pub struct Config { + #[default("Wokwi-GUEST")] + wifi_ssid: &'static str, + #[default("")] + wifi_psk: &'static str, +} + +/// Entry point to our application. +/// +/// It sets up a Wi-Fi connection to the Access Point given in the +/// configuration, then blinks the RGB LED green/blue. +/// +/// If the LED goes solid red, then it was unable to connect to your Wi-Fi +/// network. +fn main() -> Result<()> { + esp_idf_svc::sys::link_patches(); + esp_idf_svc::log::EspLogger::initialize_default(); + + let peripherals = Peripherals::take().unwrap(); + let sysloop = EspSystemEventLoop::take()?; + + info!("Hello, world!"); + + // Start the LED off yellow + let mut led = WS2812RMT::new(peripherals.pins.gpio2, peripherals.rmt.channel0)?; + led.set_pixel(RGB8::new(50, 50, 0))?; + + // The constant `CONFIG` is auto-generated by `toml_config`. + let app_config = CONFIG; + + // Connect to the Wi-Fi network + let _wifi = match wifi( + app_config.wifi_ssid, + app_config.wifi_psk, + peripherals.modem, + sysloop, + ) { + Ok(inner) => inner, + Err(err) => { + // Red! + led.set_pixel(RGB8::new(50, 0, 0))?; + bail!("Could not connect to Wi-Fi network: {:?}", err) + } + }; + + loop { + // Blue! + led.set_pixel(RGB8::new(0, 0, 50))?; + // Wait... + std::thread::sleep(std::time::Duration::from_secs(1)); + info!("Hello, world!"); + + // Green! + led.set_pixel(RGB8::new(0, 50, 0))?; + // Wait... + std::thread::sleep(std::time::Duration::from_secs(1)); + } +} diff --git a/workspace.code-workspace b/workspace.code-workspace new file mode 100644 index 0000000..3fa907f --- /dev/null +++ b/workspace.code-workspace @@ -0,0 +1,12 @@ +{ + "folders": [ + { + "path": ".", + "name": "ESP32" + }, + // { "path": "/usr/src/libperiCORE", "name":"libperiCORE" }, + // { "path": "/usr/src/seve", "name":"sève" }, + // { "path": "/usr/src/periCORE-buildsystem", "name":"periCORE-buildsystem" }, + // { "path": "/usr/src/", "name": "/usr/src" } + ] +}