From c94f5bdb45ae6c02534a9c76b5ed94c05bff9177 Mon Sep 17 00:00:00 2001 From: Empire Date: Sat, 20 Sep 2025 11:31:51 +0200 Subject: [PATCH] get log to work, make time accessible --- rust/Cargo.toml | 7 +- rust/src/hal/esp.rs | 80 +++++++++--------- rust/src/hal/mod.rs | 144 +++++++++++++++++++++++--------- rust/src/log/mod.rs | 170 +++++++++++++++++++++++--------------- rust/src/main.rs | 42 +++++----- rust/src/webserver/mod.rs | 103 ++++++++++++++--------- 6 files changed, 334 insertions(+), 212 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index d1ac493..71624d9 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -133,16 +133,11 @@ serde = { version = "1.0.219", features = ["derive", "alloc"], default-features serde_json = { version = "1.0.143", default-features = false, features = ["alloc"] } #timezone - 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"] } eeprom24x = "0.7.2" -#url = "2.5.3" crc = "3.2.1" -bincode = { version = "2.0.1", default-features = false, features = ["alloc", "serde"] } -ringbuffer = "0.15.0" strum_macros = "0.27.0" -#esp-ota = { version = "0.2.2", features = ["log"] } unit-enum = "1.4.1" pca9535 = { version = "2.0.0" } ina219 = { version = "0.2.0" } @@ -157,10 +152,10 @@ edge-dhcp = "0.6.0" edge-nal = "0.5.0" edge-nal-embassy = "0.6.0" static_cell = "2.1.1" -cfg-if = "1.0.3" edge-http = { version = "0.6.1", features = ["log"] } littlefs2 = { version = "0.6.1", features = ["c-stubs", "alloc"] } littlefs2-core = "0.1.1" +bytemuck = { version = "1.23.2", features = ["derive", "min_const_generics", "pod_saturating", "extern_crate_alloc"] } [patch.crates-io] diff --git a/rust/src/hal/esp.rs b/rust/src/hal/esp.rs index 2549865..5a49049 100644 --- a/rust/src/hal/esp.rs +++ b/rust/src/hal/esp.rs @@ -1,9 +1,9 @@ use crate::config::{NetworkConfig, PlantControllerConfig}; -use crate::hal::{GW_IP_ADDR_ENV, PLANT_COUNT}; -use crate::log::{log, LogMessage}; +use crate::hal::{GW_IP_ADDR_ENV, PLANT_COUNT, TIME_ACCESS}; +use crate::log::{ LogArray, LogMessage, LOG_ACCESS}; use crate::STAY_ALIVE; use anyhow::{anyhow, bail, Context}; -use chrono::{DateTime, Utc}; +use chrono::{DateTime, FixedOffset, Utc}; use serde::Serialize; use crate::hal::little_fs2storage_adapter::LittleFs2Filesystem; @@ -13,12 +13,10 @@ use alloc::{format, string::String, vec::Vec}; use core::marker::PhantomData; use core::net::{IpAddr, Ipv4Addr}; use core::str::FromStr; -use embassy_executor::{SendSpawner, Spawner}; -use embassy_net::tcp::TcpSocket; -use embassy_net::{IpListenEndpoint, Ipv4Cidr, Runner, Stack, StackResources, StaticConfigV4}; +use embassy_executor::{Spawner}; +use embassy_net::{Ipv4Cidr, Runner, Stack, StackResources, StaticConfigV4}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::mutex::Mutex; -use embassy_sync::rwlock::TryLockError; use embassy_time::{Duration, Instant, Timer}; use embedded_storage::nor_flash::ReadNorFlash; use embedded_storage::Storage; @@ -26,25 +24,27 @@ use esp_bootloader_esp_idf::ota::{Ota, OtaImageState, Slot}; use esp_bootloader_esp_idf::partitions::{Error, FlashRegion, PartitionEntry, PartitionTable}; use esp_hal::gpio::Input; use esp_hal::rng::Rng; +use esp_hal::rtc_cntl::Rtc; use esp_hal::rtc_cntl::sleep::RtcSleepConfig; -use esp_println::{print, println}; +use esp_hal::system::software_reset; +use esp_println::{println}; use esp_storage::FlashStorage; use esp_wifi::wifi::{ AccessPointConfiguration, AccessPointInfo, Configuration, Interfaces, ScanConfig, - ScanTypeConfig, WifiController, WifiDevice, WifiEvent, WifiState, + ScanTypeConfig, WifiController, WifiDevice, }; use littlefs2::fs::Filesystem; -use littlefs2_core::{DynFile, FileType, OpenSeekFrom, Path, PathBuf, SeekFrom}; -use log::{info, warn}; +use littlefs2_core::{DynFile, FileType, PathBuf, SeekFrom}; +use log::{info}; -#[link_section = ".rtc.data"] +#[esp_hal::ram(rtc_fast, persistent)] static mut LAST_WATERING_TIMESTAMP: [i64; PLANT_COUNT] = [0; PLANT_COUNT]; -#[link_section = ".rtc.data"] +#[esp_hal::ram(rtc_fast, persistent)] static mut CONSECUTIVE_WATERING_PLANT: [u32; PLANT_COUNT] = [0; PLANT_COUNT]; -#[link_section = ".rtc.data"] -static mut LOW_VOLTAGE_DETECTED: bool = false; -#[link_section = ".rtc.data"] -static mut RESTART_TO_CONF: bool = false; +#[esp_hal::ram(rtc_fast, persistent)] +static mut LOW_VOLTAGE_DETECTED: i8 = 0; +#[esp_hal::ram(rtc_fast, persistent)] +static mut RESTART_TO_CONF: i8 = 0; static CONFIG_FILE: &str = "config.json"; @@ -239,10 +239,6 @@ impl Esp<'_> { bail!("not implemented") } - pub(crate) fn time(&mut self) -> DateTime { - let wall_clock = Instant::now().as_millis() + self.wall_clock_offset; - DateTime::from_timestamp_millis(wall_clock as i64).unwrap() - } pub(crate) async fn wifi_scan(&mut self) -> anyhow::Result> { info!("start wifi scan"); @@ -277,17 +273,17 @@ impl Esp<'_> { } pub(crate) fn set_low_voltage_in_cycle(&mut self) { unsafe { - LOW_VOLTAGE_DETECTED = true; + LOW_VOLTAGE_DETECTED = 1; } } pub(crate) fn clear_low_voltage_in_cycle(&mut self) { unsafe { - LOW_VOLTAGE_DETECTED = false; + LOW_VOLTAGE_DETECTED = 1; } } pub(crate) fn low_voltage_in_cycle(&mut self) -> bool { - unsafe { LOW_VOLTAGE_DETECTED } + unsafe { LOW_VOLTAGE_DETECTED == 1 } } pub(crate) fn store_consecutive_pump_count(&mut self, plant: usize, count: u32) { unsafe { @@ -298,11 +294,15 @@ impl Esp<'_> { unsafe { CONSECUTIVE_WATERING_PLANT[plant] } } pub(crate) fn get_restart_to_conf(&mut self) -> bool { - unsafe { RESTART_TO_CONF } + unsafe { RESTART_TO_CONF == 1} } pub(crate) fn set_restart_to_conf(&mut self, to_conf: bool) { unsafe { - RESTART_TO_CONF = to_conf; + if to_conf { + RESTART_TO_CONF = 1; + } else { + RESTART_TO_CONF = 0; + } } } @@ -374,10 +374,9 @@ impl Esp<'_> { //unsafe { // //allow early wakeup by pressing the boot button if duration_in_ms == 0 { - loop { - info!("todo reboot") - } + software_reset(); } else { + loop { info!("todo deepsleep") } @@ -547,31 +546,34 @@ impl Esp<'_> { unsafe { LAST_WATERING_TIMESTAMP = [0; PLANT_COUNT]; CONSECUTIVE_WATERING_PLANT = [0; PLANT_COUNT]; - LOW_VOLTAGE_DETECTED = false; - crate::log::init().await; - RESTART_TO_CONF = to_config_mode; + LOW_VOLTAGE_DETECTED = 0; + if to_config_mode { + RESTART_TO_CONF = 1 + } else { + RESTART_TO_CONF = 0; + } }; } else { unsafe { if to_config_mode { - RESTART_TO_CONF = true; + RESTART_TO_CONF = 1; } - log( + LOG_ACCESS.lock().await.log( LogMessage::RestartToConfig, RESTART_TO_CONF as u32, 0, "", "", - ) - .await; - log( + ).await + ; + LOG_ACCESS.lock().await.log( LogMessage::LowVoltage, LOW_VOLTAGE_DETECTED as u32, 0, "", "", - ) - .await; + ).await + ; for i in 0..PLANT_COUNT { log::info!( "LAST_WATERING_TIMESTAMP[{}] = UTC {}", diff --git a/rust/src/hal/mod.rs b/rust/src/hal/mod.rs index 7059545..09a585f 100644 --- a/rust/src/hal/mod.rs +++ b/rust/src/hal/mod.rs @@ -18,13 +18,15 @@ use crate::{ battery::{BatteryInteraction, NoBatteryMonitor}, esp::Esp, }, - log::{log, LogMessage}, + log::{LogMessage}, }; use alloc::boxed::Box; use alloc::format; use alloc::sync::Arc; +use core::cell::OnceCell; use anyhow::{bail, Ok, Result}; use async_trait::async_trait; +use chrono::{DateTime, FixedOffset, Utc}; use embassy_executor::Spawner; //use battery::BQ34Z100G1; //use bq34z100::Bq34z100g1Driver; @@ -38,16 +40,22 @@ use measurements::{Current, Voltage}; use crate::hal::little_fs2storage_adapter::LittleFs2Filesystem; use embassy_sync::mutex::Mutex; +use embassy_sync::once_lock::OnceLock; use esp_alloc as _; use esp_backtrace as _; use esp_bootloader_esp_idf::ota::Slot; use esp_hal::rng::Rng; +use esp_hal::rtc_cntl::{Rtc, SocResetReason}; +use esp_hal::system::reset_reason; use esp_hal::timer::timg::TimerGroup; use esp_storage::FlashStorage; use esp_wifi::{init, EspWifiController}; use littlefs2::fs::{Allocation, Filesystem as lfs2Filesystem}; use littlefs2::object_safe::DynStorage; use log::{info, warn}; +use crate::log::{LogArray, LOG_ACCESS}; + +pub static TIME_ACCESS: OnceLock = OnceLock::new(); //Only support for 8 right now! pub const PLANT_COUNT: usize = 8; @@ -181,6 +189,13 @@ impl PlantHal { esp_alloc::heap_allocator!(size: 64 * 1024); esp_alloc::heap_allocator!(#[link_section = ".dram2_uninit"] size: 64000); + + let rtc: Rtc = Rtc::new(peripherals.LPWR); + match(TIME_ACCESS.init(rtc)){ + Result::Ok(_) => {} + Err(_) => {} + } + let systimer = SystemTimer::new(peripherals.SYSTIMER); let boot_button = Input::new( @@ -335,36 +350,78 @@ impl PlantHal { //init,reset rtc memory depending on cause let mut init_rtc_store: bool = false; let mut to_config_mode: bool = false; - let reasons = ""; - // let reasons = ResetReason::get(); - // match reasons { - // ResetReason::Software => {} - // ResetReason::ExternalPin => {} - // ResetReason::Watchdog => { - // init_rtc_store = true; - // } - // ResetReason::Sdio => init_rtc_store = true, - // ResetReason::Panic => init_rtc_store = true, - // ResetReason::InterruptWatchdog => init_rtc_store = true, - // ResetReason::PowerOn => init_rtc_store = true, - // ResetReason::Unknown => init_rtc_store = true, - // ResetReason::Brownout => init_rtc_store = true, - // ResetReason::TaskWatchdog => init_rtc_store = true, - // ResetReason::DeepSleep => {} - // ResetReason::USBPeripheral => { - // init_rtc_store = true; - // to_config_mode = true; - // } - // ResetReason::JTAG => init_rtc_store = true, - // }; - log( + let reasons = match reset_reason() { + None => { + "unknown" + } + Some(reason) => { + match reason { + SocResetReason::ChipPowerOn => { + "power on" + } + SocResetReason::CoreSw => { + "software reset" + } + SocResetReason::CoreDeepSleep => { + "deep sleep" + } + SocResetReason::CoreSDIO => { + "sdio reset" + } + SocResetReason::CoreMwdt0 => { + "Watchdog Main" + } + SocResetReason::CoreMwdt1 => { + "Watchdog 1" + } + SocResetReason::CoreRtcWdt => { + "Watchdog RTC" + } + SocResetReason::Cpu0Mwdt0 => { + "Watchdog MCpu0" + } + SocResetReason::Cpu0Sw => { + "software reset cpu0" + } + SocResetReason::Cpu0RtcWdt => { + init_rtc_store = true; + "Watchdog RTC cpu0" + } + SocResetReason::SysBrownOut => { + "sys brown out" + } + SocResetReason::SysRtcWdt => { + "Watchdog Sys rtc" + } + SocResetReason::Cpu0Mwdt1 => { + "cpu0 mwdt1" + } + SocResetReason::SysSuperWdt => { + "Watchdog Super" + } + SocResetReason::CoreEfuseCrc => { + "core efuse crc" + } + SocResetReason::CoreUsbUart => { + to_config_mode = true; + "core usb uart" + } + SocResetReason::CoreUsbJtag => { + "core usb jtag" + } + SocResetReason::Cpu0JtagCpu => { + "cpu0 jtag cpu" + } + } + } + }; + LOG_ACCESS.lock().await.log( LogMessage::ResetReason, init_rtc_store as u32, to_config_mode as u32, "", &format!("{reasons:?}"), - ) - .await; + ).await; esp.init_rtc_deepsleep_memory(init_rtc_store, to_config_mode) .await; @@ -430,32 +487,32 @@ impl PlantHal { } }; - let board_hal: Box = match config.hardware.board { - BoardVersion::INITIAL => { + let board_hal: Box = //match config.hardware.board { + //BoardVersion::INITIAL => { initial_hal::create_initial_board(free_pins, config, esp)? - } + ; + //} // BoardVersion::V3 => { // v3_hal::create_v3(free_pins, esp, config, battery_interaction, rtc_module)? // } - // BoardVersion::V4 => { - // v4_hal::create_v4(free_pins, esp, config, battery_interaction, rtc_module)? - // } - _ => { - todo!() - } - }; + //BoardVersion::V4 => { + // v4_hal::create_v4(free_pins, esp, config, battery_interaction, rtc_module)? + //} + //_ => { + // todo!() + //} + //}; HAL { board_hal } } Err(err) => { - log( + LOG_ACCESS.lock().await.log( LogMessage::ConfigModeMissingConfig, 0, 0, "", &err.to_string(), - ) - .await; + ).await; HAL { board_hal: initial_hal::create_initial_board( free_pins, @@ -469,3 +526,12 @@ impl PlantHal { Ok(Mutex::new(hal)) } } + + +pub async fn esp_time() -> DateTime { + DateTime::from_timestamp_micros(TIME_ACCESS.get().await.current_time_us() as i64).unwrap() +} + +pub async fn esp_set_time(time: DateTime) { + TIME_ACCESS.get().await.set_current_time_us(time.timestamp_micros() as u64); +} diff --git a/rust/src/log/mod.rs b/rust/src/log/mod.rs index ae3514a..2241f83 100644 --- a/rust/src/log/mod.rs +++ b/rust/src/log/mod.rs @@ -1,47 +1,122 @@ use crate::vec; use alloc::string::ToString; use alloc::vec::Vec; +use bytemuck::{AnyBitPattern, Contiguous, Pod, Zeroable}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use embassy_sync::lazy_lock::LazyLock; use embassy_sync::mutex::Mutex; use embassy_time::Instant; -use esp_println::println; +use esp_hal::Persistable; use log::info; use serde::Serialize; use strum_macros::IntoStaticStr; - -use ringbuffer::{ConstGenericRingBuffer, RingBuffer}; use unit_enum::UnitEnum; +use crate::hal::TIME_ACCESS; + +#[esp_hal::ram(rtc_fast, persistent)] +static mut LOG_ARRAY: LogArray = LogArray { + buffer: [LogEntryInner { timestamp: 0, message_id: 0, a: 0, b: 0, txt_short: [0;TXT_SHORT_LENGTH], txt_long: [0;TXT_LONG_LENGTH] }; 256], + head: 0, +}; +pub static LOG_ACCESS: Mutex = Mutex::new(unsafe { LOG_ARRAY }); const TXT_SHORT_LENGTH: usize = 8; const TXT_LONG_LENGTH: usize = 32; -const BUFFER_SIZE: usize = 220; -#[link_section = ".rtc.data"] -static mut BUFFER: ConstGenericRingBuffer = - ConstGenericRingBuffer::::new(); -#[allow(static_mut_refs)] -static BUFFER_ACCESS: LazyLock< - Mutex>, -> = LazyLock::new(|| unsafe { Mutex::new(&mut BUFFER) }); +#[derive(Debug, Clone, Copy, AnyBitPattern)] +#[repr(C)] +pub struct LogArray{ + buffer: [LogEntryInner; (u8::MAX_VALUE as usize) +1], + head: u8 +} -#[derive(Serialize, Debug, Clone)] +unsafe impl Persistable for LogArray {} +unsafe impl Zeroable for LogEntryInner {} + +unsafe impl Pod for LogEntryInner{} + +#[derive(Debug, Clone, Copy)] +struct LogEntryInner { + pub timestamp: u64, + pub message_id: u16, + pub a: u32, + pub b: u32, + pub txt_short: [u8; TXT_SHORT_LENGTH], + pub txt_long: [u8; TXT_LONG_LENGTH], +} + +#[derive(Serialize)] pub struct LogEntry { pub timestamp: u64, pub message_id: u16, pub a: u32, pub b: u32, - pub txt_short: heapless::String, - pub txt_long: heapless::String, + pub txt_short: alloc::string::String, + pub txt_long: alloc::string::String, } -pub async fn init() { - unsafe { - BUFFER = ConstGenericRingBuffer::::new(); - }; - let mut access = BUFFER_ACCESS.get().lock().await; - access.drain().for_each(|_| {}); +impl From for LogEntry { + fn from(value: LogEntryInner) -> Self { + LogEntry{ + timestamp: value.timestamp, + message_id: value.message_id, + a: value.a, + b: value.b, + txt_short: alloc::string::String::from_utf8_lossy_owned(value.txt_short.to_vec()), + txt_long: alloc::string::String::from_utf8_lossy_owned(value.txt_long.to_vec()), + } + } +} + +impl LogArray { + pub fn get(&mut self) -> Vec { + let mut rv: Vec = Vec::new(); + let mut index = self.head.wrapping_sub(1); + for _ in 0..self.buffer.len() { + let entry = self.buffer[index as usize]; + if (entry.message_id as usize) != LogMessage::Empty.ordinal() { + rv.push(entry.into()); + } + index = index.wrapping_sub(1); + } + rv + } + + pub async fn log( + &mut self, + message_key: LogMessage, + number_a: u32, + number_b: u32, + txt_short: &str, + txt_long: &str, + ) { + let mut txt_short_stack: heapless::String = heapless::String::new(); + let mut txt_long_stack: heapless::String = heapless::String::new(); + + limit_length(txt_short, &mut txt_short_stack); + limit_length(txt_long, &mut txt_long_stack); + + let time = TIME_ACCESS.get().await.current_time_us()/1000; + + let ordinal = message_key.ordinal() as u16; + let template: &str = message_key.into(); + let mut template_string = template.to_string(); + template_string = template_string.replace("${number_a}", number_a.to_string().as_str()); + template_string = template_string.replace("${number_b}", number_b.to_string().as_str()); + template_string = template_string.replace("${txt_long}", txt_long); + template_string = template_string.replace("${txt_short}", txt_short); + + info!("{}", template_string); + + let to_modify = &mut self.buffer[self.head as usize]; + to_modify.timestamp = time; + to_modify.message_id = ordinal; + to_modify.a = number_a; + to_modify.b = number_b; + to_modify.txt_short.clone_from_slice(&txt_short_stack.as_bytes()); + to_modify.txt_long.clone_from_slice(&txt_long_stack.as_bytes()); + self.head = self.head.wrapping_add(1); + } } fn limit_length(input: &str, target: &mut heapless::String) { @@ -60,60 +135,19 @@ fn limit_length(input: &str, target: &mut heapless::String Vec { - let buffer = BUFFER_ACCESS.get().lock().await; - let mut read_copy = Vec::new(); - for entry in buffer.iter() { - let copy = entry.clone(); - read_copy.push(copy); + while target.len() < LIMIT { + target.push(' ').unwrap(); } - drop(buffer); - read_copy } -pub async fn log( - message_key: LogMessage, - number_a: u32, - number_b: u32, - txt_short: &str, - txt_long: &str, -) { - let mut txt_short_stack: heapless::String = heapless::String::new(); - let mut txt_long_stack: heapless::String = heapless::String::new(); - limit_length(txt_short, &mut txt_short_stack); - limit_length(txt_long, &mut txt_long_stack); - //TODO - let time = Instant::now().as_secs(); - // let time = EspSystemTime {}.now().as_millis() as u64; - // - let ordinal = message_key.ordinal() as u16; - let template: &str = message_key.into(); - let mut template_string = template.to_string(); - template_string = template_string.replace("${number_a}", number_a.to_string().as_str()); - template_string = template_string.replace("${number_b}", number_b.to_string().as_str()); - template_string = template_string.replace("${txt_long}", txt_long); - template_string = template_string.replace("${txt_short}", txt_short); - - info!("LOG: {} : {}", time, template_string); - - let entry = LogEntry { - timestamp: time, - message_id: ordinal, - a: number_a, - b: number_b, - txt_short: txt_short_stack, - txt_long: txt_long_stack, - }; - - let mut buffer = BUFFER_ACCESS.get().lock().await; - buffer.push(entry); -} #[derive(IntoStaticStr, Serialize, PartialEq, Eq, PartialOrd, Ord, Clone, UnitEnum)] pub enum LogMessage { + #[strum( + serialize = "" + )] + Empty, #[strum( serialize = "Reset due to ${txt_long} requires rtc clear ${number_a} and force config mode ${number_b}" )] diff --git a/rust/src/main.rs b/rust/src/main.rs index 39f5fef..f1c8a21 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -1,6 +1,7 @@ #![no_std] #![no_main] #![feature(never_type)] +#![feature(string_from_utf8_lossy_owned)] #![deny( clippy::mem_forget, reason = "mem::forget is generally not safe to do with esp_hal types, especially those \ @@ -35,9 +36,11 @@ use esp_hal::rom::ets_delay_us; use esp_hal::system::software_reset; use esp_println::{logger, println}; use hal::battery::BatteryState; -use log::{log, LogMessage}; +use log::{ LogMessage}; use plant_state::PlantState; use serde::{Deserialize, Serialize}; +use crate::hal::esp_time; +use crate::log::LOG_ACCESS; #[no_mangle] extern "C" fn custom_halt() -> ! { @@ -180,6 +183,7 @@ async fn safe_main(spawner: Spawner) -> anyhow::Result<()> { let _ota_state_string = "unknown"; board.board_hal.general_fault(false).await; + let time = esp_time().await; let cur = board .board_hal .get_rtc_module() @@ -188,19 +192,19 @@ async fn safe_main(spawner: Spawner) -> anyhow::Result<()> { .or_else(|err| { info!("rtc module error: {:?}", err); board.board_hal.general_fault(true); - anyhow::Ok(board.board_hal.get_esp().time()) + anyhow::Ok(time) })?; //check if we know the time current > 2020 (plausibility checks, this code is newer than 2020) if cur.year() < 2020 { to_config = true; - log(LogMessage::YearInplausibleForceConfig, 0, 0, "", "").await; + LOG_ACCESS.lock().await.log(LogMessage::YearInplausibleForceConfig, 0, 0, "", "").await; } info!("cur is {}", cur); update_charge_indicator(&mut board).await; println!("faul led3"); if board.board_hal.get_esp().get_restart_to_conf() { - log(LogMessage::ConfigModeSoftwareOverride, 0, 0, "", "").await; + LOG_ACCESS.lock().await.log(LogMessage::ConfigModeSoftwareOverride, 0, 0, "", "").await; for _i in 0..2 { board.board_hal.general_fault(true).await; Timer::after_millis(100).await; @@ -212,7 +216,7 @@ async fn safe_main(spawner: Spawner) -> anyhow::Result<()> { board.board_hal.get_esp().set_restart_to_conf(false); } else if board.board_hal.get_esp().mode_override_pressed() { board.board_hal.general_fault(true).await; - log(LogMessage::ConfigModeButtonOverride, 0, 0, "", "").await; + LOG_ACCESS.lock().await.log(LogMessage::ConfigModeButtonOverride, 0, 0, "", "").await; for _i in 0..5 { board.board_hal.general_fault(true).await; Timer::after_millis(100).await; @@ -293,7 +297,7 @@ async fn safe_main(spawner: Spawner) -> anyhow::Result<()> { let _ = publish_mppt_state(&mut board).await; } - log( + LOG_ACCESS.lock().await.log( LogMessage::StartupInfo, matches!(network_mode, NetworkMode::WIFI { .. }) as u32, matches!( @@ -307,8 +311,8 @@ async fn safe_main(spawner: Spawner) -> anyhow::Result<()> { .to_string() .as_str(), "", - ) - .await; + ).await + ; if to_config { //check if client or ap mode and init Wi-Fi @@ -319,7 +323,7 @@ async fn safe_main(spawner: Spawner) -> anyhow::Result<()> { let board = BOARD_ACCESS.get().await.lock().await; wait_infinity(board, WaitType::ConfigButton, reboot_now.clone()).await; } else { - log(LogMessage::NormalRun, 0, 0, "", "").await; + LOG_ACCESS.lock().await.log(LogMessage::NormalRun, 0, 0, "", "").await; } let _dry_run = false; @@ -658,14 +662,14 @@ pub async fn do_secure_pump( let high_current = current_ma > plant_config.max_pump_current_ma; if high_current { if first_error { - log( + LOG_ACCESS.lock().await.log( LogMessage::PumpOverCurrent, plant_id as u32 + 1, current_ma as u32, plant_config.max_pump_current_ma.to_string().as_str(), step.to_string().as_str(), - ) - .await; + ).await + ; board.board_hal.general_fault(true).await; board.board_hal.fault(plant_id, true).await?; if !plant_config.ignore_current_error { @@ -678,14 +682,14 @@ pub async fn do_secure_pump( let low_current = current_ma < plant_config.min_pump_current_ma; if low_current { if first_error { - log( + LOG_ACCESS.lock().await.log( LogMessage::PumpOpenLoopCurrent, plant_id as u32 + 1, current_ma as u32, plant_config.min_pump_current_ma.to_string().as_str(), step.to_string().as_str(), - ) - .await; + ).await + ; board.board_hal.general_fault(true).await; board.board_hal.fault(plant_id, true).await?; if !plant_config.ignore_current_error { @@ -699,14 +703,14 @@ pub async fn do_secure_pump( Err(err) => { if !plant_config.ignore_current_error { info!("Error getting pump current: {}", err); - log( + LOG_ACCESS.lock().await.log( LogMessage::PumpMissingSensorCurrent, plant_id as u32, 0, "", "", - ) - .await; + ).await + ; error = true; break; } else { @@ -1058,7 +1062,7 @@ async fn wait_infinity( .lock() .await .board_hal - .deep_sleep(1); + .deep_sleep(0).await; } } } diff --git a/rust/src/webserver/mod.rs b/rust/src/webserver/mod.rs index 4b501e9..35017c5 100644 --- a/rust/src/webserver/mod.rs +++ b/rust/src/webserver/mod.rs @@ -3,29 +3,30 @@ use crate::config::PlantControllerConfig; use crate::{get_version, log::LogMessage, BOARD_ACCESS}; use alloc::borrow::ToOwned; -use alloc::fmt::format; use alloc::format; use alloc::string::{String, ToString}; use alloc::sync::Arc; use alloc::vec::Vec; -use anyhow::bail; +use anyhow::{bail}; use core::fmt::{Debug, Display}; use core::net::{IpAddr, Ipv4Addr, SocketAddr}; use core::result::Result::Ok; use core::str::from_utf8; use core::sync::atomic::{AtomicBool, Ordering}; +use chrono::DateTime; use edge_http::io::server::{Connection, Handler, Server}; use edge_http::io::Error; use edge_http::Method; -use edge_nal::{TcpBind, TcpSplit}; +use edge_nal::{TcpBind}; use edge_nal_embassy::{Tcp, TcpBuffers}; use embassy_net::Stack; use embassy_time::Instant; use embedded_io_async::{Read, Write}; use esp_println::println; -use littlefs2_core::Path; use log::info; use serde::{Deserialize, Serialize}; +use crate::hal::{esp_set_time, esp_time}; +use crate::log::{LOG_ACCESS}; #[derive(Serialize, Debug)] struct SSIDList { @@ -72,25 +73,6 @@ pub struct NightLampCommand { active: bool, } // -// fn write_time( -// request: &mut Request<&mut EspHttpConnection>, -// ) -> Result, anyhow::Error> { -// let actual_data = read_up_to_bytes_from_request(request, None)?; -// let time: SetTime = serde_json::from_slice(&actual_data)?; -// let parsed = DateTime::parse_from_rfc3339(time.time).map_err(|err| anyhow::anyhow!(err))?; -// let mut board = BOARD_ACCESS.lock().expect("board access"); -// -// let now = timeval { -// tv_sec: parsed.to_utc().timestamp(), -// tv_usec: 0, -// }; -// unsafe { settimeofday(&now, core::ptr::null_mut()) }; -// board -// .board_hal -// .get_rtc_module() -// .set_rtc_time(&parsed.to_utc())?; -// anyhow::Ok(None) -// } // // @@ -430,12 +412,10 @@ impl Handler for HttpHandler { conn.write_all(include_bytes!("bundle.js")).await?; Some(200) } - "/reboot" => { - let mut board = BOARD_ACCESS.get().await.lock().await; - board.board_hal.get_esp().set_restart_to_conf(true); - self.reboot_now.store(true, Ordering::Relaxed); + "/log" => { + let buf = get_log(conn).await; Some(200) - } + }, &_ => { let json = match path { "/version" => Some(get_version_web(conn).await), @@ -445,7 +425,6 @@ impl Handler for HttpHandler { "/get_config" => Some(get_config(conn).await), "/files" => Some(list_files(conn).await), "/log_localization" => Some(get_log_localization_config(conn).await), - "/log" => Some(get_log(conn).await), "/wifiscan" => Some(wifi_scan(conn).await), _ => None, }; @@ -459,6 +438,13 @@ impl Handler for HttpHandler { let json = match path { "/wifiscan" => Some(wifi_scan(conn).await), "/set_config" => Some(set_config(conn).await), + "/time" => Some(write_time(conn).await), + "/reboot" => { + let mut board = BOARD_ACCESS.get().await.lock().await; + board.board_hal.get_esp().set_restart_to_conf(true); + self.reboot_now.store(true, Ordering::Relaxed); + Some(Ok(None)) + } _ => None, }; match json { @@ -568,6 +554,20 @@ impl Handler for HttpHandler { // }) // .unwrap(); +async fn write_time( + request: &mut Connection<'_, T, N>, +) -> Result, anyhow::Error> +where + T: Read + Write +{ + let actual_data = read_up_to_bytes_from_request(request, None).await?; + let time: SetTime = serde_json::from_slice(&actual_data)?; + let parsed = DateTime::parse_from_rfc3339(time.time).unwrap(); + esp_set_time(parsed).await; + anyhow::Ok(None) +} + + async fn set_config( request: &mut Connection<'_, T, N>, ) -> Result, anyhow::Error> @@ -633,10 +633,30 @@ async fn wifi_scan( } async fn get_log( - _request: &mut Connection<'_, T, N>, -) -> Result, anyhow::Error> { - let output = crate::log::get_log().await; - anyhow::Ok(Some(serde_json::to_string(&output)?)) + conn: &mut Connection<'_, T, N>, +) -> anyhow::Result<()> +where + T: Read + Write,{ + let log = LOG_ACCESS.lock().await.get(); + conn.initiate_response( + 200, + Some("OK"), + &[("Content-Type", "text/javascript")], + ) + .await + .unwrap(); + conn.write_all("[".as_bytes()).await.unwrap(); + let mut append = false; + for entry in log { + if append { + conn.write_all(",".as_bytes()).await.unwrap(); + } + append = true; + let json = serde_json::to_string(&entry)?; + conn.write_all(json.as_bytes()).await.unwrap(); + } + conn.write_all("]".as_bytes()).await.unwrap(); + Ok(()) } async fn get_log_localization_config( @@ -698,16 +718,17 @@ async fn get_time( ) -> Result, anyhow::Error> { let mut board = BOARD_ACCESS.get().await.lock().await; //TODO do not fail if rtc module is missing - let native = board.board_hal.get_esp().time().to_rfc3339(); - let rtc = board - .board_hal - .get_rtc_module() - .get_rtc_time() - .await? - .to_rfc3339(); + let native = esp_time().await.to_rfc3339(); + let rtc = "todo"; + // board + // .board_hal + // .get_rtc_module() + // .get_rtc_time() + // .await? + // .to_rfc3339(); let data = LoadData { - rtc: rtc.as_str(), + rtc, native: native.as_str(), }; let json = serde_json::to_string(&data)?;