started cleanup and moving from std to no_std
This commit is contained in:
196
rust/src/main.rs
196
rust/src/main.rs
@@ -1,38 +1,41 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![deny(
|
||||
clippy::mem_forget,
|
||||
reason = "mem::forget is generally not safe to do with esp_hal types, especially those \
|
||||
holding buffers for the duration of a data transfer."
|
||||
)]
|
||||
use crate::config::PlantConfig;
|
||||
use crate::{
|
||||
config::BoardVersion::INITIAL,
|
||||
hal::{PlantHal, HAL, PLANT_COUNT},
|
||||
webserver::httpd,
|
||||
//webserver::httpd,
|
||||
};
|
||||
use alloc::borrow::ToOwned;
|
||||
use alloc::fmt::format;
|
||||
use alloc::string::{String, ToString};
|
||||
use anyhow::{bail, Context};
|
||||
use chrono::{DateTime, Datelike, Timelike, Utc};
|
||||
use chrono_tz::Tz::{self, UTC};
|
||||
use esp_idf_hal::delay::Delay;
|
||||
use esp_idf_sys::{
|
||||
esp_ota_get_app_partition_count, esp_ota_get_running_partition, esp_ota_get_state_partition,
|
||||
esp_ota_img_states_t, esp_ota_img_states_t_ESP_OTA_IMG_ABORTED,
|
||||
esp_ota_img_states_t_ESP_OTA_IMG_INVALID, esp_ota_img_states_t_ESP_OTA_IMG_NEW,
|
||||
esp_ota_img_states_t_ESP_OTA_IMG_PENDING_VERIFY, esp_ota_img_states_t_ESP_OTA_IMG_UNDEFINED,
|
||||
esp_ota_img_states_t_ESP_OTA_IMG_VALID,
|
||||
};
|
||||
use esp_ota::{mark_app_valid, rollback_and_reboot};
|
||||
use embassy_executor::Spawner;
|
||||
use hal::battery::BatteryState;
|
||||
use log::{log, LogMessage};
|
||||
use once_cell::sync::Lazy;
|
||||
use plant_state::PlantState;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::{atomic::AtomicBool, Arc, Mutex, MutexGuard};
|
||||
use embassy_sync::{Mutex, LazyLock};
|
||||
use portable_atomic::AtomicBool;
|
||||
use tank::*;
|
||||
|
||||
mod config;
|
||||
mod hal;
|
||||
mod log;
|
||||
mod plant_state;
|
||||
mod tank;
|
||||
mod webserver;
|
||||
|
||||
pub static BOARD_ACCESS: Lazy<Mutex<HAL>> = Lazy::new(|| PlantHal::create().unwrap());
|
||||
pub static STAY_ALIVE: Lazy<AtomicBool> = Lazy::new(|| AtomicBool::new(false));
|
||||
extern crate alloc;
|
||||
//mod webserver;
|
||||
|
||||
pub static BOARD_ACCESS: LazyLock<Mutex<HAL>> = LazyLock::new(|| PlantHal::create().unwrap());
|
||||
pub static STAY_ALIVE: LazyLock<AtomicBool> = LazyLock::new(|| AtomicBool::new(false));
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
enum WaitType {
|
||||
@@ -110,55 +113,45 @@ enum NetworkMode {
|
||||
}
|
||||
|
||||
fn safe_main() -> anyhow::Result<()> {
|
||||
// It is necessary to call this function once. Otherwise, some patches to the runtime
|
||||
// implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
|
||||
esp_idf_svc::sys::link_patches();
|
||||
|
||||
// Bind the log crate to the ESP Logging facilities
|
||||
esp_idf_svc::log::EspLogger::initialize_default();
|
||||
|
||||
if esp_idf_sys::CONFIG_MAIN_TASK_STACK_SIZE < 25000 {
|
||||
bail!(
|
||||
"stack too small: {} bail!",
|
||||
esp_idf_sys::CONFIG_MAIN_TASK_STACK_SIZE
|
||||
)
|
||||
}
|
||||
println!("Startup Rust");
|
||||
log::info!("Startup Rust");
|
||||
|
||||
let mut to_config = false;
|
||||
|
||||
let version = get_version();
|
||||
println!(
|
||||
log::info!(
|
||||
"Version using git has {} build on {}",
|
||||
version.git_hash, version.build_time
|
||||
);
|
||||
|
||||
let count = unsafe { esp_ota_get_app_partition_count() };
|
||||
println!("Partition count is {}", count);
|
||||
let mut ota_state: esp_ota_img_states_t = 0;
|
||||
let running_partition = unsafe { esp_ota_get_running_partition() };
|
||||
let address = unsafe { (*running_partition).address };
|
||||
println!("Partition address is {}", address);
|
||||
//TODO
|
||||
//let count = unsafe { esp_ota_get_app_partition_count() };
|
||||
//log::info!("Partition count is {}", count);
|
||||
//let mut ota_state: esp_ota_img_states_t = 0;
|
||||
//let running_partition = unsafe { esp_ota_get_running_partition() };
|
||||
//let address = unsafe { (*running_partition).address };
|
||||
//log::info!("Partition address is {}", address);
|
||||
|
||||
let ota_state_string = unsafe {
|
||||
esp_ota_get_state_partition(running_partition, &mut ota_state);
|
||||
if ota_state == esp_ota_img_states_t_ESP_OTA_IMG_NEW {
|
||||
"ESP_OTA_IMG_NEW"
|
||||
} else if ota_state == esp_ota_img_states_t_ESP_OTA_IMG_PENDING_VERIFY {
|
||||
"ESP_OTA_IMG_PENDING_VERIFY"
|
||||
} else if ota_state == esp_ota_img_states_t_ESP_OTA_IMG_VALID {
|
||||
"ESP_OTA_IMG_VALID"
|
||||
} else if ota_state == esp_ota_img_states_t_ESP_OTA_IMG_INVALID {
|
||||
"ESP_OTA_IMG_INVALID"
|
||||
} else if ota_state == esp_ota_img_states_t_ESP_OTA_IMG_ABORTED {
|
||||
"ESP_OTA_IMG_ABORTED"
|
||||
} else if ota_state == esp_ota_img_states_t_ESP_OTA_IMG_UNDEFINED {
|
||||
"ESP_OTA_IMG_UNDEFINED"
|
||||
} else {
|
||||
&format!("unknown {ota_state}")
|
||||
}
|
||||
};
|
||||
log(LogMessage::PartitionState, 0, 0, "", ota_state_string);
|
||||
// TODO
|
||||
//let ota_state_string = unsafe {
|
||||
//esp_ota_get_state_partition(running_partition, &mut ota_state);
|
||||
//if ota_state == esp_ota_img_states_t_ESP_OTA_IMG_NEW {
|
||||
//"ESP_OTA_IMG_NEW"
|
||||
//} else if ota_state == esp_ota_img_states_t_ESP_OTA_IMG_PENDING_VERIFY {
|
||||
//"ESP_OTA_IMG_PENDING_VERIFY"
|
||||
//} else if ota_state == esp_ota_img_states_t_ESP_OTA_IMG_VALID {
|
||||
//"ESP_OTA_IMG_VALID"
|
||||
//} else if ota_state == esp_ota_img_states_t_ESP_OTA_IMG_INVALID {
|
||||
//"ESP_OTA_IMG_INVALID"
|
||||
//} else if ota_state == esp_ota_img_states_t_ESP_OTA_IMG_ABORTED {
|
||||
//"ESP_OTA_IMG_ABORTED"
|
||||
//} else if ota_state == esp_ota_img_states_t_ESP_OTA_IMG_UNDEFINED {
|
||||
//"ESP_OTA_IMG_UNDEFINED"
|
||||
//} else {
|
||||
//&format!("unknown {ota_state}")
|
||||
//}
|
||||
//};
|
||||
//log(LogMessage::PartitionState, 0, 0, "", ota_state_string);
|
||||
|
||||
let mut board = BOARD_ACCESS
|
||||
.lock()
|
||||
@@ -170,7 +163,7 @@ fn safe_main() -> anyhow::Result<()> {
|
||||
.get_rtc_module()
|
||||
.get_rtc_time()
|
||||
.or_else(|err| {
|
||||
println!("rtc module error: {:?}", err);
|
||||
log::info!("rtc module error: {:?}", err);
|
||||
board.board_hal.general_fault(true);
|
||||
board.board_hal.get_esp().time()
|
||||
})
|
||||
@@ -185,7 +178,7 @@ fn safe_main() -> anyhow::Result<()> {
|
||||
log(LogMessage::YearInplausibleForceConfig, 0, 0, "", "");
|
||||
}
|
||||
|
||||
println!("cur is {}", cur);
|
||||
log::info!("cur is {}", cur);
|
||||
update_charge_indicator(&mut board);
|
||||
|
||||
if board.board_hal.get_esp().get_restart_to_conf() {
|
||||
@@ -223,40 +216,41 @@ fn safe_main() -> anyhow::Result<()> {
|
||||
let _ = board.board_hal.get_esp().wifi_ap();
|
||||
drop(board);
|
||||
let reboot_now = Arc::new(AtomicBool::new(false));
|
||||
let _webserver = httpd(reboot_now.clone());
|
||||
//TODO
|
||||
//let _webserver = httpd(reboot_now.clone());
|
||||
wait_infinity(WaitType::MissingConfig, reboot_now.clone());
|
||||
}
|
||||
|
||||
println!("attempting to connect wifi");
|
||||
log::info!("attempting to connect wifi");
|
||||
let network_mode = if board.board_hal.get_config().network.ssid.is_some() {
|
||||
try_connect_wifi_sntp_mqtt(&mut board)
|
||||
} else {
|
||||
println!("No wifi configured");
|
||||
log::info!("No wifi configured");
|
||||
//the current sensors require this amount to stabilize, in case of wifi this is already handles for sure;
|
||||
board.board_hal.get_esp().delay.delay_ms(100);
|
||||
NetworkMode::OFFLINE
|
||||
};
|
||||
|
||||
if matches!(network_mode, NetworkMode::OFFLINE) && to_config {
|
||||
println!("Could not connect to station and config mode forced, switching to ap mode!");
|
||||
log::info!("Could not connect to station and config mode forced, switching to ap mode!");
|
||||
match board.board_hal.get_esp().wifi_ap() {
|
||||
Ok(_) => {
|
||||
println!("Started ap, continuing")
|
||||
log::info!("Started ap, continuing")
|
||||
}
|
||||
Err(err) => println!("Could not start config override ap mode due to {}", err),
|
||||
Err(err) => log::info!("Could not start config override ap mode due to {}", err),
|
||||
}
|
||||
}
|
||||
|
||||
let timezone = match &board.board_hal.get_config().timezone {
|
||||
Some(tz_str) => tz_str.parse::<Tz>().unwrap_or_else(|_| {
|
||||
println!("Invalid timezone '{}', falling back to UTC", tz_str);
|
||||
log::info!("Invalid timezone '{}', falling back to UTC", tz_str);
|
||||
UTC
|
||||
}),
|
||||
None => UTC, // Fallback to UTC if no timezone is set
|
||||
};
|
||||
|
||||
let timezone_time = cur.with_timezone(&timezone);
|
||||
println!(
|
||||
log::info!(
|
||||
"Running logic at utc {} and {} {}",
|
||||
cur,
|
||||
timezone.name(),
|
||||
@@ -294,11 +288,12 @@ fn safe_main() -> anyhow::Result<()> {
|
||||
|
||||
if to_config {
|
||||
//check if client or ap mode and init Wi-Fi
|
||||
println!("executing config mode override");
|
||||
log::info!("executing config mode override");
|
||||
//config upload will trigger reboot!
|
||||
drop(board);
|
||||
let reboot_now = Arc::new(AtomicBool::new(false));
|
||||
let _webserver = httpd(reboot_now.clone());
|
||||
//TODO
|
||||
//let _webserver = httpd(reboot_now.clone());
|
||||
wait_infinity(WaitType::ConfigButton, reboot_now.clone());
|
||||
} else {
|
||||
log(LogMessage::NormalRun, 0, 0, "", "");
|
||||
@@ -506,7 +501,7 @@ fn safe_main() -> anyhow::Result<()> {
|
||||
board.board_hal.light(false)?;
|
||||
}
|
||||
|
||||
println!("Lightstate is {:?}", light_state);
|
||||
log::info!("Lightstate is {:?}", light_state);
|
||||
}
|
||||
|
||||
match serde_json::to_string(&light_state) {
|
||||
@@ -517,7 +512,7 @@ fn safe_main() -> anyhow::Result<()> {
|
||||
.mqtt_publish("/light", state.as_bytes());
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error publishing lightstate {}", err);
|
||||
log::info!("Error publishing lightstate {}", err);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -551,24 +546,27 @@ fn safe_main() -> anyhow::Result<()> {
|
||||
//is light out of work trigger soon?
|
||||
//is battery low ??
|
||||
//is deep sleep
|
||||
mark_app_valid();
|
||||
//TODO
|
||||
//mark_app_valid();
|
||||
|
||||
let stay_alive_mqtt = STAY_ALIVE.load(std::sync::atomic::Ordering::Relaxed);
|
||||
|
||||
let stay_alive = stay_alive_mqtt;
|
||||
println!("Check stay alive, current state is {}", stay_alive);
|
||||
log::info!("Check stay alive, current state is {}", stay_alive);
|
||||
|
||||
if stay_alive {
|
||||
println!("Go to stay alive move");
|
||||
log::info!("Go to stay alive move");
|
||||
drop(board);
|
||||
let reboot_now = Arc::new(AtomicBool::new(false));
|
||||
let _webserver = httpd(reboot_now.clone());
|
||||
//TODO
|
||||
//let _webserver = httpd(reboot_now.clone());
|
||||
wait_infinity(WaitType::MqttConfig, reboot_now.clone());
|
||||
}
|
||||
board.board_hal.get_esp().set_restart_to_conf(false);
|
||||
board
|
||||
.board_hal
|
||||
.deep_sleep(1000 * 1000 * 60 * deep_sleep_duration_minutes as u64);
|
||||
anyhow::Ok(())
|
||||
}
|
||||
|
||||
pub fn do_secure_pump(
|
||||
@@ -604,12 +602,12 @@ pub fn do_secure_pump(
|
||||
flow_collector[step] = flow_value;
|
||||
let flow_value_ml = flow_value as f32 * board.board_hal.get_config().tank.ml_per_pulse;
|
||||
|
||||
println!(
|
||||
log::info!(
|
||||
"Flow value is {} ml, limit is {} ml raw sensor {}",
|
||||
flow_value_ml, plant_config.pump_limit_ml, flow_value
|
||||
);
|
||||
if flow_value_ml > plant_config.pump_limit_ml as f32 {
|
||||
println!("Flow value is reached, stopping");
|
||||
log::info!("Flow value is reached, stopping");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -659,7 +657,7 @@ pub fn do_secure_pump(
|
||||
}
|
||||
Err(err) => {
|
||||
if !plant_config.ignore_current_error {
|
||||
println!("Error getting pump current: {}", err);
|
||||
log::info!("Error getting pump current: {}", err);
|
||||
log(
|
||||
LogMessage::PumpMissingSensorCurrent,
|
||||
plant_id as u32,
|
||||
@@ -685,7 +683,7 @@ pub fn do_secure_pump(
|
||||
.unwrap()
|
||||
.get_flow_meter_value();
|
||||
let flow_value_ml = final_flow_value as f32 * board.board_hal.get_config().tank.ml_per_pulse;
|
||||
println!(
|
||||
log::info!(
|
||||
"Final flow value is {} with {} ml",
|
||||
final_flow_value, flow_value_ml
|
||||
);
|
||||
@@ -736,7 +734,7 @@ fn publish_tank_state(
|
||||
.mqtt_publish("/water", state.as_bytes());
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error publishing tankstate {}", err);
|
||||
log::info!("Error publishing tankstate {}", err);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -762,7 +760,7 @@ fn publish_plant_states(
|
||||
board.board_hal.get_esp().delay.delay_ms(200);
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error publishing plant state {}", err);
|
||||
log::info!("Error publishing plant state {}", err);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -812,12 +810,12 @@ fn try_connect_wifi_sntp_mqtt(board: &mut MutexGuard<HAL>) -> NetworkMode {
|
||||
Ok(ip_info) => {
|
||||
let sntp_mode: SntpMode = match board.board_hal.get_esp().sntp(1000 * 10) {
|
||||
Ok(new_time) => {
|
||||
println!("Using time from sntp");
|
||||
log::info!("Using time from sntp");
|
||||
let _ = board.board_hal.get_rtc_module().set_rtc_time(&new_time);
|
||||
SntpMode::SYNC { current: new_time }
|
||||
}
|
||||
Err(err) => {
|
||||
println!("sntp error: {}", err);
|
||||
log::info!("sntp error: {}", err);
|
||||
board.board_hal.general_fault(true);
|
||||
SntpMode::OFFLINE
|
||||
}
|
||||
@@ -826,11 +824,11 @@ fn try_connect_wifi_sntp_mqtt(board: &mut MutexGuard<HAL>) -> NetworkMode {
|
||||
let nw_config = &board.board_hal.get_config().network.clone();
|
||||
match board.board_hal.get_esp().mqtt(nw_config) {
|
||||
Ok(_) => {
|
||||
println!("Mqtt connection ready");
|
||||
log::info!("Mqtt connection ready");
|
||||
true
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Could not connect mqtt due to {}", err);
|
||||
log::info!("Could not connect mqtt due to {}", err);
|
||||
false
|
||||
}
|
||||
}
|
||||
@@ -844,7 +842,7 @@ fn try_connect_wifi_sntp_mqtt(board: &mut MutexGuard<HAL>) -> NetworkMode {
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
println!("Offline mode");
|
||||
log::info!("Offline mode");
|
||||
board.board_hal.general_fault(true);
|
||||
NetworkMode::OFFLINE
|
||||
}
|
||||
@@ -879,7 +877,7 @@ fn pump_info(
|
||||
Delay::new_default().delay_ms(200);
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error publishing pump state {}", err);
|
||||
log::info!("Error publishing pump state {}", err);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -975,13 +973,26 @@ fn wait_infinity(wait_type: WaitType, reboot_now: Arc<AtomicBool>) -> ! {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[esp_hal_embassy::main]
|
||||
async fn main(spawner: Spawner) {
|
||||
// intialize embassy
|
||||
esp_log::info::logger::init_logger_from_env();
|
||||
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);
|
||||
|
||||
info!("Embassy initialized!");
|
||||
|
||||
let result = safe_main();
|
||||
match result {
|
||||
// this should not get triggered, safe_main should not return but go into deep sleep with sensible
|
||||
// timeout, this is just a fallback
|
||||
Ok(_) => {
|
||||
println!("Main app finished, restarting");
|
||||
log::info!("Main app finished, restarting");
|
||||
BOARD_ACCESS
|
||||
.lock()
|
||||
.unwrap()
|
||||
@@ -992,8 +1003,9 @@ fn main() {
|
||||
}
|
||||
// if safe_main exists with an error, rollback to a known good ota version
|
||||
Err(err) => {
|
||||
println!("Failed main {}", err);
|
||||
let _rollback_successful = rollback_and_reboot();
|
||||
log::info!("Failed main {}", err);
|
||||
//TODO
|
||||
//let _rollback_successful = rollback_and_reboot();
|
||||
panic!("Failed to rollback :(");
|
||||
}
|
||||
}
|
||||
@@ -1014,8 +1026,10 @@ fn get_version() -> VersionInfo {
|
||||
let branch = env!("VERGEN_GIT_BRANCH").to_owned();
|
||||
let hash = &env!("VERGEN_GIT_SHA")[0..8];
|
||||
|
||||
let running_partition = unsafe { esp_ota_get_running_partition() };
|
||||
let address = unsafe { (*running_partition).address };
|
||||
//TODO
|
||||
//let running_partition = unsafe { esp_ota_get_running_partition() };
|
||||
let address = 0;
|
||||
//let address = unsafe { (*running_partition).address };
|
||||
let partition = if address > 100000 {
|
||||
"ota_1 @ "
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user