diff --git a/rust/src/hal/battery.rs b/rust/src/hal/battery.rs index 2165970..15eea22 100644 --- a/rust/src/hal/battery.rs +++ b/rust/src/hal/battery.rs @@ -11,7 +11,7 @@ use esp_hal::Blocking; use measurements::Temperature; use serde::Serialize; -#[async_trait] +#[async_trait(?Send)] pub trait BatteryInteraction { async fn state_charge_percent(&mut self) -> FatResult; async fn remaining_milli_ampere_hour(&mut self) -> FatResult; @@ -51,7 +51,7 @@ pub enum BatteryState { /// If no battery monitor is installed this implementation will be used pub struct NoBatteryMonitor {} -#[async_trait] +#[async_trait(?Send)] impl BatteryInteraction for NoBatteryMonitor { async fn state_charge_percent(&mut self) -> FatResult { // No monitor configured: assume full battery for lightstate logic @@ -105,7 +105,7 @@ pub struct BQ34Z100G1 { pub battery_driver: Bq34z100g1Driver, } -#[async_trait] +#[async_trait(?Send)] impl BatteryInteraction for BQ34Z100G1 { async fn state_charge_percent(&mut self) -> FatResult { self.battery_driver diff --git a/rust/src/hal/esp.rs b/rust/src/hal/esp.rs index 755b62d..c79e54a 100644 --- a/rust/src/hal/esp.rs +++ b/rust/src/hal/esp.rs @@ -1,6 +1,6 @@ use crate::bail; use crate::config::{NetworkConfig, PlantControllerConfig}; -use crate::hal::{get_current_slot_and_fix_ota_data, PLANT_COUNT, TIME_ACCESS}; +use crate::hal::{PLANT_COUNT, TIME_ACCESS}; use crate::log::{LogMessage, LOG_ACCESS}; use chrono::{DateTime, Utc}; use serde::Serialize; diff --git a/rust/src/hal/initial_hal.rs b/rust/src/hal/initial_hal.rs index 6cec44b..ec14533 100644 --- a/rust/src/hal/initial_hal.rs +++ b/rust/src/hal/initial_hal.rs @@ -24,7 +24,7 @@ pub struct Initial<'a> { pub(crate) struct NoRTC {} -#[async_trait] +#[async_trait(?Send)] impl RTCModuleInteraction for NoRTC { async fn get_backup_info(&mut self) -> Result { bail!("Please configure board revision") @@ -68,7 +68,7 @@ pub(crate) fn create_initial_board( Ok(Box::new(v)) } -#[async_trait] +#[async_trait(?Send)] impl<'a> BoardInteraction<'a> for Initial<'a> { fn get_tank_sensor(&mut self) -> Result<&mut TankSensor<'a>, FatError> { bail!("Please configure board revision") diff --git a/rust/src/hal/mod.rs b/rust/src/hal/mod.rs index f6c2d0c..10e2f1c 100644 --- a/rust/src/hal/mod.rs +++ b/rust/src/hal/mod.rs @@ -130,7 +130,7 @@ pub struct HAL<'a> { pub board_hal: Box + Send>, } -#[async_trait] +#[async_trait(?Send)] pub trait BoardInteraction<'a> { fn get_tank_sensor(&mut self) -> Result<&mut TankSensor<'a>, FatError>; fn get_esp(&mut self) -> &mut Esp<'a>; diff --git a/rust/src/hal/rtc.rs b/rust/src/hal/rtc.rs index 73e996b..cf7e647 100644 --- a/rust/src/hal/rtc.rs +++ b/rust/src/hal/rtc.rs @@ -21,7 +21,7 @@ use serde::{Deserialize, Serialize}; pub const X25: crc::Crc = crc::Crc::::new(&crc::CRC_16_IBM_SDLC); const CONFIG: Configuration = config::standard(); // -#[async_trait] +#[async_trait(?Send)] pub trait RTCModuleInteraction { async fn get_backup_info(&mut self) -> FatResult; async fn get_backup_config(&mut self, chunk: usize) -> FatResult<([u8; 32], usize, u16)>; @@ -55,7 +55,7 @@ pub struct DS3231Module { >, } -#[async_trait] +#[async_trait(?Send)] impl RTCModuleInteraction for DS3231Module { async fn get_backup_info(&mut self) -> FatResult { let mut header_page_buffer = [0_u8; BACKUP_HEADER_MAX_SIZE]; diff --git a/rust/src/hal/v3_hal.rs b/rust/src/hal/v3_hal.rs index 3d838fd..6582e3c 100644 --- a/rust/src/hal/v3_hal.rs +++ b/rust/src/hal/v3_hal.rs @@ -170,7 +170,7 @@ pub(crate) fn create_v3( })) } -#[async_trait] +#[async_trait(?Send)] impl<'a> BoardInteraction<'a> for V3<'a> { fn get_tank_sensor(&mut self) -> Result<&mut TankSensor<'a>, FatError> { Ok(&mut self.tank_sensor) diff --git a/rust/src/hal/v4_hal.rs b/rust/src/hal/v4_hal.rs index 2159b55..734d646 100644 --- a/rust/src/hal/v4_hal.rs +++ b/rust/src/hal/v4_hal.rs @@ -297,7 +297,7 @@ pub(crate) async fn create_v4( Ok(Box::new(v)) } -#[async_trait] +#[async_trait(?Send)] impl<'a> BoardInteraction<'a> for V4<'a> { fn get_tank_sensor(&mut self) -> Result<&mut TankSensor<'a>, FatError> { Ok(&mut self.tank_sensor) @@ -461,7 +461,6 @@ impl<'a> BoardInteraction<'a> for V4<'a> { async fn detect_sensors(&mut self) -> Result { // Delegate to sensor autodetect and build JSON - use alloc::string::ToString; let detected = self.sensor.autodetect().await?; // Build JSON manually to avoid exposing internal types let mut s = alloc::string::String::from("{\"plants\":["); diff --git a/rust/src/hal/v4_sensor.rs b/rust/src/hal/v4_sensor.rs index b265cb0..a64dee8 100644 --- a/rust/src/hal/v4_sensor.rs +++ b/rust/src/hal/v4_sensor.rs @@ -9,24 +9,21 @@ use alloc::string::ToString; use async_trait::async_trait; use bincode::config; use bincode::error::DecodeError; -use core::mem; use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use embassy_sync::mutex::Mutex; use embassy_time::{Instant, Timer, WithTimeout}; -use embedded_can::nb::Can; use embedded_can::Frame; use esp_hal::gpio::Output; use esp_hal::i2c::master::I2c; use esp_hal::pcnt::unit::Unit; -use esp_hal::twai::{EspTwaiError, EspTwaiFrame, StandardId, Twai, TwaiConfiguration}; -use esp_hal::Blocking; +use esp_hal::twai::{EspTwaiFrame, StandardId, Twai, TwaiConfiguration}; +use esp_hal::{Async, Blocking}; use log::info; use pca9535::{GPIOBank, Pca9535Immediate, StandardExpanderInterface}; const REPEAT_MOIST_MEASURE: usize = 10; -#[async_trait] +#[async_trait(?Send)] pub trait SensorInteraction { async fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> FatResult; } @@ -50,7 +47,7 @@ pub enum SensorImpl { }, } -#[async_trait] +#[async_trait(?Send)] impl SensorInteraction for SensorImpl { async fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> FatResult { match self { @@ -180,8 +177,10 @@ impl SensorImpl { } => { // Power on CAN transceiver and start controller can_power.set_high(); - let config = twai_config.take().expect("twai config not set"); - let mut twai = config.start(); + let mut config = twai_config.take().expect("twai config not set"); + let mut as_async = config.into_async().start(); + Timer::after_millis(10).await; + // Give CAN some time to stabilize Timer::after_millis(10).await; @@ -197,7 +196,7 @@ impl SensorImpl { { if let Some(frame) = EspTwaiFrame::new(address, &can_buffer) { // Try a few times; we intentionally ignore rx here and rely on stub logic - let resu = twai.transmit(&frame); + let resu = as_async.transmit_async(&frame).await; match resu { Ok(_) => { info!( @@ -217,22 +216,23 @@ impl SensorImpl { } } } + // Poll for messages for ~100 ms + let detect_timeout = Instant::now() + .checked_add(embassy_time::Duration::from_millis(100)) + .unwrap(); + loop { - let rec = twai - .receive() - .with_timeout(embassy_time::Duration::from_millis(100)) - .await; - match rec { - Ok(msg) => match msg { - Ok(or) => { - info!("Received CAN message: {:?}", or); - } - Err(err) => { - info!("Error receiving CAN message: {:?}", err); + match as_async.receive() { + Ok(or) => { + info!("Received CAN message: {:?}", or); + } + Err(nb::Error::WouldBlock) => { + if Instant::now() > detect_timeout { break; } - }, - Err(err) => { + Timer::after_millis(10).await; + } + Err(nb::Error::Other(err)) => { info!("Error receiving CAN message: {:?}", err); break; } @@ -242,6 +242,7 @@ impl SensorImpl { // Wait for acknowledgements on the bus (stub: just wait 5 seconds) Timer::after_millis(5_000).await; // Stop CAN and power down + let config = as_async.stop().into_blocking(); can_power.set_low(); twai_config.replace(config);