2.0 KiB · text History b85db9e
//! Provisioning mode: SoftAP + captive DNS + HTTP config form.
//!
//! Blocks until the user submits a usable config, then reboots into normal
//! operation.

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

use anyhow::Result;
use esp_idf_svc::eventloop::EspSystemEventLoop;
use esp_idf_svc::hal::delay::FreeRtos;
use esp_idf_svc::hal::modem::WifiModemPeripheral;
use esp_idf_svc::hal::reset;

use crate::config::PortalConfig;
use crate::dns;
use crate::portal::{self, Pages};
use crate::store::ConfigStore;
use crate::wifi::{self, AP_IP};

/// Stack for the captive-DNS thread. It handles one 512-byte datagram at a
/// time and allocates only the reply vector.
const DNS_STACK: usize = 4096;

/// How long to let the confirmation page flush before resetting.
const FLUSH_DELAY_MS: u32 = 1500;

/// How often to check whether a config has landed.
const POLL_MS: u32 = 200;

/// Run provisioning until a config is saved, then reboot. Never returns
/// normally; the `Ok` variant exists only so callers can use `?`.
pub fn run<C, M>(
    modem: M,
    sysloop: EspSystemEventLoop,
    store: ConfigStore,
    ssid: &str,
    pages: Pages,
) -> Result<()>
where
    C: PortalConfig,
    M: WifiModemPeripheral + 'static,
{
    // Keep the AP handle alive for the duration of provisioning.
    let _ap = wifi::start_ap(modem, sysloop, store.partition().clone(), ssid)?;

    std::thread::Builder::new()
        .stack_size(DNS_STACK)
        .spawn(move || dns::serve(AP_IP))?;

    let saved = Arc::new(AtomicBool::new(false));
    // Keep the server alive; dropping it would unregister the handlers.
    let _server = portal::start::<C>(store, saved.clone(), pages)?;

    log::info!("provisioning ready: join '{ssid}', config opens automatically");

    loop {
        if saved.load(Ordering::SeqCst) {
            log::info!("config saved; rebooting into normal operation");
            FreeRtos::delay_ms(FLUSH_DELAY_MS);
            reset::restart();
        }
        FreeRtos::delay_ms(POLL_MS);
    }
}