refactor: consolidate logging and time handling, remove TIME_ACCESS and LOG_ACCESS

This commit is contained in:
2026-04-10 18:53:30 +02:00
parent 301298522b
commit bc25fef5ec
7 changed files with 232 additions and 302 deletions

View File

@@ -1,8 +1,8 @@
use crate::bail; use crate::bail;
use crate::config::{NetworkConfig, PlantControllerConfig}; use crate::config::{NetworkConfig, PlantControllerConfig};
use crate::hal::savegame_manager::SavegameManager; use crate::hal::savegame_manager::SavegameManager;
use crate::hal::{PLANT_COUNT, TIME_ACCESS}; use crate::hal::PLANT_COUNT;
use crate::log::{LogMessage, LOG_ACCESS}; use crate::log::{log, LogMessage};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use crate::fat_error::{ContextExt, FatError, FatResult}; use crate::fat_error::{ContextExt, FatError, FatResult};
@@ -16,7 +16,7 @@ use embassy_executor::Spawner;
use embassy_net::udp::UdpSocket; use embassy_net::udp::UdpSocket;
use embassy_net::{DhcpConfig, Ipv4Cidr, Runner, Stack, StackResources, StaticConfigV4}; use embassy_net::{DhcpConfig, Ipv4Cidr, Runner, Stack, StackResources, StaticConfigV4};
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::mutex::{Mutex, MutexGuard}; use embassy_sync::mutex::Mutex;
use embassy_sync::once_lock::OnceLock; 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, RmwNorFlashStorage}; use embedded_storage::nor_flash::{check_erase, NorFlash, ReadNorFlash, RmwNorFlashStorage};
@@ -112,6 +112,8 @@ pub struct Esp<'a> {
pub wake_gpio1: esp_hal::peripherals::GPIO1<'static>, pub wake_gpio1: esp_hal::peripherals::GPIO1<'static>,
pub uart0: Uart<'a, Blocking>, pub uart0: Uart<'a, Blocking>,
pub rtc: Rtc<'a>,
pub ota: Ota<'static, RmwNorFlashStorage<'static, &'static mut MutexFlashStorage>>, pub ota: Ota<'static, RmwNorFlashStorage<'static, &'static mut MutexFlashStorage>>,
pub ota_target: &'static mut FlashRegion<'static, MutexFlashStorage>, pub ota_target: &'static mut FlashRegion<'static, MutexFlashStorage>,
pub current: AppPartitionSubType, pub current: AppPartitionSubType,
@@ -137,6 +139,14 @@ macro_rules! mk_static {
} }
impl Esp<'_> { impl Esp<'_> {
pub fn get_time(&self) -> DateTime<Utc> {
DateTime::from_timestamp_micros(self.rtc.current_time_us() as i64).unwrap_or(DateTime::UNIX_EPOCH)
}
pub fn set_time(&mut self, time: DateTime<Utc>) {
self.rtc.set_current_time_us(time.timestamp_micros() as u64);
}
pub(crate) async fn read_serial_line(&mut self) -> FatResult<Option<alloc::string::String>> { pub(crate) async fn read_serial_line(&mut self) -> FatResult<Option<alloc::string::String>> {
let mut buf = [0u8; 1]; let mut buf = [0u8; 1];
let mut line = String::new(); let mut line = String::new();
@@ -442,70 +452,65 @@ impl Esp<'_> {
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?;
let timeout = { let res = async {
let guard = TIME_ACCESS.get().await.lock().await; loop {
guard.current_time_us() let state = esp_radio::wifi::sta_state();
} + max_wait as u64 * 1000; if state == WifiStaState::Started {
loop { self.controller.lock().await.connect()?;
let state = esp_radio::wifi::sta_state(); break;
if state == WifiStaState::Started { }
self.controller.lock().await.connect()?; Timer::after(Duration::from_millis(500)).await;
break;
} }
if { Ok::<(), FatError>(())
let guard = TIME_ACCESS.get().await.lock().await;
guard.current_time_us()
} > timeout
{
bail!("Timeout waiting for wifi sta ready")
}
Timer::after(Duration::from_millis(500)).await;
} }
let timeout = { .with_timeout(Duration::from_millis(max_wait as u64 * 1000))
let guard = TIME_ACCESS.get().await.lock().await; .await;
guard.current_time_us()
} + max_wait as u64 * 1000; if res.is_err() {
loop { bail!("Timeout waiting for wifi sta ready")
let state = esp_radio::wifi::sta_state();
if state == WifiStaState::Connected {
break;
}
if {
let guard = TIME_ACCESS.get().await.lock().await;
guard.current_time_us()
} > timeout
{
bail!("Timeout waiting for wifi sta connected")
}
Timer::after(Duration::from_millis(500)).await;
} }
let timeout = {
let guard = TIME_ACCESS.get().await.lock().await; let res = async {
guard.current_time_us() loop {
} + max_wait as u64 * 1000; let state = esp_radio::wifi::sta_state();
while !stack.is_link_up() { if state == WifiStaState::Connected {
if { break;
let guard = TIME_ACCESS.get().await.lock().await; }
guard.current_time_us() Timer::after(Duration::from_millis(500)).await;
} > timeout
{
bail!("Timeout waiting for wifi link up")
} }
Timer::after(Duration::from_millis(500)).await; Ok::<(), FatError>(())
} }
let timeout = { .with_timeout(Duration::from_millis(max_wait as u64 * 1000))
let guard = TIME_ACCESS.get().await.lock().await; .await;
guard.current_time_us()
} + max_wait as u64 * 1000; if res.is_err() {
while !stack.is_config_up() { bail!("Timeout waiting for wifi sta connected")
if { }
let guard = TIME_ACCESS.get().await.lock().await;
guard.current_time_us() let res = async {
} > timeout while !stack.is_link_up() {
{ Timer::after(Duration::from_millis(500)).await;
bail!("Timeout waiting for wifi config up")
} }
Timer::after(Duration::from_millis(100)).await Ok::<(), FatError>(())
}
.with_timeout(Duration::from_millis(max_wait as u64 * 1000))
.await;
if res.is_err() {
bail!("Timeout waiting for wifi link up")
}
let res = async {
while !stack.is_config_up() {
Timer::after(Duration::from_millis(100)).await
}
Ok::<(), FatError>(())
}
.with_timeout(Duration::from_millis(max_wait as u64 * 1000))
.await;
if res.is_err() {
bail!("Timeout waiting for wifi config up")
} }
info!("Connected WIFI, dhcp: {:?}", stack.config_v4()); info!("Connected WIFI, dhcp: {:?}", stack.config_v4());
@@ -515,7 +520,6 @@ impl Esp<'_> {
pub fn deep_sleep( pub fn deep_sleep(
&mut self, &mut self,
duration_in_ms: u64, duration_in_ms: u64,
mut rtc: MutexGuard<CriticalSectionRawMutex, Rtc>,
) -> ! { ) -> ! {
// Mark the current OTA image as valid if we reached here while in pending verify. // Mark the current OTA image as valid if we reached here while in pending verify.
if let Ok(cur) = self.ota.current_ota_state() { if let Ok(cur) = self.ota.current_ota_state() {
@@ -536,7 +540,7 @@ impl Esp<'_> {
let mut wake_pins: [(&mut dyn RtcPinWithResistors, WakeupLevel); 1] = let mut wake_pins: [(&mut dyn RtcPinWithResistors, WakeupLevel); 1] =
[(&mut self.wake_gpio1, WakeupLevel::Low)]; [(&mut self.wake_gpio1, WakeupLevel::Low)];
let ext1 = esp_hal::rtc_cntl::sleep::Ext1WakeupSource::new(&mut wake_pins); let ext1 = esp_hal::rtc_cntl::sleep::Ext1WakeupSource::new(&mut wake_pins);
rtc.sleep_deep(&[&timer, &ext1]); self.rtc.sleep_deep(&[&timer, &ext1]);
} }
} }
@@ -603,28 +607,15 @@ impl Esp<'_> {
if to_config_mode { if to_config_mode {
RESTART_TO_CONF = 1; RESTART_TO_CONF = 1;
} }
LOG_ACCESS log(LogMessage::RestartToConfig, RESTART_TO_CONF as u32, 0, "", "").await;
.lock() log(
.await LogMessage::LowVoltage,
.log( LOW_VOLTAGE_DETECTED as u32,
LogMessage::RestartToConfig, 0,
RESTART_TO_CONF as u32, "",
0, "",
"", )
"", .await;
)
.await;
LOG_ACCESS
.lock()
.await
.log(
LogMessage::LowVoltage,
LOW_VOLTAGE_DETECTED as u32,
0,
"",
"",
)
.await;
// is executed before main, no other code will alter these values during printing // is executed before main, no other code will alter these values during printing
#[allow(static_mut_refs)] #[allow(static_mut_refs)]
for (i, time) in LAST_WATERING_TIMESTAMP.iter().enumerate() { for (i, time) in LAST_WATERING_TIMESTAMP.iter().enumerate() {
@@ -703,29 +694,22 @@ impl Esp<'_> {
))?; ))?;
spawner.spawn(mqtt_runner(task))?; spawner.spawn(mqtt_runner(task))?;
LOG_ACCESS log(LogMessage::StayAlive, 0, 0, "", &stay_alive_topic).await;
.lock()
.await
.log(LogMessage::StayAlive, 0, 0, "", &stay_alive_topic)
.await;
LOG_ACCESS log(LogMessage::MqttInfo, 0, 0, "", mqtt_url).await;
.lock()
.await
.log(LogMessage::MqttInfo, 0, 0, "", mqtt_url)
.await;
let mqtt_timeout = 15000; let mqtt_timeout = 15000;
let timeout = { let res = async {
let guard = TIME_ACCESS.get().await.lock().await; while !MQTT_CONNECTED_EVENT_RECEIVED.load(Ordering::Relaxed) {
guard.current_time_us() Timer::after(Duration::from_millis(100)).await;
} + mqtt_timeout as u64 * 1000;
while !MQTT_CONNECTED_EVENT_RECEIVED.load(Ordering::Relaxed) {
let cur = TIME_ACCESS.get().await.lock().await.current_time_us();
if cur > timeout {
bail!("Timeout waiting MQTT connect event")
} }
Timer::after(Duration::from_millis(100)).await; Ok::<(), FatError>(())
}
.with_timeout(Duration::from_millis(mqtt_timeout as u64))
.await;
if res.is_err() {
bail!("Timeout waiting MQTT connect event")
} }
let _ = Topic::General(round_trip_topic.clone()) let _ = Topic::General(round_trip_topic.clone())
@@ -733,18 +717,19 @@ impl Esp<'_> {
.publish() .publish()
.await; .await;
let timeout = { let res = async {
let guard = TIME_ACCESS.get().await.lock().await; while !MQTT_ROUND_TRIP_RECEIVED.load(Ordering::Relaxed) {
guard.current_time_us() Timer::after(Duration::from_millis(100)).await;
} + mqtt_timeout as u64 * 1000;
while !MQTT_ROUND_TRIP_RECEIVED.load(Ordering::Relaxed) {
let cur = TIME_ACCESS.get().await.lock().await.current_time_us();
if cur > timeout {
//ensure we do not further try to publish
MQTT_CONNECTED_EVENT_RECEIVED.store(false, Ordering::Relaxed);
bail!("Timeout waiting MQTT roundtrip")
} }
Timer::after(Duration::from_millis(100)).await; Ok::<(), FatError>(())
}
.with_timeout(Duration::from_millis(mqtt_timeout as u64))
.await;
if res.is_err() {
//ensure we do not further try to publish
MQTT_CONNECTED_EVENT_RECEIVED.store(false, Ordering::Relaxed);
bail!("Timeout waiting MQTT roundtrip")
} }
Ok(()) Ok(())
} }
@@ -851,18 +836,10 @@ async fn mqtt_incoming_task(
true => 1, true => 1,
false => 0, false => 0,
}; };
LOG_ACCESS log(LogMessage::MqttStayAliveRec, a, 0, "", "").await;
.lock()
.await
.log(LogMessage::MqttStayAliveRec, a, 0, "", "")
.await;
MQTT_STAY_ALIVE.store(value, Ordering::Relaxed); MQTT_STAY_ALIVE.store(value, Ordering::Relaxed);
} else { } else {
LOG_ACCESS log(LogMessage::UnknownTopic, 0, 0, "", &topic).await;
.lock()
.await
.log(LogMessage::UnknownTopic, 0, 0, "", &topic)
.await;
} }
} }
}, },

View File

@@ -44,8 +44,8 @@ use crate::{
battery::{BatteryInteraction, NoBatteryMonitor}, battery::{BatteryInteraction, NoBatteryMonitor},
esp::Esp, esp::Esp,
}, },
log::log,
log::LogMessage, log::LogMessage,
BOARD_ACCESS,
}; };
use alloc::boxed::Box; use alloc::boxed::Box;
use alloc::format; use alloc::format;
@@ -77,7 +77,6 @@ use crate::fat_error::{ContextExt, FatError, FatResult};
use crate::hal::battery::WCHI2CSlave; use crate::hal::battery::WCHI2CSlave;
use crate::hal::savegame_manager::SavegameManager; use crate::hal::savegame_manager::SavegameManager;
use crate::hal::water::TankSensor; use crate::hal::water::TankSensor;
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::RmwNorFlashStorage; use embedded_storage::nor_flash::RmwNorFlashStorage;
@@ -104,8 +103,6 @@ use portable_atomic::AtomicBool;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use shared_flash::MutexFlashStorage; use shared_flash::MutexFlashStorage;
pub static TIME_ACCESS: OnceLock<Mutex<CriticalSectionRawMutex, Rtc>> = OnceLock::new();
//Only support for 8 right now! //Only support for 8 right now!
pub const PLANT_COUNT: usize = 8; pub const PLANT_COUNT: usize = 8;
@@ -145,6 +142,8 @@ pub trait BoardInteraction<'a> {
fn get_config(&mut self) -> &PlantControllerConfig; fn get_config(&mut self) -> &PlantControllerConfig;
fn get_battery_monitor(&mut self) -> &mut Box<dyn BatteryInteraction + Send>; fn get_battery_monitor(&mut self) -> &mut Box<dyn BatteryInteraction + Send>;
fn get_rtc_module(&mut self) -> &mut Box<dyn RTCModuleInteraction + Send>; fn get_rtc_module(&mut self) -> &mut Box<dyn RTCModuleInteraction + Send>;
async fn get_time(&mut self) -> DateTime<Utc>;
async fn set_time(&mut self, time: &DateTime<FixedOffset>) -> FatResult<()>;
async fn set_charge_indicator(&mut self, charging: bool) -> Result<(), FatError>; async fn set_charge_indicator(&mut self, charging: bool) -> Result<(), FatError>;
async fn deep_sleep(&mut self, duration_in_ms: u64) -> !; async fn deep_sleep(&mut self, duration_in_ms: u64) -> !;
@@ -246,12 +245,7 @@ impl PlantHal {
esp_alloc::heap_allocator!(size: 64 * 1024); esp_alloc::heap_allocator!(size: 64 * 1024);
esp_alloc::heap_allocator!(#[link_section = ".dram2_uninit"] size: 64000); esp_alloc::heap_allocator!(#[link_section = ".dram2_uninit"] size: 64000);
let rtc: Rtc = Rtc::new(peripherals.LPWR); let rtc_peripheral: Rtc = Rtc::new(peripherals.LPWR);
TIME_ACCESS
.init(Mutex::new(rtc))
.map_err(|_| FatError::String {
error: "Init error rct".to_string(),
})?;
let timg0 = TimerGroup::new(peripherals.TIMG0); let timg0 = TimerGroup::new(peripherals.TIMG0);
let sw_int = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); let sw_int = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
@@ -409,6 +403,7 @@ impl PlantHal {
slot0_state: state_0, slot0_state: state_0,
slot1_state: state_1, slot1_state: state_1,
uart0, uart0,
rtc: rtc_peripheral,
}; };
//init,reset rtc memory depending on cause //init,reset rtc memory depending on cause
@@ -444,17 +439,14 @@ impl PlantHal {
SocResetReason::Cpu0JtagCpu => "cpu0 jtag cpu", SocResetReason::Cpu0JtagCpu => "cpu0 jtag cpu",
}, },
}; };
LOG_ACCESS log(
.lock() LogMessage::ResetReason,
.await init_rtc_store as u32,
.log( to_config_mode as u32,
LogMessage::ResetReason, "",
init_rtc_store as u32, &format!("{reasons:?}"),
to_config_mode as u32, )
"", .await;
&format!("{reasons:?}"),
)
.await;
esp.init_rtc_deepsleep_memory(init_rtc_store, to_config_mode) esp.init_rtc_deepsleep_memory(init_rtc_store, to_config_mode)
.await; .await;
@@ -548,17 +540,14 @@ impl PlantHal {
HAL { board_hal } HAL { board_hal }
} }
Err(err) => { Err(err) => {
LOG_ACCESS log(
.lock() LogMessage::ConfigModeMissingConfig,
.await 0,
.log( 0,
LogMessage::ConfigModeMissingConfig, "",
0, &err.to_string(),
0, )
"", .await;
&err.to_string(),
)
.await;
HAL { HAL {
board_hal: v4_hal::create_v4( board_hal: v4_hal::create_v4(
free_pins, free_pins,
@@ -641,27 +630,6 @@ pub fn next_partition(current: AppPartitionSubType) -> FatResult<AppPartitionSub
Ok(next) Ok(next)
} }
pub async fn esp_time() -> DateTime<Utc> {
let guard = TIME_ACCESS.get().await.lock().await;
DateTime::from_timestamp_micros(guard.current_time_us() as i64).unwrap_or(DateTime::UNIX_EPOCH)
}
pub async fn esp_set_time(time: DateTime<FixedOffset>) -> FatResult<()> {
{
let guard = TIME_ACCESS.get().await.lock().await;
guard.set_current_time_us(time.timestamp_micros() as u64);
}
BOARD_ACCESS
.get()
.await
.lock()
.await
.board_hal
.get_rtc_module()
.set_rtc_time(&time.to_utc())
.await
}
#[derive(Debug, Clone, Copy, PartialEq, Default, Serialize)] #[derive(Debug, Clone, Copy, PartialEq, Default, Serialize)]
pub struct Moistures { pub struct Moistures {
pub sensor_a_hz: [Option<f32>; PLANT_COUNT], pub sensor_a_hz: [Option<f32>; PLANT_COUNT],

View File

@@ -7,15 +7,15 @@ use crate::hal::rtc::{BackupHeader, RTCModuleInteraction, EEPROM_PAGE, X25};
use crate::hal::water::TankSensor; use crate::hal::water::TankSensor;
use crate::hal::{ use crate::hal::{
BoardInteraction, Detection, FreePeripherals, Moistures, Sensor, I2C_DRIVER, PLANT_COUNT, BoardInteraction, Detection, FreePeripherals, Moistures, Sensor, I2C_DRIVER, PLANT_COUNT,
TIME_ACCESS,
}; };
use crate::log::{LogMessage, LOG_ACCESS}; use crate::log::{log, LogMessage};
use alloc::boxed::Box; use alloc::boxed::Box;
use alloc::string::ToString; use alloc::string::ToString;
use async_trait::async_trait; use async_trait::async_trait;
use bincode::config; use bincode::config;
use canapi::id::{classify, plant_id, MessageKind, IDENTIFY_CMD_OFFSET}; use canapi::id::{classify, plant_id, MessageKind, IDENTIFY_CMD_OFFSET};
use canapi::SensorSlot; use canapi::SensorSlot;
use chrono::{DateTime, FixedOffset, Utc};
use core::cmp::min; use core::cmp::min;
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;
@@ -300,6 +300,16 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
&mut self.rtc_module &mut self.rtc_module
} }
async fn get_time(&mut self) -> DateTime<Utc> {
self.esp.get_time()
}
async fn set_time(&mut self, time: &DateTime<FixedOffset>) -> FatResult<()> {
self.rtc_module.set_rtc_time(&time.to_utc()).await?;
self.esp.set_time(time.to_utc());
Ok(())
}
async fn set_charge_indicator(&mut self, charging: bool) -> Result<(), FatError> { async fn set_charge_indicator(&mut self, charging: bool) -> Result<(), FatError> {
self.charger.set_charge_indicator(charging) self.charger.set_charge_indicator(charging)
} }
@@ -307,8 +317,7 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
async fn deep_sleep(&mut self, duration_in_ms: u64) -> ! { async fn deep_sleep(&mut self, duration_in_ms: u64) -> ! {
self.awake.set_low(); self.awake.set_low();
self.charger.power_save(); self.charger.power_save();
let rtc = TIME_ACCESS.get().await.lock().await; self.esp.deep_sleep(duration_in_ms);
self.esp.deep_sleep(duration_in_ms, rtc);
} }
fn is_day(&self) -> bool { fn is_day(&self) -> bool {
@@ -507,10 +516,7 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
for plant in 0..PLANT_COUNT { for plant in 0..PLANT_COUNT {
let a = moisture.sensor_a_hz[plant].unwrap_or(0.0) as u32; let a = moisture.sensor_a_hz[plant].unwrap_or(0.0) as u32;
let b = moisture.sensor_b_hz[plant].unwrap_or(0.0) as u32; let b = moisture.sensor_b_hz[plant].unwrap_or(0.0) as u32;
LOG_ACCESS log(LogMessage::TestSensor, a, b, &(plant + 1).to_string(), "")
.lock()
.await
.log(LogMessage::TestSensor, a, b, &(plant + 1).to_string(), "")
.await; .await;
} }
Timer::after_millis(10).await; Timer::after_millis(10).await;

View File

@@ -1,10 +1,11 @@
use crate::hal::TIME_ACCESS; use crate::BOARD_ACCESS;
use crate::vec; use crate::vec;
use alloc::string::ToString; use alloc::string::ToString;
use alloc::vec::Vec; use alloc::vec::Vec;
use bytemuck::{AnyBitPattern, Pod, Zeroable}; use bytemuck::{AnyBitPattern, Pod, Zeroable};
use deranged::RangedU8; use deranged::RangedU8;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::channel::Channel;
use embassy_sync::mutex::Mutex; use embassy_sync::mutex::Mutex;
use esp_hal::Persistable; use esp_hal::Persistable;
use log::{info, warn}; use log::{info, warn};
@@ -32,6 +33,34 @@ static mut LOG_ARRAY: LogArray = LogArray {
pub static LOG_ACCESS: Mutex<CriticalSectionRawMutex, &'static mut LogArray> = pub static LOG_ACCESS: Mutex<CriticalSectionRawMutex, &'static mut LogArray> =
unsafe { Mutex::new(&mut LOG_ARRAY) }; unsafe { Mutex::new(&mut LOG_ARRAY) };
pub struct LogRequest {
pub message_key: LogMessage,
pub number_a: u32,
pub number_b: u32,
pub txt_short: heapless::String<TXT_SHORT_LENGTH>,
pub txt_long: heapless::String<TXT_LONG_LENGTH>,
}
static LOG_CHANNEL: Channel<CriticalSectionRawMutex, LogRequest, 16> = Channel::new();
#[embassy_executor::task]
pub async fn log_task() {
loop {
let request = LOG_CHANNEL.receive().await;
LOG_ACCESS
.lock()
.await
.log(
request.message_key,
request.number_a,
request.number_b,
request.txt_short.as_str(),
request.txt_long.as_str(),
)
.await;
}
}
const TXT_SHORT_LENGTH: usize = 8; const TXT_SHORT_LENGTH: usize = 8;
const TXT_LONG_LENGTH: usize = 32; const TXT_LONG_LENGTH: usize = 32;
@@ -87,11 +116,21 @@ pub async fn log(
txt_short: &str, txt_short: &str,
txt_long: &str, txt_long: &str,
) { ) {
LOG_ACCESS let mut txt_short_stack: heapless::String<TXT_SHORT_LENGTH> = heapless::String::new();
.lock() let mut txt_long_stack: heapless::String<TXT_LONG_LENGTH> = heapless::String::new();
.await
.log(message_key, number_a, number_b, txt_short, txt_long) limit_length(txt_short, &mut txt_short_stack);
.await limit_length(txt_long, &mut txt_long_stack);
LOG_CHANNEL
.send(LogRequest {
message_key,
number_a,
number_b,
txt_short: txt_short_stack,
txt_long: txt_long_stack,
})
.await;
} }
impl LogArray { impl LogArray {
@@ -122,15 +161,9 @@ impl LogArray {
let mut head: RangedU8<0, MAX_LOG_ARRAY_INDEX> = let mut head: RangedU8<0, MAX_LOG_ARRAY_INDEX> =
RangedU8::new(self.head).unwrap_or(RangedU8::new_saturating(0)); RangedU8::new(self.head).unwrap_or(RangedU8::new_saturating(0));
let mut txt_short_stack: heapless::String<TXT_SHORT_LENGTH> = heapless::String::new();
let mut txt_long_stack: heapless::String<TXT_LONG_LENGTH> = heapless::String::new();
limit_length(txt_short, &mut txt_short_stack);
limit_length(txt_long, &mut txt_long_stack);
let time = { let time = {
let guard = TIME_ACCESS.get().await.lock().await; let mut guard = BOARD_ACCESS.get().await.lock().await;
guard.current_time_us() guard.board_hal.get_esp().rtc.current_time_us()
} / 1000; } / 1000;
let ordinal = message_key.ordinal() as u16; let ordinal = message_key.ordinal() as u16;
@@ -148,12 +181,8 @@ impl LogArray {
to_modify.message_id = ordinal; to_modify.message_id = ordinal;
to_modify.a = number_a; to_modify.a = number_a;
to_modify.b = number_b; to_modify.b = number_b;
to_modify to_modify.txt_short.clone_from_slice(txt_short.as_bytes());
.txt_short to_modify.txt_long.clone_from_slice(txt_long.as_bytes());
.clone_from_slice(txt_short_stack.as_bytes());
to_modify
.txt_long
.clone_from_slice(txt_long_stack.as_bytes());
head = head.wrapping_add(1); head = head.wrapping_add(1);
self.head = head.get(); self.head = head.get();
} }

View File

@@ -18,8 +18,7 @@ use crate::config::{NetworkConfig, PlantConfig, PlantControllerConfig};
use crate::fat_error::FatResult; use crate::fat_error::FatResult;
use crate::hal::esp::MQTT_STAY_ALIVE; use crate::hal::esp::MQTT_STAY_ALIVE;
use crate::hal::PROGRESS_ACTIVE; use crate::hal::PROGRESS_ACTIVE;
use crate::hal::{esp_time, TIME_ACCESS}; use crate::log::log;
use crate::log::{log, LOG_ACCESS};
use crate::tank::{determine_tank_state, TankError, TankState, WATER_FROZEN_THRESH}; use crate::tank::{determine_tank_state, TankError, TankState, WATER_FROZEN_THRESH};
use crate::webserver::http_server; use crate::webserver::http_server;
use crate::{ use crate::{
@@ -168,26 +167,21 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
let cur = match board.board_hal.get_rtc_module().get_rtc_time().await { let cur = match board.board_hal.get_rtc_module().get_rtc_time().await {
Ok(value) => { Ok(value) => {
{ {
let guard = TIME_ACCESS.get().await.lock().await; board.board_hal.get_esp().rtc.set_current_time_us(value.timestamp_micros() as u64);
guard.set_current_time_us(value.timestamp_micros() as u64);
} }
value value
} }
Err(err) => { Err(err) => {
info!("rtc module error: {err:?}"); info!("rtc module error: {err:?}");
board.board_hal.general_fault(true).await; board.board_hal.general_fault(true).await;
esp_time().await board.board_hal.get_time().await
} }
}; };
//check if we know the time current > 2020 (plausibility checks, this code is newer than 2020) //check if we know the time current > 2020 (plausibility checks, this code is newer than 2020)
if cur.year() < 2020 { if cur.year() < 2020 {
to_config = true; to_config = true;
LOG_ACCESS log(LogMessage::YearInplausibleForceConfig, 0, 0, "", "").await;
.lock()
.await
.log(LogMessage::YearInplausibleForceConfig, 0, 0, "", "")
.await;
} }
info!("cur is {cur}"); info!("cur is {cur}");
match update_charge_indicator(&mut board).await { match update_charge_indicator(&mut board).await {
@@ -200,11 +194,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
} }
} }
if board.board_hal.get_esp().get_restart_to_conf() { if board.board_hal.get_esp().get_restart_to_conf() {
LOG_ACCESS log(LogMessage::ConfigModeSoftwareOverride, 0, 0, "", "").await;
.lock()
.await
.log(LogMessage::ConfigModeSoftwareOverride, 0, 0, "", "")
.await;
for _i in 0..2 { for _i in 0..2 {
board.board_hal.general_fault(true).await; board.board_hal.general_fault(true).await;
Timer::after_millis(100).await; Timer::after_millis(100).await;
@@ -216,11 +206,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
board.board_hal.get_esp().set_restart_to_conf(false); board.board_hal.get_esp().set_restart_to_conf(false);
} else if board.board_hal.get_esp().mode_override_pressed() { } else if board.board_hal.get_esp().mode_override_pressed() {
board.board_hal.general_fault(true).await; board.board_hal.general_fault(true).await;
LOG_ACCESS log(LogMessage::ConfigModeButtonOverride, 0, 0, "", "").await;
.lock()
.await
.log(LogMessage::ConfigModeButtonOverride, 0, 0, "", "")
.await;
for _i in 0..5 { for _i in 0..5 {
board.board_hal.general_fault(true).await; board.board_hal.general_fault(true).await;
Timer::after_millis(100).await; Timer::after_millis(100).await;
@@ -304,25 +290,22 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
let _ = publish_mppt_state(&mut board).await; let _ = publish_mppt_state(&mut board).await;
} }
LOG_ACCESS log(
.lock() LogMessage::StartupInfo,
.await matches!(network_mode, NetworkMode::Wifi { .. }) as u32,
.log( matches!(
LogMessage::StartupInfo, network_mode,
matches!(network_mode, NetworkMode::Wifi { .. }) as u32, NetworkMode::Wifi {
matches!( sntp: SntpMode::Sync { .. },
network_mode, ..
NetworkMode::Wifi { }
sntp: SntpMode::Sync { .. }, ) as u32,
.. matches!(network_mode, NetworkMode::Wifi { mqtt: true, .. })
} .to_string()
) as u32, .as_str(),
matches!(network_mode, NetworkMode::Wifi { mqtt: true, .. }) "",
.to_string() )
.as_str(), .await;
"",
)
.await;
if to_config { if to_config {
//check if client or ap mode and init Wi-Fi //check if client or ap mode and init Wi-Fi
@@ -337,14 +320,10 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
} }
wait_infinity(board, WaitType::ConfigButton, reboot_now.clone()).await; wait_infinity(board, WaitType::ConfigButton, reboot_now.clone()).await;
} else { } else {
LOG_ACCESS log(LogMessage::NormalRun, 0, 0, "", "").await;
.lock()
.await
.log(LogMessage::NormalRun, 0, 0, "", "")
.await;
} }
let dry_run = false; let dry_run = MQTT_STAY_ALIVE.load(Ordering::Relaxed);
let tank_state = determine_tank_state(&mut board).await; let tank_state = determine_tank_state(&mut board).await;
@@ -353,37 +332,20 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
match err { match err {
TankError::SensorDisabled => { /* unreachable */ } TankError::SensorDisabled => { /* unreachable */ }
TankError::SensorMissing(raw_value_mv) => { TankError::SensorMissing(raw_value_mv) => {
LOG_ACCESS log(LogMessage::TankSensorMissing, raw_value_mv as u32, 0, "", "").await
.lock()
.await
.log(
LogMessage::TankSensorMissing,
raw_value_mv as u32,
0,
"",
"",
)
.await
} }
TankError::SensorValueError { value, min, max } => { TankError::SensorValueError { value, min, max } => {
LOG_ACCESS log(
.lock() LogMessage::TankSensorValueRangeError,
.await min as u32,
.log( max as u32,
LogMessage::TankSensorValueRangeError, &format!("{value}"),
min as u32, "",
max as u32, )
&format!("{value}"), .await
"",
)
.await
} }
TankError::BoardError(err) => { TankError::BoardError(err) => {
LOG_ACCESS log(LogMessage::TankSensorBoardError, 0, 0, "", &err.to_string()).await
.lock()
.await
.log(LogMessage::TankSensorBoardError, 0, 0, "", &err.to_string())
.await
} }
} }
// disabled cannot trigger this because of wrapping if is_enabled // disabled cannot trigger this because of wrapping if is_enabled
@@ -392,11 +354,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
.warn_level(&board.board_hal.get_config().tank) .warn_level(&board.board_hal.get_config().tank)
.is_ok_and(|warn| warn) .is_ok_and(|warn| warn)
{ {
LOG_ACCESS log(LogMessage::TankWaterLevelLow, 0, 0, "", "").await;
.lock()
.await
.log(LogMessage::TankWaterLevelLow, 0, 0, "", "")
.await;
board.board_hal.general_fault(true).await; board.board_hal.general_fault(true).await;
} }
} }
@@ -445,11 +403,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
.any(|(it, conf)| it.needs_to_be_watered(conf, &timezone_time)) .any(|(it, conf)| it.needs_to_be_watered(conf, &timezone_time))
&& !water_frozen; && !water_frozen;
if pump_required { if pump_required {
LOG_ACCESS log(LogMessage::EnableMain, dry_run as u32, 0, "", "").await;
.lock()
.await
.log(LogMessage::EnableMain, dry_run as u32, 0, "", "")
.await;
for (plant_id, (state, plant_config)) in plantstate for (plant_id, (state, plant_config)) in plantstate
.iter() .iter()
.zip(&board.board_hal.get_config().plants.clone()) .zip(&board.board_hal.get_config().plants.clone())
@@ -489,12 +443,13 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
board.board_hal.get_esp().last_pump_time(plant_id); board.board_hal.get_esp().last_pump_time(plant_id);
//state.active = true; //state.active = true;
pump_info(plant_id, true, pump_ineffective, 0, 0, 0, false).await; pump_info(&mut board, plant_id, true, pump_ineffective, 0, 0, 0, false).await;
let result = do_secure_pump(&mut board, plant_id, plant_config, dry_run).await?; let result = do_secure_pump(&mut board, plant_id, plant_config, dry_run).await?;
//stop pump regardless of prior result//todo refactor to inner? //stop pump regardless of prior result//todo refactor to inner?
board.board_hal.pump(plant_id, false).await?; board.board_hal.pump(plant_id, false).await?;
pump_info( pump_info(
&mut board,
plant_id, plant_id,
false, false,
pump_ineffective, pump_ineffective,
@@ -947,6 +902,7 @@ async fn try_connect_wifi_sntp_mqtt(
} }
async fn pump_info( async fn pump_info(
board: &mut MutexGuard<'_, CriticalSectionRawMutex, HAL<'static>>,
plant_id: usize, plant_id: usize,
pump_active: bool, pump_active: bool,
pump_ineffective: bool, pump_ineffective: bool,
@@ -966,15 +922,7 @@ async fn pump_info(
match serde_json::to_string(&pump_info) { match serde_json::to_string(&pump_info) {
Ok(state) => { Ok(state) => {
BOARD_ACCESS board.board_hal.get_esp().mqtt_publish(&pump_topic, &state).await;
.get()
.await
.lock()
.await
.board_hal
.get_esp()
.mqtt_publish(&pump_topic, &state)
.await;
} }
Err(err) => { Err(err) => {
warn!("Error publishing pump state {err}"); warn!("Error publishing pump state {err}");
@@ -1222,6 +1170,7 @@ use embassy_time::WithTimeout;
async fn main(spawner: Spawner) -> ! { async fn main(spawner: Spawner) -> ! {
// intialize embassy // intialize embassy
logger::init_logger_from_env(); logger::init_logger_from_env();
spawner.must_spawn(crate::log::log_task());
//force init here! //force init here!
match BOARD_ACCESS.init( match BOARD_ACCESS.init(
PlantHal::create() PlantHal::create()

View File

@@ -1,5 +1,5 @@
use crate::fat_error::{FatError, FatResult}; use crate::fat_error::{FatError, FatResult};
use crate::hal::{esp_time, PLANT_COUNT}; use crate::hal::PLANT_COUNT;
use crate::log::LogMessage; use crate::log::LogMessage;
use crate::plant_state::{MoistureSensorState, PlantState}; use crate::plant_state::{MoistureSensorState, PlantState};
use crate::tank::determine_tank_state; use crate::tank::determine_tank_state;
@@ -174,7 +174,7 @@ pub(crate) async fn get_time<T, const N: usize>(
}, },
}; };
let native = esp_time().await.with_timezone(&tz).to_rfc3339(); let native = board.board_hal.get_time().await.with_timezone(&tz).to_rfc3339();
let rtc = match board.board_hal.get_rtc_module().get_rtc_time().await { let rtc = match board.board_hal.get_rtc_module().get_rtc_time().await {
Ok(time) => time.with_timezone(&tz).to_rfc3339(), Ok(time) => time.with_timezone(&tz).to_rfc3339(),

View File

@@ -1,6 +1,6 @@
use crate::config::PlantControllerConfig; use crate::config::PlantControllerConfig;
use crate::fat_error::FatResult; use crate::fat_error::FatResult;
use crate::hal::{esp_set_time, Detection}; use crate::hal::Detection;
use crate::webserver::read_up_to_bytes_from_request; use crate::webserver::read_up_to_bytes_from_request;
use crate::{do_secure_pump, BOARD_ACCESS}; use crate::{do_secure_pump, BOARD_ACCESS};
use alloc::string::{String, ToString}; use alloc::string::{String, ToString};
@@ -109,7 +109,8 @@ where
let actual_data = read_up_to_bytes_from_request(request, None).await?; let actual_data = read_up_to_bytes_from_request(request, None).await?;
let time: SetTime = serde_json::from_slice(&actual_data)?; let time: SetTime = serde_json::from_slice(&actual_data)?;
let parsed = DateTime::parse_from_rfc3339(time.time)?; let parsed = DateTime::parse_from_rfc3339(time.time)?;
esp_set_time(parsed).await?; let mut board = BOARD_ACCESS.get().await.lock().await;
board.board_hal.set_time(&parsed).await?;
Ok(None) Ok(None)
} }