145 lines
4.4 KiB
Rust
145 lines
4.4 KiB
Rust
use crate::Mutex;
|
|
use crate::alloc::string::ToString;
|
|
use crate::Signal;
|
|
use crate::navigation::outputs::Outputs;
|
|
use crate::peripherals::Peripherals;
|
|
#[cfg(not(feature = "wokwi"))]
|
|
use crate::peripherals::storage::wifistore::WifiStore;
|
|
use crate::peripherals::storage::wifistore::WifiStoreError;
|
|
use alloc::string::String;
|
|
use core::error::Error;
|
|
use core::fmt::Display;
|
|
use esp_radio::wifi::WifiController;
|
|
use esp_radio::*;
|
|
|
|
#[derive(Debug)]
|
|
pub struct WifiCredentials {
|
|
pub ssid: String,
|
|
pub pass: String,
|
|
}
|
|
|
|
pub static WIFI_CREDENTIALS: Signal<WifiCredentials> = Signal::new();
|
|
|
|
|
|
#[derive(Debug)]
|
|
pub struct Wifi {
|
|
pub controller: WifiController<'static>,
|
|
pub interfaces: wifi::Interfaces<'static>,
|
|
pub credentials: WifiCredentials,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum WifiError {
|
|
Store(WifiStoreError),
|
|
Radio(esp_radio::wifi::WifiError),
|
|
NoCredentialsStored,
|
|
}
|
|
|
|
impl Error for WifiError {}
|
|
|
|
impl Display for WifiError {
|
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
match self {
|
|
WifiError::Store(e) => e.fmt(f),
|
|
WifiError::Radio(e) => e.fmt(f),
|
|
WifiError::NoCredentialsStored => write!(f, "No WiFi credentials stored in flash"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<WifiStoreError> for WifiError {
|
|
fn from(error: WifiStoreError) -> WifiError {
|
|
WifiError::Store(error)
|
|
}
|
|
}
|
|
|
|
impl From<esp_radio::wifi::WifiError> for WifiError {
|
|
fn from(error: esp_radio::wifi::WifiError) -> WifiError {
|
|
WifiError::Radio(error)
|
|
}
|
|
}
|
|
|
|
impl Wifi {
|
|
pub fn new(
|
|
wifi: esp_hal::peripherals::WIFI<'static>,
|
|
credentials: WifiCredentials
|
|
) -> Result<Self, WifiError> {
|
|
let wifi = wifi::new(wifi, Default::default())?;
|
|
|
|
Ok(Self {
|
|
controller: wifi.0,
|
|
interfaces: wifi.1,
|
|
credentials
|
|
})
|
|
}
|
|
|
|
pub async fn initialize_credentials(
|
|
wifi_store: &WifiStore,
|
|
) -> Result<WifiCredentials, WifiError> {
|
|
let stored_credentials = wifi_store.load_credentials().await?;
|
|
let ssid = option_env!("WIFI_SSID").map_or(stored_credentials.ssid, |v| v.to_string());
|
|
let pass = option_env!("WIFI_PASS").map_or(stored_credentials.pass, |v| v.to_string());
|
|
|
|
log::info!("initial wifi credentials:\nssid:{ssid}, pass:{pass}");
|
|
Ok(WifiCredentials {ssid, pass})
|
|
}
|
|
|
|
#[cfg(feature = "wokwi")]
|
|
pub async fn setup(
|
|
wifi: esp_hal::peripherals::WIFI<'static>,
|
|
nvs: Arc<Mutex<Nvs>>,
|
|
spawner: &Spawner,
|
|
) {
|
|
log::info!("Wokwi mode active: pre-seeding WiFi Manager with Wokwi credentials");
|
|
|
|
const WIFIMANAGER_NAMESPACE: Key = Key::from_str("wifimanager");
|
|
const WIFIMANAGER_NVS_KEY: Key = Key::from_str("WIFI_SETUP");
|
|
|
|
if let Err(e) = nvs.lock().await.set(
|
|
&WIFIMANAGER_NAMESPACE,
|
|
&WIFIMANAGER_NVS_KEY,
|
|
"{\"ssid\":\"Wokwi-GUEST\",\"psk\":\"\",\"data\":{}}",
|
|
) {
|
|
log::error!("Failed to store Wokwi WiFi config in NVS: {e:?}");
|
|
return;
|
|
}
|
|
|
|
// Preload connection data so init_wm can connect immediately without AP setup.
|
|
let nvs = esp_hal_wifimanager::Nvs::new_from_nvs(nvs, 0, 0);
|
|
|
|
let mut wm_settings = esp_hal_wifimanager::WmSettings::default();
|
|
|
|
// Wokwi simulation uses a default open network called "Wokwi-GUEST"
|
|
wm_settings.ssid.clear();
|
|
_ = core::fmt::write(&mut wm_settings.ssid, format_args!("Wokwi-GUEST"));
|
|
|
|
wm_settings.wifi_conn_timeout = 30000;
|
|
|
|
// Initialize Wi-Fi connection through WiFi Manager using the pre-seeded NVS data.
|
|
let wifi_res =
|
|
esp_hal_wifimanager::init_wm(wm_settings, spawner, Some(&nvs), wifi, None).await;
|
|
|
|
log::info!("Wokwi wifi_res: {wifi_res:?}");
|
|
}
|
|
}
|
|
|
|
#[embassy_executor::task]
|
|
pub async fn wait_for_wifi_credentials(_outputs: &'static Mutex<Outputs>, peripherals: &'static Peripherals) {
|
|
|
|
loop {
|
|
log::info!("Waiting for new WiFi credentials");
|
|
let credentials = WIFI_CREDENTIALS.wait().await;
|
|
|
|
log::info!("Received new WiFi credentials:\nssid: {}, pass: {}", credentials.ssid, credentials.pass);
|
|
if let Err(err) = peripherals.store.lock().await.wifi_store.save_credentials(&credentials).await {
|
|
log::error!("Error storing credentials: {err}");
|
|
continue;
|
|
}
|
|
|
|
log::info!("Saved new WiFi credentials. Restarting WiFi");
|
|
|
|
}
|
|
}
|
|
|
|
|