set read config initial somewhat ready
This commit is contained in:
		@@ -1,4 +1,4 @@
 | 
			
		||||
use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
 | 
			
		||||
use embedded_storage::{ReadStorage, Storage};
 | 
			
		||||
use esp_bootloader_esp_idf::partitions::FlashRegion;
 | 
			
		||||
use esp_storage::FlashStorage;
 | 
			
		||||
use littlefs2::consts::U1 as lfs2Array1;
 | 
			
		||||
@@ -7,7 +7,7 @@ use littlefs2::driver::Storage as lfs2Storage;
 | 
			
		||||
use littlefs2::fs::Filesystem as lfs2Filesystem;
 | 
			
		||||
use littlefs2::io::Error as lfs2Error;
 | 
			
		||||
use littlefs2::io::Result as lfs2Result;
 | 
			
		||||
use log::error;
 | 
			
		||||
use log::{error, info};
 | 
			
		||||
 | 
			
		||||
pub struct LittleFs2Filesystem {
 | 
			
		||||
    pub(crate) storage: &'static mut FlashRegion<'static, FlashStorage>,
 | 
			
		||||
@@ -16,13 +16,18 @@ pub struct LittleFs2Filesystem {
 | 
			
		||||
impl lfs2Storage for LittleFs2Filesystem {
 | 
			
		||||
    const READ_SIZE: usize = 512;
 | 
			
		||||
    const WRITE_SIZE: usize = 512;
 | 
			
		||||
    const BLOCK_SIZE: usize = 32 * 1024; //usually optimal for flash access
 | 
			
		||||
    const BLOCK_COUNT: usize = 8 * 1024 * 1024 / 32 * 1024; //8mb in 32blocks
 | 
			
		||||
    const BLOCK_CYCLES: isize = 0;
 | 
			
		||||
    const BLOCK_SIZE: usize = 1024; //usually optimal for flash access
 | 
			
		||||
    const BLOCK_COUNT: usize = 8 * 1024 * 1024 / 1024; //8mb in 32kb blocks
 | 
			
		||||
    const BLOCK_CYCLES: isize = 100;
 | 
			
		||||
    type CACHE_SIZE = lfs2Array512;
 | 
			
		||||
    type LOOKAHEAD_SIZE = lfs2Array1;
 | 
			
		||||
 | 
			
		||||
    fn read(&mut self, off: usize, buf: &mut [u8]) -> lfs2Result<usize> {
 | 
			
		||||
        info!(
 | 
			
		||||
            "Littlefs2Filesystem read at offset {} with len {}",
 | 
			
		||||
            off,
 | 
			
		||||
            buf.len()
 | 
			
		||||
        );
 | 
			
		||||
        let read_size: usize = Self::READ_SIZE;
 | 
			
		||||
        assert_eq!(off % read_size, 0);
 | 
			
		||||
        assert_eq!(buf.len() % read_size, 0);
 | 
			
		||||
@@ -36,6 +41,11 @@ impl lfs2Storage for LittleFs2Filesystem {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn write(&mut self, off: usize, data: &[u8]) -> lfs2Result<usize> {
 | 
			
		||||
        info!(
 | 
			
		||||
            "Littlefs2Filesystem write at offset {} with len {}",
 | 
			
		||||
            off,
 | 
			
		||||
            data.len()
 | 
			
		||||
        );
 | 
			
		||||
        let write_size: usize = Self::WRITE_SIZE;
 | 
			
		||||
        assert_eq!(off % write_size, 0);
 | 
			
		||||
        assert_eq!(data.len() % write_size, 0);
 | 
			
		||||
@@ -49,15 +59,20 @@ impl lfs2Storage for LittleFs2Filesystem {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn erase(&mut self, off: usize, len: usize) -> lfs2Result<usize> {
 | 
			
		||||
        info!(
 | 
			
		||||
            "Littlefs2Filesystem erase at offset {} with len {}",
 | 
			
		||||
            off, len
 | 
			
		||||
        );
 | 
			
		||||
        let block_size: usize = Self::BLOCK_SIZE;
 | 
			
		||||
        debug_assert!(off % block_size == 0);
 | 
			
		||||
        debug_assert!(len % block_size == 0);
 | 
			
		||||
        match self.storage.erase(off as u32, len as u32) {
 | 
			
		||||
            anyhow::Result::Ok(..) => lfs2Result::Ok(len),
 | 
			
		||||
            Err(err) => {
 | 
			
		||||
                error!("Littlefs2Filesystem erase error: {:?}", err);
 | 
			
		||||
                Err(lfs2Error::IO)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        //match self.storage.erase(off as u32, len as u32) {
 | 
			
		||||
        //anyhow::Result::Ok(..) => lfs2Result::Ok(len),
 | 
			
		||||
        //Err(err) => {
 | 
			
		||||
        //error!("Littlefs2Filesystem erase error: {:?}", err);
 | 
			
		||||
        //Err(lfs2Error::IO)
 | 
			
		||||
        //    }
 | 
			
		||||
        //}
 | 
			
		||||
        lfs2Result::Ok(len)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -46,6 +46,8 @@ static mut LOW_VOLTAGE_DETECTED: bool = false;
 | 
			
		||||
#[link_section = ".rtc.data"]
 | 
			
		||||
static mut RESTART_TO_CONF: bool = false;
 | 
			
		||||
 | 
			
		||||
static CONFIG_FILE: &str = "config.json";
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize, Debug)]
 | 
			
		||||
pub struct FileInfo {
 | 
			
		||||
    filename: String,
 | 
			
		||||
@@ -87,6 +89,14 @@ pub struct Esp<'a> {
 | 
			
		||||
    pub ota_next: &'static mut FlashRegion<'static, FlashStorage>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SAFETY: On this target we never move Esp across OS threads; the firmware runs single-core
 | 
			
		||||
// cooperative tasks with Embassy. All interior mutability of non-Send peripherals is gated
 | 
			
		||||
// behind &mut self or embassy_sync Mutex with CriticalSectionRawMutex, which does not rely on
 | 
			
		||||
// thread scheduling. Therefore it is sound to mark Esp as Send to satisfy trait object bounds
 | 
			
		||||
// (e.g., Box<dyn BoardInteraction + Send>). If you add fields that are accessed from multiple
 | 
			
		||||
// CPU cores/threads, reconsider this.
 | 
			
		||||
unsafe impl Send for Esp<'_> {}
 | 
			
		||||
 | 
			
		||||
pub struct IpInfo {
 | 
			
		||||
    pub(crate) ip: IpAddr,
 | 
			
		||||
    netmask: IpAddr,
 | 
			
		||||
@@ -224,7 +234,7 @@ impl Esp<'_> {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) async fn wifi_ap(&mut self) -> anyhow::Result<Stack<'static>> {
 | 
			
		||||
        let ssid = match self.load_config() {
 | 
			
		||||
        let ssid = match self.load_config().await {
 | 
			
		||||
            Ok(config) => config.network.ap_ssid.as_str().to_string(),
 | 
			
		||||
            Err(_) => "PlantCtrl Emergency Mode".to_string(),
 | 
			
		||||
        };
 | 
			
		||||
@@ -370,50 +380,29 @@ impl Esp<'_> {
 | 
			
		||||
        // log(LogMessage::WifiInfo, 0, 0, "", &format!("{address:?}"));
 | 
			
		||||
        // anyhow::Ok(address)
 | 
			
		||||
    }
 | 
			
		||||
    pub(crate) fn load_config(&mut self) -> anyhow::Result<PlantControllerConfig> {
 | 
			
		||||
        bail!("todo");
 | 
			
		||||
        // let cfg = File::open(Self::CONFIG_FILE)?;
 | 
			
		||||
        // let config: PlantControllerConfig = serde_json::from_reader(cfg)?;
 | 
			
		||||
        // anyhow::Ok(config)
 | 
			
		||||
    pub(crate) async fn load_config(&mut self) -> anyhow::Result<PlantControllerConfig> {
 | 
			
		||||
        let cfg = PathBuf::try_from(CONFIG_FILE).unwrap();
 | 
			
		||||
        match self.fs.lock().await.read::<4096>(&cfg) {
 | 
			
		||||
            Ok(data) => {
 | 
			
		||||
                let config: PlantControllerConfig = serde_json::from_slice(&data)?;
 | 
			
		||||
                anyhow::Ok(config)
 | 
			
		||||
            }
 | 
			
		||||
            Err(err) => {
 | 
			
		||||
                bail!(format!("{err:?}"))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pub(crate) async fn save_config(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        _config: &PlantControllerConfig,
 | 
			
		||||
    ) -> anyhow::Result<()> {
 | 
			
		||||
        bail!("todo");
 | 
			
		||||
        // let mut cfg = File::create(Self::CONFIG_FILE)?;
 | 
			
		||||
        // serde_json::to_writer(&mut cfg, &config)?;
 | 
			
		||||
        // log::info!("Wrote config config {:?}", config);
 | 
			
		||||
        // anyhow::Ok(())
 | 
			
		||||
    }
 | 
			
		||||
    pub(crate) fn mount_file_system(&mut self) -> anyhow::Result<()> {
 | 
			
		||||
        bail!("fail");
 | 
			
		||||
        // log(LogMessage::MountingFilesystem, 0, 0, "", "");
 | 
			
		||||
        // let base_path = String::try_from("/spiffs")?;
 | 
			
		||||
        // let storage = String::try_from(Self::SPIFFS_PARTITION_NAME)?;
 | 
			
		||||
        //let conf = todo!();
 | 
			
		||||
    pub(crate) async fn save_config(&mut self, config: Vec<u8>) -> anyhow::Result<()> {
 | 
			
		||||
        let filesystem = self.fs.lock().await;
 | 
			
		||||
        let cfg = PathBuf::try_from(CONFIG_FILE).unwrap();
 | 
			
		||||
 | 
			
		||||
        //let conf = esp_idf_sys::esp_vfs_spiffs_conf_t {
 | 
			
		||||
        //base_path: base_path.as_ptr(),
 | 
			
		||||
        //partition_label: storage.as_ptr(),
 | 
			
		||||
        //max_files: 5,
 | 
			
		||||
        //format_if_mount_failed: true,
 | 
			
		||||
        //};
 | 
			
		||||
 | 
			
		||||
        //TODO
 | 
			
		||||
        //unsafe {
 | 
			
		||||
        //esp_idf_sys::esp!(esp_idf_sys::esp_vfs_spiffs_register(&conf))?;
 | 
			
		||||
        //}
 | 
			
		||||
 | 
			
		||||
        // let free_space = self.file_system_size()?;
 | 
			
		||||
        // log(
 | 
			
		||||
        //     LogMessage::FilesystemMount,
 | 
			
		||||
        //     free_space.free_size as u32,
 | 
			
		||||
        //     free_space.total_size as u32,
 | 
			
		||||
        //     &free_space.used_size.to_string(),
 | 
			
		||||
        //     "",
 | 
			
		||||
        // );
 | 
			
		||||
        // anyhow::Ok(())
 | 
			
		||||
        match filesystem.write(&cfg, &*config) {
 | 
			
		||||
            Ok(_) => {}
 | 
			
		||||
            Err(err) => {
 | 
			
		||||
                bail!(format!("{err:?}"))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        anyhow::Ok(())
 | 
			
		||||
    }
 | 
			
		||||
    async fn file_system_size(&mut self) -> anyhow::Result<FileSystemSizeInfo> {
 | 
			
		||||
        bail!("fail");
 | 
			
		||||
 
 | 
			
		||||
@@ -125,11 +125,8 @@ impl<'a> BoardInteraction<'a> for Initial<'a> {
 | 
			
		||||
        bail!("Please configure board revision")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn set_config(&mut self, config: PlantControllerConfig) -> anyhow::Result<()> {
 | 
			
		||||
    fn set_config(&mut self, config: PlantControllerConfig) {
 | 
			
		||||
        self.config = config;
 | 
			
		||||
        //TODO
 | 
			
		||||
        //        self.esp.save_config(&self.config)?;
 | 
			
		||||
        anyhow::Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn get_mptt_voltage(&mut self) -> Result<Voltage> {
 | 
			
		||||
 
 | 
			
		||||
@@ -49,6 +49,7 @@ use esp_storage::FlashStorage;
 | 
			
		||||
use esp_wifi::{init, EspWifiController};
 | 
			
		||||
use littlefs2::fs::{Allocation, Filesystem as lfs2Filesystem};
 | 
			
		||||
use littlefs2::object_safe::DynStorage;
 | 
			
		||||
use log::{info, warn};
 | 
			
		||||
 | 
			
		||||
//Only support for 8 right now!
 | 
			
		||||
pub const PLANT_COUNT: usize = 8;
 | 
			
		||||
@@ -88,7 +89,7 @@ pub trait BoardInteraction<'a> {
 | 
			
		||||
    async fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> Result<f32>;
 | 
			
		||||
    async fn general_fault(&mut self, enable: bool);
 | 
			
		||||
    async fn test(&mut self) -> Result<()>;
 | 
			
		||||
    async fn set_config(&mut self, config: PlantControllerConfig) -> Result<()>;
 | 
			
		||||
    fn set_config(&mut self, config: PlantControllerConfig);
 | 
			
		||||
    async fn get_mptt_voltage(&mut self) -> anyhow::Result<Voltage>;
 | 
			
		||||
    async fn get_mptt_current(&mut self) -> anyhow::Result<Current>;
 | 
			
		||||
}
 | 
			
		||||
@@ -99,7 +100,12 @@ impl dyn BoardInteraction<'_> {
 | 
			
		||||
        let even = counter % 2 == 0;
 | 
			
		||||
        let current = counter / (PLANT_COUNT as u32);
 | 
			
		||||
        for led in 0..PLANT_COUNT {
 | 
			
		||||
            self.fault(led, current == led as u32).await.unwrap();
 | 
			
		||||
            match self.fault(led, current == led as u32).await {
 | 
			
		||||
                Result::Ok(_) => {}
 | 
			
		||||
                Err(err) => {
 | 
			
		||||
                    warn!("Fault on plant {}: {:?}", led, err);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        let _ = self.general_fault(even.into());
 | 
			
		||||
    }
 | 
			
		||||
@@ -187,11 +193,11 @@ impl PlantHal {
 | 
			
		||||
        let timg0 = TimerGroup::new(peripherals.TIMG0);
 | 
			
		||||
        let esp_wifi_ctrl = &*mk_static!(
 | 
			
		||||
            EspWifiController<'static>,
 | 
			
		||||
            init(timg0.timer0, rng.clone()).unwrap()
 | 
			
		||||
            init(timg0.timer0, rng.clone()).expect("Could not init wifi controller")
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let (controller, interfaces) =
 | 
			
		||||
            esp_wifi::wifi::new(&esp_wifi_ctrl, peripherals.WIFI).unwrap();
 | 
			
		||||
            esp_wifi::wifi::new(&esp_wifi_ctrl, peripherals.WIFI).expect("Could not init wifi");
 | 
			
		||||
 | 
			
		||||
        use esp_hal::timer::systimer::SystemTimer;
 | 
			
		||||
        esp_hal_embassy::init(systimer.alarm0);
 | 
			
		||||
@@ -234,11 +240,9 @@ impl PlantHal {
 | 
			
		||||
        };
 | 
			
		||||
        //
 | 
			
		||||
 | 
			
		||||
        let tablebuffer: [u8; esp_bootloader_esp_idf::partitions::PARTITION_TABLE_MAX_LEN] =
 | 
			
		||||
            [0u8; esp_bootloader_esp_idf::partitions::PARTITION_TABLE_MAX_LEN];
 | 
			
		||||
        let tablebuffer = mk_static!(
 | 
			
		||||
            [u8; esp_bootloader_esp_idf::partitions::PARTITION_TABLE_MAX_LEN],
 | 
			
		||||
            tablebuffer
 | 
			
		||||
            [0u8; esp_bootloader_esp_idf::partitions::PARTITION_TABLE_MAX_LEN]
 | 
			
		||||
        );
 | 
			
		||||
        let storage_ota = mk_static!(FlashStorage, FlashStorage::new());
 | 
			
		||||
        let pt =
 | 
			
		||||
@@ -246,36 +250,37 @@ impl PlantHal {
 | 
			
		||||
 | 
			
		||||
        // List all partitions - this is just FYI
 | 
			
		||||
        for i in 0..pt.len() {
 | 
			
		||||
            println!("{:?}", pt.get_partition(i));
 | 
			
		||||
            info!("{:?}", pt.get_partition(i));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let ota_data = pt
 | 
			
		||||
            .find_partition(esp_bootloader_esp_idf::partitions::PartitionType::Data(
 | 
			
		||||
        let ota_data = mk_static!(
 | 
			
		||||
            PartitionEntry,
 | 
			
		||||
            pt.find_partition(esp_bootloader_esp_idf::partitions::PartitionType::Data(
 | 
			
		||||
                DataPartitionSubType::Ota,
 | 
			
		||||
            ))?
 | 
			
		||||
            .unwrap();
 | 
			
		||||
            .expect("No OTA data partition found")
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let ota_data = mk_static!(PartitionEntry, ota_data);
 | 
			
		||||
 | 
			
		||||
        let ota_data = ota_data.as_embedded_storage(storage_ota);
 | 
			
		||||
        let ota_data = mk_static!(FlashRegion<FlashStorage>, ota_data);
 | 
			
		||||
        let ota_data = mk_static!(
 | 
			
		||||
            FlashRegion<FlashStorage>,
 | 
			
		||||
            ota_data.as_embedded_storage(storage_ota)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let mut ota = esp_bootloader_esp_idf::ota::Ota::new(ota_data)?;
 | 
			
		||||
 | 
			
		||||
        let ota_partition = match ota.current_slot()? {
 | 
			
		||||
            Slot::None => {
 | 
			
		||||
                panic!("No OTA slot found");
 | 
			
		||||
                panic!("No OTA slot active?");
 | 
			
		||||
            }
 | 
			
		||||
            Slot::Slot0 => pt
 | 
			
		||||
                .find_partition(esp_bootloader_esp_idf::partitions::PartitionType::App(
 | 
			
		||||
                    AppPartitionSubType::Ota0,
 | 
			
		||||
                ))?
 | 
			
		||||
                .unwrap(),
 | 
			
		||||
                .expect("No OTA slot0 found"),
 | 
			
		||||
            Slot::Slot1 => pt
 | 
			
		||||
                .find_partition(esp_bootloader_esp_idf::partitions::PartitionType::App(
 | 
			
		||||
                    AppPartitionSubType::Ota1,
 | 
			
		||||
                ))?
 | 
			
		||||
                .unwrap(),
 | 
			
		||||
                .expect("No OTA slot1 found"),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let ota_next = mk_static!(PartitionEntry, ota_partition);
 | 
			
		||||
@@ -289,11 +294,11 @@ impl PlantHal {
 | 
			
		||||
            .find_partition(esp_bootloader_esp_idf::partitions::PartitionType::Data(
 | 
			
		||||
                DataPartitionSubType::LittleFs,
 | 
			
		||||
            ))?
 | 
			
		||||
            .unwrap();
 | 
			
		||||
            .expect("Data partition with littlefs not found");
 | 
			
		||||
        let data_partition = mk_static!(PartitionEntry, data_partition);
 | 
			
		||||
 | 
			
		||||
        let storage_data = mk_static!(FlashStorage, FlashStorage::new());
 | 
			
		||||
        let mut data = mk_static!(
 | 
			
		||||
        let data = mk_static!(
 | 
			
		||||
            FlashRegion<FlashStorage>,
 | 
			
		||||
            data_partition.as_embedded_storage(storage_data)
 | 
			
		||||
        );
 | 
			
		||||
@@ -313,7 +318,7 @@ impl PlantHal {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let fs = Arc::new(Mutex::new(
 | 
			
		||||
            lfs2Filesystem::mount(alloc, lfs2filesystem).unwrap(),
 | 
			
		||||
            lfs2Filesystem::mount(alloc, lfs2filesystem).expect("Could not mount lfs2 filesystem"),
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
        let mut esp = Esp {
 | 
			
		||||
@@ -362,9 +367,8 @@ impl PlantHal {
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        esp.init_rtc_deepsleep_memory(init_rtc_store, to_config_mode);
 | 
			
		||||
        let fs_mount_error = esp.mount_file_system().is_err();
 | 
			
		||||
 | 
			
		||||
        let config = esp.load_config();
 | 
			
		||||
        let config = esp.load_config().await;
 | 
			
		||||
 | 
			
		||||
        log::info!("Init rtc driver");
 | 
			
		||||
        // let mut rtc = Ds323x::new_ds3231(MutexDevice::new(&I2C_DRIVER));
 | 
			
		||||
 
 | 
			
		||||
@@ -232,8 +232,10 @@ async fn safe_main(spawner: Spawner) -> anyhow::Result<()> {
 | 
			
		||||
        info!("no mode override");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if board.board_hal.get_config().hardware.board == INITIAL
 | 
			
		||||
        && board.board_hal.get_config().network.ssid.is_none()
 | 
			
		||||
    //TODO hack
 | 
			
		||||
    if true
 | 
			
		||||
        || (board.board_hal.get_config().hardware.board == INITIAL
 | 
			
		||||
            && board.board_hal.get_config().network.ssid.is_none())
 | 
			
		||||
    {
 | 
			
		||||
        info!("No wifi configured, starting initial config mode");
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +1,21 @@
 | 
			
		||||
//offer ota and config mode
 | 
			
		||||
 | 
			
		||||
use crate::config::PlantControllerConfig;
 | 
			
		||||
use crate::{get_version, log::LogMessage, BOARD_ACCESS};
 | 
			
		||||
use alloc::borrow::ToOwned;
 | 
			
		||||
use alloc::string::{String, ToString};
 | 
			
		||||
use alloc::sync::Arc;
 | 
			
		||||
use alloc::vec::Vec;
 | 
			
		||||
use anyhow::bail;
 | 
			
		||||
use core::fmt::{Debug, Display};
 | 
			
		||||
use core::net::{IpAddr, Ipv4Addr, SocketAddr};
 | 
			
		||||
use core::result::Result::Ok;
 | 
			
		||||
use core::str::from_utf8;
 | 
			
		||||
use core::sync::atomic::{AtomicBool, Ordering};
 | 
			
		||||
use edge_http::io::server::{Connection, Handler, Server};
 | 
			
		||||
use edge_http::io::Error;
 | 
			
		||||
use edge_http::Method;
 | 
			
		||||
use edge_nal::TcpBind;
 | 
			
		||||
use edge_nal::{TcpBind, TcpSplit};
 | 
			
		||||
use edge_nal_embassy::{Tcp, TcpBuffers};
 | 
			
		||||
use embassy_net::Stack;
 | 
			
		||||
use embassy_time::Instant;
 | 
			
		||||
@@ -185,16 +189,7 @@ pub struct NightLampCommand {
 | 
			
		||||
//     anyhow::Ok(Some(json))
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// fn set_config(
 | 
			
		||||
//     request: &mut Request<&mut EspHttpConnection>,
 | 
			
		||||
// ) -> Result<Option<std::string::String>, anyhow::Error> {
 | 
			
		||||
//     let all = read_up_to_bytes_from_request(request, Some(4096))?;
 | 
			
		||||
//     let config: PlantControllerConfig = serde_json::from_slice(&all)?;
 | 
			
		||||
//
 | 
			
		||||
//     let mut board = BOARD_ACCESS.lock().expect("board access");
 | 
			
		||||
//     board.board_hal.set_config(config)?;
 | 
			
		||||
//     anyhow::Ok(Some("saved".to_owned()))
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
@@ -314,11 +309,7 @@ struct HttpHandler {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Handler for HttpHandler {
 | 
			
		||||
    type Error<E>
 | 
			
		||||
        = Error<E>
 | 
			
		||||
    where
 | 
			
		||||
        E: Debug;
 | 
			
		||||
 | 
			
		||||
    type Error<E: core::fmt::Debug> = Error<E>;
 | 
			
		||||
    async fn handle<'a, T, const N: usize>(
 | 
			
		||||
        &self,
 | 
			
		||||
        _task_id: impl Display + Copy,
 | 
			
		||||
@@ -381,6 +372,7 @@ impl Handler for HttpHandler {
 | 
			
		||||
            Method::Post => {
 | 
			
		||||
                let json = match path {
 | 
			
		||||
                    "/wifiscan" => Some(wifi_scan(conn).await),
 | 
			
		||||
                    "/set_config" => Some(set_config(conn).await),
 | 
			
		||||
                    _ => None,
 | 
			
		||||
                };
 | 
			
		||||
                match json {
 | 
			
		||||
@@ -398,7 +390,6 @@ impl Handler for HttpHandler {
 | 
			
		||||
            }
 | 
			
		||||
            Some(code) => code,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        conn.complete().await?;
 | 
			
		||||
        let response_time = Instant::now().duration_since(start).as_millis();
 | 
			
		||||
 | 
			
		||||
@@ -407,28 +398,65 @@ impl Handler for HttpHandler {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//     .fn_handler("/reboot", Method::Post, move |_| {
 | 
			
		||||
//         BOARD_ACCESS
 | 
			
		||||
//             .lock()
 | 
			
		||||
//             .unwrap()
 | 
			
		||||
//             .board_hal
 | 
			
		||||
//             .get_esp()
 | 
			
		||||
//             .set_restart_to_conf(true);
 | 
			
		||||
//         reboot_now_for_reboot.store(true, std::sync::atomic::Ordering::Relaxed);
 | 
			
		||||
//         anyhow::Ok(())
 | 
			
		||||
 | 
			
		||||
// fn wifi_scan(
 | 
			
		||||
//     _request: &mut Request<&mut EspHttpConnection>,
 | 
			
		||||
// fn set_config(
 | 
			
		||||
//     request: &mut Request<&mut EspHttpConnection>,
 | 
			
		||||
// ) -> Result<Option<std::string::String>, anyhow::Error> {
 | 
			
		||||
//     let mut board = BOARD_ACCESS.lock().unwrap();
 | 
			
		||||
//     let scan_result = board.board_hal.get_esp().wifi_scan()?;
 | 
			
		||||
//     let mut ssids: Vec<&String<32>> = Vec::new();
 | 
			
		||||
//     scan_result.iter().for_each(|s| ssids.push(&s.ssid));
 | 
			
		||||
//     let ssid_json = serde_json::to_string(&SSIDList { ssids })?;
 | 
			
		||||
//     log::info!("Sending ssid list {}", &ssid_json);
 | 
			
		||||
//     anyhow::Ok(Some(ssid_json))
 | 
			
		||||
//     let all = read_up_to_bytes_from_request(request, Some(4096))?;
 | 
			
		||||
//     let config: PlantControllerConfig = serde_json::from_slice(&all)?;
 | 
			
		||||
//
 | 
			
		||||
//     let mut board = BOARD_ACCESS.lock().expect("board access");
 | 
			
		||||
//     board.board_hal.set_config(config)?;
 | 
			
		||||
//     anyhow::Ok(Some("saved".to_owned()))
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
async fn set_config<T, const N: usize>(
 | 
			
		||||
    request: &mut Connection<'_, T, N>,
 | 
			
		||||
) -> Result<Option<String>, anyhow::Error>
 | 
			
		||||
where
 | 
			
		||||
    T: Read + Write,
 | 
			
		||||
{
 | 
			
		||||
    let all = read_up_to_bytes_from_request(request, Some(4096)).await?;
 | 
			
		||||
    let length = all.len();
 | 
			
		||||
    let config: PlantControllerConfig = serde_json::from_slice(&all)?;
 | 
			
		||||
 | 
			
		||||
    let mut board = BOARD_ACCESS.get().await.lock().await;
 | 
			
		||||
    board.board_hal.get_esp().save_config(all).await?;
 | 
			
		||||
    log::info!("Wrote config config {:?} with size {}", config, length);
 | 
			
		||||
    board.board_hal.set_config(config);
 | 
			
		||||
    anyhow::Ok(Some("saved".to_string()))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async fn read_up_to_bytes_from_request<T, const N: usize>(
 | 
			
		||||
    request: &mut Connection<'_, T, N>,
 | 
			
		||||
    limit: Option<usize>,
 | 
			
		||||
) -> Result<Vec<u8>, anyhow::Error>
 | 
			
		||||
where
 | 
			
		||||
    T: Read + Write,
 | 
			
		||||
{
 | 
			
		||||
    let max_read = limit.unwrap_or(1024);
 | 
			
		||||
    let mut data_store = Vec::new();
 | 
			
		||||
    let mut total_read = 0;
 | 
			
		||||
    loop {
 | 
			
		||||
        let mut buf = [0_u8; 64];
 | 
			
		||||
        let read = match request.read(&mut buf).await {
 | 
			
		||||
            Ok(read) => read,
 | 
			
		||||
            Err(e) => bail!("Error reading request {:?}", e),
 | 
			
		||||
        };
 | 
			
		||||
        if read == 0 {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        let actual_data = &buf[0..read];
 | 
			
		||||
        total_read += read;
 | 
			
		||||
        if total_read > max_read {
 | 
			
		||||
            bail!("Request too large {total_read} > {max_read}");
 | 
			
		||||
        }
 | 
			
		||||
        data_store.push(actual_data.to_owned());
 | 
			
		||||
    }
 | 
			
		||||
    let allvec = data_store.concat();
 | 
			
		||||
    log::info!("Raw data {}", from_utf8(&allvec)?);
 | 
			
		||||
    Ok(allvec)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async fn wifi_scan<T, const N: usize>(
 | 
			
		||||
    _request: &mut Connection<'_, T, N>,
 | 
			
		||||
) -> Result<Option<String>, anyhow::Error> {
 | 
			
		||||
@@ -463,7 +491,7 @@ async fn list_files<T, const N: usize>(
 | 
			
		||||
    _request: &mut Connection<'_, T, N>,
 | 
			
		||||
) -> Result<Option<String>, anyhow::Error> {
 | 
			
		||||
    let mut board = BOARD_ACCESS.get().await.lock().await;
 | 
			
		||||
    let result = board.board_hal.get_esp().list_files().await;
 | 
			
		||||
    let result = board.board_hal.get_esp().list_files().await?;
 | 
			
		||||
    let file_list_json = serde_json::to_string(&result)?;
 | 
			
		||||
    anyhow::Ok(Some(file_list_json))
 | 
			
		||||
}
 | 
			
		||||
@@ -537,7 +565,7 @@ pub async fn httpd(reboot_now: Arc<AtomicBool>, stack: Stack<'static>) {
 | 
			
		||||
        .await
 | 
			
		||||
        .unwrap();
 | 
			
		||||
 | 
			
		||||
    let mut server: Server<2, 512, 10> = Server::new();
 | 
			
		||||
    let mut server: Server<2, 512, 15> = Server::new();
 | 
			
		||||
    server
 | 
			
		||||
        .run(Some(5000), acceptor, HttpHandler { reboot_now })
 | 
			
		||||
        .await
 | 
			
		||||
@@ -637,11 +665,6 @@ pub async fn httpd(reboot_now: Arc<AtomicBool>, stack: Stack<'static>) {
 | 
			
		||||
    //     .unwrap();
 | 
			
		||||
    //
 | 
			
		||||
    // server
 | 
			
		||||
    //     .fn_handler("/set_config", Method::Post, move |request| {
 | 
			
		||||
    //         handle_error_to500(request, set_config)
 | 
			
		||||
    //     })
 | 
			
		||||
    //     .unwrap();
 | 
			
		||||
    // server
 | 
			
		||||
    //     .fn_handler("/backup_config", Method::Post, move |request| {
 | 
			
		||||
    //         handle_error_to500(request, backup_config)
 | 
			
		||||
    //     })
 | 
			
		||||
@@ -817,30 +840,6 @@ pub async fn httpd(reboot_now: Arc<AtomicBool>, stack: Stack<'static>) {
 | 
			
		||||
    //server
 | 
			
		||||
}
 | 
			
		||||
//
 | 
			
		||||
// fn read_up_to_bytes_from_request(
 | 
			
		||||
//     request: &mut Request<&mut EspHttpConnection<'_>>,
 | 
			
		||||
//     limit: Option<usize>,
 | 
			
		||||
// ) -> Result<Vec<u8>, anyhow::Error> {
 | 
			
		||||
//     let max_read = limit.unwrap_or(1024);
 | 
			
		||||
//     let mut data_store = Vec::new();
 | 
			
		||||
//     let mut total_read = 0;
 | 
			
		||||
//     loop {
 | 
			
		||||
//         let mut buf = [0_u8; 64];
 | 
			
		||||
//         let read = request.read(&mut buf)?;
 | 
			
		||||
//         if read == 0 {
 | 
			
		||||
//             break;
 | 
			
		||||
//         }
 | 
			
		||||
//         let actual_data = &buf[0..read];
 | 
			
		||||
//         total_read += read;
 | 
			
		||||
//         if total_read > max_read {
 | 
			
		||||
//             bail!("Request too large {total_read} > {max_read}");
 | 
			
		||||
//         }
 | 
			
		||||
//         data_store.push(actual_data.to_owned());
 | 
			
		||||
//     }
 | 
			
		||||
//     let allvec = data_store.concat();
 | 
			
		||||
//     log::info!("Raw data {}", from_utf8(&allvec)?);
 | 
			
		||||
//     Ok(allvec)
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
async fn handle_json<'a, T, const N: usize>(
 | 
			
		||||
    conn: &mut Connection<'a, T, N>,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user