Aller au contenu
  1. Blog/

Un répeteur Wifi via Esp32 🦀 - Part 2

3 mins· ·
new micro-electronic rust esp32
Sommaire

Attention, cet article est le second de la suite “Un répeteur Wifi via Esp32 🦀”.

Voici la partie 1, vous y trouverez le contexte du projet.

Reprenont là où nous nous sommes arretés. En effet j’avais reçut le matériel, une idée clair en tête.

Faire un réperteur wifi. Dans le schéma de la partie 1, la première étape était de manipuler le Non-Volatile Storage (NVS).

De fait c’est la première chose que l’on manipulera dans notre code.

Manipulation du NVS
#

Nous allons créer une structure Rust pour manipuler et lire l’espace de stockage persistant.

Le NVS s’étant de l’adresse 0x9000 à 0xf000 soit 24.576 octets.

Si nous reprenons la donnée que nous devons stocker nous avons :

  • ssid_name, Le nom du WIFi du routeur auquel nous voulons récupérer le réseau
  • ssid_password, Le mot de passe WiFi du routeur
  • access_ssid_name, Le nom du WiFi que nous voulons que l’ESP expose (potentiellement le même dans le cas d’une répétition de WiFi)
  • access_ssid_password, Le mot de passe du WiFi que nous volons que l’ESP utilise pour sécuriser la connexion

Rust AppStoredConfig

Le code définit deux notions qui proviennent de IEEE 802.11x :

  • Le nom WiFi mesure 32 octets
  • Le mot de passe WiFi mesure 64 octets

Quelques méthodes on été codé, de quoi configurer la structure par défaut (si pas de réseau initial choisit), afficher les informations de connexions, etc…

Rust Impl AppStoredConfig

La structure AppStoredConfig est prête à être utilisé par le système de stockage dans la mémoire persitante de l’ESP.

Pour cela nous créons un manager pilotant la donnée.

pub struct ConfigStorage {
    flash: EspNvs<NvsDefault>,
}

impl ConfigStorage {
    pub fn new() -> Self {
        let nvs_default_partition: EspNvsPartition<NvsDefault> =
            EspDefaultNvsPartition::take().unwrap();
        let flash = EspNvs::new(nvs_default_partition, NAMESPACE, true)
            .expect("Could not get nvs partition");
        ConfigStorage { flash }
    }
    pub fn store_to_flash(&mut self, config: AppStoredConfig) -> Result<(), Error> {
        let data_buffer = unsafe {
            core::slice::from_raw_parts(
                &config as *const _ as *mut u8,
                core::mem::size_of::<AppStoredConfig>(),
            )
        };

        let result = self.flash.set_blob(BLOB_NAME, data_buffer);
        if result.is_err() {
            bail!("Failed to store the config")
        } else {
            Ok(())
        }
    }

    pub fn load_from_flash(&mut self) -> Result<AppStoredConfig, Error> {
        let config = AppStoredConfig::default();
        let data_buffer = unsafe {
            core::slice::from_raw_parts_mut(
                &config as *const _ as *mut u8,
                core::mem::size_of::<AppStoredConfig>(),
            )
        };

        let size = self.flash.blob_len(BLOB_NAME);
        match size {
            Ok(None) => bail!("Flash memory is empty."),
            Err(e) => bail!("Failed to load the config"),
            _ => info!("Flash memory is not empty. Lenght: {:?}", size),
        }

        let result = self.flash.get_blob(BLOB_NAME, data_buffer);
        if result.is_err() {
            bail!("Failed to load the config")
        } else {
            Ok(config)
        }
    }
}

Deux méthodes sont disponnibles load_from_flash et store_to_flash pour manipuler la donnée.

Il est nécéssaire de rendre accessible via un Mutex un objet permettant de charger la configuration et de récuperer la configuration chargé à certains moment dans le code.

use lazy_static::lazy_static;
use std::sync::Mutex;

lazy_static! {
    pub static ref APP_CONFIG_STORE: Mutex<ConfigStorage> = Mutex::new(ConfigStorage::new());
}

Avec tout ces outils il est maintenant possible de charger dans la fonction main la configuration applicative :

fn main() -> anyhow::Result<()> {
    info!("Load NV config.");
    let mut config_store = APP_CONFIG_STORE.lock().unwrap();

    let config: AppStoredConfig = match config_store.load_from_flash() {
        Ok(config) => {
            info!("Config OK");
            config
        }
        Err(e) => {
            info!("Config loading failed: {:?}", e);
            AppStoredConfig::access_point()
        }
    };

    config.display();

    Ok(())
}

Lors du premier démarrage nous observons :

SSID Name:
SSID Password:
Access SSID Name: Espressif
Access SSID Password: Espressif

Et voilà ! Nous verrons dans la prochaine partie la création du réseau WiFi et la connexion au routeur.

To Be Continued…

Articles connexes

Un répeteur Wifi via Esp32 🦀
2 mins
new micro-electronic rust esp32