make async can useable

This commit is contained in:
2025-10-08 19:48:13 +02:00
parent 7f3910bcd0
commit e5c5f31112
8 changed files with 35 additions and 35 deletions

View File

@@ -11,7 +11,7 @@ use esp_hal::Blocking;
use measurements::Temperature; use measurements::Temperature;
use serde::Serialize; use serde::Serialize;
#[async_trait] #[async_trait(?Send)]
pub trait BatteryInteraction { pub trait BatteryInteraction {
async fn state_charge_percent(&mut self) -> FatResult<f32>; async fn state_charge_percent(&mut self) -> FatResult<f32>;
async fn remaining_milli_ampere_hour(&mut self) -> FatResult<u16>; async fn remaining_milli_ampere_hour(&mut self) -> FatResult<u16>;
@@ -51,7 +51,7 @@ pub enum BatteryState {
/// If no battery monitor is installed this implementation will be used /// If no battery monitor is installed this implementation will be used
pub struct NoBatteryMonitor {} pub struct NoBatteryMonitor {}
#[async_trait] #[async_trait(?Send)]
impl BatteryInteraction for NoBatteryMonitor { impl BatteryInteraction for NoBatteryMonitor {
async fn state_charge_percent(&mut self) -> FatResult<f32> { async fn state_charge_percent(&mut self) -> FatResult<f32> {
// No monitor configured: assume full battery for lightstate logic // No monitor configured: assume full battery for lightstate logic
@@ -105,7 +105,7 @@ pub struct BQ34Z100G1 {
pub battery_driver: Bq34z100g1Driver<I2cDev, Delay>, pub battery_driver: Bq34z100g1Driver<I2cDev, Delay>,
} }
#[async_trait] #[async_trait(?Send)]
impl BatteryInteraction for BQ34Z100G1 { impl BatteryInteraction for BQ34Z100G1 {
async fn state_charge_percent(&mut self) -> FatResult<f32> { async fn state_charge_percent(&mut self) -> FatResult<f32> {
self.battery_driver self.battery_driver

View File

@@ -1,6 +1,6 @@
use crate::bail; use crate::bail;
use crate::config::{NetworkConfig, PlantControllerConfig}; 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 crate::log::{LogMessage, LOG_ACCESS};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::Serialize; use serde::Serialize;

View File

@@ -24,7 +24,7 @@ pub struct Initial<'a> {
pub(crate) struct NoRTC {} pub(crate) struct NoRTC {}
#[async_trait] #[async_trait(?Send)]
impl RTCModuleInteraction for NoRTC { impl RTCModuleInteraction for NoRTC {
async fn get_backup_info(&mut self) -> Result<BackupHeader, FatError> { async fn get_backup_info(&mut self) -> Result<BackupHeader, FatError> {
bail!("Please configure board revision") bail!("Please configure board revision")
@@ -68,7 +68,7 @@ pub(crate) fn create_initial_board(
Ok(Box::new(v)) Ok(Box::new(v))
} }
#[async_trait] #[async_trait(?Send)]
impl<'a> BoardInteraction<'a> for Initial<'a> { impl<'a> BoardInteraction<'a> for Initial<'a> {
fn get_tank_sensor(&mut self) -> Result<&mut TankSensor<'a>, FatError> { fn get_tank_sensor(&mut self) -> Result<&mut TankSensor<'a>, FatError> {
bail!("Please configure board revision") bail!("Please configure board revision")

View File

@@ -130,7 +130,7 @@ pub struct HAL<'a> {
pub board_hal: Box<dyn BoardInteraction<'a> + Send>, pub board_hal: Box<dyn BoardInteraction<'a> + Send>,
} }
#[async_trait] #[async_trait(?Send)]
pub trait BoardInteraction<'a> { pub trait BoardInteraction<'a> {
fn get_tank_sensor(&mut self) -> Result<&mut TankSensor<'a>, FatError>; fn get_tank_sensor(&mut self) -> Result<&mut TankSensor<'a>, FatError>;
fn get_esp(&mut self) -> &mut Esp<'a>; fn get_esp(&mut self) -> &mut Esp<'a>;

View File

@@ -21,7 +21,7 @@ use serde::{Deserialize, Serialize};
pub const X25: crc::Crc<u16> = crc::Crc::<u16>::new(&crc::CRC_16_IBM_SDLC); pub const X25: crc::Crc<u16> = crc::Crc::<u16>::new(&crc::CRC_16_IBM_SDLC);
const CONFIG: Configuration = config::standard(); const CONFIG: Configuration = config::standard();
// //
#[async_trait] #[async_trait(?Send)]
pub trait RTCModuleInteraction { pub trait RTCModuleInteraction {
async fn get_backup_info(&mut self) -> FatResult<BackupHeader>; async fn get_backup_info(&mut self) -> FatResult<BackupHeader>;
async fn get_backup_config(&mut self, chunk: usize) -> FatResult<([u8; 32], usize, u16)>; 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 { impl RTCModuleInteraction for DS3231Module {
async fn get_backup_info(&mut self) -> FatResult<BackupHeader> { async fn get_backup_info(&mut self) -> FatResult<BackupHeader> {
let mut header_page_buffer = [0_u8; BACKUP_HEADER_MAX_SIZE]; let mut header_page_buffer = [0_u8; BACKUP_HEADER_MAX_SIZE];

View File

@@ -170,7 +170,7 @@ pub(crate) fn create_v3(
})) }))
} }
#[async_trait] #[async_trait(?Send)]
impl<'a> BoardInteraction<'a> for V3<'a> { impl<'a> BoardInteraction<'a> for V3<'a> {
fn get_tank_sensor(&mut self) -> Result<&mut TankSensor<'a>, FatError> { fn get_tank_sensor(&mut self) -> Result<&mut TankSensor<'a>, FatError> {
Ok(&mut self.tank_sensor) Ok(&mut self.tank_sensor)

View File

@@ -297,7 +297,7 @@ pub(crate) async fn create_v4(
Ok(Box::new(v)) Ok(Box::new(v))
} }
#[async_trait] #[async_trait(?Send)]
impl<'a> BoardInteraction<'a> for V4<'a> { impl<'a> BoardInteraction<'a> for V4<'a> {
fn get_tank_sensor(&mut self) -> Result<&mut TankSensor<'a>, FatError> { fn get_tank_sensor(&mut self) -> Result<&mut TankSensor<'a>, FatError> {
Ok(&mut self.tank_sensor) Ok(&mut self.tank_sensor)
@@ -461,7 +461,6 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
async fn detect_sensors(&mut self) -> Result<alloc::string::String, FatError> { async fn detect_sensors(&mut self) -> Result<alloc::string::String, FatError> {
// Delegate to sensor autodetect and build JSON // Delegate to sensor autodetect and build JSON
use alloc::string::ToString;
let detected = self.sensor.autodetect().await?; let detected = self.sensor.autodetect().await?;
// Build JSON manually to avoid exposing internal types // Build JSON manually to avoid exposing internal types
let mut s = alloc::string::String::from("{\"plants\":["); let mut s = alloc::string::String::from("{\"plants\":[");

View File

@@ -9,24 +9,21 @@ use alloc::string::ToString;
use async_trait::async_trait; use async_trait::async_trait;
use bincode::config; use bincode::config;
use bincode::error::DecodeError; use bincode::error::DecodeError;
use core::mem;
use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice; use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::mutex::Mutex;
use embassy_time::{Instant, Timer, WithTimeout}; use embassy_time::{Instant, Timer, WithTimeout};
use embedded_can::nb::Can;
use embedded_can::Frame; use embedded_can::Frame;
use esp_hal::gpio::Output; use esp_hal::gpio::Output;
use esp_hal::i2c::master::I2c; use esp_hal::i2c::master::I2c;
use esp_hal::pcnt::unit::Unit; use esp_hal::pcnt::unit::Unit;
use esp_hal::twai::{EspTwaiError, EspTwaiFrame, StandardId, Twai, TwaiConfiguration}; use esp_hal::twai::{EspTwaiFrame, StandardId, Twai, TwaiConfiguration};
use esp_hal::Blocking; use esp_hal::{Async, Blocking};
use log::info; use log::info;
use pca9535::{GPIOBank, Pca9535Immediate, StandardExpanderInterface}; use pca9535::{GPIOBank, Pca9535Immediate, StandardExpanderInterface};
const REPEAT_MOIST_MEASURE: usize = 10; const REPEAT_MOIST_MEASURE: usize = 10;
#[async_trait] #[async_trait(?Send)]
pub trait SensorInteraction { pub trait SensorInteraction {
async fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> FatResult<f32>; async fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> FatResult<f32>;
} }
@@ -50,7 +47,7 @@ pub enum SensorImpl {
}, },
} }
#[async_trait] #[async_trait(?Send)]
impl SensorInteraction for SensorImpl { impl SensorInteraction for SensorImpl {
async fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> FatResult<f32> { async fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> FatResult<f32> {
match self { match self {
@@ -180,8 +177,10 @@ impl SensorImpl {
} => { } => {
// Power on CAN transceiver and start controller // Power on CAN transceiver and start controller
can_power.set_high(); can_power.set_high();
let config = twai_config.take().expect("twai config not set"); let mut config = twai_config.take().expect("twai config not set");
let mut twai = config.start(); let mut as_async = config.into_async().start();
Timer::after_millis(10).await;
// Give CAN some time to stabilize // Give CAN some time to stabilize
Timer::after_millis(10).await; Timer::after_millis(10).await;
@@ -197,7 +196,7 @@ impl SensorImpl {
{ {
if let Some(frame) = EspTwaiFrame::new(address, &can_buffer) { if let Some(frame) = EspTwaiFrame::new(address, &can_buffer) {
// Try a few times; we intentionally ignore rx here and rely on stub logic // 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 { match resu {
Ok(_) => { Ok(_) => {
info!( 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 { loop {
let rec = twai match as_async.receive() {
.receive()
.with_timeout(embassy_time::Duration::from_millis(100))
.await;
match rec {
Ok(msg) => match msg {
Ok(or) => { Ok(or) => {
info!("Received CAN message: {:?}", or); info!("Received CAN message: {:?}", or);
} }
Err(err) => { Err(nb::Error::WouldBlock) => {
info!("Error receiving CAN message: {:?}", err); if Instant::now() > detect_timeout {
break; break;
} }
}, Timer::after_millis(10).await;
Err(err) => { }
Err(nb::Error::Other(err)) => {
info!("Error receiving CAN message: {:?}", err); info!("Error receiving CAN message: {:?}", err);
break; break;
} }
@@ -242,6 +242,7 @@ impl SensorImpl {
// Wait for acknowledgements on the bus (stub: just wait 5 seconds) // Wait for acknowledgements on the bus (stub: just wait 5 seconds)
Timer::after_millis(5_000).await; Timer::after_millis(5_000).await;
// Stop CAN and power down // Stop CAN and power down
let config = as_async.stop().into_blocking();
can_power.set_low(); can_power.set_low();
twai_config.replace(config); twai_config.replace(config);