startup and ota state detection working, now wifi_ap next
This commit is contained in:
@@ -1,23 +1,20 @@
|
||||
use alloc::string::String;
|
||||
use crate::hal::Box;
|
||||
use anyhow::anyhow;
|
||||
use alloc::string::String;
|
||||
use async_trait::async_trait;
|
||||
use bq34z100::{Bq34Z100Error, Bq34z100g1Driver};
|
||||
use measurements::Temperature;
|
||||
use serde::Serialize;
|
||||
|
||||
#[async_trait]
|
||||
pub trait BatteryInteraction {
|
||||
async fn state_charge_percent(& mut self) -> Result<f32, BatteryError>;
|
||||
async fn remaining_milli_ampere_hour(& mut self) -> Result<u16, BatteryError>;
|
||||
async fn max_milli_ampere_hour(& mut self) -> Result<u16, BatteryError>;
|
||||
async fn design_milli_ampere_hour(& mut self) -> Result<u16, BatteryError>;
|
||||
async fn voltage_milli_volt(& mut self) -> Result<u16, BatteryError>;
|
||||
async fn average_current_milli_ampere(& mut self) -> Result<i16, BatteryError>;
|
||||
async fn cycle_count(& mut self) -> Result<u16, BatteryError>;
|
||||
async fn state_health_percent(& mut self) -> Result<u16, BatteryError>;
|
||||
async fn bat_temperature(& mut self) -> Result<u16, BatteryError>;
|
||||
async fn get_battery_state(& mut self) -> Result<BatteryState, BatteryError>;
|
||||
async fn state_charge_percent(&mut self) -> Result<f32, BatteryError>;
|
||||
async fn remaining_milli_ampere_hour(&mut self) -> Result<u16, BatteryError>;
|
||||
async fn max_milli_ampere_hour(&mut self) -> Result<u16, BatteryError>;
|
||||
async fn design_milli_ampere_hour(&mut self) -> Result<u16, BatteryError>;
|
||||
async fn voltage_milli_volt(&mut self) -> Result<u16, BatteryError>;
|
||||
async fn average_current_milli_ampere(&mut self) -> Result<i16, BatteryError>;
|
||||
async fn cycle_count(&mut self) -> Result<u16, BatteryError>;
|
||||
async fn state_health_percent(&mut self) -> Result<u16, BatteryError>;
|
||||
async fn bat_temperature(&mut self) -> Result<u16, BatteryError>;
|
||||
async fn get_battery_state(&mut self) -> Result<BatteryState, BatteryError>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
@@ -56,31 +53,31 @@ pub enum BatteryState {
|
||||
pub struct NoBatteryMonitor {}
|
||||
#[async_trait]
|
||||
impl BatteryInteraction for NoBatteryMonitor {
|
||||
async fn state_charge_percent(& mut self) -> Result<f32, BatteryError> {
|
||||
async fn state_charge_percent(&mut self) -> Result<f32, BatteryError> {
|
||||
Err(BatteryError::NoBatteryMonitor)
|
||||
}
|
||||
|
||||
async fn remaining_milli_ampere_hour(& mut self) -> Result<u16, BatteryError> {
|
||||
async fn remaining_milli_ampere_hour(&mut self) -> Result<u16, BatteryError> {
|
||||
Err(BatteryError::NoBatteryMonitor)
|
||||
}
|
||||
|
||||
async fn max_milli_ampere_hour(& mut self) -> Result<u16, BatteryError> {
|
||||
async fn max_milli_ampere_hour(&mut self) -> Result<u16, BatteryError> {
|
||||
Err(BatteryError::NoBatteryMonitor)
|
||||
}
|
||||
|
||||
async fn design_milli_ampere_hour(& mut self) -> Result<u16, BatteryError> {
|
||||
async fn design_milli_ampere_hour(&mut self) -> Result<u16, BatteryError> {
|
||||
Err(BatteryError::NoBatteryMonitor)
|
||||
}
|
||||
|
||||
async fn voltage_milli_volt(& mut self) -> Result<u16, BatteryError> {
|
||||
async fn voltage_milli_volt(&mut self) -> Result<u16, BatteryError> {
|
||||
Err(BatteryError::NoBatteryMonitor)
|
||||
}
|
||||
|
||||
async fn average_current_milli_ampere(& mut self) -> Result<i16, BatteryError> {
|
||||
async fn average_current_milli_ampere(&mut self) -> Result<i16, BatteryError> {
|
||||
Err(BatteryError::NoBatteryMonitor)
|
||||
}
|
||||
|
||||
async fn cycle_count(& mut self) -> Result<u16, BatteryError> {
|
||||
async fn cycle_count(&mut self) -> Result<u16, BatteryError> {
|
||||
Err(BatteryError::NoBatteryMonitor)
|
||||
}
|
||||
|
||||
@@ -92,7 +89,7 @@ impl BatteryInteraction for NoBatteryMonitor {
|
||||
Err(BatteryError::NoBatteryMonitor)
|
||||
}
|
||||
|
||||
async fn get_battery_state(& mut self) -> Result<BatteryState, BatteryError> {
|
||||
async fn get_battery_state(&mut self) -> Result<BatteryState, BatteryError> {
|
||||
Ok(BatteryState::Unknown)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,14 @@ use anyhow::{anyhow, bail, Context};
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::Serialize;
|
||||
|
||||
use alloc::{
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
use alloc::{string::String, vec::Vec};
|
||||
use core::marker::PhantomData;
|
||||
use core::net::IpAddr;
|
||||
use core::str::FromStr;
|
||||
use embassy_time::{Instant, Timer};
|
||||
use embassy_time::Instant;
|
||||
use esp_bootloader_esp_idf::ota::OtaImageState;
|
||||
use esp_hal::gpio::Input;
|
||||
use esp_storage::FlashStorage;
|
||||
|
||||
#[link_section = ".rtc.data"]
|
||||
static mut LAST_WATERING_TIMESTAMP: [i64; PLANT_COUNT] = [0; PLANT_COUNT];
|
||||
@@ -51,11 +51,16 @@ pub struct MqttClient<'a> {
|
||||
base_topic: heapless::String<64>,
|
||||
}
|
||||
pub struct Esp<'a> {
|
||||
pub boot_button: Input<'a>,
|
||||
pub(crate) mqtt_client: Option<MqttClient<'a>>,
|
||||
pub(crate) dummy: PhantomData<&'a ()>,
|
||||
pub(crate) wall_clock_offset: u64
|
||||
pub(crate) wall_clock_offset: u64,
|
||||
//pub(crate) wifi_driver: EspWifi<'a>,
|
||||
//pub(crate) boot_button: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, esp_idf_hal::gpio::Input>,
|
||||
pub storage: FlashStorage,
|
||||
pub slot: usize,
|
||||
pub next_slot: usize,
|
||||
pub ota_state: OtaImageState,
|
||||
}
|
||||
|
||||
pub struct IpInfo {
|
||||
@@ -72,10 +77,9 @@ impl Esp<'_> {
|
||||
const BASE_PATH: &'static str = "/spiffs";
|
||||
|
||||
pub(crate) fn mode_override_pressed(&mut self) -> bool {
|
||||
todo!();
|
||||
//self.boot_button.get_level() == Level::Low
|
||||
self.boot_button.is_low()
|
||||
}
|
||||
pub(crate) async fn sntp(&mut self, max_wait_ms: u32) -> anyhow::Result<DateTime<Utc>> {
|
||||
pub(crate) async fn sntp(&mut self, _max_wait_ms: u32) -> anyhow::Result<DateTime<Utc>> {
|
||||
//let sntp = sntp::EspSntp::new_default()?;
|
||||
//let mut counter = 0;
|
||||
//while sntp.get_sync_status() != SyncStatus::Completed {
|
||||
@@ -147,10 +151,11 @@ impl Esp<'_> {
|
||||
}
|
||||
|
||||
pub(crate) async fn wifi_ap(&mut self) -> anyhow::Result<()> {
|
||||
let ssid = match self.load_config() {
|
||||
let _ssid = match self.load_config() {
|
||||
Ok(config) => config.network.ap_ssid.clone(),
|
||||
Err(_) => heapless::String::from_str("PlantCtrl Emergency Mode").unwrap(),
|
||||
};
|
||||
|
||||
todo!("todo");
|
||||
//
|
||||
// let apconfig = AccessPointConfiguration {
|
||||
@@ -165,15 +170,13 @@ impl Esp<'_> {
|
||||
// anyhow::Ok(())
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub(crate) async fn wifi(&mut self, network_config: &NetworkConfig) -> anyhow::Result<IpInfo> {
|
||||
let ssid = network_config
|
||||
let _ssid = network_config
|
||||
.ssid
|
||||
.clone()
|
||||
.ok_or(anyhow!("No ssid configured"))?;
|
||||
let password = network_config.password.clone();
|
||||
let max_wait = network_config.max_wait;
|
||||
let _password = network_config.password.clone();
|
||||
let _max_wait = network_config.max_wait;
|
||||
bail!("todo")
|
||||
// match password {
|
||||
// Some(pw) => {
|
||||
@@ -237,7 +240,7 @@ impl Esp<'_> {
|
||||
}
|
||||
pub(crate) async fn save_config(
|
||||
&mut self,
|
||||
config: &PlantControllerConfig,
|
||||
_config: &PlantControllerConfig,
|
||||
) -> anyhow::Result<()> {
|
||||
bail!("todo");
|
||||
// let mut cfg = File::create(Self::CONFIG_FILE)?;
|
||||
@@ -247,9 +250,9 @@ impl Esp<'_> {
|
||||
}
|
||||
pub(crate) fn mount_file_system(&mut self) -> anyhow::Result<()> {
|
||||
bail!("fail");
|
||||
log(LogMessage::MountingFilesystem, 0, 0, "", "");
|
||||
let base_path = String::try_from("/spiffs")?;
|
||||
let storage = String::try_from(Self::SPIFFS_PARTITION_NAME)?;
|
||||
// log(LogMessage::MountingFilesystem, 0, 0, "", "");
|
||||
// let base_path = String::try_from("/spiffs")?;
|
||||
// let storage = String::try_from(Self::SPIFFS_PARTITION_NAME)?;
|
||||
//let conf = todo!();
|
||||
|
||||
//let conf = esp_idf_sys::esp_vfs_spiffs_conf_t {
|
||||
@@ -272,7 +275,7 @@ impl Esp<'_> {
|
||||
// &free_space.used_size.to_string(),
|
||||
// "",
|
||||
// );
|
||||
anyhow::Ok(())
|
||||
// anyhow::Ok(())
|
||||
}
|
||||
async fn file_system_size(&mut self) -> anyhow::Result<FileSystemSizeInfo> {
|
||||
bail!("fail");
|
||||
@@ -348,7 +351,7 @@ impl Esp<'_> {
|
||||
// iter_error,
|
||||
// }
|
||||
}
|
||||
pub(crate) async fn delete_file(&self, filename: &str) -> anyhow::Result<()> {
|
||||
pub(crate) async fn delete_file(&self, _filename: &str) -> anyhow::Result<()> {
|
||||
bail!("todo");
|
||||
// let filepath = Path::new(Self::BASE_PATH).join(Path::new(filename));
|
||||
// match fs::remove_file(filepath) {
|
||||
@@ -425,7 +428,7 @@ impl Esp<'_> {
|
||||
if base_topic.is_empty() {
|
||||
bail!("Mqtt base_topic was empty")
|
||||
}
|
||||
let base_topic_copy = base_topic.clone();
|
||||
let _base_topic_copy = base_topic.clone();
|
||||
let mqtt_url = network_config
|
||||
.mqtt_url
|
||||
.as_ref()
|
||||
@@ -583,8 +586,8 @@ impl Esp<'_> {
|
||||
}
|
||||
pub(crate) async fn mqtt_publish(
|
||||
&mut self,
|
||||
subtopic: &str,
|
||||
message: &[u8],
|
||||
_subtopic: &str,
|
||||
_message: &[u8],
|
||||
) -> anyhow::Result<()> {
|
||||
bail!("todo");
|
||||
//
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use alloc::vec::Vec;
|
||||
use crate::hal::esp::Esp;
|
||||
use crate::hal::rtc::{BackupHeader, RTCModuleInteraction};
|
||||
use alloc::vec::Vec;
|
||||
//use crate::hal::water::TankSensor;
|
||||
use crate::alloc::boxed::Box;
|
||||
use crate::hal::{deep_sleep, BoardInteraction, FreePeripherals, Sensor};
|
||||
use crate::{
|
||||
config::PlantControllerConfig,
|
||||
@@ -10,9 +11,7 @@ use crate::{
|
||||
use anyhow::{bail, Result};
|
||||
use async_trait::async_trait;
|
||||
use chrono::{DateTime, Utc};
|
||||
use embedded_hal::digital::OutputPin;
|
||||
use measurements::{Current, Voltage};
|
||||
use crate::alloc::boxed::Box;
|
||||
|
||||
pub struct Initial<'a> {
|
||||
//pub(crate) general_fault: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>,
|
||||
@@ -49,7 +48,7 @@ impl RTCModuleInteraction for NoRTC {
|
||||
|
||||
pub(crate) fn create_initial_board(
|
||||
//free_pins: FreePeripherals,
|
||||
fs_mount_error: bool,
|
||||
_fs_mount_error: bool,
|
||||
config: PlantControllerConfig,
|
||||
esp: Esp<'static>,
|
||||
) -> Result<Box<dyn BoardInteraction<'static> + Send>> {
|
||||
@@ -123,7 +122,7 @@ impl<'a> BoardInteraction<'a> for Initial<'a> {
|
||||
bail!("Please configure board revision")
|
||||
}
|
||||
|
||||
async fn general_fault(&mut self, enable: bool) {
|
||||
async fn general_fault(&mut self, _enable: bool) {
|
||||
//let _ = self.general_fault.set_state(enable.into());
|
||||
}
|
||||
|
||||
@@ -134,7 +133,7 @@ impl<'a> BoardInteraction<'a> for Initial<'a> {
|
||||
async fn set_config(&mut self, config: PlantControllerConfig) -> anyhow::Result<()> {
|
||||
self.config = config;
|
||||
//TODO
|
||||
// self.esp.save_config(&self.config)?;
|
||||
// self.esp.save_config(&self.config)?;
|
||||
anyhow::Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ mod rtc;
|
||||
//mod water;
|
||||
|
||||
use crate::alloc::string::ToString;
|
||||
use crate::hal::rtc::{RTCModuleInteraction};
|
||||
use crate::hal::rtc::RTCModuleInteraction;
|
||||
//use crate::hal::water::TankSensor;
|
||||
use crate::{
|
||||
config::{BatteryBoardVersion, BoardVersion, PlantControllerConfig},
|
||||
@@ -17,20 +17,24 @@ use crate::{
|
||||
};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::format;
|
||||
use core::marker::PhantomData;
|
||||
use anyhow::{Ok, Result};
|
||||
use async_trait::async_trait;
|
||||
use core::marker::PhantomData;
|
||||
use embassy_executor::Spawner;
|
||||
//use battery::BQ34Z100G1;
|
||||
use bq34z100::Bq34z100g1Driver;
|
||||
use ds323x::{DateTimeAccess, Ds323x};
|
||||
use eeprom24x::{Eeprom24x, SlaveAddr, Storage};
|
||||
use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex};
|
||||
//use bq34z100::Bq34z100g1Driver;
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::mutex::Mutex;
|
||||
use embassy_sync::lazy_lock::LazyLock;
|
||||
use esp_bootloader_esp_idf::partitions::DataPartitionSubType;
|
||||
use esp_hal::clock::CpuClock;
|
||||
use esp_hal::gpio::{Input, InputConfig, Pull};
|
||||
use esp_hal::timer::systimer::SystemTimer;
|
||||
use esp_println::println;
|
||||
use measurements::{Current, Voltage};
|
||||
|
||||
use esp_alloc as _;
|
||||
use esp_backtrace as _;
|
||||
|
||||
//Only support for 8 right now!
|
||||
pub const PLANT_COUNT: usize = 8;
|
||||
|
||||
@@ -38,24 +42,34 @@ const TANK_MULTI_SAMPLE: usize = 11;
|
||||
|
||||
//pub static I2C_DRIVER: LazyLock<Mutex<CriticalSectionRawMutex,I2cDriver<'static>>> = LazyLock::new(PlantHal::create_i2c);
|
||||
|
||||
fn deep_sleep(duration_in_ms: u64) -> ! {
|
||||
// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html
|
||||
macro_rules! mk_static {
|
||||
($t:ty,$val:expr) => {{
|
||||
static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new();
|
||||
#[deny(unused_attributes)]
|
||||
let x = STATIC_CELL.uninit().write(($val));
|
||||
x
|
||||
}};
|
||||
}
|
||||
|
||||
fn deep_sleep(_duration_in_ms: u64) -> ! {
|
||||
//unsafe {
|
||||
// //if we don't do this here, we might just revert newly flashed firmware
|
||||
// mark_app_valid();
|
||||
// //allow early wakeup by pressing the boot button
|
||||
// if duration_in_ms == 0 {
|
||||
// esp_restart();
|
||||
// } else {
|
||||
// //configure gpio 1 to wakeup on low, reused boot button for this
|
||||
// esp_sleep_enable_ext1_wakeup(
|
||||
// 0b10u64,
|
||||
// esp_sleep_ext1_wakeup_mode_t_ESP_EXT1_WAKEUP_ANY_LOW,
|
||||
// );
|
||||
// esp_deep_sleep(duration_in_ms);
|
||||
// }
|
||||
loop {
|
||||
todo!()
|
||||
}
|
||||
// //if we don't do this here, we might just revert newly flashed firmware
|
||||
// mark_app_valid();
|
||||
// //allow early wakeup by pressing the boot button
|
||||
// if duration_in_ms == 0 {
|
||||
// esp_restart();
|
||||
// } else {
|
||||
// //configure gpio 1 to wakeup on low, reused boot button for this
|
||||
// esp_sleep_enable_ext1_wakeup(
|
||||
// 0b10u64,
|
||||
// esp_sleep_ext1_wakeup_mode_t_ESP_EXT1_WAKEUP_ANY_LOW,
|
||||
// );
|
||||
// esp_deep_sleep(duration_in_ms);
|
||||
// }
|
||||
loop {
|
||||
todo!()
|
||||
}
|
||||
//};
|
||||
}
|
||||
|
||||
@@ -95,7 +109,6 @@ pub trait BoardInteraction<'a> {
|
||||
async fn get_mptt_current(&mut self) -> anyhow::Result<Current>;
|
||||
}
|
||||
|
||||
|
||||
impl dyn BoardInteraction<'_> {
|
||||
//the counter is just some arbitrary number that increases whenever some progress was made, try to keep the updates < 10 per second for ux reasons
|
||||
async fn _progress(&mut self, counter: u32) {
|
||||
@@ -163,17 +176,19 @@ impl PlantHal {
|
||||
// Mutex::new(I2cDriver::new(i2c, sda, scl, &config).unwrap())
|
||||
// }
|
||||
|
||||
pub fn create() -> Result<Mutex<CriticalSectionRawMutex, HAL<'static>>> {
|
||||
pub fn create(spawner: Spawner) -> Result<Mutex<CriticalSectionRawMutex, HAL<'static>>> {
|
||||
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
|
||||
let peripherals = esp_hal::init(config);
|
||||
|
||||
esp_alloc::heap_allocator!(size: 64 * 1024);
|
||||
let timer0 = SystemTimer::new(peripherals.SYSTIMER);
|
||||
esp_hal_embassy::init(timer0.alarm0);
|
||||
let systimer = SystemTimer::new(peripherals.SYSTIMER);
|
||||
esp_hal_embassy::init(systimer.alarm0);
|
||||
|
||||
let boot_button = Input::new(
|
||||
peripherals.GPIO9,
|
||||
InputConfig::default().with_pull(Pull::None),
|
||||
);
|
||||
|
||||
// let mut boot_button = PinDriver::input(peripherals.pins.gpio9.downgrade())?;
|
||||
// boot_button.set_pull(Pull::Floating)?;
|
||||
//
|
||||
// let free_pins = FreePeripherals {
|
||||
// can: peripherals.can,
|
||||
@@ -210,13 +225,46 @@ impl PlantHal {
|
||||
// gpio30: peripherals.pins.gpio30,
|
||||
// };
|
||||
//
|
||||
|
||||
let mut storage = esp_storage::FlashStorage::new();
|
||||
let mut buffer = [0u8; esp_bootloader_esp_idf::partitions::PARTITION_TABLE_MAX_LEN];
|
||||
let pt =
|
||||
esp_bootloader_esp_idf::partitions::read_partition_table(&mut storage, &mut buffer)?;
|
||||
|
||||
// List all partitions - this is just FYI
|
||||
for i in 0..pt.len() {
|
||||
println!("{:?}", pt.get_partition(i));
|
||||
}
|
||||
|
||||
// Find the OTA-data partition and show the currently active partition
|
||||
let ota_part = pt
|
||||
.find_partition(esp_bootloader_esp_idf::partitions::PartitionType::Data(
|
||||
DataPartitionSubType::Ota,
|
||||
))?
|
||||
.unwrap();
|
||||
let mut ota_part = ota_part.as_embedded_storage(&mut storage);
|
||||
println!("Found ota data");
|
||||
|
||||
let mut ota = esp_bootloader_esp_idf::ota::Ota::new(&mut ota_part)?;
|
||||
let current = ota.current_slot()?;
|
||||
println!(
|
||||
"current image state {:?} (only relevant if the bootloader was built with auto-rollback support)",
|
||||
ota.current_ota_state()
|
||||
);
|
||||
println!("current {:?} - next {:?}", current, current.next());
|
||||
let ota_state = ota.current_ota_state()?;
|
||||
|
||||
let mut esp = Esp {
|
||||
mqtt_client: None,
|
||||
boot_button,
|
||||
mqtt_client: None,
|
||||
storage,
|
||||
slot: current.number(),
|
||||
next_slot: current.next().number(),
|
||||
ota_state,
|
||||
dummy: PhantomData::default(),
|
||||
wall_clock_offset : 0
|
||||
// wifi_driver,
|
||||
// boot_button
|
||||
};
|
||||
wall_clock_offset: 0, // wifi_driver,
|
||||
// boot_button
|
||||
};
|
||||
|
||||
//init,reset rtc memory depending on cause
|
||||
let mut init_rtc_store: bool = false;
|
||||
|
||||
Reference in New Issue
Block a user