Compare commits
No commits in common. "cd63e76469655b2b48c0d3d11f994538bae6511f" and "1c84cd00daba19b30f3e1b430dd518bc1b84ee74" have entirely different histories.
cd63e76469
...
1c84cd00da
@ -159,8 +159,6 @@ edge-nal-embassy = "0.6.0"
|
|||||||
static_cell = "2.1.1"
|
static_cell = "2.1.1"
|
||||||
cfg-if = "1.0.3"
|
cfg-if = "1.0.3"
|
||||||
edge-http = { version = "0.6.1", features = ["log"] }
|
edge-http = { version = "0.6.1", features = ["log"] }
|
||||||
littlefs2 = { version = "0.6.1", features = ["c-stubs", "alloc", "serde"] }
|
|
||||||
littlefs2-core = "0.1.1"
|
|
||||||
|
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
[connection]
|
format = "EspIdf"
|
||||||
|
|
||||||
[[usb_device]]
|
[idf_format_args]
|
||||||
vid = "303a"
|
|
||||||
pid = "1001"
|
|
||||||
|
|
||||||
[flash]
|
[flash]
|
||||||
size = "16MB"
|
size = "16MB"
|
||||||
|
@ -3,4 +3,4 @@ otadata, data, ota, , 8k,
|
|||||||
phy_init, data, phy, , 4k,
|
phy_init, data, phy, , 4k,
|
||||||
ota_0, app, ota_0, , 3968k,
|
ota_0, app, ota_0, , 3968k,
|
||||||
ota_1, app, ota_1, , 3968k,
|
ota_1, app, ota_1, , 3968k,
|
||||||
storage, data, littlefs,, 8M,
|
storage, data, spiffs, , 8M,
|
||||||
|
|
@ -1,78 +0,0 @@
|
|||||||
use embedded_storage::{ReadStorage, Storage};
|
|
||||||
use esp_bootloader_esp_idf::partitions::FlashRegion;
|
|
||||||
use esp_storage::FlashStorage;
|
|
||||||
use littlefs2::consts::U1 as lfs2Array1;
|
|
||||||
use littlefs2::consts::U512 as lfs2Array512;
|
|
||||||
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, info};
|
|
||||||
|
|
||||||
pub struct LittleFs2Filesystem {
|
|
||||||
pub(crate) storage: &'static mut FlashRegion<'static, FlashStorage>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl lfs2Storage for LittleFs2Filesystem {
|
|
||||||
const READ_SIZE: usize = 512;
|
|
||||||
const WRITE_SIZE: usize = 512;
|
|
||||||
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);
|
|
||||||
match self.storage.read(off as u32, buf) {
|
|
||||||
anyhow::Result::Ok(..) => lfs2Result::Ok(buf.len()),
|
|
||||||
Err(err) => {
|
|
||||||
error!("Littlefs2Filesystem read error: {:?}", err);
|
|
||||||
Err(lfs2Error::IO)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
match self.storage.write(off as u32, data) {
|
|
||||||
anyhow::Result::Ok(..) => lfs2Result::Ok(data.len()),
|
|
||||||
Err(err) => {
|
|
||||||
error!("Littlefs2Filesystem write error: {:?}", err);
|
|
||||||
Err(lfs2Error::IO)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
lfs2Result::Ok(len)
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,7 +6,6 @@ use anyhow::{anyhow, bail, Context};
|
|||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::hal::LittleFS2StorageAdapter::LittleFs2Filesystem;
|
|
||||||
use alloc::string::ToString;
|
use alloc::string::ToString;
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use alloc::{format, string::String, vec::Vec};
|
use alloc::{format, string::String, vec::Vec};
|
||||||
@ -18,7 +17,6 @@ use embassy_net::tcp::TcpSocket;
|
|||||||
use embassy_net::{IpListenEndpoint, Ipv4Cidr, Runner, Stack, StackResources, StaticConfigV4};
|
use embassy_net::{IpListenEndpoint, Ipv4Cidr, Runner, Stack, StackResources, StaticConfigV4};
|
||||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
use embassy_sync::mutex::Mutex;
|
use embassy_sync::mutex::Mutex;
|
||||||
use embassy_sync::rwlock::TryLockError;
|
|
||||||
use embassy_time::{Duration, Instant, Timer};
|
use embassy_time::{Duration, Instant, Timer};
|
||||||
use embedded_storage::nor_flash::ReadNorFlash;
|
use embedded_storage::nor_flash::ReadNorFlash;
|
||||||
use embedded_storage::Storage;
|
use embedded_storage::Storage;
|
||||||
@ -31,10 +29,8 @@ use esp_println::{print, println};
|
|||||||
use esp_storage::FlashStorage;
|
use esp_storage::FlashStorage;
|
||||||
use esp_wifi::wifi::{
|
use esp_wifi::wifi::{
|
||||||
AccessPointConfiguration, AccessPointInfo, Configuration, Interfaces, ScanConfig,
|
AccessPointConfiguration, AccessPointInfo, Configuration, Interfaces, ScanConfig,
|
||||||
ScanTypeConfig, WifiController, WifiDevice, WifiEvent, WifiState,
|
WifiController, WifiDevice, WifiEvent, WifiState,
|
||||||
};
|
};
|
||||||
use littlefs2::fs::Filesystem;
|
|
||||||
use littlefs2_core::{FileType, PathBuf};
|
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
|
||||||
#[link_section = ".rtc.data"]
|
#[link_section = ".rtc.data"]
|
||||||
@ -46,8 +42,6 @@ static mut LOW_VOLTAGE_DETECTED: bool = false;
|
|||||||
#[link_section = ".rtc.data"]
|
#[link_section = ".rtc.data"]
|
||||||
static mut RESTART_TO_CONF: bool = false;
|
static mut RESTART_TO_CONF: bool = false;
|
||||||
|
|
||||||
static CONFIG_FILE: &str = "config.json";
|
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
#[derive(Serialize, Debug)]
|
||||||
pub struct FileInfo {
|
pub struct FileInfo {
|
||||||
filename: String,
|
filename: String,
|
||||||
@ -59,6 +53,8 @@ pub struct FileList {
|
|||||||
total: usize,
|
total: usize,
|
||||||
used: usize,
|
used: usize,
|
||||||
files: Vec<FileInfo>,
|
files: Vec<FileInfo>,
|
||||||
|
file_system_corrupt: Option<String>,
|
||||||
|
iter_error: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FileSystemSizeInfo {
|
pub struct FileSystemSizeInfo {
|
||||||
@ -73,7 +69,6 @@ pub struct MqttClient<'a> {
|
|||||||
base_topic: heapless::String<64>,
|
base_topic: heapless::String<64>,
|
||||||
}
|
}
|
||||||
pub struct Esp<'a> {
|
pub struct Esp<'a> {
|
||||||
pub fs: Arc<Mutex<CriticalSectionRawMutex, Filesystem<'static, LittleFs2Filesystem>>>,
|
|
||||||
pub rng: Rng,
|
pub rng: Rng,
|
||||||
//first starter (ap or sta will take these)
|
//first starter (ap or sta will take these)
|
||||||
pub interfaces: Option<Interfaces<'static>>,
|
pub interfaces: Option<Interfaces<'static>>,
|
||||||
@ -89,14 +84,6 @@ pub struct Esp<'a> {
|
|||||||
pub ota_next: &'static mut FlashRegion<'static, FlashStorage>,
|
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 struct IpInfo {
|
||||||
pub(crate) ip: IpAddr,
|
pub(crate) ip: IpAddr,
|
||||||
netmask: IpAddr,
|
netmask: IpAddr,
|
||||||
@ -112,7 +99,13 @@ macro_rules! mk_static {
|
|||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static WIFI_CONTROLLER: static_cell::StaticCell<WifiController> = static_cell::StaticCell::new();
|
||||||
|
|
||||||
impl Esp<'_> {
|
impl Esp<'_> {
|
||||||
|
const SPIFFS_PARTITION_NAME: &'static str = "storage";
|
||||||
|
const CONFIG_FILE: &'static str = "/spiffs/config.cfg";
|
||||||
|
const BASE_PATH: &'static str = "/spiffs";
|
||||||
|
|
||||||
pub(crate) fn get_ota_slot(&mut self) -> String {
|
pub(crate) fn get_ota_slot(&mut self) -> String {
|
||||||
match self.ota.current_slot() {
|
match self.ota.current_slot() {
|
||||||
Ok(slot) => {
|
Ok(slot) => {
|
||||||
@ -171,26 +164,14 @@ impl Esp<'_> {
|
|||||||
DateTime::from_timestamp_millis(wall_clock as i64).unwrap()
|
DateTime::from_timestamp_millis(wall_clock as i64).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn wifi_scan(&mut self) -> anyhow::Result<Vec<AccessPointInfo>> {
|
pub(crate) async fn wifi_scan(&mut self) -> Vec<AccessPointInfo> {
|
||||||
info!("start wifi scan");
|
info!("start wifi scan");
|
||||||
let mut lock = self
|
let mut lock = self.controller.try_lock().unwrap();
|
||||||
.controller
|
|
||||||
.try_lock()
|
|
||||||
.map_err(|_| anyhow!("Could not lock wifi controller, currently in use"))?;
|
|
||||||
info!("start wifi scan lock");
|
info!("start wifi scan lock");
|
||||||
let scan_config = ScanConfig {
|
let scan_config = ScanConfig::default();
|
||||||
ssid: None,
|
let rv = lock.scan_with_config_sync(scan_config).unwrap();
|
||||||
bssid: None,
|
|
||||||
channel: None,
|
|
||||||
show_hidden: false,
|
|
||||||
scan_type: ScanTypeConfig::Passive(core::time::Duration::from_secs(2)),
|
|
||||||
};
|
|
||||||
let rv = lock
|
|
||||||
.scan_with_config_async(scan_config)
|
|
||||||
.await
|
|
||||||
.map_err(|err| anyhow!("Could not scan wifi: {:?}", err))?;
|
|
||||||
info!("end wifi scan lock");
|
info!("end wifi scan lock");
|
||||||
Ok(rv)
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn last_pump_time(&self, plant: usize) -> Option<DateTime<Utc>> {
|
pub(crate) fn last_pump_time(&self, plant: usize) -> Option<DateTime<Utc>> {
|
||||||
@ -234,7 +215,7 @@ impl Esp<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn wifi_ap(&mut self) -> anyhow::Result<Stack<'static>> {
|
pub(crate) async fn wifi_ap(&mut self) -> anyhow::Result<Stack<'static>> {
|
||||||
let ssid = match self.load_config().await {
|
let ssid = match self.load_config() {
|
||||||
Ok(config) => config.network.ap_ssid.as_str().to_string(),
|
Ok(config) => config.network.ap_ssid.as_str().to_string(),
|
||||||
Err(_) => "PlantCtrl Emergency Mode".to_string(),
|
Err(_) => "PlantCtrl Emergency Mode".to_string(),
|
||||||
};
|
};
|
||||||
@ -242,7 +223,7 @@ impl Esp<'_> {
|
|||||||
let spawner = Spawner::for_current_executor().await;
|
let spawner = Spawner::for_current_executor().await;
|
||||||
|
|
||||||
let device = self.interfaces.take().unwrap().ap;
|
let device = self.interfaces.take().unwrap().ap;
|
||||||
let gw_ip_addr_str = "192.168.71.1";
|
let gw_ip_addr_str = GW_IP_ADDR_ENV.unwrap_or("192.168.2.1");
|
||||||
let gw_ip_addr = Ipv4Addr::from_str(gw_ip_addr_str).expect("failed to parse gateway ip");
|
let gw_ip_addr = Ipv4Addr::from_str(gw_ip_addr_str).expect("failed to parse gateway ip");
|
||||||
|
|
||||||
let config = embassy_net::Config::ipv4_static(StaticConfigV4 {
|
let config = embassy_net::Config::ipv4_static(StaticConfigV4 {
|
||||||
@ -380,29 +361,50 @@ impl Esp<'_> {
|
|||||||
// log(LogMessage::WifiInfo, 0, 0, "", &format!("{address:?}"));
|
// log(LogMessage::WifiInfo, 0, 0, "", &format!("{address:?}"));
|
||||||
// anyhow::Ok(address)
|
// anyhow::Ok(address)
|
||||||
}
|
}
|
||||||
pub(crate) async fn load_config(&mut self) -> anyhow::Result<PlantControllerConfig> {
|
pub(crate) fn load_config(&mut self) -> anyhow::Result<PlantControllerConfig> {
|
||||||
let cfg = PathBuf::try_from(CONFIG_FILE).unwrap();
|
bail!("todo");
|
||||||
match self.fs.lock().await.read::<4096>(&cfg) {
|
// let cfg = File::open(Self::CONFIG_FILE)?;
|
||||||
Ok(data) => {
|
// let config: PlantControllerConfig = serde_json::from_reader(cfg)?;
|
||||||
let config: PlantControllerConfig = serde_json::from_slice(&data)?;
|
// anyhow::Ok(config)
|
||||||
anyhow::Ok(config)
|
|
||||||
}
|
}
|
||||||
Err(err) => {
|
pub(crate) async fn save_config(
|
||||||
bail!(format!("{err:?}"))
|
&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");
|
||||||
pub(crate) async fn save_config(&mut self, config: Vec<u8>) -> anyhow::Result<()> {
|
// log(LogMessage::MountingFilesystem, 0, 0, "", "");
|
||||||
let filesystem = self.fs.lock().await;
|
// let base_path = String::try_from("/spiffs")?;
|
||||||
let cfg = PathBuf::try_from(CONFIG_FILE).unwrap();
|
// let storage = String::try_from(Self::SPIFFS_PARTITION_NAME)?;
|
||||||
|
//let conf = todo!();
|
||||||
|
|
||||||
match filesystem.write(&cfg, &*config) {
|
//let conf = esp_idf_sys::esp_vfs_spiffs_conf_t {
|
||||||
Ok(_) => {}
|
//base_path: base_path.as_ptr(),
|
||||||
Err(err) => {
|
//partition_label: storage.as_ptr(),
|
||||||
bail!(format!("{err:?}"))
|
//max_files: 5,
|
||||||
}
|
//format_if_mount_failed: true,
|
||||||
}
|
//};
|
||||||
anyhow::Ok(())
|
|
||||||
|
//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(())
|
||||||
}
|
}
|
||||||
async fn file_system_size(&mut self) -> anyhow::Result<FileSystemSizeInfo> {
|
async fn file_system_size(&mut self) -> anyhow::Result<FileSystemSizeInfo> {
|
||||||
bail!("fail");
|
bail!("fail");
|
||||||
@ -423,32 +425,60 @@ impl Esp<'_> {
|
|||||||
// })
|
// })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn list_files(&self) -> anyhow::Result<FileList> {
|
pub(crate) async fn list_files(&self) -> FileList {
|
||||||
let path = PathBuf::new();
|
return FileList {
|
||||||
|
|
||||||
let mut result = FileList {
|
|
||||||
total: 0,
|
total: 0,
|
||||||
used: 0,
|
used: 0,
|
||||||
|
file_system_corrupt: None,
|
||||||
files: Vec::new(),
|
files: Vec::new(),
|
||||||
|
iter_error: None,
|
||||||
};
|
};
|
||||||
|
//
|
||||||
match self.fs.lock().await.read_dir_and_then(&path, |dir| {
|
// let storage = CString::new(Self::SPIFFS_PARTITION_NAME).unwrap();
|
||||||
for entry in dir {
|
//
|
||||||
let e = entry?;
|
// let mut file_system_corrupt = None;
|
||||||
|
//
|
||||||
result.files.push(FileInfo {
|
// let mut iter_error = None;
|
||||||
filename: e.path().to_string(),
|
// let mut result = Vec::new();
|
||||||
size: e.metadata().len(),
|
//
|
||||||
});
|
// let filepath = Path::new(Self::BASE_PATH);
|
||||||
}
|
// let read_dir = fs::read_dir(filepath);
|
||||||
Result::Ok(())
|
// match read_dir {
|
||||||
}) {
|
// OkStd(read_dir) => {
|
||||||
Ok(_) => {}
|
// for item in read_dir {
|
||||||
Err(err) => {
|
// match item {
|
||||||
bail!(format!("{err:?}"))
|
// OkStd(file) => {
|
||||||
}
|
// let f = FileInfo {
|
||||||
}
|
// filename: file.file_name().into_string().unwrap(),
|
||||||
Ok(result)
|
// size: file.metadata().map(|it| it.len()).unwrap_or_default()
|
||||||
|
// as usize,
|
||||||
|
// };
|
||||||
|
// result.push(f);
|
||||||
|
// }
|
||||||
|
// Err(err) => {
|
||||||
|
// iter_error = Some(format!("{err:?}"));
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// Err(err) => {
|
||||||
|
// file_system_corrupt = Some(format!("{err:?}"));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// let mut total: usize = 0;
|
||||||
|
// let mut used: usize = 0;
|
||||||
|
// unsafe {
|
||||||
|
// esp_spiffs_info(storage.as_ptr(), &mut total, &mut used);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// FileList {
|
||||||
|
// total,
|
||||||
|
// used,
|
||||||
|
// file_system_corrupt,
|
||||||
|
// files: result,
|
||||||
|
// iter_error,
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
pub(crate) async fn delete_file(&self, _filename: &str) -> anyhow::Result<()> {
|
pub(crate) async fn delete_file(&self, _filename: &str) -> anyhow::Result<()> {
|
||||||
bail!("todo");
|
bail!("todo");
|
||||||
|
@ -125,8 +125,11 @@ impl<'a> BoardInteraction<'a> for Initial<'a> {
|
|||||||
bail!("Please configure board revision")
|
bail!("Please configure board revision")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_config(&mut self, config: PlantControllerConfig) {
|
async fn set_config(&mut self, config: PlantControllerConfig) -> anyhow::Result<()> {
|
||||||
self.config = config;
|
self.config = config;
|
||||||
|
//TODO
|
||||||
|
// self.esp.save_config(&self.config)?;
|
||||||
|
anyhow::Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_mptt_voltage(&mut self) -> Result<Voltage> {
|
async fn get_mptt_voltage(&mut self) -> Result<Voltage> {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
mod LittleFS2StorageAdapter;
|
|
||||||
pub(crate) mod battery;
|
pub(crate) mod battery;
|
||||||
pub mod esp;
|
pub mod esp;
|
||||||
mod initial_hal;
|
mod initial_hal;
|
||||||
@ -23,7 +22,7 @@ use crate::{
|
|||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use alloc::format;
|
use alloc::format;
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use anyhow::{bail, Ok, Result};
|
use anyhow::{Ok, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
//use battery::BQ34Z100G1;
|
//use battery::BQ34Z100G1;
|
||||||
@ -33,13 +32,11 @@ use esp_bootloader_esp_idf::partitions::{
|
|||||||
AppPartitionSubType, DataPartitionSubType, FlashRegion, PartitionEntry,
|
AppPartitionSubType, DataPartitionSubType, FlashRegion, PartitionEntry,
|
||||||
};
|
};
|
||||||
use esp_hal::clock::CpuClock;
|
use esp_hal::clock::CpuClock;
|
||||||
use esp_hal::gpio::{Input, InputConfig, Pull};
|
use esp_hal::gpio::{Input, InputConfig, Io, Pull};
|
||||||
use esp_println::println;
|
use esp_println::println;
|
||||||
use measurements::{Current, Voltage};
|
use measurements::{Current, Voltage};
|
||||||
|
|
||||||
use crate::hal::LittleFS2StorageAdapter::LittleFs2Filesystem;
|
|
||||||
use embassy_sync::mutex::Mutex;
|
use embassy_sync::mutex::Mutex;
|
||||||
use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
|
|
||||||
use esp_alloc as _;
|
use esp_alloc as _;
|
||||||
use esp_backtrace as _;
|
use esp_backtrace as _;
|
||||||
use esp_bootloader_esp_idf::ota::Slot;
|
use esp_bootloader_esp_idf::ota::Slot;
|
||||||
@ -47,9 +44,6 @@ use esp_hal::rng::Rng;
|
|||||||
use esp_hal::timer::timg::TimerGroup;
|
use esp_hal::timer::timg::TimerGroup;
|
||||||
use esp_storage::FlashStorage;
|
use esp_storage::FlashStorage;
|
||||||
use esp_wifi::{init, EspWifiController};
|
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!
|
//Only support for 8 right now!
|
||||||
pub const PLANT_COUNT: usize = 8;
|
pub const PLANT_COUNT: usize = 8;
|
||||||
@ -89,7 +83,7 @@ pub trait BoardInteraction<'a> {
|
|||||||
async fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> Result<f32>;
|
async fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> Result<f32>;
|
||||||
async fn general_fault(&mut self, enable: bool);
|
async fn general_fault(&mut self, enable: bool);
|
||||||
async fn test(&mut self) -> Result<()>;
|
async fn test(&mut self) -> Result<()>;
|
||||||
fn set_config(&mut self, config: PlantControllerConfig);
|
async fn set_config(&mut self, config: PlantControllerConfig) -> Result<()>;
|
||||||
async fn get_mptt_voltage(&mut self) -> anyhow::Result<Voltage>;
|
async fn get_mptt_voltage(&mut self) -> anyhow::Result<Voltage>;
|
||||||
async fn get_mptt_current(&mut self) -> anyhow::Result<Current>;
|
async fn get_mptt_current(&mut self) -> anyhow::Result<Current>;
|
||||||
}
|
}
|
||||||
@ -100,12 +94,7 @@ impl dyn BoardInteraction<'_> {
|
|||||||
let even = counter % 2 == 0;
|
let even = counter % 2 == 0;
|
||||||
let current = counter / (PLANT_COUNT as u32);
|
let current = counter / (PLANT_COUNT as u32);
|
||||||
for led in 0..PLANT_COUNT {
|
for led in 0..PLANT_COUNT {
|
||||||
match self.fault(led, current == led as u32).await {
|
self.fault(led, current == led as u32).await.unwrap();
|
||||||
Result::Ok(_) => {}
|
|
||||||
Err(err) => {
|
|
||||||
warn!("Fault on plant {}: {:?}", led, err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let _ = self.general_fault(even.into());
|
let _ = self.general_fault(even.into());
|
||||||
}
|
}
|
||||||
@ -193,11 +182,11 @@ impl PlantHal {
|
|||||||
let timg0 = TimerGroup::new(peripherals.TIMG0);
|
let timg0 = TimerGroup::new(peripherals.TIMG0);
|
||||||
let esp_wifi_ctrl = &*mk_static!(
|
let esp_wifi_ctrl = &*mk_static!(
|
||||||
EspWifiController<'static>,
|
EspWifiController<'static>,
|
||||||
init(timg0.timer0, rng.clone()).expect("Could not init wifi controller")
|
init(timg0.timer0, rng.clone()).unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
let (controller, interfaces) =
|
let (controller, interfaces) =
|
||||||
esp_wifi::wifi::new(&esp_wifi_ctrl, peripherals.WIFI).expect("Could not init wifi");
|
esp_wifi::wifi::new(&esp_wifi_ctrl, peripherals.WIFI).unwrap();
|
||||||
|
|
||||||
use esp_hal::timer::systimer::SystemTimer;
|
use esp_hal::timer::systimer::SystemTimer;
|
||||||
esp_hal_embassy::init(systimer.alarm0);
|
esp_hal_embassy::init(systimer.alarm0);
|
||||||
@ -240,9 +229,11 @@ 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!(
|
let tablebuffer = mk_static!(
|
||||||
[u8; esp_bootloader_esp_idf::partitions::PARTITION_TABLE_MAX_LEN],
|
[u8; esp_bootloader_esp_idf::partitions::PARTITION_TABLE_MAX_LEN],
|
||||||
[0u8; esp_bootloader_esp_idf::partitions::PARTITION_TABLE_MAX_LEN]
|
tablebuffer
|
||||||
);
|
);
|
||||||
let storage_ota = mk_static!(FlashStorage, FlashStorage::new());
|
let storage_ota = mk_static!(FlashStorage, FlashStorage::new());
|
||||||
let pt =
|
let pt =
|
||||||
@ -250,79 +241,46 @@ impl PlantHal {
|
|||||||
|
|
||||||
// List all partitions - this is just FYI
|
// List all partitions - this is just FYI
|
||||||
for i in 0..pt.len() {
|
for i in 0..pt.len() {
|
||||||
info!("{:?}", pt.get_partition(i));
|
println!("{:?}", pt.get_partition(i));
|
||||||
}
|
}
|
||||||
let ota_data = mk_static!(
|
|
||||||
PartitionEntry,
|
let ota_data = pt
|
||||||
pt.find_partition(esp_bootloader_esp_idf::partitions::PartitionType::Data(
|
.find_partition(esp_bootloader_esp_idf::partitions::PartitionType::Data(
|
||||||
DataPartitionSubType::Ota,
|
DataPartitionSubType::Ota,
|
||||||
))?
|
))?
|
||||||
.expect("No OTA data partition found")
|
.unwrap();
|
||||||
);
|
|
||||||
|
|
||||||
let ota_data = mk_static!(
|
let ota_data = mk_static!(PartitionEntry, ota_data);
|
||||||
FlashRegion<FlashStorage>,
|
|
||||||
ota_data.as_embedded_storage(storage_ota)
|
let ota_data = ota_data.as_embedded_storage(storage_ota);
|
||||||
);
|
let ota_data = mk_static!(FlashRegion<FlashStorage>, ota_data);
|
||||||
|
|
||||||
let mut ota = esp_bootloader_esp_idf::ota::Ota::new(ota_data)?;
|
let mut ota = esp_bootloader_esp_idf::ota::Ota::new(ota_data)?;
|
||||||
|
|
||||||
let ota_partition = match ota.current_slot()? {
|
let ota_partition = match ota.current_slot()? {
|
||||||
Slot::None => {
|
Slot::None => {
|
||||||
panic!("No OTA slot active?");
|
panic!("No OTA slot found");
|
||||||
}
|
}
|
||||||
Slot::Slot0 => pt
|
Slot::Slot0 => pt
|
||||||
.find_partition(esp_bootloader_esp_idf::partitions::PartitionType::App(
|
.find_partition(esp_bootloader_esp_idf::partitions::PartitionType::App(
|
||||||
AppPartitionSubType::Ota0,
|
AppPartitionSubType::Ota0,
|
||||||
))?
|
))?
|
||||||
.expect("No OTA slot0 found"),
|
.unwrap(),
|
||||||
Slot::Slot1 => pt
|
Slot::Slot1 => pt
|
||||||
.find_partition(esp_bootloader_esp_idf::partitions::PartitionType::App(
|
.find_partition(esp_bootloader_esp_idf::partitions::PartitionType::App(
|
||||||
AppPartitionSubType::Ota1,
|
AppPartitionSubType::Ota1,
|
||||||
))?
|
))?
|
||||||
.expect("No OTA slot1 found"),
|
.unwrap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let ota_next = mk_static!(PartitionEntry, ota_partition);
|
let ota_next = mk_static!(PartitionEntry, ota_partition);
|
||||||
let storage_ota = mk_static!(FlashStorage, FlashStorage::new());
|
let storage_ota_next = mk_static!(FlashStorage, FlashStorage::new());
|
||||||
let ota_next = mk_static!(
|
let ota_next = mk_static!(
|
||||||
FlashRegion<FlashStorage>,
|
FlashRegion<FlashStorage>,
|
||||||
ota_next.as_embedded_storage(storage_ota)
|
ota_next.as_embedded_storage(storage_ota_next)
|
||||||
);
|
);
|
||||||
|
|
||||||
let data_partition = pt
|
|
||||||
.find_partition(esp_bootloader_esp_idf::partitions::PartitionType::Data(
|
|
||||||
DataPartitionSubType::LittleFs,
|
|
||||||
))?
|
|
||||||
.expect("Data partition with littlefs not found");
|
|
||||||
let data_partition = mk_static!(PartitionEntry, data_partition);
|
|
||||||
|
|
||||||
let storage_data = mk_static!(FlashStorage, FlashStorage::new());
|
|
||||||
let data = mk_static!(
|
|
||||||
FlashRegion<FlashStorage>,
|
|
||||||
data_partition.as_embedded_storage(storage_data)
|
|
||||||
);
|
|
||||||
let lfs2filesystem = mk_static!(LittleFs2Filesystem, LittleFs2Filesystem { storage: data });
|
|
||||||
let alloc = mk_static!(Allocation<LittleFs2Filesystem>, lfs2Filesystem::allocate());
|
|
||||||
if lfs2filesystem.is_mountable() {
|
|
||||||
log::info!("Littlefs2 filesystem is mountable");
|
|
||||||
} else {
|
|
||||||
match lfs2filesystem.format() {
|
|
||||||
Result::Ok(..) => {
|
|
||||||
log::info!("Littlefs2 filesystem is formatted");
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
bail!("Littlefs2 filesystem could not be formatted: {:?}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let fs = Arc::new(Mutex::new(
|
|
||||||
lfs2Filesystem::mount(alloc, lfs2filesystem).expect("Could not mount lfs2 filesystem"),
|
|
||||||
));
|
|
||||||
|
|
||||||
let mut esp = Esp {
|
let mut esp = Esp {
|
||||||
fs,
|
|
||||||
rng,
|
rng,
|
||||||
controller: Arc::new(Mutex::new(controller)),
|
controller: Arc::new(Mutex::new(controller)),
|
||||||
interfaces: Some(interfaces),
|
interfaces: Some(interfaces),
|
||||||
@ -367,8 +325,9 @@ impl PlantHal {
|
|||||||
);
|
);
|
||||||
|
|
||||||
esp.init_rtc_deepsleep_memory(init_rtc_store, to_config_mode);
|
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().await;
|
let config = esp.load_config();
|
||||||
|
|
||||||
log::info!("Init rtc driver");
|
log::info!("Init rtc driver");
|
||||||
// let mut rtc = Ds323x::new_ds3231(MutexDevice::new(&I2C_DRIVER));
|
// let mut rtc = Ds323x::new_ds3231(MutexDevice::new(&I2C_DRIVER));
|
||||||
|
@ -232,10 +232,8 @@ async fn safe_main(spawner: Spawner) -> anyhow::Result<()> {
|
|||||||
info!("no mode override");
|
info!("no mode override");
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO hack
|
if board.board_hal.get_config().hardware.board == INITIAL
|
||||||
if true
|
&& board.board_hal.get_config().network.ssid.is_none()
|
||||||
|| (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");
|
info!("No wifi configured, starting initial config mode");
|
||||||
|
|
||||||
|
@ -1,21 +1,17 @@
|
|||||||
//offer ota and config mode
|
//offer ota and config mode
|
||||||
|
|
||||||
use crate::config::PlantControllerConfig;
|
|
||||||
use crate::{get_version, log::LogMessage, BOARD_ACCESS};
|
use crate::{get_version, log::LogMessage, BOARD_ACCESS};
|
||||||
use alloc::borrow::ToOwned;
|
|
||||||
use alloc::string::{String, ToString};
|
use alloc::string::{String, ToString};
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use anyhow::bail;
|
|
||||||
use core::fmt::{Debug, Display};
|
use core::fmt::{Debug, Display};
|
||||||
use core::net::{IpAddr, Ipv4Addr, SocketAddr};
|
use core::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
use core::result::Result::Ok;
|
use core::result::Result::Ok;
|
||||||
use core::str::from_utf8;
|
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
use edge_http::io::server::{Connection, Handler, Server};
|
use edge_http::io::server::{Connection, Handler, Server};
|
||||||
use edge_http::io::Error;
|
use edge_http::io::Error;
|
||||||
use edge_http::Method;
|
use edge_http::Method;
|
||||||
use edge_nal::{TcpBind, TcpSplit};
|
use edge_nal::TcpBind;
|
||||||
use edge_nal_embassy::{Tcp, TcpBuffers};
|
use edge_nal_embassy::{Tcp, TcpBuffers};
|
||||||
use embassy_net::Stack;
|
use embassy_net::Stack;
|
||||||
use embassy_time::Instant;
|
use embassy_time::Instant;
|
||||||
@ -189,7 +185,16 @@ pub struct NightLampCommand {
|
|||||||
// anyhow::Ok(Some(json))
|
// 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()))
|
||||||
|
// }
|
||||||
//
|
//
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -309,7 +314,11 @@ struct HttpHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Handler for HttpHandler {
|
impl Handler for HttpHandler {
|
||||||
type Error<E: core::fmt::Debug> = Error<E>;
|
type Error<E>
|
||||||
|
= Error<E>
|
||||||
|
where
|
||||||
|
E: Debug;
|
||||||
|
|
||||||
async fn handle<'a, T, const N: usize>(
|
async fn handle<'a, T, const N: usize>(
|
||||||
&self,
|
&self,
|
||||||
_task_id: impl Display + Copy,
|
_task_id: impl Display + Copy,
|
||||||
@ -372,7 +381,6 @@ impl Handler for HttpHandler {
|
|||||||
Method::Post => {
|
Method::Post => {
|
||||||
let json = match path {
|
let json = match path {
|
||||||
"/wifiscan" => Some(wifi_scan(conn).await),
|
"/wifiscan" => Some(wifi_scan(conn).await),
|
||||||
"/set_config" => Some(set_config(conn).await),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
match json {
|
match json {
|
||||||
@ -390,6 +398,7 @@ impl Handler for HttpHandler {
|
|||||||
}
|
}
|
||||||
Some(code) => code,
|
Some(code) => code,
|
||||||
};
|
};
|
||||||
|
|
||||||
conn.complete().await?;
|
conn.complete().await?;
|
||||||
let response_time = Instant::now().duration_since(start).as_millis();
|
let response_time = Instant::now().duration_since(start).as_millis();
|
||||||
|
|
||||||
@ -398,76 +407,38 @@ impl Handler for HttpHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn set_config(
|
// .fn_handler("/reboot", Method::Post, move |_| {
|
||||||
// request: &mut Request<&mut EspHttpConnection>,
|
// 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>,
|
||||||
// ) -> Result<Option<std::string::String>, anyhow::Error> {
|
// ) -> Result<Option<std::string::String>, anyhow::Error> {
|
||||||
// let all = read_up_to_bytes_from_request(request, Some(4096))?;
|
// let mut board = BOARD_ACCESS.lock().unwrap();
|
||||||
// let config: PlantControllerConfig = serde_json::from_slice(&all)?;
|
// let scan_result = board.board_hal.get_esp().wifi_scan()?;
|
||||||
//
|
// let mut ssids: Vec<&String<32>> = Vec::new();
|
||||||
// let mut board = BOARD_ACCESS.lock().expect("board access");
|
// scan_result.iter().for_each(|s| ssids.push(&s.ssid));
|
||||||
// board.board_hal.set_config(config)?;
|
// let ssid_json = serde_json::to_string(&SSIDList { ssids })?;
|
||||||
// anyhow::Ok(Some("saved".to_owned()))
|
// log::info!("Sending ssid list {}", &ssid_json);
|
||||||
|
// anyhow::Ok(Some(ssid_json))
|
||||||
// }
|
// }
|
||||||
|
|
||||||
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>(
|
async fn wifi_scan<T, const N: usize>(
|
||||||
_request: &mut Connection<'_, T, N>,
|
_request: &mut Connection<'_, T, N>,
|
||||||
) -> Result<Option<String>, anyhow::Error> {
|
) -> Result<Option<String>, anyhow::Error> {
|
||||||
let mut board = BOARD_ACCESS.get().await.lock().await;
|
let mut board = BOARD_ACCESS.get().await.lock().await;
|
||||||
info!("start wifi scan");
|
info!("start wifi scan");
|
||||||
//let scan_result = board.board_hal.get_esp().wifi_scan().await?
|
let scan_result = board.board_hal.get_esp().wifi_scan().await;
|
||||||
//FIXME currently panics
|
|
||||||
let mut ssids: Vec<String> = Vec::new();
|
let mut ssids: Vec<String> = Vec::new();
|
||||||
//scan_result
|
scan_result
|
||||||
//.iter()
|
.iter()
|
||||||
//.for_each(|s| ssids.push(s.ssid.to_string()));
|
.for_each(|s| ssids.push(s.ssid.to_string()));
|
||||||
let ssid_json = serde_json::to_string(&SSIDList { ssids })?;
|
let ssid_json = serde_json::to_string(&SSIDList { ssids })?;
|
||||||
info!("Sending ssid list {}", &ssid_json);
|
info!("Sending ssid list {}", &ssid_json);
|
||||||
anyhow::Ok(Some(ssid_json))
|
anyhow::Ok(Some(ssid_json))
|
||||||
@ -491,7 +462,7 @@ async fn list_files<T, const N: usize>(
|
|||||||
_request: &mut Connection<'_, T, N>,
|
_request: &mut Connection<'_, T, N>,
|
||||||
) -> Result<Option<String>, anyhow::Error> {
|
) -> Result<Option<String>, anyhow::Error> {
|
||||||
let mut board = BOARD_ACCESS.get().await.lock().await;
|
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)?;
|
let file_list_json = serde_json::to_string(&result)?;
|
||||||
anyhow::Ok(Some(file_list_json))
|
anyhow::Ok(Some(file_list_json))
|
||||||
}
|
}
|
||||||
@ -561,11 +532,11 @@ pub async fn httpd(reboot_now: Arc<AtomicBool>, stack: Stack<'static>) {
|
|||||||
let buffer: TcpBuffers<2, 1024, 1024> = TcpBuffers::new();
|
let buffer: TcpBuffers<2, 1024, 1024> = TcpBuffers::new();
|
||||||
let tcp = Tcp::new(stack, &buffer);
|
let tcp = Tcp::new(stack, &buffer);
|
||||||
let acceptor = tcp
|
let acceptor = tcp
|
||||||
.bind(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 80))
|
.bind(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8080))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut server: Server<2, 512, 15> = Server::new();
|
let mut server: Server<2, 512, 10> = Server::new();
|
||||||
server
|
server
|
||||||
.run(Some(5000), acceptor, HttpHandler { reboot_now })
|
.run(Some(5000), acceptor, HttpHandler { reboot_now })
|
||||||
.await
|
.await
|
||||||
@ -665,6 +636,11 @@ pub async fn httpd(reboot_now: Arc<AtomicBool>, stack: Stack<'static>) {
|
|||||||
// .unwrap();
|
// .unwrap();
|
||||||
//
|
//
|
||||||
// server
|
// 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| {
|
// .fn_handler("/backup_config", Method::Post, move |request| {
|
||||||
// handle_error_to500(request, backup_config)
|
// handle_error_to500(request, backup_config)
|
||||||
// })
|
// })
|
||||||
@ -840,6 +816,30 @@ pub async fn httpd(reboot_now: Arc<AtomicBool>, stack: Stack<'static>) {
|
|||||||
//server
|
//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>(
|
async fn handle_json<'a, T, const N: usize>(
|
||||||
conn: &mut Connection<'a, T, N>,
|
conn: &mut Connection<'a, T, N>,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user