Merge branch 'goodby-espidf' of ssh://git.mannheim.ccc.de:1337/C3MA/PlantCtrl into goodby-espidf

This commit is contained in:
2025-11-13 20:08:45 +01:00
18 changed files with 256 additions and 188 deletions

View File

@@ -40,14 +40,14 @@ partition_table = "partitions.csv"
# Shared CAN API # Shared CAN API
canapi = { path = "../../Shared/canapi" } canapi = { path = "../../Shared/canapi" }
#ESP stuff #ESP stuff
esp-bootloader-esp-idf = { version = "0.2.0", features = ["esp32c6"] } esp-bootloader-esp-idf = { version = "0.4.0", features = ["esp32c6"] }
esp-hal = { version = "=1.0.0-rc.0", features = [ esp-hal = { version = "1.0.0", features = [
"esp32c6", "esp32c6",
"log-04", "log-04",
"unstable", "unstable",
"rt" "rt"
] } ] }
log = "0.4.27" log = "0.4.28"
embassy-net = { version = "0.7.1", default-features = false, features = [ embassy-net = { version = "0.7.1", default-features = false, features = [
"dhcpv4", "dhcpv4",
@@ -58,35 +58,32 @@ embassy-net = { version = "0.7.1", default-features = false, features = [
"proto-ipv4", "proto-ipv4",
"dns" "dns"
] } ] }
embedded-io = "0.6.1" embedded-io = "0.7.1"
embedded-io-async = "0.6.1" embedded-io-async = "0.7.0"
esp-alloc = "0.8.0" esp-alloc = "0.8.0"
esp-backtrace = { version = "0.17.0", features = [ esp-backtrace = { version = "0.18.1", features = [
"esp32c6", "esp32c6",
"exception-handler",
"panic-handler", "panic-handler",
"println", "println",
"colors", "colors",
"custom-halt" "custom-halt"
] } ] }
esp-println = { version = "0.15.0", features = ["esp32c6", "log-04"] } esp-println = { version = "0.16.1", features = ["esp32c6", "log-04"] }
# for more networking protocol support see https://crates.io/crates/edge-net # for more networking protocol support see https://crates.io/crates/edge-net
embassy-executor = { version = "0.7.0", features = [ embassy-executor = { version = "0.9.1", features = [
"log", "log",
"task-arena-size-64",
"nightly" "nightly"
] } ] }
embassy-time = { version = "0.5.0", features = ["log"], default-features = false } embassy-time = { version = "0.5.0", features = ["log"], default-features = false }
esp-hal-embassy = { version = "0.9.0", features = ["esp32c6", "log-04"] } esp-storage = { version = "0.8.1", features = ["esp32c6"] }
esp-storage = { version = "0.7.0", features = ["esp32c6"] }
esp-wifi = { version = "0.15.0", features = [ esp-radio = { version = "0.17.0", features = [
"builtin-scheduler",
"esp-alloc", "esp-alloc",
"esp32c6", "esp32c6",
"log-04", "log-04",
"smoltcp", "smoltcp",
"wifi", "wifi",
"unstable"
] } ] }
smoltcp = { version = "0.12.0", default-features = false, features = [ smoltcp = { version = "0.12.0", default-features = false, features = [
"alloc", "alloc",
@@ -112,22 +109,22 @@ embedded-hal-bus = { version = "0.3.0" }
#bq34z100 = { version = "0.3.0", default-features = false } #bq34z100 = { version = "0.3.0", default-features = false }
onewire = "0.4.0" onewire = "0.4.0"
#strum = { version = "0.27.0", default-feature = false, features = ["derive"] } #strum = { version = "0.27.0", default-feature = false, features = ["derive"] }
measurements = "0.11.0" measurements = "0.11.1"
ds323x = "0.6.0" ds323x = "0.7.0"
#json #json
serde = { version = "1.0.219", features = ["derive", "alloc"], default-features = false } serde = { version = "1.0.228", features = ["derive", "alloc"], default-features = false }
serde_json = { version = "1.0.143", default-features = false, features = ["alloc"] } serde_json = { version = "1.0.145", default-features = false, features = ["alloc"] }
chrono = { version = "0.4.42", default-features = false, features = ["iana-time-zone", "alloc", "serde"] } chrono = { version = "0.4.42", default-features = false, features = ["iana-time-zone", "alloc", "serde"] }
chrono-tz = { version = "0.10.4", default-features = false, features = ["filter-by-regex"] } chrono-tz = { version = "0.10.4", default-features = false, features = ["filter-by-regex"] }
eeprom24x = "0.7.2" eeprom24x = "0.7.2"
crc = "3.2.1" crc = "3.3.0"
strum_macros = "0.27.0" strum_macros = "0.27.2"
unit-enum = "1.4.1" unit-enum = "1.4.3"
pca9535 = { version = "2.0.0" } pca9535 = { version = "2.0.0" }
ina219 = { version = "0.2.0" } ina219 = { version = "0.2.0" }
embedded-storage = "=0.3.1" embedded-storage = "0.3.1"
portable-atomic = "1.11.1" portable-atomic = "1.11.1"
embassy-sync = { version = "0.7.2", features = ["log"] } embassy-sync = { version = "0.7.2", features = ["log"] }
async-trait = "0.1.89" async-trait = "0.1.89"
@@ -138,12 +135,12 @@ edge-nal-embassy = "0.6.0"
static_cell = "2.1.1" static_cell = "2.1.1"
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"] } littlefs2 = { version = "0.6.1", features = ["c-stubs", "alloc"] }
littlefs2-core = "0.1.1" littlefs2-core = "0.1.2"
bytemuck = { version = "1.23.2", features = ["derive", "min_const_generics", "pod_saturating", "extern_crate_alloc"] } bytemuck = { version = "1.24.0", features = ["derive", "min_const_generics", "pod_saturating", "extern_crate_alloc"] }
deranged = "0.5.3" deranged = "0.5.5"
embassy-embedded-hal = "0.5.0" embassy-embedded-hal = "0.5.0"
bincode = { version = "2.0.1", default-features = false, features = ["derive"] } bincode = { version = "2.0.1", default-features = false, features = ["derive"] }
sntpc = { version = "0.6.0", default-features = false, features = ["log", "embassy-socket", "embassy-socket-ipv6"] } sntpc = { version = "0.6.1", default-features = false, features = ["log", "embassy-socket", "embassy-socket-ipv6"] }
option-lock = { version = "0.3.1", default-features = false } option-lock = { version = "0.3.1", default-features = false }
#stay in sync with mcutie version here! #stay in sync with mcutie version here!
@@ -151,9 +148,7 @@ heapless = { version = "0.7.17", features = ["serde"] }
mcutie = { version = "0.3.0", default-features = false, features = ["log", "homeassistant"] } mcutie = { version = "0.3.0", default-features = false, features = ["log", "homeassistant"] }
nb = "1.1.0" nb = "1.1.0"
embedded-can = "0.4.1" embedded-can = "0.4.1"
no-panic = "0.1.35" esp-rtos = { version = "0.2.0", features = ["esp32c6", "embassy"] }
dont_panic = "0.1.0"
[patch.crates-io] [patch.crates-io]
@@ -161,4 +156,4 @@ mcutie = { git = 'https://github.com/empirephoenix/mcutie.git' }
#bq34z100 = { path = "../../bq34z100_rust" } #bq34z100 = { path = "../../bq34z100_rust" }
[build-dependencies] [build-dependencies]
vergen = { version = "8.2.6", features = ["build", "git", "gitcl"] } vergen = { version = "8.3.2", features = ["build", "git", "gitcl"] }

View File

@@ -10,7 +10,7 @@ use embedded_storage::nor_flash::NorFlashErrorKind;
use esp_hal::i2c::master::ConfigError; use esp_hal::i2c::master::ConfigError;
use esp_hal::pcnt::unit::{InvalidHighLimit, InvalidLowLimit}; use esp_hal::pcnt::unit::{InvalidHighLimit, InvalidLowLimit};
use esp_hal::twai::EspTwaiError; use esp_hal::twai::EspTwaiError;
use esp_wifi::wifi::WifiError; use esp_radio::wifi::WifiError;
use ina219::errors::{BusVoltageReadError, ShuntVoltageReadError}; use ina219::errors::{BusVoltageReadError, ShuntVoltageReadError};
use littlefs2_core::PathError; use littlefs2_core::PathError;
use onewire::Error; use onewire::Error;
@@ -316,4 +316,3 @@ impl From<sntpc::Error> for FatError {
FatError::SNTPError { error: value } FatError::SNTPError { error: value }
} }
} }

View File

@@ -7,6 +7,7 @@ use serde::Serialize;
use crate::fat_error::{ContextExt, FatError, FatResult}; use crate::fat_error::{ContextExt, FatError, FatResult};
use crate::hal::little_fs2storage_adapter::LittleFs2Filesystem; use crate::hal::little_fs2storage_adapter::LittleFs2Filesystem;
use crate::hal::shared_flash::MutexFlashStorage;
use alloc::string::ToString; use alloc::string::ToString;
use alloc::sync::Arc; use alloc::sync::Arc;
use alloc::{format, string::String, vec, vec::Vec}; use alloc::{format, string::String, vec, vec::Vec};
@@ -22,8 +23,8 @@ use embassy_sync::once_lock::OnceLock;
use embassy_time::{Duration, Timer, WithTimeout}; use embassy_time::{Duration, Timer, WithTimeout};
use embedded_storage::nor_flash::{check_erase, NorFlash, ReadNorFlash}; use embedded_storage::nor_flash::{check_erase, NorFlash, ReadNorFlash};
use esp_bootloader_esp_idf::ota::OtaImageState::Valid; use esp_bootloader_esp_idf::ota::OtaImageState::Valid;
use esp_bootloader_esp_idf::ota::{Ota, OtaImageState, Slot}; use esp_bootloader_esp_idf::ota::{Ota, OtaImageState};
use esp_bootloader_esp_idf::partitions::FlashRegion; use esp_bootloader_esp_idf::partitions::{AppPartitionSubType, FlashRegion};
use esp_hal::gpio::{Input, RtcPinWithResistors}; use esp_hal::gpio::{Input, RtcPinWithResistors};
use esp_hal::rng::Rng; use esp_hal::rng::Rng;
use esp_hal::rtc_cntl::{ use esp_hal::rtc_cntl::{
@@ -32,10 +33,9 @@ use esp_hal::rtc_cntl::{
}; };
use esp_hal::system::software_reset; use esp_hal::system::software_reset;
use esp_println::println; use esp_println::println;
use esp_storage::FlashStorage; use esp_radio::wifi::{
use esp_wifi::wifi::{ AccessPointConfig, AccessPointInfo, AuthMethod, ClientConfig, ModeConfig, ScanConfig,
AccessPointConfiguration, AccessPointInfo, AuthMethod, ClientConfiguration, Configuration, ScanTypeConfig, WifiController, WifiDevice, WifiStaState,
ScanConfig, ScanTypeConfig, WifiController, WifiDevice, WifiState,
}; };
use littlefs2::fs::Filesystem; use littlefs2::fs::Filesystem;
use littlefs2_core::{FileType, PathBuf, SeekFrom}; use littlefs2_core::{FileType, PathBuf, SeekFrom};
@@ -49,13 +49,13 @@ use smoltcp::socket::udp::PacketMetadata;
use smoltcp::wire::DnsQueryType; use smoltcp::wire::DnsQueryType;
use sntpc::{get_time, NtpContext, NtpTimestampGenerator}; use sntpc::{get_time, NtpContext, NtpTimestampGenerator};
#[esp_hal::ram(rtc_fast, persistent)] #[esp_hal::ram(unstable(rtc_fast), unstable(persistent))]
static mut LAST_WATERING_TIMESTAMP: [i64; PLANT_COUNT] = [0; PLANT_COUNT]; static mut LAST_WATERING_TIMESTAMP: [i64; PLANT_COUNT] = [0; PLANT_COUNT];
#[esp_hal::ram(rtc_fast, persistent)] #[esp_hal::ram(unstable(rtc_fast), unstable(persistent))]
static mut CONSECUTIVE_WATERING_PLANT: [u32; PLANT_COUNT] = [0; PLANT_COUNT]; static mut CONSECUTIVE_WATERING_PLANT: [u32; PLANT_COUNT] = [0; PLANT_COUNT];
#[esp_hal::ram(rtc_fast, persistent)] #[esp_hal::ram(unstable(rtc_fast), unstable(persistent))]
static mut LOW_VOLTAGE_DETECTED: i8 = 0; static mut LOW_VOLTAGE_DETECTED: i8 = 0;
#[esp_hal::ram(rtc_fast, persistent)] #[esp_hal::ram(unstable(rtc_fast), unstable(persistent))]
static mut RESTART_TO_CONF: i8 = 0; static mut RESTART_TO_CONF: i8 = 0;
const CONFIG_FILE: &str = "config.json"; const CONFIG_FILE: &str = "config.json";
@@ -127,9 +127,9 @@ pub struct Esp<'a> {
// RTC-capable GPIO used as external wake source (store the raw peripheral) // RTC-capable GPIO used as external wake source (store the raw peripheral)
pub wake_gpio1: esp_hal::peripherals::GPIO1<'static>, pub wake_gpio1: esp_hal::peripherals::GPIO1<'static>,
pub ota: Ota<'static, FlashStorage>, pub ota: Ota<'static, MutexFlashStorage>,
pub ota_target: &'static mut FlashRegion<'static, FlashStorage>, pub ota_target: &'static mut FlashRegion<'static, MutexFlashStorage>,
pub current: Slot, pub current: AppPartitionSubType,
pub slot0_state: OtaImageState, pub slot0_state: OtaImageState,
pub slot1_state: OtaImageState, pub slot1_state: OtaImageState,
} }
@@ -236,13 +236,19 @@ impl Esp<'_> {
} }
pub(crate) async fn finalize_ota(&mut self) -> Result<(), FatError> { pub(crate) async fn finalize_ota(&mut self) -> Result<(), FatError> {
let current = self.ota.current_slot()?; let current = self.ota.current_app_partition()?;
if self.ota.current_ota_state()? != OtaImageState::Valid { if self.ota.current_ota_state()? != Valid {
info!("Validating current slot {current:?} as it was able to ota"); info!("Validating current slot {current:?} as it was able to ota");
self.ota.set_current_ota_state(Valid)?; self.ota.set_current_ota_state(Valid)?;
} }
let next = match current {
self.ota.set_current_slot(current.next())?; AppPartitionSubType::Ota0 => AppPartitionSubType::Ota1,
AppPartitionSubType::Ota1 => AppPartitionSubType::Ota0,
_ => {
bail!("Invalid current slot {current:?} for ota");
}
};
self.ota.set_current_app_partition(next)?;
info!("switched slot"); info!("switched slot");
self.ota.set_current_ota_state(OtaImageState::New)?; self.ota.set_current_ota_state(OtaImageState::New)?;
info!("switched state for new partition"); info!("switched state for new partition");
@@ -319,16 +325,10 @@ impl Esp<'_> {
info!("start wifi scan"); info!("start wifi scan");
let mut lock = self.controller.try_lock()?; let mut lock = self.controller.try_lock()?;
info!("start wifi scan lock"); info!("start wifi scan lock");
let scan_config = ScanConfig { let scan_config = ScanConfig::default().with_scan_type(ScanTypeConfig::Active {
ssid: None, min: Default::default(),
bssid: None, max: Default::default(),
channel: None, });
show_hidden: false,
scan_type: ScanTypeConfig::Active {
min: Default::default(),
max: Default::default(),
},
};
let rv = lock.scan_with_config_async(scan_config).await?; let rv = lock.scan_with_config_async(scan_config).await?;
info!("end wifi scan lock"); info!("end wifi scan lock");
Ok(rv) Ok(rv)
@@ -378,14 +378,12 @@ impl Esp<'_> {
} }
} }
pub(crate) async fn wifi_ap(&mut self) -> FatResult<Stack<'static>> { pub(crate) async fn wifi_ap(&mut self, spawner: Spawner) -> FatResult<Stack<'static>> {
let ssid = match self.load_config().await { let ssid = match self.load_config().await {
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(),
}; };
let spawner = Spawner::for_current_executor().await;
let device = self.interface_ap.take().unwrap(); let device = self.interface_ap.take().unwrap();
let gw_ip_addr_str = "192.168.71.1"; let gw_ip_addr_str = "192.168.71.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");
@@ -408,15 +406,9 @@ impl Esp<'_> {
); );
let stack = mk_static!(Stack, stack); let stack = mk_static!(Stack, stack);
let client_config = Configuration::AccessPoint(AccessPointConfiguration { let client_config =
ssid: ssid.clone(), ModeConfig::AccessPoint(AccessPointConfig::default().with_ssid(ssid.clone()));
..Default::default() self.controller.lock().await.set_config(&client_config)?;
});
self.controller
.lock()
.await
.set_configuration(&client_config)?;
println!("start new"); println!("start new");
self.controller.lock().await.start()?; self.controller.lock().await.start()?;
@@ -445,8 +437,9 @@ impl Esp<'_> {
pub(crate) async fn wifi( pub(crate) async fn wifi(
&mut self, &mut self,
network_config: &NetworkConfig, network_config: &NetworkConfig,
spawner: Spawner,
) -> FatResult<Stack<'static>> { ) -> FatResult<Stack<'static>> {
esp_wifi::wifi_set_log_verbose(); esp_radio::wifi_set_log_verbose();
let ssid = network_config.ssid.clone(); let ssid = network_config.ssid.clone();
match &ssid { match &ssid {
Some(ssid) => { Some(ssid) => {
@@ -466,8 +459,6 @@ impl Esp<'_> {
}; };
let max_wait = network_config.max_wait; let max_wait = network_config.max_wait;
let spawner = Spawner::for_current_executor().await;
let device = self.interface_sta.take().unwrap(); let device = self.interface_sta.take().unwrap();
let config = embassy_net::Config::dhcpv4(DhcpConfig::default()); let config = embassy_net::Config::dhcpv4(DhcpConfig::default());
@@ -482,17 +473,15 @@ impl Esp<'_> {
); );
let stack = mk_static!(Stack, stack); let stack = mk_static!(Stack, stack);
let client_config = Configuration::Client(ClientConfiguration { let client_config = ClientConfig::default()
ssid, .with_ssid(ssid)
bssid: None, .with_auth_method(AuthMethod::Wpa2Personal)
auth_method: AuthMethod::WPA2Personal, //FIXME read from config, fill via scan .with_password(password);
password,
channel: None,
});
self.controller self.controller
.lock() .lock()
.await .await
.set_configuration(&client_config)?; .set_config(&ModeConfig::Client(client_config))?;
spawner.spawn(net_task(runner)).ok(); spawner.spawn(net_task(runner)).ok();
self.controller.lock().await.start_async().await?; self.controller.lock().await.start_async().await?;
@@ -501,8 +490,8 @@ impl Esp<'_> {
guard.current_time_us() guard.current_time_us()
} + max_wait as u64 * 1000; } + max_wait as u64 * 1000;
loop { loop {
let state = esp_wifi::wifi::sta_state(); let state = esp_radio::wifi::sta_state();
if state == WifiState::StaStarted { if state == WifiStaState::Started {
self.controller.lock().await.connect()?; self.controller.lock().await.connect()?;
break; break;
} }
@@ -520,8 +509,8 @@ impl Esp<'_> {
guard.current_time_us() guard.current_time_us()
} + max_wait as u64 * 1000; } + max_wait as u64 * 1000;
loop { loop {
let state = esp_wifi::wifi::sta_state(); let state = esp_radio::wifi::sta_state();
if state == WifiState::StaConnected { if state == WifiStaState::Connected {
break; break;
} }
if { if {
@@ -699,6 +688,7 @@ impl Esp<'_> {
&mut self, &mut self,
network_config: &'static NetworkConfig, network_config: &'static NetworkConfig,
stack: Stack<'static>, stack: Stack<'static>,
spawner: Spawner,
) -> FatResult<()> { ) -> FatResult<()> {
let base_topic = network_config let base_topic = network_config
.base_topic .base_topic
@@ -751,7 +741,6 @@ impl Esp<'_> {
let keep_alive = Duration::from_secs(60 * 60 * 2).as_secs() as u16; let keep_alive = Duration::from_secs(60 * 60 * 2).as_secs() as u16;
let (receiver, task) = builder.build(keep_alive); let (receiver, task) = builder.build(keep_alive);
let spawner = Spawner::for_current_executor().await;
spawner.spawn(mqtt_incoming_task( spawner.spawn(mqtt_incoming_task(
receiver, receiver,
round_trip_topic.clone(), round_trip_topic.clone(),

View File

@@ -1,6 +1,6 @@
use crate::hal::shared_flash::MutexFlashStorage;
use embedded_storage::nor_flash::{check_erase, NorFlash, ReadNorFlash}; use embedded_storage::nor_flash::{check_erase, NorFlash, ReadNorFlash};
use esp_bootloader_esp_idf::partitions::FlashRegion; use esp_bootloader_esp_idf::partitions::FlashRegion;
use esp_storage::FlashStorage;
use littlefs2::consts::U4096 as lfsCache; use littlefs2::consts::U4096 as lfsCache;
use littlefs2::consts::U512 as lfsLookahead; use littlefs2::consts::U512 as lfsLookahead;
use littlefs2::driver::Storage as lfs2Storage; use littlefs2::driver::Storage as lfs2Storage;
@@ -9,7 +9,7 @@ use littlefs2::io::Result as lfs2Result;
use log::error; use log::error;
pub struct LittleFs2Filesystem { pub struct LittleFs2Filesystem {
pub(crate) storage: &'static mut FlashRegion<'static, FlashStorage>, pub(crate) storage: &'static mut FlashRegion<'static, MutexFlashStorage>,
} }
impl lfs2Storage for LittleFs2Filesystem { impl lfs2Storage for LittleFs2Filesystem {

View File

@@ -4,11 +4,13 @@ pub mod esp;
mod initial_hal; mod initial_hal;
mod little_fs2storage_adapter; mod little_fs2storage_adapter;
pub(crate) mod rtc; pub(crate) mod rtc;
mod shared_flash;
mod v3_hal; mod v3_hal;
mod v3_shift_register; mod v3_shift_register;
mod v4_hal; mod v4_hal;
pub(crate) mod v4_sensor; pub(crate) mod v4_sensor;
mod water; mod water;
use crate::alloc::string::ToString; use crate::alloc::string::ToString;
use crate::hal::rtc::{DS3231Module, RTCModuleInteraction}; use crate::hal::rtc::{DS3231Module, RTCModuleInteraction};
use esp_hal::peripherals::Peripherals; use esp_hal::peripherals::Peripherals;
@@ -27,14 +29,8 @@ use esp_hal::peripherals::GPIO2;
use esp_hal::peripherals::GPIO21; use esp_hal::peripherals::GPIO21;
use esp_hal::peripherals::GPIO22; use esp_hal::peripherals::GPIO22;
use esp_hal::peripherals::GPIO23; use esp_hal::peripherals::GPIO23;
use esp_hal::peripherals::GPIO24;
use esp_hal::peripherals::GPIO25;
use esp_hal::peripherals::GPIO26;
use esp_hal::peripherals::GPIO27; use esp_hal::peripherals::GPIO27;
use esp_hal::peripherals::GPIO28;
use esp_hal::peripherals::GPIO29;
use esp_hal::peripherals::GPIO3; use esp_hal::peripherals::GPIO3;
use esp_hal::peripherals::GPIO30;
use esp_hal::peripherals::GPIO4; use esp_hal::peripherals::GPIO4;
use esp_hal::peripherals::GPIO5; use esp_hal::peripherals::GPIO5;
use esp_hal::peripherals::GPIO6; use esp_hal::peripherals::GPIO6;
@@ -85,13 +81,13 @@ use crate::hal::water::TankSensor;
use crate::log::LOG_ACCESS; use crate::log::LOG_ACCESS;
use embassy_sync::mutex::Mutex; use embassy_sync::mutex::Mutex;
use embassy_sync::once_lock::OnceLock; use embassy_sync::once_lock::OnceLock;
use embedded_storage::nor_flash::ReadNorFlash; use embedded_storage::ReadStorage;
use esp_alloc as _; use esp_alloc as _;
use esp_backtrace as _; use esp_backtrace as _;
use esp_bootloader_esp_idf::ota::{Ota, OtaImageState}; use esp_bootloader_esp_idf::ota::{Ota, OtaImageState};
use esp_bootloader_esp_idf::ota::{Slot as ota_slot, Slot};
use esp_hal::delay::Delay; use esp_hal::delay::Delay;
use esp_hal::i2c::master::{BusTimeout, Config, I2c}; use esp_hal::i2c::master::{BusTimeout, Config, I2c};
use esp_hal::interrupt::software::SoftwareInterruptControl;
use esp_hal::pcnt::unit::Unit; use esp_hal::pcnt::unit::Unit;
use esp_hal::pcnt::Pcnt; use esp_hal::pcnt::Pcnt;
use esp_hal::rng::Rng; use esp_hal::rng::Rng;
@@ -100,13 +96,14 @@ use esp_hal::system::reset_reason;
use esp_hal::time::Rate; use esp_hal::time::Rate;
use esp_hal::timer::timg::TimerGroup; use esp_hal::timer::timg::TimerGroup;
use esp_hal::Blocking; use esp_hal::Blocking;
use esp_radio::{init, Controller};
use esp_storage::FlashStorage; use esp_storage::FlashStorage;
use esp_wifi::{init, EspWifiController};
use littlefs2::fs::{Allocation, Filesystem as lfs2Filesystem}; use littlefs2::fs::{Allocation, Filesystem as lfs2Filesystem};
use littlefs2::object_safe::DynStorage; use littlefs2::object_safe::DynStorage;
use log::{error, info, warn}; use log::{error, info, warn};
use portable_atomic::AtomicBool; use portable_atomic::AtomicBool;
use serde::Serialize; use serde::Serialize;
use shared_flash::MutexFlashStorage;
pub static TIME_ACCESS: OnceLock<Mutex<CriticalSectionRawMutex, Rtc>> = OnceLock::new(); pub static TIME_ACCESS: OnceLock<Mutex<CriticalSectionRawMutex, Rtc>> = OnceLock::new();
@@ -221,13 +218,7 @@ pub struct FreePeripherals<'a> {
pub gpio21: GPIO21<'a>, pub gpio21: GPIO21<'a>,
pub gpio22: GPIO22<'a>, pub gpio22: GPIO22<'a>,
pub gpio23: GPIO23<'a>, pub gpio23: GPIO23<'a>,
pub gpio24: GPIO24<'a>,
pub gpio25: GPIO25<'a>,
pub gpio26: GPIO26<'a>,
pub gpio27: GPIO27<'a>, pub gpio27: GPIO27<'a>,
pub gpio28: GPIO28<'a>,
pub gpio29: GPIO29<'a>,
pub gpio30: GPIO30<'a>,
pub twai: TWAI0<'a>, pub twai: TWAI0<'a>,
pub pcnt0: Unit<'a, 0>, pub pcnt0: Unit<'a, 0>,
pub pcnt1: Unit<'a, 1>, pub pcnt1: Unit<'a, 1>,
@@ -258,7 +249,9 @@ impl PlantHal {
error: "Init error rct".to_string(), error: "Init error rct".to_string(),
})?; })?;
let systimer = SystemTimer::new(peripherals.SYSTIMER); let timg0 = TimerGroup::new(peripherals.TIMG0);
let sw_int = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
esp_rtos::start(timg0.timer0, sw_int.software_interrupt0);
let boot_button = Input::new( let boot_button = Input::new(
peripherals.GPIO9, peripherals.GPIO9,
@@ -268,21 +261,15 @@ impl PlantHal {
// Reserve GPIO1 for deep sleep wake (configured just before entering sleep) // Reserve GPIO1 for deep sleep wake (configured just before entering sleep)
let wake_gpio1 = peripherals.GPIO1; let wake_gpio1 = peripherals.GPIO1;
let rng = Rng::new(peripherals.RNG); let rng = Rng::new();
let timg0 = TimerGroup::new(peripherals.TIMG0);
let esp_wifi_ctrl = &*mk_static!( let esp_wifi_ctrl = &*mk_static!(
EspWifiController<'static>, Controller<'static>,
init(timg0.timer0, rng).expect("Could not init wifi controller") init().expect("Could not init wifi controller")
); );
let (controller, interfaces) = let (controller, interfaces) =
esp_wifi::wifi::new(esp_wifi_ctrl, peripherals.WIFI).expect("Could not init wifi"); esp_radio::wifi::new(esp_wifi_ctrl, peripherals.WIFI, Default::default())
.expect("Could not init wifi");
use esp_hal::timer::systimer::SystemTimer;
esp_hal_embassy::init(systimer.alarm0);
//let mut adc1 = Adc::new(peripherals.ADC1, adc1_config);
//
let pcnt_module = Pcnt::new(peripherals.PCNT); let pcnt_module = Pcnt::new(peripherals.PCNT);
@@ -311,13 +298,7 @@ impl PlantHal {
gpio21: peripherals.GPIO21, gpio21: peripherals.GPIO21,
gpio22: peripherals.GPIO22, gpio22: peripherals.GPIO22,
gpio23: peripherals.GPIO23, gpio23: peripherals.GPIO23,
gpio24: peripherals.GPIO24,
gpio25: peripherals.GPIO25,
gpio26: peripherals.GPIO26,
gpio27: peripherals.GPIO27, gpio27: peripherals.GPIO27,
gpio28: peripherals.GPIO28,
gpio29: peripherals.GPIO29,
gpio30: peripherals.GPIO30,
twai: peripherals.TWAI0, twai: peripherals.TWAI0,
pcnt0: pcnt_module.unit0, pcnt0: pcnt_module.unit0,
pcnt1: pcnt_module.unit1, pcnt1: pcnt_module.unit1,
@@ -328,9 +309,18 @@ impl PlantHal {
[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] [0u8; esp_bootloader_esp_idf::partitions::PARTITION_TABLE_MAX_LEN]
); );
let storage_ota = mk_static!(FlashStorage, FlashStorage::new());
let bullshit = MutexFlashStorage {
inner: Arc::new(CriticalSectionMutex::new(RefCell::new(FlashStorage::new(
peripherals.FLASH,
)))),
};
let flash_storage = mk_static!(MutexFlashStorage, bullshit.clone());
let flash_storage_2 = mk_static!(MutexFlashStorage, bullshit.clone());
let flash_storage_3 = mk_static!(MutexFlashStorage, bullshit.clone());
let pt = let pt =
esp_bootloader_esp_idf::partitions::read_partition_table(storage_ota, tablebuffer)?; esp_bootloader_esp_idf::partitions::read_partition_table(flash_storage, tablebuffer)?;
let ota_data = mk_static!( let ota_data = mk_static!(
PartitionEntry, PartitionEntry,
@@ -341,15 +331,15 @@ impl PlantHal {
); );
let ota_data = mk_static!( let ota_data = mk_static!(
FlashRegion<FlashStorage>, FlashRegion<MutexFlashStorage>,
ota_data.as_embedded_storage(storage_ota) ota_data.as_embedded_storage(flash_storage_2)
); );
let state_0 = ota_state(ota_slot::Slot0, ota_data); let state_0 = ota_state(AppPartitionSubType::Ota0, ota_data);
let state_1 = ota_state(ota_slot::Slot1, ota_data); let state_1 = ota_state(AppPartitionSubType::Ota1, ota_data);
let mut ota = Ota::new(ota_data)?; let mut ota = Ota::new(ota_data, 2)?;
let running = get_current_slot_and_fix_ota_data(&mut ota, state_0, state_1)?; let running = get_current_slot_and_fix_ota_data(&mut ota, state_0, state_1)?;
let target = running.next(); let target = next_partition(running)?;
info!("Currently running OTA slot: {running:?}"); info!("Currently running OTA slot: {running:?}");
info!("Slot0 state: {state_0:?}"); info!("Slot0 state: {state_0:?}");
@@ -357,26 +347,25 @@ impl PlantHal {
//obtain current_state and next_state here! //obtain current_state and next_state here!
let ota_target = match target { let ota_target = match target {
Slot::None => { AppPartitionSubType::Ota0 => pt
panic!("No OTA slot active?");
}
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,
))? ))?
.context("Partition table invalid no ota0")?, .context("Partition table invalid no ota0")?,
Slot::Slot1 => pt AppPartitionSubType::Ota1 => pt
.find_partition(esp_bootloader_esp_idf::partitions::PartitionType::App( .find_partition(esp_bootloader_esp_idf::partitions::PartitionType::App(
AppPartitionSubType::Ota1, AppPartitionSubType::Ota1,
))? ))?
.context("Partition table invalid no ota1")?, .context("Partition table invalid no ota1")?,
_ => {
bail!("Invalid target partition");
}
}; };
let ota_target = mk_static!(PartitionEntry, ota_target); let ota_target = mk_static!(PartitionEntry, ota_target);
let storage_ota = mk_static!(FlashStorage, FlashStorage::new());
let ota_target = mk_static!( let ota_target = mk_static!(
FlashRegion<FlashStorage>, FlashRegion<MutexFlashStorage>,
ota_target.as_embedded_storage(storage_ota) ota_target.as_embedded_storage(flash_storage)
); );
let data_partition = pt let data_partition = pt
@@ -386,10 +375,9 @@ impl PlantHal {
.expect("Data partition with littlefs not found"); .expect("Data partition with littlefs not found");
let data_partition = mk_static!(PartitionEntry, data_partition); let data_partition = mk_static!(PartitionEntry, data_partition);
let storage_data = mk_static!(FlashStorage, FlashStorage::new());
let data = mk_static!( let data = mk_static!(
FlashRegion<FlashStorage>, FlashRegion<MutexFlashStorage>,
data_partition.as_embedded_storage(storage_data) data_partition.as_embedded_storage(flash_storage_3)
); );
let lfs2filesystem = mk_static!(LittleFs2Filesystem, LittleFs2Filesystem { storage: data }); let lfs2filesystem = mk_static!(LittleFs2Filesystem, LittleFs2Filesystem { storage: data });
let alloc = mk_static!(Allocation<LittleFs2Filesystem>, lfs2Filesystem::allocate()); let alloc = mk_static!(Allocation<LittleFs2Filesystem>, lfs2Filesystem::allocate());
@@ -607,18 +595,18 @@ impl PlantHal {
} }
} }
fn ota_state(slot: ota_slot, ota_data: &mut FlashRegion<FlashStorage>) -> OtaImageState { fn ota_state(
slot: AppPartitionSubType,
ota_data: &mut FlashRegion<MutexFlashStorage>,
) -> OtaImageState {
// Read and log OTA states for both slots before constructing Ota // Read and log OTA states for both slots before constructing Ota
// Each OTA select entry is 32 bytes: [seq:4][label:20][state:4][crc:4] // Each OTA select entry is 32 bytes: [seq:4][label:20][state:4][crc:4]
// Offsets within the OTA data partition: slot0 @ 0x0000, slot1 @ 0x1000 // Offsets within the OTA data partition: slot0 @ 0x0000, slot1 @ 0x1000
if slot == ota_slot::None {
return OtaImageState::Undefined;
}
let mut slot_buf = [0u8; 32]; let mut slot_buf = [0u8; 32];
if slot == ota_slot::Slot0 { if slot == AppPartitionSubType::Ota0 {
let _ = ota_data.read(0x0000, &mut slot_buf); let _ = ReadStorage::read(ota_data, 0x0000, &mut slot_buf);
} else { } else {
let _ = ota_data.read(0x1000, &mut slot_buf); let _ = ReadStorage::read(ota_data, 0x1000, &mut slot_buf);
} }
let raw_state = u32::from_le_bytes(slot_buf[24..28].try_into().unwrap_or([0xff; 4])); let raw_state = u32::from_le_bytes(slot_buf[24..28].try_into().unwrap_or([0xff; 4]));
@@ -626,10 +614,10 @@ fn ota_state(slot: ota_slot, ota_data: &mut FlashRegion<FlashStorage>) -> OtaIma
} }
fn get_current_slot_and_fix_ota_data( fn get_current_slot_and_fix_ota_data(
ota: &mut Ota<FlashStorage>, ota: &mut Ota<MutexFlashStorage>,
state0: OtaImageState, state0: OtaImageState,
state1: OtaImageState, state1: OtaImageState,
) -> Result<ota_slot, FatError> { ) -> Result<AppPartitionSubType, FatError> {
let state = ota.current_ota_state().unwrap_or_default(); let state = ota.current_ota_state().unwrap_or_default();
let swap = match state { let swap = match state {
OtaImageState::Invalid => true, OtaImageState::Invalid => true,
@@ -640,11 +628,11 @@ fn get_current_slot_and_fix_ota_data(
} }
_ => false, _ => false,
}; };
let current = ota.current_slot()?; let current = ota.current_app_partition()?;
if swap { if swap {
let other = match current { let other = match current {
ota_slot::Slot0 => state1, AppPartitionSubType::Ota0 => state1,
ota_slot::Slot1 => state0, AppPartitionSubType::Ota1 => state0,
_ => OtaImageState::Invalid, _ => OtaImageState::Invalid,
}; };
@@ -668,13 +656,26 @@ fn get_current_slot_and_fix_ota_data(
_ => {} _ => {}
} }
info!("Current slot has state {state:?} other state has {other:?} swapping"); info!("Current slot has state {state:?} other state has {other:?} swapping");
ota.set_current_slot(current.next())?; let next = next_partition(current)?;
ota.set_current_app_partition(next)?;
//we actually booted other slot, than partition table assumes //we actually booted other slot, than partition table assumes
return Ok(ota.current_slot()?); return Ok(ota.current_app_partition()?);
}; };
Ok(current) Ok(current)
} }
pub fn next_partition(current: AppPartitionSubType) -> FatResult<AppPartitionSubType> {
let next = match current {
AppPartitionSubType::Ota0 => AppPartitionSubType::Ota1,
AppPartitionSubType::Ota1 => AppPartitionSubType::Ota0,
_ => {
bail!("Current slot is not ota0 or ota1");
}
};
Ok(next)
}
pub async fn esp_time() -> DateTime<Utc> { pub async fn esp_time() -> DateTime<Utc> {
let guard = TIME_ACCESS.get().await.lock().await; let guard = TIME_ACCESS.get().await.lock().await;
DateTime::from_timestamp_micros(guard.current_time_us() as i64).unwrap() DateTime::from_timestamp_micros(guard.current_time_us() as i64).unwrap()

View File

@@ -0,0 +1,63 @@
use alloc::sync::Arc;
use core::cell::RefCell;
use core::ops::{Deref, DerefMut};
use embassy_sync::blocking_mutex::CriticalSectionMutex;
use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash};
use embedded_storage::ReadStorage;
use esp_storage::{FlashStorage, FlashStorageError};
#[derive(Clone)]
pub struct MutexFlashStorage {
pub(crate) inner: Arc<CriticalSectionMutex<RefCell<FlashStorage<'static>>>>,
}
impl ReadStorage for MutexFlashStorage {
type Error = FlashStorageError;
fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), FlashStorageError> {
self.inner
.lock(|f| ReadStorage::read(f.borrow_mut().deref_mut(), offset, bytes))
}
fn capacity(&self) -> usize {
self.inner
.lock(|f| ReadStorage::capacity(f.borrow().deref()))
}
}
impl embedded_storage::Storage for MutexFlashStorage {
fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
NorFlash::write(self, offset, bytes)
}
}
impl ErrorType for MutexFlashStorage {
type Error = FlashStorageError;
}
impl ReadNorFlash for MutexFlashStorage {
const READ_SIZE: usize = 0;
fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
ReadStorage::read(self, offset, bytes)
}
fn capacity(&self) -> usize {
ReadStorage::capacity(self)
}
}
impl NorFlash for MutexFlashStorage {
const WRITE_SIZE: usize = 0;
const ERASE_SIZE: usize = 0;
fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
self.inner
.lock(|f| NorFlash::erase(f.borrow_mut().deref_mut(), from, to))
}
fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
self.inner
.lock(|f| NorFlash::write(f.borrow_mut().deref_mut(), offset, bytes))
}
}

View File

@@ -101,8 +101,9 @@ impl SensorInteraction for SensorImpl {
Timer::after_millis(10).await; Timer::after_millis(10).await;
let mut moistures = Moistures::default(); let mut moistures = Moistures::default();
let _ = Self::wait_for_can_measurements(&mut twai, &mut moistures).with_timeout(Duration::from_millis(5000)).await; let _ = Self::wait_for_can_measurements(&mut twai, &mut moistures)
.with_timeout(Duration::from_millis(5000))
.await;
can_power.set_low(); can_power.set_low();
@@ -170,7 +171,7 @@ impl SensorImpl {
can_power.set_low(); can_power.set_low();
twai_config.replace(config); twai_config.replace(config);
let result= moistures.into(); let result = moistures.into();
info!("Autodetection result: {result:?}"); info!("Autodetection result: {result:?}");
Ok(result) Ok(result)
@@ -182,7 +183,6 @@ impl SensorImpl {
as_async: &mut Twai<'_, Async>, as_async: &mut Twai<'_, Async>,
moistures: &mut Moistures, moistures: &mut Moistures,
) -> FatResult<()> { ) -> FatResult<()> {
loop { loop {
match as_async.receive_async().await { match as_async.receive_async().await {
Ok(can_frame) => match can_frame.id() { Ok(can_frame) => match can_frame.id() {
@@ -200,7 +200,7 @@ impl SensorImpl {
let plant = msg.1 as usize; let plant = msg.1 as usize;
let sensor = msg.2; let sensor = msg.2;
let data = can_frame.data(); let data = can_frame.data();
match sensor { match sensor {
SensorSlot::A => { SensorSlot::A => {
moistures.sensor_a_hz[plant] = data[0] as f32; moistures.sensor_a_hz[plant] = data[0] as f32;
@@ -319,4 +319,4 @@ impl From<Moistures> for DetectionResult {
} }
result result
} }
} }

View File

@@ -14,7 +14,7 @@ use unit_enum::UnitEnum;
const LOG_ARRAY_SIZE: u8 = 220; const LOG_ARRAY_SIZE: u8 = 220;
const MAX_LOG_ARRAY_INDEX: u8 = LOG_ARRAY_SIZE - 1; const MAX_LOG_ARRAY_INDEX: u8 = LOG_ARRAY_SIZE - 1;
#[esp_hal::ram(rtc_fast, persistent)] #[esp_hal::ram(unstable(rtc_fast), unstable(persistent))]
static mut LOG_ARRAY: LogArray = LogArray { static mut LOG_ARRAY: LogArray = LogArray {
buffer: [LogEntryInner { buffer: [LogEntryInner {
timestamp: 0, timestamp: 0,
@@ -159,7 +159,6 @@ impl LogArray {
} }
} }
fn limit_length<const LIMIT: usize>(input: &str, target: &mut heapless::String<LIMIT>) { fn limit_length<const LIMIT: usize>(input: &str, target: &mut heapless::String<LIMIT>) {
for char in input.chars() { for char in input.chars() {
match target.push(char) { match target.push(char) {
@@ -171,16 +170,20 @@ fn limit_length<const LIMIT: usize>(input: &str, target: &mut heapless::String<L
target.pop(); target.pop();
} }
//add .. to shortened strings //add .. to shortened strings
match target.push('.'){ match target.push('.') {
Ok(_) => {} Ok(_) => {}
Err(_) => { Err(_) => {
warn!("Error pushin . to limit {LIMIT} current value {target} input {input}") warn!(
"Error pushin . to limit {LIMIT} current value {target} input {input}"
)
} }
} }
match target.push('.'){ match target.push('.') {
Ok(_) => {} Ok(_) => {}
Err(_) => { Err(_) => {
warn!("Error pushin . to limit {LIMIT} current value {target} input {input}") warn!(
"Error pushin . to limit {LIMIT} current value {target} input {input}"
)
} }
} }
return; return;

View File

@@ -233,7 +233,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
{ {
info!("No wifi configured, starting initial config mode"); info!("No wifi configured, starting initial config mode");
let stack = board.board_hal.get_esp().wifi_ap().await?; let stack = board.board_hal.get_esp().wifi_ap(spawner).await?;
let reboot_now = Arc::new(AtomicBool::new(false)); let reboot_now = Arc::new(AtomicBool::new(false));
println!("starting webserver"); println!("starting webserver");
@@ -244,7 +244,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
let mut stack: OptionLock<Stack> = OptionLock::empty(); let mut stack: OptionLock<Stack> = OptionLock::empty();
let network_mode = if board.board_hal.get_config().network.ssid.is_some() { let network_mode = if board.board_hal.get_config().network.ssid.is_some() {
try_connect_wifi_sntp_mqtt(&mut board, &mut stack).await try_connect_wifi_sntp_mqtt(&mut board, &mut stack, spawner).await
} else { } else {
info!("No wifi configured"); info!("No wifi configured");
//the current sensors require this amount to stabilize, in the case of Wi-Fi this is already handled due to connect timings; //the current sensors require this amount to stabilize, in the case of Wi-Fi this is already handled due to connect timings;
@@ -257,7 +257,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
let res = { let res = {
let esp = board.board_hal.get_esp(); let esp = board.board_hal.get_esp();
esp.wifi_ap().await esp.wifi_ap(spawner).await
}; };
match res { match res {
Ok(ap_stack) => { Ok(ap_stack) => {
@@ -839,9 +839,10 @@ macro_rules! mk_static {
async fn try_connect_wifi_sntp_mqtt( async fn try_connect_wifi_sntp_mqtt(
board: &mut MutexGuard<'static, CriticalSectionRawMutex, HAL<'static>>, board: &mut MutexGuard<'static, CriticalSectionRawMutex, HAL<'static>>,
stack_store: &mut OptionLock<Stack<'static>>, stack_store: &mut OptionLock<Stack<'static>>,
spawner: Spawner,
) -> NetworkMode { ) -> NetworkMode {
let nw_conf = &board.board_hal.get_config().network.clone(); let nw_conf = &board.board_hal.get_config().network.clone();
match board.board_hal.get_esp().wifi(nw_conf).await { match board.board_hal.get_esp().wifi(nw_conf, spawner).await {
Ok(stack) => { Ok(stack) => {
stack_store.replace(stack); stack_store.replace(stack);
@@ -865,7 +866,12 @@ async fn try_connect_wifi_sntp_mqtt(
let mqtt_connected = if board.board_hal.get_config().network.mqtt_url.is_some() { let mqtt_connected = if board.board_hal.get_config().network.mqtt_url.is_some() {
let nw_config = board.board_hal.get_config().network.clone(); let nw_config = board.board_hal.get_config().network.clone();
let nw_config = mk_static!(NetworkConfig, nw_config); let nw_config = mk_static!(NetworkConfig, nw_config);
match board.board_hal.get_esp().mqtt(nw_config, stack).await { match board
.board_hal
.get_esp()
.mqtt(nw_config, stack, spawner)
.await
{
Ok(_) => { Ok(_) => {
info!("Mqtt connection ready"); info!("Mqtt connection ready");
true true
@@ -1052,7 +1058,7 @@ async fn wait_infinity(
} }
} }
#[esp_hal_embassy::main] #[esp_rtos::main]
async fn main(spawner: Spawner) -> ! { async fn main(spawner: Spawner) -> ! {
// intialize embassy // intialize embassy
logger::init_logger_from_env(); logger::init_logger_from_env();

View File

@@ -120,8 +120,12 @@ impl PlantState {
let raw = moistures.sensor_a_hz[plant_id]; let raw = moistures.sensor_a_hz[plant_id];
match map_range_moisture( match map_range_moisture(
raw, raw,
board.board_hal.get_config().plants[plant_id].moisture_sensor_min_frequency.map(|a| a as f32), board.board_hal.get_config().plants[plant_id]
board.board_hal.get_config().plants[plant_id].moisture_sensor_max_frequency.map(|b| b as f32), .moisture_sensor_min_frequency
.map(|a| a as f32),
board.board_hal.get_config().plants[plant_id]
.moisture_sensor_max_frequency
.map(|b| b as f32),
) { ) {
Ok(moisture_percent) => MoistureSensorState::MoistureValue { Ok(moisture_percent) => MoistureSensorState::MoistureValue {
raw_hz: raw, raw_hz: raw,
@@ -137,8 +141,12 @@ impl PlantState {
let raw = moistures.sensor_b_hz[plant_id]; let raw = moistures.sensor_b_hz[plant_id];
match map_range_moisture( match map_range_moisture(
raw, raw,
board.board_hal.get_config().plants[plant_id].moisture_sensor_min_frequency.map(|a| a as f32), board.board_hal.get_config().plants[plant_id]
board.board_hal.get_config().plants[plant_id].moisture_sensor_max_frequency.map(|b| b as f32) .moisture_sensor_min_frequency
.map(|a| a as f32),
board.board_hal.get_config().plants[plant_id]
.moisture_sensor_max_frequency
.map(|b| b as f32),
) { ) {
Ok(moisture_percent) => MoistureSensorState::MoistureValue { Ok(moisture_percent) => MoistureSensorState::MoistureValue {
raw_hz: raw, raw_hz: raw,
@@ -196,8 +204,12 @@ impl PlantState {
(Some(moisture_a), Some(moisture_b)) => { (Some(moisture_a), Some(moisture_b)) => {
(Some(((moisture_a + moisture_b) / 2.) as u8), (None, None)) (Some(((moisture_a + moisture_b) / 2.) as u8), (None, None))
} }
(Some(moisture_percent), _) => (Some(moisture_percent as u8), (None, self.sensor_b.is_err())), (Some(moisture_percent), _) => {
(_, Some(moisture_percent)) => (Some(moisture_percent as u8), (self.sensor_a.is_err(), None)), (Some(moisture_percent as u8), (None, self.sensor_b.is_err()))
}
(_, Some(moisture_percent)) => {
(Some(moisture_percent as u8), (self.sensor_a.is_err(), None))
}
_ => (None, (self.sensor_a.is_err(), self.sensor_b.is_err())), _ => (None, (self.sensor_a.is_err(), self.sensor_b.is_err())),
} }
} }

View File

@@ -6,7 +6,7 @@ use alloc::format;
use alloc::string::{String, ToString}; use alloc::string::{String, ToString};
use chrono::DateTime; use chrono::DateTime;
use edge_http::io::server::Connection; use edge_http::io::server::Connection;
use embedded_io_async::{Read, Write}; use edge_nal::io::{Read, Write};
use log::info; use log::info;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};

View File

@@ -6,7 +6,7 @@ use alloc::format;
use alloc::string::String; use alloc::string::String;
use edge_http::io::server::Connection; use edge_http::io::server::Connection;
use edge_http::Method; use edge_http::Method;
use embedded_io_async::{Read, Write}; use edge_nal::io::{Read, Write};
use log::info; use log::info;
pub(crate) async fn list_files<T, const N: usize>( pub(crate) async fn list_files<T, const N: usize>(

View File

@@ -10,7 +10,7 @@ use alloc::vec::Vec;
use chrono_tz::Tz; use chrono_tz::Tz;
use core::str::FromStr; use core::str::FromStr;
use edge_http::io::server::Connection; use edge_http::io::server::Connection;
use embedded_io_async::{Read, Write}; use edge_nal::io::{Read, Write};
use log::info; use log::info;
use serde::Serialize; use serde::Serialize;

View File

@@ -1,7 +1,7 @@
use crate::fat_error::FatResult; use crate::fat_error::FatResult;
use crate::log::LOG_ACCESS; use crate::log::LOG_ACCESS;
use edge_http::io::server::Connection; use edge_http::io::server::Connection;
use embedded_io_async::{Read, Write}; use edge_nal::io::{Read, Write};
pub(crate) async fn get_log<T, const N: usize>( pub(crate) async fn get_log<T, const N: usize>(
conn: &mut Connection<'_, T, N>, conn: &mut Connection<'_, T, N>,

View File

@@ -1,6 +1,6 @@
use crate::fat_error::FatError; use crate::fat_error::FatError;
use edge_http::io::server::Connection; use edge_http::io::server::Connection;
use embedded_io_async::{Read, Write}; use edge_nal::io::{Read, Write};
pub(crate) async fn serve_favicon<T, const N: usize>( pub(crate) async fn serve_favicon<T, const N: usize>(
conn: &mut Connection<'_, T, { N }>, conn: &mut Connection<'_, T, { N }>,

View File

@@ -32,11 +32,11 @@ use core::result::Result::Ok;
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::Method; use edge_http::Method;
use edge_nal::io::{Read, Write};
use edge_nal::TcpBind; 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;
use embedded_io_async::{Read, Write};
use log::{error, info}; use log::{error, info};
struct HTTPRequestRouter { struct HTTPRequestRouter {
@@ -203,7 +203,7 @@ async fn handle_json<'a, T, const N: usize>(
) -> FatResult<u32> ) -> FatResult<u32>
where where
T: Read + Write, T: Read + Write,
<T as embedded_io_async::ErrorType>::Error: Debug, <T as edge_nal::io::ErrorType>::Error: Debug,
{ {
match chain { match chain {
Ok(answer) => match answer { Ok(answer) => match answer {

View File

@@ -3,7 +3,7 @@ use crate::webserver::read_up_to_bytes_from_request;
use crate::BOARD_ACCESS; use crate::BOARD_ACCESS;
use edge_http::io::server::Connection; use edge_http::io::server::Connection;
use edge_http::Method; use edge_http::Method;
use embedded_io_async::{Read, Write}; use edge_nal::io::{Read, Write};
use log::info; use log::info;
pub(crate) async fn ota_operations<T, const N: usize>( pub(crate) async fn ota_operations<T, const N: usize>(

View File

@@ -7,7 +7,7 @@ use alloc::string::{String, ToString};
use alloc::vec::Vec; use alloc::vec::Vec;
use chrono::DateTime; use chrono::DateTime;
use edge_http::io::server::Connection; use edge_http::io::server::Connection;
use embedded_io_async::{Read, Write}; use edge_nal::io::{Read, Write};
use log::info; use log::info;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};