get log to work, make time accessible
This commit is contained in:
parent
584d6df2d0
commit
c94f5bdb45
@ -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]
|
||||
|
@ -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<Utc> {
|
||||
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<Vec<AccessPointInfo>> {
|
||||
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 {}",
|
||||
|
@ -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<Rtc> = 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<dyn BoardInteraction + Send> = match config.hardware.board {
|
||||
BoardVersion::INITIAL => {
|
||||
let board_hal: Box<dyn BoardInteraction + Send> = //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!()
|
||||
}
|
||||
};
|
||||
//_ => {
|
||||
// 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<Utc> {
|
||||
DateTime::from_timestamp_micros(TIME_ACCESS.get().await.current_time_us() as i64).unwrap()
|
||||
}
|
||||
|
||||
pub async fn esp_set_time(time: DateTime<FixedOffset>) {
|
||||
TIME_ACCESS.get().await.set_current_time_us(time.timestamp_micros() as u64);
|
||||
}
|
||||
|
@ -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<CriticalSectionRawMutex, LogArray> = 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<LogEntry, BUFFER_SIZE> =
|
||||
ConstGenericRingBuffer::<LogEntry, BUFFER_SIZE>::new();
|
||||
#[allow(static_mut_refs)]
|
||||
static BUFFER_ACCESS: LazyLock<
|
||||
Mutex<CriticalSectionRawMutex, &mut ConstGenericRingBuffer<LogEntry, BUFFER_SIZE>>,
|
||||
> = 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<TXT_SHORT_LENGTH>,
|
||||
pub txt_long: heapless::String<TXT_LONG_LENGTH>,
|
||||
pub txt_short: alloc::string::String,
|
||||
pub txt_long: alloc::string::String,
|
||||
}
|
||||
|
||||
pub async fn init() {
|
||||
unsafe {
|
||||
BUFFER = ConstGenericRingBuffer::<LogEntry, BUFFER_SIZE>::new();
|
||||
};
|
||||
let mut access = BUFFER_ACCESS.get().lock().await;
|
||||
access.drain().for_each(|_| {});
|
||||
impl From<LogEntryInner> 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<LogEntry> {
|
||||
let mut rv: Vec<LogEntry> = 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<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 = 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<const LIMIT: usize>(input: &str, target: &mut heapless::String<LIMIT>) {
|
||||
@ -60,60 +135,19 @@ fn limit_length<const LIMIT: usize>(input: &str, target: &mut heapless::String<L
|
||||
}
|
||||
}
|
||||
}
|
||||
while target.len() < LIMIT {
|
||||
target.push(' ').unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_log() -> Vec<LogEntry> {
|
||||
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);
|
||||
}
|
||||
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<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);
|
||||
|
||||
//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}"
|
||||
)]
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<Option<std::string::String>, 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<T, const N: usize>(
|
||||
request: &mut Connection<'_, T, N>,
|
||||
) -> Result<Option<String>, 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<T, const N: usize>(
|
||||
request: &mut Connection<'_, T, N>,
|
||||
) -> Result<Option<String>, anyhow::Error>
|
||||
@ -633,10 +633,30 @@ async fn wifi_scan<T, const N: usize>(
|
||||
}
|
||||
|
||||
async fn get_log<T, const N: usize>(
|
||||
_request: &mut Connection<'_, T, N>,
|
||||
) -> Result<Option<String>, 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<T, const N: usize>(
|
||||
@ -698,16 +718,17 @@ async fn get_time<T, const N: usize>(
|
||||
) -> Result<Option<String>, 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)?;
|
||||
|
Loading…
x
Reference in New Issue
Block a user