From 7ef35692c958ddcf27497c9e043294c2cca2834a Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Thu, 9 Jun 2022 22:10:18 +0800 Subject: [PATCH] feat: support connect wifi. Closed #2. --- .cargo/config.toml | 1 + Cargo.toml | 2 + src/main.rs | 6 +++ src/wifi.rs | 117 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 126 insertions(+) create mode 100644 src/wifi.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index 73706ed..c4c6c6a 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -32,3 +32,4 @@ build-std = ["std", "panic_abort"] #ESP_IDF_VERSION = { value = "branch:release/v4.4" } # Enables the esp-idf-sys "native" build feature (`cargo build --features native`) to build against ESP-IDF master (mainline) ESP_IDF_VERSION = { value = "master" } + diff --git a/Cargo.toml b/Cargo.toml index 2e72964..8efccd8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,8 +20,10 @@ anyhow = {version = "1.0.57", features = ["backtrace"]} embedded-graphics = "0.7.1" embedded-hal = "1.0.0-alpha.8" embedded-hal-0-2 = {package = "embedded-hal", version = "0.2.7", features = ["unproven"]} +embedded-svc = "0.21.3" env_logger = "0.9.0" esp-idf-hal = { git = "https://github.com/esp-rs/esp-idf-hal", branch="master" } +esp-idf-svc = { git = "https://github.com/IvanLi-CN/esp-idf-svc", branch="master" } esp-idf-sys = {version = "0.31.5", features = ["binstart"]} log = "0.4.17" retry = "1.3.1" diff --git a/src/main.rs b/src/main.rs index 5a5abf8..66c9096 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,11 +3,14 @@ use esp_idf_sys as _; use log::{error, info}; use std::{thread, time::Duration, sync::mpsc, env}; +use crate::wifi::WiFi; + mod beep; mod blink; mod dc_out_controller; mod manager; mod screen; +mod wifi; fn main() { env::set_var("DEFMT_LOG", "trace"); env::set_var("RUST_LOG", "trace"); @@ -71,6 +74,9 @@ fn main() { battery_pin.into_analog_atten_11db().expect("Failed to set GPIO2 as analog input"), tx, ).expect("Failed to create manager"); + + let wifi = WiFi::new(); + loop { match manager.handling_once() { Ok(_) => {} diff --git a/src/wifi.rs b/src/wifi.rs new file mode 100644 index 0000000..d6bad3a --- /dev/null +++ b/src/wifi.rs @@ -0,0 +1,117 @@ +use std::{sync::Arc, time::Duration}; + +use anyhow::{ + bail, + Result, Ok, +}; +use esp_idf_svc::ping::EspPing; +use esp_idf_svc::{ + netif::EspNetifStack, nvs::EspDefaultNvs, sysloop::EspSysLoopStack, wifi::EspWifi +}; +use embedded_svc::{wifi::*, ipv4}; +use embedded_svc::ping::Ping; +use log::info; + +pub struct WiFi { + wifi: Box, +} + +impl WiFi { + pub fn new() -> Result { + let netif_stack = Arc::new(EspNetifStack::new()?); + let sys_loop_stack = Arc::new(EspSysLoopStack::new()?); + let default_nvs = Arc::new(EspDefaultNvs::new()?); + + let mut wifi = Self::wifi( + netif_stack.clone(), + sys_loop_stack.clone(), + default_nvs.clone(), + )?; + + Ok(Self { wifi }) + } + + fn wifi( + netif_stack: Arc, + sys_loop_stack: Arc, + default_nvs: Arc, + ) -> Result> { + const SSID: &str = "Ivan Li"; + const PASSWORD: &str = "ivanli.cc"; + let mut wifi = Box::new(EspWifi::new(netif_stack, sys_loop_stack, default_nvs)?); + + info!("Wifi created, about to scan"); + + 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::Mixed( + ClientConfiguration { + ssid: SSID.into(), + password: PASSWORD.into(), + channel, + ..Default::default() + }, + AccessPointConfiguration { + ssid: "aptest".into(), + channel: channel.unwrap_or(1), + ..Default::default() + }, + ))?; + + info!("Wifi configuration set, about to get status"); + + wifi.wait_status_with_timeout(Duration::from_secs(20), |status| !status.is_transitional()) + .map_err(|e| anyhow::anyhow!("Unexpected Wifi status: {:?}", e))?; + + let status = wifi.get_status(); + + if let Status( + ClientStatus::Started(ClientConnectionStatus::Connected(ClientIpStatus::Done( + ip_settings, + ))), + ApStatus::Started(ApIpStatus::Done), + ) = status + { + info!("Wifi connected"); + + Self::ping(&ip_settings)?; + } else { + bail!("Unexpected Wifi status: {:?}", status); + } + + Ok(wifi) + } + + fn ping(ip_settings: &ipv4::ClientSettings) -> Result<()> { + info!("About to do some pings for {:?}", ip_settings); + + let ping_summary = + EspPing::default().ping(ip_settings.subnet.gateway, &Default::default())?; + if ping_summary.transmitted != ping_summary.received { + bail!( + "Pinging gateway {} resulted in timeouts", + ip_settings.subnet.gateway + ); + } + + info!("Pinging done"); + + Ok(()) +} +}