From 07b103f81071b56ead8b46aebd2ed7e61ad1cf17 Mon Sep 17 00:00:00 2001 From: Michael de Silva Date: Sun, 10 Dec 2023 12:25:20 +0530 Subject: [PATCH 01/11] Update for espup upgrade to v0.10.0 --- .cargo/config.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 16fef72..5352c04 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -34,7 +34,8 @@ build-std = ["std", "panic_abort"] [env] CARGO_WORKSPACE_DIR = { value = "", relative = true } -LIBCLANG_PATH = "/home/mdesilva/.espressif/tools/xtensa-esp32-elf-clang/esp-15.0.0-20221014-x86_64-unknown-linux-gnu/esp-clang/lib" +# LIBCLANG_PATH = "/home/mdesilva/.espressif/tools/xtensa-esp32-elf-clang/esp-15.0.0-20221014-x86_64-unknown-linux-gnu/esp-clang/lib" +LIBCLANG_PATH = "/home/mdesilva/.espup/esp-clang" # Uncomment this to build against ESP-IDF master (currently unreleased ESP IDF 5.1) #ESP_IDF_VERSION = "master" # Don't forget to uncomment also the `rustflags` parameter in your "target" section above From 1a705a696a2cffb65447f578bd7518e866e7bbde Mon Sep 17 00:00:00 2001 From: Michael de Silva Date: Sun, 10 Dec 2023 18:22:50 +0530 Subject: [PATCH 02/11] Upgrade in progress --- Cargo.toml | 4 +++- rued-esp32/Cargo.toml | 28 +++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fb79f39..80404b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,9 @@ embedded-hal = { git = "https://github.com/rust-embedded/embedded-hal" } # esp-idf-svc = { git = "https://github.com/esp-rs/esp-idf-svc" } # edge-frame = { git = "https://github.com/ivmarkov/edge-frame" } embedded-io = { git = "https://github.com/ivmarkov/embedded-io" } -shared-bus = { git = "https://github.com/taks/shared-bus", branch = "embedded-hal-1.0.0-alpha.9" } +# shared-bus = { git = "https://github.com/taks/shared-bus", branch = "embedded-hal-1.0.0-alpha.10" } +# shared-bus = { git = "https://github.com/taks/shared-bus" } +crossbeam-utils = { git = "https://github.com/crossbeam-rs/crossbeam" } #socket2 = { git = "https://github.com/esp-rs-compat/socket2" } #polling = { git = "https://github.com/esp-rs-compat/polling" } diff --git a/rued-esp32/Cargo.toml b/rued-esp32/Cargo.toml index f9d4af0..a7d5285 100644 --- a/rued-esp32/Cargo.toml +++ b/rued-esp32/Cargo.toml @@ -6,8 +6,7 @@ edition = "2021" resolver = "2" [features] -pio = ["esp-idf-sys/pio"] -default = ["edge-executor", "system", "experimental"] # Note that edge-executor requires alloc +default = ["system", "experimental"] # Note that edge-executor requires alloc # system = ["display-i2c"] system = ["display-spi", "nvs", "external-rtc", "board"] @@ -28,7 +27,7 @@ experimental = ["esp-idf-svc/experimental", "embedded-svc/experimental"] [dependencies] anyhow = "1" -heapless = { version = "0.7" } +heapless = { version = "0.8.0" } enumset = "1" log = { version = "0.4", features = [ "max_level_debug", @@ -39,19 +38,17 @@ serde = { version = "1", default-features = false } postcard = "0.7" critical-section = "1.1" embedded-hal = { git = "https://github.com/rust-embedded/embedded-hal" } -embedded-hal-0-2 = { package = "embedded-hal", version = "0.2.7", features = ["unproven"] } -embedded-svc = { version = "0.24.0", features = ["nightly", "experimental"] } -esp-idf-sys = { version = "0.32.1", features = ["binstart"] } -esp-idf-svc = { version = "0.45.0", features = ["nightly", "experimental", "embassy-time-isr-queue"] } +# embedded-hal-0-2 = { package = "embedded-hal", version = "0.2.7", features = ["unproven"] } +embedded-svc = { version = "0.26.4", features = ["nightly", "experimental"] } +esp-idf-svc = { version = "0.47.3", features = ["nightly", "experimental", "embassy-time-isr-queue"] } # esp-idf-svc = { path = "/home/mdesilva/esp/esp-idf-svc_fork", features = ["nightly", "experimental", "embassy-time-isr-queue"] } -esp-idf-hal = { version = "0.40.1", features = ["edge-executor", "embassy-sync", "critical-section"] } embassy-futures = { version = "0.1" } -embassy-sync = { version = "0.1", features = ["std"] } +embassy-sync = { version = "0.5.0", features = ["std"] } embassy-time = { version = "0.1" } -static_cell = { version = "1" } -edge-frame = { version = "0.5", default-features = false, features = ["dto"], git = "https://github.com/ivmarkov/edge-frame" } -edge-executor = { version = "0.3", optional = true } -channel-bridge = { version = "0.2", git = "https://github.com/ivmarkov/channel-bridge", default-features = false, features = ["notification", "nightly", "embedded-svc"] } +static_cell = { version = "2.0.0" } +edge-frame = { version = "0.7.0", default-features = false, features = ["dto"], git = "https://github.com/ivmarkov/edge-frame" } +# edge-executor = { version = "0.4.1", optional = true } +channel-bridge = { version = "0.6", git = "https://github.com/ivmarkov/channel-bridge", default-features = false, features = ["nightly", "embedded-svc"] } http = "0.2" # time = { version = "0.3.17", features = ["macros"] } @@ -64,7 +61,8 @@ serde_json = "1.0.87" cstr_core = "0.2.6" uncased = { version = "0.9.7" } shared-bus = { version = "0.2", features = ["std"] } -rv8803-rs = { git = "https://github.com/bsodmike/rv8803-rs" } +# rv8803-rs = { git = "https://github.com/bsodmike/rv8803-rs" } +rv8803 = { path = "/home/mdesilva/esp/rv8803-rs" } embedded-sdmmc = { git = "https://github.com/rust-embedded-community/embedded-sdmmc-rs", branch = "develop" } # optional dependencies @@ -74,5 +72,5 @@ ssd1351 = { version = "0.4", optional = true } mipidsi = { git = "https://github.com/almindor/mipidsi", optional = true } [build-dependencies] -embuild = { version = "0.30.4", features = ["elf"] } +embuild = { version = "0.31.4", features = ["elf"] } anyhow = "1" From 8c4c462dfefb972538cd87d3b4d5b89bc0d4a5d5 Mon Sep 17 00:00:00 2001 From: Michael de Silva Date: Tue, 12 Dec 2023 20:31:23 +0530 Subject: [PATCH 03/11] Further progress... --- .cargo/config.toml | 2 +- Cargo.toml | 5 +- rued-esp32/Cargo.toml | 31 +- rued-esp32/build.rs | 6 +- rued-esp32/src/core/internal/battery.rs | 20 +- rued-esp32/src/core/internal/external_rtc.rs | 4 +- rued-esp32/src/core/internal/httpd.rs | 8 +- rued-esp32/src/core/internal/inspector.rs | 2 +- rued-esp32/src/core/internal/mqtt.rs | 6 +- rued-esp32/src/core/internal/ota.rs | 15 +- rued-esp32/src/core/internal/pwm.rs | 8 +- rued-esp32/src/core/internal/quit.rs | 4 +- rued-esp32/src/core/internal/screen.rs | 2 +- rued-esp32/src/core/internal/sntp.rs | 4 +- rued-esp32/src/core/internal/spawn.rs | 297 +++++++++---------- rued-esp32/src/core/internal/ws.rs | 22 +- rued-esp32/src/errors.rs | 14 +- rued-esp32/src/httpd.rs | 2 +- rued-esp32/src/main.rs | 270 ++++++++--------- rued-esp32/src/models.rs | 19 +- rued-esp32/src/peripherals.rs | 15 +- rued-esp32/src/services.rs | 154 ++++++---- rued-esp32/src/services/httpd.rs | 6 +- 23 files changed, 468 insertions(+), 448 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 5352c04..b8451f1 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -42,7 +42,7 @@ LIBCLANG_PATH = "/home/mdesilva/.espup/esp-clang" # Uncomment this to build against ESP-IDF 5.0 # Don't forget to uncomment also the `rustflags` parameter in your "target" section above -ESP_IDF_VERSION = "release/v5.0" +ESP_IDF_VERSION = "v5.1.1" # Comment out this when using the PlatformIO build, i.e. `cargo build --features pio` (it only supports `v4.3.2`) # ESP_IDF_VERSION = "release/v4.4" diff --git a/Cargo.toml b/Cargo.toml index 80404b9..43cb88b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,15 +8,14 @@ members = [ # exclude = [] [patch.crates-io] -embedded-hal = { git = "https://github.com/rust-embedded/embedded-hal" } +crossbeam-utils = { git = "https://github.com/crossbeam-rs/crossbeam" } +# embedded-hal = { git = "https://github.com/rust-embedded/embedded-hal" } # embedded-svc = { git = "https://github.com/esp-rs/embedded-svc" } # esp-idf-hal = { git = "https://github.com/esp-rs/esp-idf-hal" } # esp-idf-svc = { git = "https://github.com/esp-rs/esp-idf-svc" } # edge-frame = { git = "https://github.com/ivmarkov/edge-frame" } -embedded-io = { git = "https://github.com/ivmarkov/embedded-io" } # shared-bus = { git = "https://github.com/taks/shared-bus", branch = "embedded-hal-1.0.0-alpha.10" } # shared-bus = { git = "https://github.com/taks/shared-bus" } -crossbeam-utils = { git = "https://github.com/crossbeam-rs/crossbeam" } #socket2 = { git = "https://github.com/esp-rs-compat/socket2" } #polling = { git = "https://github.com/esp-rs-compat/polling" } diff --git a/rued-esp32/Cargo.toml b/rued-esp32/Cargo.toml index a7d5285..13119e5 100644 --- a/rued-esp32/Cargo.toml +++ b/rued-esp32/Cargo.toml @@ -4,9 +4,12 @@ version = "4.0.0" authors = ["Michael de Silva "] edition = "2021" resolver = "2" +license = "MIT OR Apache-2.0" +readme = "README.md" +rust-version = "1.71" [features] -default = ["system", "experimental"] # Note that edge-executor requires alloc +default = ["edge-executor", "system", "experimental"] # Note that edge-executor requires alloc # system = ["display-i2c"] system = ["display-spi", "nvs", "external-rtc", "board"] @@ -27,7 +30,6 @@ experimental = ["esp-idf-svc/experimental", "embedded-svc/experimental"] [dependencies] anyhow = "1" -heapless = { version = "0.8.0" } enumset = "1" log = { version = "0.4", features = [ "max_level_debug", @@ -36,19 +38,20 @@ log = { version = "0.4", features = [ futures = {version = "0.3", features = ["async-await"] } serde = { version = "1", default-features = false } postcard = "0.7" +heapless = "0.8" critical-section = "1.1" -embedded-hal = { git = "https://github.com/rust-embedded/embedded-hal" } -# embedded-hal-0-2 = { package = "embedded-hal", version = "0.2.7", features = ["unproven"] } -embedded-svc = { version = "0.26.4", features = ["nightly", "experimental"] } -esp-idf-svc = { version = "0.47.3", features = ["nightly", "experimental", "embassy-time-isr-queue"] } -# esp-idf-svc = { path = "/home/mdesilva/esp/esp-idf-svc_fork", features = ["nightly", "experimental", "embassy-time-isr-queue"] } +embedded-hal = { version = "1.0.0-rc.1" } +embedded-hal-async = "1.0.0-rc.1" +embedded-hal-0-2 = { package = "embedded-hal", version = "0.2", features = ["unproven"] } +embedded-svc = { version = "0.26", features = ["nightly", "experimental"] } +esp-idf-svc = { version = "0.47", features = ["nightly", "experimental", "critical-section", "embassy-time-driver"] } embassy-futures = { version = "0.1" } -embassy-sync = { version = "0.5.0", features = ["std"] } +embassy-sync = { version = "0.3", features = ["std"] } embassy-time = { version = "0.1" } -static_cell = { version = "2.0.0" } -edge-frame = { version = "0.7.0", default-features = false, features = ["dto"], git = "https://github.com/ivmarkov/edge-frame" } -# edge-executor = { version = "0.4.1", optional = true } -channel-bridge = { version = "0.6", git = "https://github.com/ivmarkov/channel-bridge", default-features = false, features = ["nightly", "embedded-svc"] } +static_cell = { version = "2" } +edge-frame = { version = "0.7", default-features = false, features = ["dto"] } +edge-executor = { version = "0.4", optional = true } +channel-bridge = { version = "0.6", default-features = false, features = ["nightly", "embedded-svc"] } http = "0.2" # time = { version = "0.3.17", features = ["macros"] } @@ -62,7 +65,7 @@ cstr_core = "0.2.6" uncased = { version = "0.9.7" } shared-bus = { version = "0.2", features = ["std"] } # rv8803-rs = { git = "https://github.com/bsodmike/rv8803-rs" } -rv8803 = { path = "/home/mdesilva/esp/rv8803-rs" } +rv8803 = { path = "/home/mike/esp/rv8803-rs" } embedded-sdmmc = { git = "https://github.com/rust-embedded-community/embedded-sdmmc-rs", branch = "develop" } # optional dependencies @@ -72,5 +75,5 @@ ssd1351 = { version = "0.4", optional = true } mipidsi = { git = "https://github.com/almindor/mipidsi", optional = true } [build-dependencies] -embuild = { version = "0.31.4", features = ["elf"] } +embuild = { version = "0.31", features = ["espidf", "elf"] } anyhow = "1" diff --git a/rued-esp32/build.rs b/rued-esp32/build.rs index 4dd5e1f..bd2524a 100644 --- a/rued-esp32/build.rs +++ b/rued-esp32/build.rs @@ -1,5 +1,5 @@ -// Necessary because of this issue: https://github.com/rust-lang/cargo/issues/9641 fn main() -> anyhow::Result<()> { - embuild::build::CfgArgs::output_propagated("ESP_IDF")?; - embuild::build::LinkArgs::output_propagated("ESP_IDF") + embuild::espidf::sysenv::output(); + + Ok(()) } diff --git a/rued-esp32/src/core/internal/battery.rs b/rued-esp32/src/core/internal/battery.rs index 3c6ccea..511cd78 100644 --- a/rued-esp32/src/core/internal/battery.rs +++ b/rued-esp32/src/core/internal/battery.rs @@ -1,5 +1,6 @@ use embassy_time::{Duration, Timer}; +use core::fmt::Debug; use embedded_hal_0_2::adc; use embedded_hal_0_2::digital::v2::InputPin; @@ -7,6 +8,12 @@ use super::state::State; pub use super::dto::battery::*; +pub trait Adc { + type Error: Debug; + + async fn read(&mut self) -> Result; +} + pub static STATE: State = State::new( "BATTERY", BatteryState::new(), @@ -19,20 +26,15 @@ pub static STATE: State = State::new( ], ); -pub async fn process( - mut one_shot: impl adc::OneShot, - mut battery_pin: BP, - power_pin: impl InputPin, -) where - BP: adc::Channel, -{ +pub async fn process(mut battery_adc: impl Adc, power_pin: impl InputPin) { const ROUND_UP: u16 = 50; // TODO: Make it smaller once ADC is connected loop { Timer::after(Duration::from_secs(2)).await; - let voltage = one_shot - .read(&mut battery_pin) + let voltage = battery_adc + .read() + .await .ok() .map(|voltage| voltage / ROUND_UP * ROUND_UP); diff --git a/rued-esp32/src/core/internal/external_rtc.rs b/rued-esp32/src/core/internal/external_rtc.rs index d198139..7945d06 100644 --- a/rued-esp32/src/core/internal/external_rtc.rs +++ b/rued-esp32/src/core/internal/external_rtc.rs @@ -4,7 +4,7 @@ use core::fmt::Debug; use channel_bridge::Receiver; use embassy_time::{Duration, Timer}; use embedded_hal_0_2::PwmPin; -use esp_idf_hal::delay::FreeRtos; +use esp_idf_svc::hal::delay::FreeRtos; use serde::{Deserialize, Serialize}; use log::trace; @@ -14,7 +14,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; use embassy_sync::signal::Signal; -use embedded_svc::executor::asynch::Unblocker; +use embedded_svc::utils::asyncify::Unblocker; use channel_bridge::notification::Notification; diff --git a/rued-esp32/src/core/internal/httpd.rs b/rued-esp32/src/core/internal/httpd.rs index 7393ad7..776ffad 100644 --- a/rued-esp32/src/core/internal/httpd.rs +++ b/rued-esp32/src/core/internal/httpd.rs @@ -11,7 +11,7 @@ use std::primitive::u8; use channel_bridge::Receiver; use embedded_hal_0_2::PwmPin; -use esp_idf_hal::delay::FreeRtos; +use esp_idf_svc::hal::delay::FreeRtos; use esp_idf_svc::http::server::{fn_handler, EspHttpServer}; use embassy_futures::select::{select, select_array, Either}; @@ -19,8 +19,8 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; use embassy_sync::signal::Signal; -use embedded_svc::executor::asynch::Unblocker; use embedded_svc::http::{Headers, Method, Query}; +use embedded_svc::utils::asyncify::Unblocker; use channel_bridge::notification::Notification; @@ -40,7 +40,7 @@ pub enum HttpdCommand { pub(crate) static COMMAND: Signal = Signal::new(); -pub async fn process<'a>(httpd: &'a mut LazyInitHttpServer) { +pub async fn process<'a>(httpd: &'a mut LazyInitHttpServer<'_>) { const FIRMWARE_VERSION: &str = env!("CARGO_PKG_VERSION"); let mut network_event = NETWORK_EVENT_CHANNEL.subscriber().unwrap(); @@ -100,7 +100,7 @@ pub async fn process<'a>(httpd: &'a mut LazyInitHttpServer) { err ); unsafe { - esp_idf_sys::esp_restart(); + esp_idf_svc::sys::esp_restart(); } } diff --git a/rued-esp32/src/core/internal/inspector.rs b/rued-esp32/src/core/internal/inspector.rs index 7bbef67..e92383a 100644 --- a/rued-esp32/src/core/internal/inspector.rs +++ b/rued-esp32/src/core/internal/inspector.rs @@ -9,7 +9,7 @@ use embassy_futures::select::select_array; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; -use embedded_svc::executor::asynch::Unblocker; +use embedded_svc::utils::asyncify::Unblocker; use channel_bridge::notification::Notification; diff --git a/rued-esp32/src/core/internal/mqtt.rs b/rued-esp32/src/core/internal/mqtt.rs index ebf08a8..025c6e1 100644 --- a/rued-esp32/src/core/internal/mqtt.rs +++ b/rued-esp32/src/core/internal/mqtt.rs @@ -15,7 +15,9 @@ use log::*; static MQTT_CONNECT_SIGNAL: Signal = Signal::new(); -pub async fn receive_task(mut connection: impl Connection>) { +pub async fn receive_task<'a>( + mut connection: impl Connection = Option> + 'a, +) { let mut app_event = APPLICATION_EVENT_CHANNEL.subscriber().unwrap(); loop { @@ -48,7 +50,7 @@ pub async fn receive_task(mut connection: impl Connection { info!("receive_task MQTT received system restart request"); unsafe { - esp_idf_sys::esp_restart(); + esp_idf_svc::sys::esp_restart(); } } } diff --git a/rued-esp32/src/core/internal/ota.rs b/rued-esp32/src/core/internal/ota.rs index 87d65c8..b3f6fde 100644 --- a/rued-esp32/src/core/internal/ota.rs +++ b/rued-esp32/src/core/internal/ota.rs @@ -8,7 +8,6 @@ use embassy_time::{Duration, Timer}; use embedded_svc::ota::{FirmwareInfo, FirmwareInfoLoader, LoadResult, Slot}; use esp_idf_svc::http::client::{Configuration, EspHttpConnection}; use esp_idf_svc::ota::{EspFirmwareInfoLoader, EspOta}; -use esp_idf_sys::*; use heapless::String; use log::*; @@ -36,9 +35,9 @@ pub async fn ota_task() { info!("Firmware update successful. Restarting device."); } - esp_idf_hal::delay::FreeRtos::delay_ms(5000); + esp_idf_svc::hal::delay::FreeRtos::delay_ms(5000); unsafe { - esp_idf_sys::esp_restart(); + esp_idf_svc::sys::esp_restart(); } } } @@ -90,8 +89,8 @@ fn perform_update(firmware_url: &str) -> Result<(), OtaError> { info!("initiating OTA update"); - let update_partition: esp_partition_t = - unsafe { *esp_ota_get_next_update_partition(ptr::null()) }; + let update_partition: esp_idf_svc::sys::esp_partition_t = + unsafe { *esp_idf_svc::sys::esp_ota_get_next_update_partition(ptr::null()) }; let partition_label = std::str::from_utf8(unsafe { std::mem::transmute(&update_partition.label as &[i8]) }) .unwrap() @@ -142,9 +141,9 @@ fn perform_update(firmware_url: &str) -> Result<(), OtaError> { // Check if first segment and process image meta data if !image_header_was_checked && data_read - > mem::size_of::() - + mem::size_of::() - + mem::size_of::() + > mem::size_of::() + + mem::size_of::() + + mem::size_of::() { let mut esp_fw_loader_info = EspFirmwareInfoLoader::new(); let res = match esp_fw_loader_info.load(&ota_write_data) { diff --git a/rued-esp32/src/core/internal/pwm.rs b/rued-esp32/src/core/internal/pwm.rs index 1b7c6e0..e20e081 100644 --- a/rued-esp32/src/core/internal/pwm.rs +++ b/rued-esp32/src/core/internal/pwm.rs @@ -3,7 +3,7 @@ use core::fmt::Debug; use channel_bridge::Receiver; use embedded_hal_0_2::PwmPin; -use esp_idf_hal::delay::FreeRtos; +use esp_idf_svc::hal::delay::FreeRtos; use serde::{Deserialize, Serialize}; use log::trace; @@ -13,7 +13,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; use embassy_sync::signal::Signal; -use embedded_svc::executor::asynch::Unblocker; +use embedded_svc::utils::asyncify::Unblocker; use channel_bridge::notification::Notification; @@ -69,6 +69,10 @@ pub async fn process<'a>( impl PwmPin + 'a, )>, ) { + let mut pwm0; + let mut pwm1; + let mut pwm2; + #[cfg(feature = "pwm")] { let (mut pwm0, mut pwm1, mut pwm2) = pwm.expect("Unwraps pwm channels"); diff --git a/rued-esp32/src/core/internal/quit.rs b/rued-esp32/src/core/internal/quit.rs index 7d3aeb7..24d2eb6 100644 --- a/rued-esp32/src/core/internal/quit.rs +++ b/rued-esp32/src/core/internal/quit.rs @@ -1,3 +1,5 @@ use channel_bridge::notification::Notification; -pub static QUIT: Notification = Notification::new(); +const INIT: Notification = Notification::new(); + +pub static QUIT: [Notification; 3] = [INIT; 3]; diff --git a/rued-esp32/src/core/internal/screen.rs b/rued-esp32/src/core/internal/screen.rs index 929312b..299af7b 100644 --- a/rued-esp32/src/core/internal/screen.rs +++ b/rued-esp32/src/core/internal/screen.rs @@ -17,7 +17,7 @@ use embassy_sync::blocking_mutex::Mutex; use gfx_xtra::draw_target::Flushable; -use embedded_svc::executor::asynch::Unblocker; +use embedded_svc::utils::asyncify::Unblocker; use channel_bridge::notification::Notification; diff --git a/rued-esp32/src/core/internal/sntp.rs b/rued-esp32/src/core/internal/sntp.rs index f741e94..144fd89 100644 --- a/rued-esp32/src/core/internal/sntp.rs +++ b/rued-esp32/src/core/internal/sntp.rs @@ -3,7 +3,7 @@ use core::fmt::Debug; use channel_bridge::Receiver; use embassy_time::{Duration, Timer}; -use esp_idf_hal::delay::FreeRtos; +use esp_idf_svc::hal::delay::FreeRtos; use serde::{Deserialize, Serialize}; use log::trace; @@ -13,7 +13,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; use embassy_sync::signal::Signal; -use embedded_svc::executor::asynch::Unblocker; +use embedded_svc::utils::asyncify::Unblocker; use channel_bridge::notification::Notification; diff --git a/rued-esp32/src/core/internal/spawn.rs b/rued-esp32/src/core/internal/spawn.rs index 6288049..16e6bd7 100644 --- a/rued-esp32/src/core/internal/spawn.rs +++ b/rued-esp32/src/core/internal/spawn.rs @@ -1,8 +1,9 @@ use core::fmt::Debug; use embedded_graphics::pixelcolor::BinaryColor; -use embedded_hal_0_2::digital::v2::{InputPin, OutputPin}; +use embedded_hal::digital::{InputPin, OutputPin}; use embedded_hal_0_2::{adc, PwmPin}; +use embedded_hal_async::digital::Wait; use embedded_svc::mqtt::client::asynch::{Client, Connection, Publish}; use embedded_svc::wifi::Wifi as WifiTrait; @@ -24,20 +25,23 @@ use crate::mqtt_msg::MqttCommand; use crate::services::httpd::LazyInitHttpServer; use crate::MQTT_MAX_TOPIC_LEN; +use futures::task::SpawnError; + use super::button::{self, PressedLevel}; use super::screen::Color; use super::web::{self, WebEvent, WebRequest}; use super::{battery, mqtt, wifi}; -pub fn high_prio<'a, ADC, BP, const C: usize, M, D>( - executor: &mut Executor<'a, C, M, Local>, - tasks: &mut heapless::Vec, C>, +pub fn high_prio<'a, const C: usize>( + executor: &LocalExecutor<'a, C>, button1_pin: impl InputPin + 'a, - battery_voltage: impl adc::OneShot + 'a, - battery_pin: BP, + battery_voltage: impl crate::core::internal::battery::Adc + 'a, power_pin: impl InputPin + 'a, - display: D, - wifi: (EspWifi<'a>, impl Receiver + 'a), + // display: D, + wifi: ( + impl embedded_svc::wifi::asynch::Wifi + 'a, + impl Receiver + 'a, + ), httpd: &'a mut LazyInitHttpServer, acceptor: Option, pwm: Option<( @@ -50,141 +54,120 @@ pub fn high_prio<'a, ADC, BP, const C: usize, M, D>( netif_notifier: impl Receiver + 'a, mqtt_topic_prefix: &'a str, mqtt_client: impl Client + Publish + 'a, - mqtt_conn: impl Connection> + 'a, -) -> Result<(), SpawnError> -where - M: Monitor + Default, - D: Flushable + 'a, - D::Error: Debug, - ADC: 'a, - BP: adc::Channel + 'a, -{ + mqtt_conn: impl Connection = Option> + 'a, +) { executor - .spawn_local_collect( - super::button::button1_process(button1_pin, super::button::PressedLevel::Low), - tasks, - )? - .spawn_local_collect(super::inspector::process(), tasks)? - .spawn_local_collect(super::keepalive::process(), tasks)? - .spawn_local_collect(screen::process(), tasks)? - .spawn_local_collect(screen::run_draw(display), tasks)? - .spawn_local_collect(super::wifi::process(wifi.0, wifi.1), tasks)? - .spawn_local_collect(super::httpd::process(httpd), tasks)? - .spawn_local_collect(super::pwm::process(pwm), tasks)? - .spawn_local_collect(super::sntp::process(), tasks)? - .spawn_local_collect(super::pwm::flash(pwm_flash), tasks)? - .spawn_local_collect( - super::battery::process(battery_voltage, battery_pin, power_pin), - tasks, - )? - // Netif State Change - .spawn_local_collect(crate::process_netif_state_change(netif_notifier), tasks)? - // OTA - .spawn_local_collect(super::ota::ota_task(), tasks)? - // MQTT - .spawn_local_collect(super::mqtt::receive_task(mqtt_conn), tasks)? - .spawn_local_collect( - super::mqtt::send_task::(mqtt_topic_prefix, mqtt_client), - tasks, - )?; + .spawn(button::button1_process(button1_pin, PressedLevel::Low)) + .detach(); + executor.spawn(super::inspector::process()).detach(); + executor.spawn(super::keepalive::process()).detach(); + // executor.spawn(screen::process()).detach(); + // executor.spawn(screen::run_draw(display)).detach(); + executor + .spawn(super::wifi::process(wifi.0, wifi.1)) + .detach(); + executor.spawn(super::httpd::process(httpd)).detach(); + executor.spawn(super::pwm::process(pwm)).detach(); + executor.spawn(super::sntp::process()).detach(); + executor.spawn(super::pwm::flash(pwm_flash)).detach(); + executor + .spawn(super::battery::process(battery_voltage, power_pin)) + .detach(); + // Netif State Change + executor + .spawn(crate::process_netif_state_change(netif_notifier)) + .detach(); + // OTA + executor.spawn(super::ota::ota_task()).detach(); + // MQTT + executor + .spawn(super::mqtt::receive_task(mqtt_conn)) + .detach(); + executor + .spawn(super::mqtt::send_task::( + mqtt_topic_prefix, + mqtt_client, + )) + .detach(); - // if let Some(acceptor) = acceptor { - // executor.spawn_local_collect(super::ws::process(acceptor), tasks)?; - // }; if let Some(rtc) = rtc { - executor.spawn_local_collect(super::external_rtc::process(rtc), tasks)?; + executor.spawn(super::external_rtc::process(rtc)).detach(); }; - - Ok(()) } -pub fn high_prio_original<'a, ADC, BP, const C: usize, M>( - executor: &mut Executor<'a, C, M, Local>, - tasks: &mut heapless::Vec, C>, - battery_voltage: impl adc::OneShot + 'a, - battery_pin: BP, - // used to indicate if powered by battery, only if this is enabled will Deep-sleep be enabled. - power_pin: impl InputPin + 'a, - roller: bool, - button1_pin: impl InputPin + 'a, - button2_pin: impl InputPin + 'a, - button3_pin: impl InputPin + 'a, -) -> Result<(), SpawnError> -where - M: Monitor + Default, - ADC: 'a, - BP: adc::Channel + 'a, -{ - executor - .spawn_local_collect( - battery::process(battery_voltage, battery_pin, power_pin), - tasks, - )? - .spawn_local_collect( - super::button::button3_process(button3_pin, super::button::PressedLevel::Low), - tasks, - )? - // .spawn_local_collect(emergency::process(), tasks)? - .spawn_local_collect(super::keepalive::process(), tasks)?; - - if roller { - executor.spawn_local_collect( - super::button::button1_button2_roller_process(button1_pin, button2_pin), - tasks, - )?; - } else { - executor - .spawn_local_collect( - super::button::button1_process(button1_pin, super::button::PressedLevel::Low), - tasks, - )? - .spawn_local_collect( - super::button::button2_process(button2_pin, super::button::PressedLevel::Low), - tasks, - )?; - } +// FIXME +// pub fn high_prio_original<'a, ADC, BP, const C: usize, M>( +// executor: &mut Executor<'a, C, M, Local>, +// tasks: &mut heapless::Vec, C>, +// battery_voltage: impl adc::OneShot + 'a, +// battery_pin: BP, +// // used to indicate if powered by battery, only if this is enabled will Deep-sleep be enabled. +// power_pin: impl InputPin + 'a, +// roller: bool, +// button1_pin: impl InputPin + 'a, +// button2_pin: impl InputPin + 'a, +// button3_pin: impl InputPin + 'a, +// ) -> Result<(), SpawnError> +// where +// M: Monitor + Default, +// ADC: 'a, +// BP: adc::Channel + 'a, +// { +// executor +// .spawn_local_collect( +// battery::process(battery_voltage, battery_pin, power_pin), +// tasks, +// )? +// .spawn_local_collect( +// super::button::button3_process(button3_pin, super::button::PressedLevel::Low), +// tasks, +// )? +// // .spawn_local_collect(emergency::process(), tasks)? +// .spawn_local_collect(super::keepalive::process(), tasks)?; + +// if roller { +// executor.spawn_local_collect( +// super::button::button1_button2_roller_process(button1_pin, button2_pin), +// tasks, +// )?; +// } else { +// executor +// .spawn_local_collect( +// super::button::button1_process(button1_pin, super::button::PressedLevel::Low), +// tasks, +// )? +// .spawn_local_collect( +// super::button::button2_process(button2_pin, super::button::PressedLevel::Low), +// tasks, +// )?; +// } - Ok(()) -} +// Ok(()) +// } -pub fn mid_prio< - 'a, - const C: usize, - M, - // D ->( - executor: &mut Executor<'a, C, M, Local>, - tasks: &mut heapless::Vec, C>, - // display: D, +pub fn mid_prio<'a, const C: usize, D>( + executor: &LocalExecutor<'a, C>, + display: D, // wm_flash: impl FnMut(WaterMeterState) + 'a, -) -> Result<(), SpawnError> -where - M: Monitor + Default, - // D: Flushable + 'a, - // D::Error: Debug, +) where + D: Flushable + 'a, + D::Error: Debug, { - // executor - // .spawn_local_collect(screen::process(), tasks)? - // .spawn_local_collect(screen::run_draw(display), tasks)?; - - // .spawn_local_collect(wm_stats::process(), tasks)? - // .spawn_local_collect(wm::flash(wm_flash), tasks)?; - - Ok(()) + executor.spawn(screen::process()).detach(); + executor.spawn(screen::run_draw(display)).detach(); + // executor.spawn(wm_stats::process()).detach(); + // executor.spawn(wm::flash(wm_flash)).detach(); } -pub fn wifi<'a, const C: usize, M, D>( - executor: &mut Executor<'a, C, M, Local>, - tasks: &mut heapless::Vec, C>, - wifi: EspWifi<'a>, +pub fn wifi<'a, const C: usize, D>( + executor: &LocalExecutor<'a, C>, + wifi: impl embedded_svc::wifi::asynch::Wifi + 'a, wifi_notif: impl Receiver + 'a, ) -> Result<(), SpawnError> where - M: Monitor + Default, D: 'a, - WifiEvent: From, { - executor.spawn_local_collect(super::wifi::process(wifi, wifi_notif), tasks)?; + executor.spawn(wifi::process(wifi, wifi_notif)).detach(); Ok(()) } @@ -217,47 +200,39 @@ where // Ok(()) // } -pub fn ws<'a, const C: usize, M>( - executor: &mut Executor<'a, C, M, Local>, - tasks: &mut heapless::Vec, C>, +pub fn ws<'a, const C: usize>( + executor: &LocalExecutor<'a, C>, acceptor: impl Acceptor + 'a, -) -> Result<(), SpawnError> -where - M: Monitor + Default, -{ - executor.spawn_local_collect(super::ws::process(acceptor), tasks)?; +) -> Result<(), SpawnError> { + executor + .spawn(crate::core::internal::ws::process(acceptor)) + .detach(); Ok(()) } -pub fn run( - executor: &mut Executor, - tasks: heapless::Vec, C>, -) where - M: Monitor + Wait + Default, -{ - // FIXME: Simulate a button press - // let condition = move || false; +// pub fn run(executor: &LocalExecutor<'_, C>) +// { +// // FIXME: Simulate a button press +// // let condition = move || false; - let condition = move || !super::quit::QUIT.triggered(); - executor.run_tasks(condition, tasks); -} +// let condition = move || !super::quit::QUIT.triggered(); +// executor.run_tasks(condition, tasks); +// // executor.spawn(ws::process(acceptor)).detach(); +// } -pub fn start( - executor: &'static mut Executor, - tasks: heapless::Vec, C>, - finished: F, -) where - M: Monitor + Start + Default, - F: FnOnce() + 'static, -{ - executor.start(move || !super::quit::QUIT.triggered(), { - let executor = &*executor; +// pub fn start(executor: &LocalExecutor<'a, C>, finished: F) +// where +// M: Monitor + Start + Default, +// F: FnOnce() + 'static, +// { +// executor.start(move || !super::quit::QUIT.triggered(), { +// let executor = &*executor; - move || { - executor.drop_tasks(tasks); +// move || { +// executor.drop_tasks(tasks); - finished(); - } - }); -} +// finished(); +// } +// }); +// } diff --git a/rued-esp32/src/core/internal/ws.rs b/rued-esp32/src/core/internal/ws.rs index bfa3485..2434c95 100644 --- a/rued-esp32/src/core/internal/ws.rs +++ b/rued-esp32/src/core/internal/ws.rs @@ -43,25 +43,13 @@ impl ws::AcceptorHandler for WebHandler { type ReceiveData = WebRequest; - type HandleFuture<'a, S, R> = impl Future> + 'a + async fn handle(&self, sender: S, receiver: R, index: usize) -> Result<(), S::Error> where - Self: 'a, - S: Sender + 'a, - R: Receiver> + 'a, - S::Error: core::fmt::Debug + 'a; - - fn handle<'a, S, R>( - &'a self, - sender: S, - receiver: R, - index: usize, - ) -> Self::HandleFuture<'a, S, R> - where - S: Sender + 'a, - R: Receiver> + 'a, - S::Error: core::fmt::Debug + 'a, + S: Sender, + R: Receiver>, + S::Error: core::fmt::Debug, { - async move { web::handle(sender, receiver, &HANDLERS_BATTERY_STATE_NOTIF[index]).await } + web::handle(sender, receiver, &HANDLERS_BATTERY_STATE_NOTIF[index]).await } } diff --git a/rued-esp32/src/errors.rs b/rued-esp32/src/errors.rs index 935530c..a3d735e 100644 --- a/rued-esp32/src/errors.rs +++ b/rued-esp32/src/errors.rs @@ -2,10 +2,12 @@ use std::error::Error as StdError; use std::fmt; use std::io::Error as IoError; -use edge_executor::SpawnError; -use esp_idf_hal::i2c::I2cError; -use esp_idf_svc::errors::EspIOError; -use esp_idf_sys::EspError; +// use edge_executor::SpawnError; +use futures::task::SpawnError; + +use esp_idf_svc::hal::i2c::I2cError; +use esp_idf_svc::io::EspIOError; +use esp_idf_svc::sys::EspError; pub type BoxError = Box; @@ -136,8 +138,8 @@ impl StdError for BlanketError { } } -impl From for BlanketError { - fn from(error: esp_idf_sys::EspError) -> Self { +impl From for BlanketError { + fn from(error: EspError) -> Self { Self { inner: error.into(), } diff --git a/rued-esp32/src/httpd.rs b/rued-esp32/src/httpd.rs index b10ef7e..9ff1082 100644 --- a/rued-esp32/src/httpd.rs +++ b/rued-esp32/src/httpd.rs @@ -14,7 +14,7 @@ use embedded_svc::{ utils::{asyncify::ws::server::Processor, mutex::RawCondvar}, ws::asynch::server::Acceptor, }; -use esp_idf_hal::task::embassy_sync::EspRawMutex; +use esp_idf_svc::hal::task::embassy_sync::EspRawMutex; use esp_idf_svc::http::server::{ fn_handler, ws::{EspHttpWsConnection, EspHttpWsProcessor}, diff --git a/rued-esp32/src/main.rs b/rued-esp32/src/main.rs index 22461c0..7f2688c 100644 --- a/rued-esp32/src/main.rs +++ b/rued-esp32/src/main.rs @@ -1,15 +1,23 @@ +#![allow(stable_features)] +#![allow(unknown_lints)] +#![feature(async_fn_in_trait)] +#![allow(async_fn_in_trait)] +#![feature(impl_trait_projections)] +#![feature(impl_trait_in_assoc_type)] #![feature(type_alias_impl_trait)] #![allow(dead_code, unused_variables, unused_imports)] +#![feature(generic_arg_infer)] extern crate alloc; // use ::core::time::Duration; +use crate::core::internal::quit; use anyhow::{Error, Result}; use chrono::{naive::NaiveDate, offset::Utc, DateTime, Datelike, NaiveDateTime, Timelike}; use http::{header::SEC_WEBSOCKET_ACCEPT, StatusCode}; use log::{debug, error, info, warn}; use peripherals::{ButtonsPeripherals, PulseCounterPeripherals, SPI_BUS_FREQ}; -use rv8803_rs::{i2c0::Bus as I2cBus, Rv8803, Rv8803Bus, TIME_ARRAY_LENGTH}; +use rv8803::{i2c0::Bus as I2cBus, Rv8803, Rv8803Bus, TIME_ARRAY_LENGTH}; use serde::{Deserialize, Serialize}; use serde_json::json; use shared_bus::{BusManager, I2cProxy}; @@ -31,34 +39,49 @@ use std::{ use embedded_hal_0_2::prelude::_embedded_hal_blocking_i2c_WriteRead; use embedded_hal_0_2::{prelude::_embedded_hal_blocking_i2c_Write, PwmPin}; -use esp_idf_hal::{ - delay::FreeRtos, - i2c::I2cError, - ledc::{LedcDriver, LedcTimerDriver}, - peripheral::Peripheral, -}; -use esp_idf_hal::{ - i2c::{config::Config as I2cConfig, I2cDriver, I2C0}, - ledc::config::TimerConfig, - units::{FromValueType, Hertz}, -}; +// use esp_idf_hal::{ +// delay::FreeRtos, +// i2c::I2cError, +// ledc::{LedcDriver, LedcTimerDriver}, +// peripheral::Peripheral, +// }; +// use esp_idf_hal::{ +// i2c::{config::Config as I2cConfig, I2cDriver, I2C0}, +// ledc::config::TimerConfig, +// units::{FromValueType, Hertz}, +// }; + use esp_idf_svc::{ + hal::{ + adc::{AdcConfig, AdcDriver}, + delay::FreeRtos, + gpio::{self, DriveStrength, Gpio5, PinDriver, RTCPin}, + i2c::{I2cConfig, I2cDriver}, + interrupt::InterruptType, + ledc::{config::TimerConfig, LedcDriver, LedcTimerDriver}, + modem::Modem, + peripheral::Peripheral, + spi::{SpiConfig, SpiDeviceDriver, SpiDriver}, + units::{FromValueType, Hertz}, + }, http::server::ws::EspHttpWsProcessor, log::EspLogger, + netif::IpEvent, sntp::{self, EspSntp, OperatingMode, SntpConf, SyncMode, SyncStatus}, + wifi::{EspWifi, WifiEvent}, }; -use esp_idf_sys::{self as _, esp_ota_mark_app_valid_cancel_rollback}; -#[allow(unused_imports)] -use esp_idf_sys::{ - self as _, esp_wifi_connect, esp_wifi_set_ps, settimeofday, sntp_get_sync_status, sntp_init, - sntp_restart, sntp_set_sync_interval, sntp_set_time_sync_notification_cb, sntp_stop, time_t, - timeval, timezone, wifi_ps_type_t_WIFI_PS_NONE, -}; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported +// use esp_idf_svc::{self as _, esp_ota_mark_app_valid_cancel_rollback}; +// #[allow(unused_imports)] +// use esp_idf_svc::{ +// self as _, esp_wifi_connect, esp_wifi_set_ps, settimeofday, sntp_get_sync_status, sntp_init, +// sntp_restart, sntp_set_sync_interval, sntp_set_time_sync_notification_cb, sntp_stop, time_t, +// timeval, timezone, wifi_ps_type_t_WIFI_PS_NONE, +// }; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported use embedded_svc::{ http::{ - server::{Connection, Io, Request, Response}, + server::{Connection, Request, Response}, Method, Query, }, io::Read, @@ -66,39 +89,34 @@ use embedded_svc::{ wifi::{self, AuthMethod, ClientConfiguration, Wifi}, ws::server::Acceptor, }; -use esp_idf_hal::modem::Modem; -use esp_idf_svc::{ - netif::IpEvent, - wifi::{EspWifi, WifiEvent, WifiWait}, -}; + +use edge_executor::LocalExecutor; use embassy_sync::blocking_mutex::raw::RawMutex; #[cfg(feature = "nvs")] use embassy_sync::blocking_mutex::Mutex as EmbassyMutex; use embassy_time::Duration; -use esp_idf_hal::task::embassy_sync::EspRawMutex; #[cfg(feature = "nvs")] use embedded_svc::storage::Storage; -use esp_idf_hal::adc::*; -use esp_idf_hal::gpio::*; -use esp_idf_hal::reset::WakeupReason; -use esp_idf_hal::spi::config::Duplex; -use esp_idf_hal::spi::*; -use esp_idf_hal::task::executor::EspExecutor; -use esp_idf_hal::task::thread::ThreadSpawnConfiguration; +use esp_idf_svc::hal::adc::attenuation; +use esp_idf_svc::hal::gpio::*; +use esp_idf_svc::hal::reset::WakeupReason; +use esp_idf_svc::hal::task::block_on; +use esp_idf_svc::hal::task::thread::ThreadSpawnConfiguration; use esp_idf_svc::eventloop::EspSystemEventLoop; use esp_idf_svc::nvs::EspDefaultNvsPartition; +use esp_idf_svc::sys::esp; +use esp_idf_svc::timer::EspTaskTimerService; + use channel_bridge::{ asynch::Receiver as AsynchReceiver, asynch::{pubsub, Sender as AsyncSender}, }; -use esp_idf_sys::esp; - use crate::{ core::internal::{ external_rtc, keepalive, pwm, spawn, @@ -121,7 +139,9 @@ mod services; /// /// # Safety -pub unsafe extern "C" fn sntp_set_time_sync_notification_cb_custom(tv: *mut timeval) { +pub unsafe extern "C" fn sntp_set_time_sync_notification_cb_custom( + tv: *mut esp_idf_svc::sys::timeval, +) { let naive_dt_opt = NaiveDateTime::from_timestamp_opt((*tv).tv_sec as i64, 0); let naive_dt = if let Some(value) = naive_dt_opt { value @@ -157,11 +177,6 @@ pub unsafe extern "C" fn sntp_set_time_sync_notification_cb_custom(tv: *mut time pub fn sntp_sync_callback(time: ::core::time::Duration) {} -pub enum SysLoopMsg { - WifiDisconnect, - IpAddressAcquired, -} - const CURRENT_YEAR: u16 = 2022; const MQTT_MAX_TOPIC_LEN: usize = 64; const SLEEP_TIME: Duration = Duration::from_secs(5); @@ -173,12 +188,11 @@ static LOGGER: EspLogger = EspLogger; // Make sure that the firmware will contain // up-to-date build time and package info coming from the binary crate -esp_idf_sys::esp_app_desc!(); +esp_idf_svc::sys::esp_app_desc!(); fn main() -> Result<(), InitError> { - esp_idf_hal::task::critical_section::link(); + esp_idf_svc::hal::task::critical_section::link(); esp_idf_svc::timer::embassy_time::driver::link(); - esp_idf_svc::timer::embassy_time::queue::link(); let wakeup_reason = WakeupReason::get(); @@ -195,7 +209,7 @@ fn main() -> Result<(), InitError> { } fn init() -> Result<(), InitError> { - esp_idf_sys::link_patches(); + esp_idf_svc::sys::link_patches(); // Bind the log crate to the ESP Logging facilities // esp_idf_svc::log::EspLogger::initialize_default(); @@ -208,7 +222,7 @@ fn init() -> Result<(), InitError> { esp!(unsafe { #[allow(clippy::needless_update)] - esp_idf_sys::esp_vfs_eventfd_register(&esp_idf_sys::esp_vfs_eventfd_config_t { + esp_idf_svc::sys::esp_vfs_eventfd_register(&esp_idf_svc::sys::esp_vfs_eventfd_config_t { max_fds: 5, ..Default::default() }) @@ -220,18 +234,19 @@ fn init() -> Result<(), InitError> { fn sleep() -> Result<(), InitError> { unsafe { #[cfg(feature = "ulp")] - esp!(esp_idf_sys::esp_sleep_enable_ulp_wakeup())?; + esp!(esp_idf_svc::sys::esp_sleep_enable_ulp_wakeup())?; - esp!(esp_idf_sys::esp_sleep_enable_timer_wakeup( + esp!(esp_idf_svc::sys::esp_sleep_enable_timer_wakeup( SLEEP_TIME.as_micros() as u64 ))?; log::info!("Going to sleep"); - esp_idf_sys::esp_deep_sleep_start(); + esp_idf_svc::sys::esp_deep_sleep_start(); } - // unreachable + #[allow(unreachable_code)] + Ok(()) } fn run(wakeup_reason: WakeupReason) -> Result<(), InitError> { @@ -266,6 +281,7 @@ fn run(wakeup_reason: WakeupReason) -> Result<(), InitError> { let nvs_default_partition = EspDefaultNvsPartition::take()?; let sysloop = EspSystemEventLoop::take()?; + let timer_service = EspTaskTimerService::new()?; // Storage @@ -308,16 +324,20 @@ fn run(wakeup_reason: WakeupReason) -> Result<(), InitError> { let sntp = sntp::EspSntp::new(&sntp_conf)?; - unsafe { - // stop the sntp instance to redefine the callback - // https://github.com/esp-rs/esp-idf-svc/blob/v0.42.5/src/sntp.rs#L155-L158 - sntp_stop(); + // FIXME + // NOTE upgrade + // unsafe { + // // stop the sntp instance to redefine the callback + // // https://github.com/esp-rs/esp-idf-svc/blob/v0.42.5/src/sntp.rs#L155-L158 + // esp_idf_svc::sys::sntp_stop(); - // redefine and restart the callback. - sntp_set_time_sync_notification_cb(Some(sntp_set_time_sync_notification_cb_custom)); + // // redefine and restart the callback. + // esp_idf_svc::sys::sntp_set_time_sync_notification_cb(Some( + // esp_idf_svc::sys::sntp_set_time_sync_notification_cb_custom, + // )); - sntp_init() - }; + // esp_idf_svc::sys::sntp_init() + // }; // FIXME enable in v0.46.0 // https://github.com/esp-rs/esp-idf-svc/pull/207 @@ -328,6 +348,7 @@ fn run(wakeup_reason: WakeupReason) -> Result<(), InitError> { let (wifi, wifi_notif) = services::wifi( peripherals.modem, sysloop.clone(), + timer_service, Some(nvs_default_partition), AuthMethod::default(), )?; @@ -362,24 +383,11 @@ fn run(wakeup_reason: WakeupReason) -> Result<(), InitError> { let config = TimerConfig::new().frequency(500.Hz().into()); let timer = Arc::new(LedcTimerDriver::new(peripherals.timer0.0, &config)?); - let channel0 = LedcDriver::new( - peripherals.ledc0.chan, - timer.clone(), - peripherals.ledc0.pin, - &config, - )?; - let channel1 = LedcDriver::new( - peripherals.ledc1.chan, - timer.clone(), - peripherals.ledc1.pin, - &config, - )?; - let channel2 = LedcDriver::new( - peripherals.ledc2.chan, - timer, - peripherals.ledc2.pin, - &config, - )?; + let channel0 = + LedcDriver::new(peripherals.ledc0.chan, timer.clone(), peripherals.ledc0.pin)?; + let channel1 = + LedcDriver::new(peripherals.ledc1.chan, timer.clone(), peripherals.ledc1.pin)?; + let channel2 = LedcDriver::new(peripherals.ledc2.chan, timer, peripherals.ledc2.pin)?; Some((channel0, channel1, channel2)) }; @@ -423,7 +431,10 @@ fn run(wakeup_reason: WakeupReason) -> Result<(), InitError> { )?; let sdmmc_cs = PinDriver::output(peripherals.sd_card.cs)?; - let sdmmc_spi = embedded_sdmmc::SdMmcSpi::new(sdmmc_spi, sdmmc_cs); + + // FIXME + // NOTE upgrade + // let sdmmc_spi = embedded_sdmmc::SdMmcSpi::new(sdmmc_spi, sdmmc_cs); // High-prio tasks @@ -437,19 +448,24 @@ fn run(wakeup_reason: WakeupReason) -> Result<(), InitError> { #[cfg(feature = "display-spi")] let display = { services::display(peripherals.display, peripherals.spi1).unwrap() }; - let mut high_prio_executor = EspExecutor::<16, _>::new(); - let mut high_prio_tasks = heapless::Vec::<_, 16>::new(); + let mut high_prio_executor = LocalExecutor::<16>::new(); + + let battery_voltage = services::adc::<{ attenuation::NONE }, _, _>( + peripherals.battery.adc, + peripherals.battery.voltage, + ) + .expect("Reads battery pin"); + + // TODO: Move off the main thread, as it has a fixed, low priority (1) spawn::high_prio( &mut high_prio_executor, - &mut high_prio_tasks, services::button( peripherals.buttons.button1, &core::internal::button::BUTTON1_PIN_EDGE, )?, - AdcDriver::new(peripherals.battery.adc, &AdcConfig::new().calibration(true))?, - AdcChannelDriver::<_, Atten0dB<_>>::new(peripherals.battery.voltage)?, + battery_voltage, PinDriver::input(peripherals.battery.power)?, - display, + // display, (wifi, wifi_notif), &mut httpd, Some(ws_acceptor), @@ -463,7 +479,7 @@ fn run(wakeup_reason: WakeupReason) -> Result<(), InitError> { mqtt_topic_prefix, mqtt_client, mqtt_conn, - )?; + ); // Mid-prio tasks @@ -473,75 +489,65 @@ fn run(wakeup_reason: WakeupReason) -> Result<(), InitError> { name: Some(b"async-exec-mid\0"), ..Default::default() } - .set()?; + .set() + .unwrap(); // // let display_peripherals = peripherals.display_i2c; // // let proxy = display_peripherals.bus.bus.acquire_i2c(); - let mid_prio_execution = services::schedule::<8, _>(50000, move || { - let mut executor = EspExecutor::new(); - let mut tasks = heapless::Vec::new(); + let mid_prio_execution = services::schedule::<8>(50000, quit::QUIT[1].wait(), move || { + let executor = LocalExecutor::new(); spawn::mid_prio( - &mut executor, - &mut tasks, - // services::display(display_peripherals) - // .expect("Return display service to the mid_prio executor"), - + &executor, + display, // move |_new_state| { // #[cfg(feature = "nvs")] // flash_wm_state(storage, _new_state); // }, - )?; + ); // spawn::wifi(&mut executor, &mut tasks, wifi, wifi_notif)?; - // spawn::mqtt_receive(&mut executor, &mut tasks, mqtt_conn)?; - Ok((executor, tasks)) + executor }); // Low-prio tasks - // log::info!("Starting low-prio executor"); - - // ThreadSpawnConfiguration { - // name: Some(b"async-exec-low\0"), - // ..Default::default() - // } - // .set()?; + log::info!("Starting low-prio executor"); - // let low_prio_execution = services::schedule::<4, _>(50000, move || { - // let mut executor = EspExecutor::new(); - // let mut tasks = heapless::Vec::new(); + ThreadSpawnConfiguration { + name: Some(b"async-exec-low\0"), + ..Default::default() + } + .set() + .unwrap(); - // // spawn::mqtt_send::( - // // &mut executor, - // // &mut tasks, - // // mqtt_topic_prefix, - // // mqtt_client, - // // )?; + let low_prio_execution = services::schedule::<4>(50000, quit::QUIT[2].wait(), move || { + let executor = LocalExecutor::new(); - // // spawn::ws(&mut executor, &mut tasks, ws_acceptor)?; + // spawn::mqtt_send::(&executor, mqtt_topic_prefix, mqtt_client); + // spawn::ws(&executor, ws_acceptor); - // Ok((executor, tasks)) - // }); + executor + }); // Start main execution log::info!("Starting high-prio executor"); - spawn::run(&mut high_prio_executor, high_prio_tasks); + block_on(high_prio_executor.run(crate::core::internal::quit::QUIT[0].wait())); log::info!("Execution finished, waiting for 2s to workaround a STD/ESP-IDF pthread (?) bug"); // This is required to allow the low prio thread to start std::thread::sleep(crate::StdDuration::from_millis(2000)); mid_prio_execution.join().unwrap(); - // low_prio_execution.join().unwrap(); + low_prio_execution.join().unwrap(); - log::info!("all tasks running"); + log::info!("Finished execution"); - unreachable!() + Ok(()) } #[inline(always)] @@ -578,7 +584,7 @@ pub async fn process_netif_state_change( // if an IP address has been succesfully assigned we consider // the application working, no rollback required. - unsafe { esp_ota_mark_app_valid_cancel_rollback() }; + unsafe { esp_idf_svc::sys::esp_ota_mark_app_valid_cancel_rollback() }; let mut publisher = NETWORK_EVENT_CHANNEL.publisher().unwrap(); let _ = publisher @@ -597,7 +603,7 @@ pub async fn process_netif_state_change( // NOTE: Start SNTP log::info!("Starting SNTP"); unsafe { - sntp_restart(); + esp_idf_svc::sys::sntp_restart(); } } _ => { @@ -664,31 +670,31 @@ fn mark_wakeup_pins( #[cfg(not(feature = "ulp"))] { // Enable power for RTC IO, sensors and ULP co-processor during Deep-sleep - esp!(esp_idf_sys::esp_sleep_pd_config( - esp_idf_sys::esp_sleep_pd_domain_t_ESP_PD_DOMAIN_RTC_PERIPH, - esp_idf_sys::esp_sleep_pd_option_t_ESP_PD_OPTION_ON + esp!(esp_idf_svc::sys::esp_sleep_pd_config( + esp_idf_svc::sys::esp_sleep_pd_domain_t_ESP_PD_DOMAIN_RTC_PERIPH, + esp_idf_svc::sys::esp_sleep_pd_option_t_ESP_PD_OPTION_ON ))?; } #[cfg(esp32c3)] #[cfg(not(feature = "ulp"))] { // Enable power for RTC IO, sensors and ULP co-processor during Deep-sleep - esp!(esp_idf_sys::esp_sleep_pd_config( - esp_idf_sys::esp_sleep_pd_domain_t_ESP_PD_DOMAIN_CPU, - esp_idf_sys::esp_sleep_pd_option_t_ESP_PD_OPTION_ON + esp!(esp_idf_svc::sys::esp_sleep_pd_config( + esp_idf_svc::sys::esp_sleep_pd_domain_t_ESP_PD_DOMAIN_CPU, + esp_idf_svc::sys::esp_sleep_pd_option_t_ESP_PD_OPTION_ON ))?; } #[cfg(any(esp32, esp32s2, esp32s3))] - esp!(esp_idf_sys::esp_sleep_enable_ext1_wakeup( + esp!(esp_idf_svc::sys::esp_sleep_enable_ext1_wakeup( mask, - esp_idf_sys::esp_sleep_ext1_wakeup_mode_t_ESP_EXT1_WAKEUP_ALL_LOW, + esp_idf_svc::sys::esp_sleep_ext1_wakeup_mode_t_ESP_EXT1_WAKEUP_ALL_LOW, ))?; #[cfg(not(any(esp32, esp32s2, esp32s3)))] - esp!(esp_idf_sys::esp_deep_sleep_enable_gpio_wakeup( + esp!(esp_idf_svc::sys::esp_deep_sleep_enable_gpio_wakeup( mask, - esp_idf_sys::esp_deepsleep_gpio_wake_up_mode_t_ESP_GPIO_WAKEUP_GPIO_LOW, + esp_idf_svc::sys::esp_deepsleep_gpio_wake_up_mode_t_ESP_GPIO_WAKEUP_GPIO_LOW, ))?; } @@ -697,7 +703,7 @@ fn mark_wakeup_pins( fn toggle_led

(driver: &mut P) where - P: esp_idf_hal::gpio::Pin + embedded_hal::digital::ToggleableOutputPin, + P: esp_idf_svc::hal::gpio::Pin + embedded_hal::digital::ToggleableOutputPin, { driver.toggle().unwrap(); diff --git a/rued-esp32/src/models.rs b/rued-esp32/src/models.rs index 7a4d8eb..734000b 100644 --- a/rued-esp32/src/models.rs +++ b/rued-esp32/src/models.rs @@ -1,11 +1,12 @@ use anyhow::{Error, Result}; use chrono::{naive::NaiveDate, offset::Utc, DateTime, Datelike}; -use esp_idf_hal::i2c::{I2cDriver, I2cError}; -use esp_idf_sys::settimeofday; -use esp_idf_sys::timeval; -use esp_idf_sys::timezone; +use esp_idf_svc::hal::i2c::{I2cDriver, I2cError}; +use esp_idf_svc::sys::settimeofday; +use esp_idf_svc::sys::time; +use esp_idf_svc::sys::timeval; +use esp_idf_svc::sys::timezone; use log::{debug, info, warn}; -use rv8803_rs::{i2c0::Bus as I2cBus, Rv8803, TIME_ARRAY_LENGTH}; +use rv8803::{i2c0::Bus as I2cBus, Rv8803, TIME_ARRAY_LENGTH}; use serde::Deserialize; use serde::Serialize; use shared_bus::{BusManager, I2cProxy}; @@ -84,7 +85,7 @@ where + embedded_hal_0_2::blocking::i2c::WriteRead, { pub fn new(bus_manager: &'a BusManager>>) -> Result { - let address = rv8803_rs::i2c0::Address::Default; + let address = rv8803::i2c0::Address::Default; let rtc = Rv8803::from_i2c0(bus_manager.acquire_i2c(), address)?; Ok(Self { @@ -97,7 +98,7 @@ where pub fn rtc(&self) -> Result>>>>> { let proxy = self.bus_manager.acquire_i2c(); - let bus = rv8803_rs::i2c0::Bus::new(proxy, rv8803_rs::i2c0::Address::Default); + let bus = rv8803::i2c0::Bus::new(proxy, rv8803::i2c0::Address::Default); Ok(Rv8803::new(bus)?) } @@ -335,7 +336,7 @@ pub(crate) mod rtc_external { use crate::UTC_OFFSET_CHRONO; use chrono::{offset::Utc, DateTime, Datelike, NaiveDateTime, Timelike}; - use esp_idf_sys::time_t; + use esp_idf_svc::sys::time_t; type I2cDriverType<'a> = I2cDriver<'a>; @@ -361,7 +362,7 @@ pub(crate) mod rtc_external { pub(crate) unsafe fn get_system_time() -> Result { let timer: *mut time_t = ptr::null_mut(); - let mut timestamp = esp_idf_sys::time(timer); + let mut timestamp = esp_idf_svc::sys::time(timer); // NOTE: Handle system time providing a wierdly large value, // > Friday, 1 January 2100 00:00:00 diff --git a/rued-esp32/src/peripherals.rs b/rued-esp32/src/peripherals.rs index 01adc20..06e72b4 100644 --- a/rued-esp32/src/peripherals.rs +++ b/rued-esp32/src/peripherals.rs @@ -1,16 +1,9 @@ use std::marker::PhantomData; -use esp_idf_hal::adc::*; -use esp_idf_hal::gpio::*; -use esp_idf_hal::i2c::*; -use esp_idf_hal::ledc::CHANNEL0; -use esp_idf_hal::ledc::CHANNEL1; -use esp_idf_hal::ledc::CHANNEL2; -use esp_idf_hal::ledc::TIMER0; -use esp_idf_hal::modem::Modem; -use esp_idf_hal::peripherals::Peripherals; -use esp_idf_hal::spi::*; -use esp_idf_hal::units::Hertz; +use esp_idf_svc::hal::{ + adc::*, gpio::*, i2c::*, interrupt::InterruptType, ledc::*, modem::Modem, + peripherals::Peripherals, spi::*, units::Hertz, +}; use shared_bus::{BusManager, NullMutex}; pub const NO_PIN: Option = None; diff --git a/rued-esp32/src/services.rs b/rued-esp32/src/services.rs index 6a7b275..081abd4 100644 --- a/rued-esp32/src/services.rs +++ b/rued-esp32/src/services.rs @@ -10,39 +10,53 @@ extern crate alloc; use embassy_sync::blocking_mutex::Mutex; use embassy_time::Duration; +use embedded_hal::digital::OutputPin as EHOutputPin; + use embedded_hal::spi::SpiDevice; -use embedded_hal_0_2::digital::v2::OutputPin as EHOutputPin; +use esp_idf_svc::tls; use embedded_svc::http::server::Method; use embedded_svc::mqtt::client::asynch::{Client, Connection, Publish}; -use embedded_svc::utils::asyncify::ws::server::Processor; use embedded_svc::utils::asyncify::Asyncify; -use embedded_svc::utils::mutex::RawCondvar; -use embedded_svc::wifi::{AuthMethod, ClientConfiguration, Configuration, Wifi}; +use embedded_svc::wifi::asynch::Wifi; +use embedded_svc::wifi::{AuthMethod, ClientConfiguration, Configuration}; use embedded_svc::ws::asynch::server::Acceptor; -use esp_idf_hal::delay; -use esp_idf_hal::delay::FreeRtos; -use esp_idf_hal::gpio::*; -use esp_idf_hal::i2c::{I2c, I2cConfig, I2cDriver}; -use esp_idf_hal::modem::WifiModemPeripheral; -use esp_idf_hal::peripheral::Peripheral; -use esp_idf_hal::prelude::*; -use esp_idf_hal::reset::WakeupReason; -use esp_idf_hal::spi::config::Duplex; -use esp_idf_hal::spi::*; -use esp_idf_hal::task::embassy_sync::EspRawMutex; - use esp_idf_svc::eventloop::EspSystemEventLoop; -use esp_idf_svc::http::server::ws::{EspHttpWsConnection, EspHttpWsProcessor}; +use esp_idf_svc::hal::adc::{Adc, AdcChannelDriver, AdcConfig, AdcDriver}; +use esp_idf_svc::hal::delay; +use esp_idf_svc::hal::delay::FreeRtos; +use esp_idf_svc::hal::gpio::*; +use esp_idf_svc::hal::modem::WifiModemPeripheral; +use esp_idf_svc::hal::peripheral::Peripheral; +use esp_idf_svc::hal::prelude::*; +use esp_idf_svc::hal::reset::WakeupReason; +use esp_idf_svc::hal::spi::*; +use esp_idf_svc::hal::task::embassy_sync::EspRawMutex; + +use esp_idf_svc::http::server::ws::EspHttpWsProcessor; use esp_idf_svc::http::server::EspHttpServer; use esp_idf_svc::mqtt::client::{EspMqttClient, MqttClientConfiguration}; -use esp_idf_svc::netif::IpEvent; use esp_idf_svc::nvs::EspDefaultNvsPartition; -use esp_idf_svc::tls; -use esp_idf_svc::wifi::{EspWifi, WifiEvent, WifiWait}; - -use esp_idf_sys::{esp, esp_restart, EspError}; +use esp_idf_svc::timer::EspTaskTimerService; +use esp_idf_svc::wifi::{AsyncWifi, BlockingWifi, EspWifi}; + +use esp_idf_svc::sys::{adc_atten_t, EspError}; + +// use esp_idf_hal::gpio::*; +// use esp_idf_hal::i2c::{I2c, I2cConfig, I2cDriver}; +// use esp_idf_hal::modem::WifiModemPeripheral; +// use esp_idf_hal::peripheral::Peripheral; +// use esp_idf_hal::prelude::*; +// use esp_idf_hal::reset::WakeupReason; +// use esp_idf_hal::spi::config::Duplex; +// use esp_idf_hal::spi::*; +// use esp_idf_hal::task::embassy_sync::EspRawMutex; +// use esp_idf_svc::hal::delay; +// use esp_idf_svc::hal::delay::FreeRtos; + +use futures::task::SpawnError; +use futures::Future; use gfx_xtra::draw_target::{Flushable, OwnedDrawTargetExt}; @@ -233,8 +247,10 @@ pub fn pulse( pub fn button<'d, P: InputPin + OutputPin>( pin: impl Peripheral

+ 'd, notification: &'static Notification, -) -> Result + 'd, InitError> { - subscribe_pin(pin, move || notification.notify()) +) -> Result { + let resp = subscribe_pin(pin, move || notification.notify())?; + + Ok(resp) } #[cfg(feature = "display-i2c")] @@ -367,12 +383,20 @@ pub fn display<'a>( Ok(display) } +// TODO: Make it async pub fn wifi<'d>( modem: impl Peripheral

+ 'd, - mut sysloop: EspSystemEventLoop, + sysloop: EspSystemEventLoop, + timer_service: EspTaskTimerService, partition: Option, auth_method: AuthMethod, -) -> Result<(EspWifi<'d>, impl Receiver), InitError> { +) -> Result< + ( + impl embedded_svc::wifi::asynch::Wifi + 'd, + impl Receiver, + ), + InitError, +> { let mut wifi = EspWifi::new(modem, sysloop.clone(), partition)?; if WIFI_PSK.is_empty() { @@ -390,23 +414,15 @@ pub fn wifi<'d>( }))?; } - let wait = WifiWait::new(&sysloop)?; + let mut bwifi = BlockingWifi::wrap(&mut wifi, sysloop.clone())?; - wifi.start()?; + bwifi.start()?; - let started = wait.wait_with_timeout(WIFI_START_TIMEOUT, || wifi.is_started().unwrap()); - if !started { - log::warn!("Wifi failed to start, restarting."); - unsafe { - esp_restart(); - } - } + bwifi.connect()?; - wifi.connect()?; + bwifi.wait_netif_up()?; - // if !PASS.is_empty() { - // wait.wait(|| wifi.is_connected().unwrap()); - // } + let wifi = AsyncWifi::wrap(wifi, sysloop, timer_service)?; Ok(( wifi, @@ -414,12 +430,12 @@ pub fn wifi<'d>( )) } -pub fn httpd() -> Result { +pub fn httpd() -> Result, InitError> { let server_certificate = tls::X509::pem_until_nul(include_bytes!( - "/home/mdesilva/esp/openssl-generate-rs/output/cert.pem" + "/home/mike/esp/openssl-generate-rs/output/cert.pem" )); let server_private_key = tls::X509::pem_until_nul(include_bytes!( - "/home/mdesilva/esp/openssl-generate-rs/output/cert_key.pem" + "/home/mike/esp/openssl-generate-rs/output/cert_key.pem" )); let mut config = esp_idf_svc::http::server::Configuration::default(); @@ -431,11 +447,11 @@ pub fn httpd() -> Result { Ok(httpd) } -pub fn mqtt() -> Result< +pub fn mqtt<'a>() -> Result< ( &'static str, impl Client + Publish, - impl Connection>, + impl Connection = Option>, ), InitError, > { @@ -456,10 +472,42 @@ pub fn mqtt() -> Result< Ok((client_id, mqtt_client, mqtt_conn)) } +pub fn adc<'d, const A: adc_atten_t, ADC: Adc + 'd, P: ADCPin>( + adc: impl Peripheral

+ 'd, + pin: impl Peripheral

+ 'd, +) -> Result { + struct AdcImpl<'d, const A: adc_atten_t, ADC, V> + where + ADC: Adc, + V: ADCPin, + { + driver: AdcDriver<'d, ADC>, + channel_driver: AdcChannelDriver<'d, A, V>, + } + + impl<'d, const A: adc_atten_t, ADC, V> crate::core::internal::battery::Adc + for AdcImpl<'d, A, ADC, V> + where + ADC: Adc, + V: ADCPin, + { + type Error = esp_idf_svc::sys::EspError; + + async fn read(&mut self) -> Result { + self.driver.read(&mut self.channel_driver) + } + } + + Ok(AdcImpl { + driver: AdcDriver::new(adc, &AdcConfig::new().calibration(true))?, + channel_driver: AdcChannelDriver::<{ A }, _>::new(pin)?, + }) +} + fn subscribe_pin<'d, P: InputPin + OutputPin>( pin: impl Peripheral

+ 'd, notify: impl Fn() + Send + 'static, -) -> Result + 'd, InitError> { +) -> Result { let mut pin = PinDriver::input(pin)?; pin.set_interrupt_type(InterruptType::NegEdge)?; @@ -471,26 +519,22 @@ fn subscribe_pin<'d, P: InputPin + OutputPin>( Ok(pin) } -pub fn schedule<'a, const C: usize, M>( +pub fn schedule<'a, const C: usize>( stack_size: usize, - spawner: impl FnOnce() -> Result<(Executor<'a, C, M, Local>, heapless::Vec, C>), SpawnError> - + Send - + 'static, -) -> std::thread::JoinHandle<()> -where - M: Monitor + Wait + Default, -{ + run: impl Future + Send + 'static, + spawner: impl FnOnce() -> LocalExecutor<'a, C> + Send + 'static, +) -> std::thread::JoinHandle<()> { std::thread::Builder::new() .stack_size(stack_size) .spawn(move || { - let (mut executor, tasks) = spawner().unwrap(); + let executor = spawner(); // info!( // "Tasks on thread {:?} scheduled, about to run the executor now", // "TODO" // ); - super::spawn::run(&mut executor, tasks); + block_on(executor.run(run)); }) .unwrap() } diff --git a/rued-esp32/src/services/httpd.rs b/rued-esp32/src/services/httpd.rs index 59fb331..5726384 100644 --- a/rued-esp32/src/services/httpd.rs +++ b/rued-esp32/src/services/httpd.rs @@ -3,12 +3,12 @@ use std::rc::Rc; use esp_idf_svc::http::server::{Configuration, EspHttpServer}; -pub struct LazyInitHttpServer { - data: Rc>>, +pub struct LazyInitHttpServer<'a> { + data: Rc>>>, config: Configuration, } -impl LazyInitHttpServer { +impl LazyInitHttpServer<'_> { pub fn new(config: Configuration) -> Self { Self { data: Rc::new(RefCell::new(None)), From ca946312a2a9743f03b1043488270fca273195a4 Mon Sep 17 00:00:00 2001 From: Michael de Silva Date: Thu, 14 Dec 2023 11:13:17 +0530 Subject: [PATCH 04/11] First working compile; FIXME httpd needs revising --- Cargo.toml | 1 - rued-esp32/Cargo.toml | 14 +- rued-esp32/src/core/internal/battery.rs | 6 +- rued-esp32/src/core/internal/button.rs | 372 ++++++------- rued-esp32/src/core/internal/httpd.rs | 2 +- rued-esp32/src/core/internal/keepalive.rs | 4 +- rued-esp32/src/core/internal/mqtt.rs | 516 +++++++++++++----- rued-esp32/src/core/internal/ota.rs | 4 +- rued-esp32/src/core/internal/pulse_counter.rs | 51 +- rued-esp32/src/core/internal/pwm.rs | 9 +- rued-esp32/src/core/internal/screen.rs | 3 +- rued-esp32/src/core/internal/spawn.rs | 74 +-- rued-esp32/src/core/internal/wifi.rs | 12 +- rued-esp32/src/httpd.rs | 25 +- rued-esp32/src/main.rs | 93 ++-- rued-esp32/src/models.rs | 49 +- rued-esp32/src/mqtt_msg.rs | 218 ++++---- rued-esp32/src/peripherals.rs | 16 +- rued-esp32/src/services.rs | 24 +- rued-esp32/src/services/httpd.rs | 6 +- 20 files changed, 868 insertions(+), 631 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 43cb88b..de8c778 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,6 @@ crossbeam-utils = { git = "https://github.com/crossbeam-rs/crossbeam" } # esp-idf-hal = { git = "https://github.com/esp-rs/esp-idf-hal" } # esp-idf-svc = { git = "https://github.com/esp-rs/esp-idf-svc" } # edge-frame = { git = "https://github.com/ivmarkov/edge-frame" } -# shared-bus = { git = "https://github.com/taks/shared-bus", branch = "embedded-hal-1.0.0-alpha.10" } # shared-bus = { git = "https://github.com/taks/shared-bus" } #socket2 = { git = "https://github.com/esp-rs-compat/socket2" } diff --git a/rued-esp32/Cargo.toml b/rued-esp32/Cargo.toml index 13119e5..60646c5 100644 --- a/rued-esp32/Cargo.toml +++ b/rued-esp32/Cargo.toml @@ -9,7 +9,7 @@ readme = "README.md" rust-version = "1.71" [features] -default = ["edge-executor", "system", "experimental"] # Note that edge-executor requires alloc +default = ["system", "experimental"] # system = ["display-i2c"] system = ["display-spi", "nvs", "external-rtc", "board"] @@ -36,21 +36,21 @@ log = { version = "0.4", features = [ "release_max_level_debug", ] } futures = {version = "0.3", features = ["async-await"] } -serde = { version = "1", default-features = false } +serde = { version = "1", default-features = false, features = ["derive"]} postcard = "0.7" -heapless = "0.8" +heapless = { version = "0.7", features = ["serde"] } critical-section = "1.1" embedded-hal = { version = "1.0.0-rc.1" } embedded-hal-async = "1.0.0-rc.1" embedded-hal-0-2 = { package = "embedded-hal", version = "0.2", features = ["unproven"] } -embedded-svc = { version = "0.26", features = ["nightly", "experimental"] } -esp-idf-svc = { version = "0.47", features = ["nightly", "experimental", "critical-section", "embassy-time-driver"] } +embedded-svc = { version = "0.26", features = ["nightly"] } +esp-idf-svc = { version = "0.47", features = ["nightly", "critical-section", "embassy-time-driver", "embassy-time-isr-queue", "wake-from-isr"] } embassy-futures = { version = "0.1" } embassy-sync = { version = "0.3", features = ["std"] } embassy-time = { version = "0.1" } static_cell = { version = "2" } edge-frame = { version = "0.7", default-features = false, features = ["dto"] } -edge-executor = { version = "0.4", optional = true } +edge-executor = { version = "0.4" } channel-bridge = { version = "0.6", default-features = false, features = ["nightly", "embedded-svc"] } http = "0.2" @@ -72,7 +72,7 @@ embedded-sdmmc = { git = "https://github.com/rust-embedded-community/embedded-sd profont = { version = "0.5", optional = true } ssd1306 = { version = "0.7", optional = true } ssd1351 = { version = "0.4", optional = true } -mipidsi = { git = "https://github.com/almindor/mipidsi", optional = true } +mipidsi = { version = "0.5", optional = true } [build-dependencies] embuild = { version = "0.31", features = ["espidf", "elf"] } diff --git a/rued-esp32/src/core/internal/battery.rs b/rued-esp32/src/core/internal/battery.rs index 511cd78..4f274a2 100644 --- a/rued-esp32/src/core/internal/battery.rs +++ b/rued-esp32/src/core/internal/battery.rs @@ -1,8 +1,8 @@ +use core::fmt::Debug; + use embassy_time::{Duration, Timer}; -use core::fmt::Debug; -use embedded_hal_0_2::adc; -use embedded_hal_0_2::digital::v2::InputPin; +use embedded_hal::digital::InputPin; use super::state::State; diff --git a/rued-esp32/src/core/internal/button.rs b/rued-esp32/src/core/internal/button.rs index 5c5467e..6bbfa72 100644 --- a/rued-esp32/src/core/internal/button.rs +++ b/rued-esp32/src/core/internal/button.rs @@ -2,14 +2,17 @@ use core::fmt::Debug; use core::future::pending; use embassy_time::{Duration, Timer}; +use embedded_hal_async::digital::Wait; use serde::{Deserialize, Serialize}; -use embassy_futures::select::{select, select3, Either, Either3}; +use embassy_futures::select::{select, Either}; -use embedded_hal_0_2::digital::v2::InputPin; +use embedded_hal::digital::InputPin; use channel_bridge::notification::Notification; +use crate::log_err; + #[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub enum PressedLevel { Low, @@ -30,50 +33,27 @@ static BUTTON2_NOTIFY: &[&Notification] = &[]; static BUTTON3_NOTIFY: &[&Notification] = &[]; // &[&crate::screen::BUTTON3_PRESSED_NOTIF]; -pub async fn button1_process(pin: impl InputPin, pressed_level: PressedLevel) { - button_process( - pin, - pressed_level, - &BUTTON1_PIN_EDGE, - "BUTTON1 STATE", - BUTTON1_NOTIFY, - ) - .await; +pub async fn button1_process(pin: impl InputPin + Wait, pressed_level: PressedLevel) { + button_process(pin, pressed_level, "BUTTON1 STATE", BUTTON1_NOTIFY).await; } -pub async fn button2_process(pin: impl InputPin, pressed_level: PressedLevel) { - button_process( - pin, - pressed_level, - &BUTTON2_PIN_EDGE, - "BUTTON2 STATE", - BUTTON2_NOTIFY, - ) - .await; +pub async fn button2_process(pin: impl InputPin + Wait, pressed_level: PressedLevel) { + button_process(pin, pressed_level, "BUTTON2 STATE", BUTTON2_NOTIFY).await; } -pub async fn button3_process(pin: impl InputPin, pressed_level: PressedLevel) { - button_process( - pin, - pressed_level, - &BUTTON3_PIN_EDGE, - "BUTTON3 STATE", - BUTTON3_NOTIFY, - ) - .await; +pub async fn button3_process(pin: impl InputPin + Wait, pressed_level: PressedLevel) { + button_process(pin, pressed_level, "BUTTON3 STATE", BUTTON3_NOTIFY).await; } async fn button_process<'a>( - pin: impl InputPin, + pin: impl InputPin + Wait, pressed_level: PressedLevel, - pin_edge: &'a Notification, pressed_sink_msg: &'a str, pressed_sink: &'a [&'a Notification], ) { process( pin, pressed_level, - pin_edge, Some(Duration::from_millis(50)), pressed_sink_msg, pressed_sink, @@ -82,15 +62,14 @@ async fn button_process<'a>( } pub async fn process<'a>( - mut pin: impl InputPin, + mut pin: impl InputPin + Wait, pressed_level: PressedLevel, - pin_edge: &'a Notification, debounce_duration: Option, pressed_sink_msg: &'a str, pressed_sink: &'a [&'a Notification], ) { loop { - wait_press(&mut pin, pressed_level, pin_edge, debounce_duration).await; + log_err!(wait_press(&mut pin, pressed_level, debounce_duration).await); log::info!("[{}]", pressed_sink_msg); @@ -100,180 +79,185 @@ pub async fn process<'a>( } } -pub async fn wait_press<'a>( - pin: &mut impl InputPin, +async fn wait_level

( + pin: &mut P, pressed_level: PressedLevel, - pin_edge: &'a Notification, + pressed: bool, debounce_duration: Option, -) { - let mut debounce = false; +) -> Result<(), P::Error> +where + P: InputPin + Wait, +{ + let has_level = |pin: &mut P| { + if matches!(pressed_level, PressedLevel::Low) && pressed { + pin.is_low() + } else { + pin.is_high() + } + }; loop { - let pin_edge = pin_edge.wait(); - - let timer = if debounce { - if let Some(debounce_duration) = debounce_duration { - futures::future::Either::Left(Timer::after(debounce_duration)) + loop { + if matches!(pressed_level, PressedLevel::Low) && pressed { + pin.wait_for_low().await?; } else { - futures::future::Either::Right(pending()) + pin.wait_for_high().await?; } - } else { - futures::future::Either::Right(pending()) - }; - - let check = match select(pin_edge, timer).await { - Either::First(_) => { - if debounce_duration.is_some() { - debounce = true; - false - } else { - true - } - } - Either::Second(_) => { - if debounce { - debounce = false; - true - } else { - false - } + if has_level(pin)? { + break; } - }; - - if check { - let pressed = pin.is_high().unwrap_or(pressed_level != PressedLevel::High) - == (pressed_level == PressedLevel::High); + } - if pressed { - return; + if let Some(debounce_duration) = debounce_duration { + if matches!( + select(pin.wait_for_any_edge(), Timer::after(debounce_duration)).await, + Either::Second(_) + ) { + if has_level(pin)? { + break; + } } } } -} -pub async fn button1_button2_roller_process<'a>( - pin_1: impl InputPin, - pin_2: impl InputPin, -) { - roller_process( - pin_1, - pin_2, - &BUTTON1_PIN_EDGE, - &BUTTON2_PIN_EDGE, - Some(Duration::from_millis(50)), - "ROLLER", - BUTTON1_NOTIFY, - BUTTON2_NOTIFY, - ) - .await; + Ok(()) } -pub async fn roller_process<'a>( - mut pin_1: impl InputPin, - mut pin_2: impl InputPin, - pin_1_edge: &'a Notification, - pin_2_edge: &'a Notification, +pub async fn wait_press

( + pin: &mut P, + pressed_level: PressedLevel, debounce_duration: Option, - rolled_sink_msg: &'a str, - rolled_clockwise_sink: &'a [&'a Notification], - rolled_counter_clockwise_sink: &'a [&'a Notification], -) { - loop { - let clockwise = wait_roller( - &mut pin_1, - &mut pin_2, - pin_1_edge, - pin_2_edge, - debounce_duration, - ) - .await; - - log::info!("[{}]: {}", rolled_sink_msg, clockwise); - - let sink = if clockwise { - rolled_clockwise_sink - } else { - rolled_counter_clockwise_sink - }; - - for notification in sink { - notification.notify(); - } - } +) -> Result<(), P::Error> +where + P: InputPin + Wait, +{ + wait_level(pin, pressed_level, false, debounce_duration).await?; + wait_level(pin, pressed_level, true, debounce_duration).await } -pub async fn wait_roller<'a>( - pin_1: &mut impl InputPin, - pin_2: &mut impl InputPin, - pin_1_edge: &'a Notification, - pin_2_edge: &'a Notification, - debounce_duration: Option, -) -> bool { - let mut debounce = false; - let mut clockwise = false; - - let mut pin_1_was_high = pin_1.is_high().unwrap(); - let mut pin_2_was_high = pin_2.is_high().unwrap(); - - loop { - let pin_a_edge = pin_1_edge.wait(); - let pin_b_edge = pin_2_edge.wait(); - - let timer = if debounce { - if let Some(debounce_duration) = debounce_duration { - futures::future::Either::Left(Timer::after(debounce_duration)) - } else { - futures::future::Either::Right(pending()) - } - } else { - futures::future::Either::Right(pending()) - }; - - let check = match select3(pin_a_edge, pin_b_edge, timer).await { - Either3::First(_) | Either3::Second(_) => { - let pin_1_high = pin_1.is_high().unwrap(); - let pin_2_high = pin_2.is_high().unwrap(); - - let pin_1_changed = pin_1_high != pin_1_was_high; - let pin_2_changed = pin_2_high != pin_2_was_high; - - if pin_1_changed != pin_2_changed { - clockwise = pin_1_changed; - - if debounce_duration.is_some() { - debounce = true; - false - } else { - return clockwise; - } - } else { - pin_1_was_high = pin_1_high; - pin_2_was_high = pin_2_high; - - false - } - } - Either3::Third(_) => { - if debounce { - debounce = false; - true - } else { - false - } - } - }; - - if check { - let pin_1_high = pin_1.is_high().unwrap(); - let pin_2_high = pin_2.is_high().unwrap(); - - if pin_1_high == pin_2_high && pin_1_high != pin_1_was_high { - return clockwise; - } - - pin_1_was_high = pin_1_high; - pin_2_was_high = pin_2_high; - } - } -} +// pub async fn button1_button2_roller_process<'a>( +// pin_1: impl InputPin, +// pin_2: impl InputPin, +// ) { +// roller_process( +// pin_1, +// pin_2, +// &BUTTON1_PIN_EDGE, +// &BUTTON2_PIN_EDGE, +// Some(Duration::from_millis(50)), +// "ROLLER", +// BUTTON1_NOTIFY, +// BUTTON2_NOTIFY, +// ) +// .await; +// } + +// pub async fn roller_process<'a>( +// mut pin_1: impl InputPin, +// mut pin_2: impl InputPin, +// pin_1_edge: &'a Notification, +// pin_2_edge: &'a Notification, +// debounce_duration: Option, +// rolled_sink_msg: &'a str, +// rolled_clockwise_sink: &'a [&'a Notification], +// rolled_counter_clockwise_sink: &'a [&'a Notification], +// ) { +// loop { +// let clockwise = wait_roller( +// &mut pin_1, +// &mut pin_2, +// pin_1_edge, +// pin_2_edge, +// debounce_duration, +// ) +// .await; + +// log::info!("[{}]: {}", rolled_sink_msg, clockwise); + +// let sink = if clockwise { +// rolled_clockwise_sink +// } else { +// rolled_counter_clockwise_sink +// }; + +// for notification in sink { +// notification.notify(); +// } +// } +// } + +// pub async fn wait_roller<'a>( +// pin_1: &mut impl InputPin, +// pin_2: &mut impl InputPin, +// pin_1_edge: &'a Notification, +// pin_2_edge: &'a Notification, +// debounce_duration: Option, +// ) -> bool { +// let mut debounce = false; +// let mut clockwise = false; + +// let mut pin_1_was_high = pin_1.is_high().unwrap(); +// let mut pin_2_was_high = pin_2.is_high().unwrap(); + +// loop { +// let pin_a_edge = pin_1_edge.wait(); +// let pin_b_edge = pin_2_edge.wait(); + +// let timer = if debounce { +// if let Some(debounce_duration) = debounce_duration { +// futures::future::Either::Left(Timer::after(debounce_duration)) +// } else { +// futures::future::Either::Right(pending()) +// } +// } else { +// futures::future::Either::Right(pending()) +// }; + +// let check = match select3(pin_a_edge, pin_b_edge, timer).await { +// Either3::First(_) | Either3::Second(_) => { +// let pin_1_high = pin_1.is_high().unwrap(); +// let pin_2_high = pin_2.is_high().unwrap(); + +// let pin_1_changed = pin_1_high != pin_1_was_high; +// let pin_2_changed = pin_2_high != pin_2_was_high; + +// if pin_1_changed != pin_2_changed { +// clockwise = pin_1_changed; + +// if debounce_duration.is_some() { +// debounce = true; +// false +// } else { +// return clockwise; +// } +// } else { +// pin_1_was_high = pin_1_high; +// pin_2_was_high = pin_2_high; + +// false +// } +// } +// Either3::Third(_) => { +// if debounce { +// debounce = false; +// true +// } else { +// false +// } +// } +// }; + +// if check { +// let pin_1_high = pin_1.is_high().unwrap(); +// let pin_2_high = pin_2.is_high().unwrap(); + +// if pin_1_high == pin_2_high && pin_1_high != pin_1_was_high { +// return clockwise; +// } + +// pin_1_was_high = pin_1_high; +// pin_2_was_high = pin_2_high; +// } +// } +// } diff --git a/rued-esp32/src/core/internal/httpd.rs b/rued-esp32/src/core/internal/httpd.rs index 776ffad..0fe40e2 100644 --- a/rued-esp32/src/core/internal/httpd.rs +++ b/rued-esp32/src/core/internal/httpd.rs @@ -40,7 +40,7 @@ pub enum HttpdCommand { pub(crate) static COMMAND: Signal = Signal::new(); -pub async fn process<'a>(httpd: &'a mut LazyInitHttpServer<'_>) { +pub async fn process<'a>(httpd: &'a mut LazyInitHttpServer<'a>) { const FIRMWARE_VERSION: &str = env!("CARGO_PKG_VERSION"); let mut network_event = NETWORK_EVENT_CHANNEL.subscriber().unwrap(); diff --git a/rued-esp32/src/core/internal/keepalive.rs b/rued-esp32/src/core/internal/keepalive.rs index bbb4ecc..79c3dfe 100644 --- a/rued-esp32/src/core/internal/keepalive.rs +++ b/rued-esp32/src/core/internal/keepalive.rs @@ -78,7 +78,9 @@ pub async fn process() { quit_time.map(|quit_time| now >= quit_time).unwrap_or(false) ); if quit_time.map(|quit_time| now >= quit_time).unwrap_or(false) { - quit::QUIT.notify(); + for notification in &quit::QUIT { + notification.notify(); + } } } } diff --git a/rued-esp32/src/core/internal/mqtt.rs b/rued-esp32/src/core/internal/mqtt.rs index 025c6e1..5b881ef 100644 --- a/rued-esp32/src/core/internal/mqtt.rs +++ b/rued-esp32/src/core/internal/mqtt.rs @@ -1,164 +1,436 @@ -use super::state::*; -use crate::{ - models::{ - ApplicationDataChange, ApplicationStateChange, APPLICATION_DATA_CHANNEL, - APPLICATION_EVENT_CHANNEL, - }, - mqtt_msg::{MqttCommand, MQTT_TOPIC_POSTFIX_BATTERY_VOLTAGE, MQTT_TOPIC_POSTFIX_COMMAND}, -}; use core::str::{self, FromStr}; -use embassy_futures::select::{select, select3, Either, Either3}; +use core::time::Duration; + +use log::{error, info}; + +use serde::{Deserialize, Serialize}; + +use heapless::String; + +use embassy_futures::select::{select, Either}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::signal::Signal; -use embedded_svc::mqtt::client::asynch::{Client, Connection, Event, Publish, QoS}; -use log::*; -static MQTT_CONNECT_SIGNAL: Signal = Signal::new(); +use embedded_svc::mqtt::client::asynch::{Client, Connection, Event, Message, Publish, QoS}; +use embedded_svc::mqtt::client::Details; -pub async fn receive_task<'a>( - mut connection: impl Connection = Option> + 'a, -) { - let mut app_event = APPLICATION_EVENT_CHANNEL.subscriber().unwrap(); +use channel_bridge::notification::Notification; + +use crate::core::internal::battery::{self, BatteryState}; + +use crate::core::internal::error; + +#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct MqttConfiguration { + protocol_311: bool, + url: heapless::String<128>, + client_id: heapless::String<64>, + username: heapless::String<64>, + password: heapless::String<64>, +} + +#[derive(Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] +pub enum MqttCommand { + KeepAlive(Duration), + Valve(bool), + FlowWatch(bool), + SystemUpdate, +} + +pub type MqttClientNotification = Result>, ()>; + +// TODO: Web: connected info at least +static PUBLISH_NOTIFY: &[&Notification] = &[ + &crate::keepalive::NOTIF, + &crate::core::internal::screen::MQTT_STATE_NOTIF, +]; +static RECEIVE_NOTIFY: &[&Notification] = &[ + &crate::keepalive::NOTIF, + &crate::core::internal::screen::MQTT_STATE_NOTIF, +]; + +pub(crate) static BATTERY_STATE_NOTIF: Notification = Notification::new(); +pub(crate) static WIFI_STATE_NOTIF: Notification = Notification::new(); + +static CONN_SIGNAL: Signal = Signal::new(); + +pub async fn send(topic_prefix: &str, mut mqtt: impl Client + Publish) { + let mut connected = false; + + let topic = |topic_suffix| { + String::::from_str(topic_prefix.as_ref()) + .and_then(|mut s| s.push_str(topic_suffix).map(|_| s)) + .unwrap_or_else(|_| panic!("")) + }; + + let topic_commands = topic("/commands/#"); + + let topic_valve = topic("/valve"); + + let topic_meter_edges = topic("/meter/edges"); + let topic_meter_armed = topic("/meter/armed"); + let topic_meter_leak = topic("/meter/leak"); + + let topic_battery_voltage = topic("/battery/voltage"); + let topic_battery_low = topic("/battery/low"); + let topic_battery_charged = topic("/battery/charged"); + + let topic_powered = topic("/powered"); + + let mut published_battery_state: Option = None; loop { - let (message, app_state_change) = - match select(connection.next(), app_event.next_message_pure()).await { - Either::First(message) => { - info!("send_task recv MQTT_CONNECT_SIGNAL"); - (message, None) + let (conn_state, battery_state) = if connected { + match select(CONN_SIGNAL.wait(), BATTERY_STATE_NOTIF.wait()).await { + Either::First(conn_state) => (Some(conn_state), None), + Either::Second(_) => (None, Some(battery::STATE.get())), + } + } else { + let conn_state = CONN_SIGNAL.wait().await; + + (Some(conn_state), None) + }; + + if let Some(conn_state) = conn_state { + if conn_state { + info!("MQTT is now connected, subscribing"); + + error::check!( + mqtt.subscribe(topic_commands.as_str(), QoS::AtLeastOnce) + .await + ) + .unwrap(); + + connected = true; + } else { + info!("MQTT disconnected"); + + connected = false; + } + } + + // if let Some(valve_state) = valve_state { + // if published_valve_state != valve_state { + // published_valve_state = valve_state; + + // let status = match valve_state { + // Some(ValveState::Open) => "open", + // Some(ValveState::Opening(_)) => "opening", + // Some(ValveState::Closed) => "closed", + // Some(ValveState::Closing(_)) => "closing", + // None => "unknown", + // }; + + // publish( + // connected, + // &mut mqtt, + // &topic_valve, + // QoS::AtLeastOnce, + // status.as_bytes(), + // ) + // .await; + // } + // } + + // if let Some(wm_state) = wm_state { + // if published_wm_state + // .map(|p| p.edges_count != wm_state.edges_count) + // .unwrap_or(true) + // { + // let num = wm_state.edges_count.to_le_bytes(); + // let num_slice: &[u8] = # + + // publish( + // connected, + // &mut mqtt, + // &topic_meter_edges, + // QoS::AtLeastOnce, + // num_slice, + // ) + // .await; + // } + + // if published_wm_state + // .map(|p| p.armed != wm_state.armed) + // .unwrap_or(true) + // { + // publish( + // connected, + // &mut mqtt, + // &topic_meter_armed, + // QoS::AtLeastOnce, + // (if wm_state.armed { "true" } else { "false" }).as_bytes(), + // ) + // .await; + // } + + // if published_wm_state + // .map(|p| p.leaking != wm_state.leaking) + // .unwrap_or(true) + // { + // publish( + // connected, + // &mut mqtt, + // &topic_meter_leak, + // QoS::AtLeastOnce, + // (if wm_state.armed { "true" } else { "false" }).as_bytes(), + // ) + // .await; + // } + + // published_wm_state = Some(wm_state); + // } + + if let Some(battery_state) = battery_state { + if published_battery_state + .map(|p| p.voltage != battery_state.voltage) + .unwrap_or(true) + { + if let Some(voltage) = battery_state.voltage { + let num = voltage.to_le_bytes(); + let num_slice: &[u8] = # + + publish( + connected, + &mut mqtt, + &topic_battery_voltage, + QoS::AtMostOnce, + num_slice, + ) + .await; + + if let Some(prev_voltage) = published_battery_state.and_then(|p| p.voltage) { + if (prev_voltage > BatteryState::LOW_VOLTAGE) + != (voltage > BatteryState::LOW_VOLTAGE) + { + let status = if voltage > BatteryState::LOW_VOLTAGE { + "false" + } else { + "true" + }; + + publish( + connected, + &mut mqtt, + &topic_battery_low, + QoS::AtLeastOnce, + status.as_bytes(), + ) + .await; + } + + if (prev_voltage >= BatteryState::MAX_VOLTAGE) + != (voltage >= BatteryState::MAX_VOLTAGE) + { + let status = if voltage >= BatteryState::MAX_VOLTAGE { + "true" + } else { + "false" + }; + + publish( + connected, + &mut mqtt, + &topic_battery_charged, + QoS::AtMostOnce, + status.as_bytes(), + ) + .await; + } + } } - Either::Second(app_state_change) => { - info!("send_task recv app_state_change"); - (None, Some(app_state_change)) + } + + if published_battery_state + .map(|p| p.powered != battery_state.powered) + .unwrap_or(true) + { + if let Some(powered) = battery_state.powered { + publish( + connected, + &mut mqtt, + &topic_powered, + QoS::AtMostOnce, + (if powered { "true" } else { "false" }).as_bytes(), + ) + .await; } - }; + } + + published_battery_state = Some(battery_state); + }; + } +} + +async fn publish(connected: bool, mqtt: &mut impl Publish, topic: &str, qos: QoS, payload: &[u8]) { + if connected { + if let Ok(_msg_id) = error::check!(mqtt.publish(topic, qos, false, payload).await) { + // TODO + info!("Published to {}", topic); + + if qos >= QoS::AtLeastOnce { + for notification in PUBLISH_NOTIFY { + notification.notify(); + } + } + } + } else { + error!("Client not connected, skipping publishment to {}", topic); + } +} + +pub async fn receive( + mut connection: impl for<'a> Connection = Option> + 'static, +) { + loop { + let message = connection.next().await; if let Some(message) = message { - info!("receive_task [MQTT/CONNECTION]: {:?}", message); + info!("[MQTT/CONNECTION]: {:?}", message); if let Ok(Event::Received(Some(cmd))) = &message { match cmd { - MqttCommand::ExecOTAUpdate(url) => { - info!( - "receive_task MQTT received OTA update request. url = {}", - url - ); - let publisher = APPLICATION_EVENT_CHANNEL.publisher().unwrap(); - let data = ApplicationStateChange::OTAUpdateRequest(url.clone()); - publisher.publish(data).await; + MqttCommand::Valve(open) => { + // valve::COMMAND.signal(if *open { + // ValveCommand::Open + // } else { + // ValveCommand::Close + // }); } - MqttCommand::SystemRestart => { - info!("receive_task MQTT received system restart request"); - unsafe { - esp_idf_svc::sys::esp_restart(); - } + MqttCommand::FlowWatch(enable) => { + // wm::COMMAND.signal(if *enable { + // WaterMeterCommand::Arm + // } else { + // WaterMeterCommand::Disarm + // }); } + _ => (), } } else if matches!(&message, Ok(Event::Connected(_))) { - MQTT_CONNECT_SIGNAL.signal(true); + CONN_SIGNAL.signal(true); } else if matches!(&message, Ok(Event::Disconnected)) { - MQTT_CONNECT_SIGNAL.signal(false); + CONN_SIGNAL.signal(false); } - } - if let Some(ApplicationStateChange::OTAUpdateStarted) = app_state_change { - info!("receive_task OTA Update started shutting down mqtt receive_task"); - // No clean-up of the mqtt object here as this has been done in - // send_task + for notification in RECEIVE_NOTIFY { + notification.notify(); + } + } else { break; } } } -// send will react on application state change event and then send the MQTT message -// the application state change event will be fired if new wind data is availbale. -// the requence in which MQTT messages are send depends on how often the application -// state change events gets fired. -// we are not implementing explicit re-connect logic, as this is already implemented -// in ESP IDF for MQTT. -pub async fn send_task(topic_prefix: &str, mut mqtt: impl Client + Publish) { - let mut connected = false; +#[derive(Default)] +pub struct MessageParser { + #[allow(clippy::type_complexity)] + command_parser: Option Option>, + payload_buf: [u8; 16], +} - let topic = |topic_suffix| { - heapless::String::::from_str(topic_prefix) - .and_then(|mut s| s.push_str(topic_suffix).map(|_| s)) - .unwrap_or_else(|_| panic!("failed to construct topic")) - }; +impl MessageParser { + pub fn new() -> Self { + Default::default() + } - let topic_commands = topic(MQTT_TOPIC_POSTFIX_COMMAND); - let topic_battery_voltage = topic(MQTT_TOPIC_POSTFIX_BATTERY_VOLTAGE); + pub fn convert( + &mut self, + event: &Result, E>, + ) -> Result>, E> + where + M: Message, + E: Clone, + { + event + .as_ref() + .map(|event| event.transform_received(|message| self.process(message))) + .map_err(|e| e.clone()) + } - let mut app_event = APPLICATION_EVENT_CHANNEL.subscriber().unwrap(); - let mut app_data = APPLICATION_DATA_CHANNEL.subscriber().unwrap(); + fn process(&mut self, message: &M) -> Option + where + M: Message, + { + match message.details() { + Details::Complete => Self::parse_command(message.topic().unwrap()) + .and_then(|parser| parser(message.data())), + Details::InitialChunk(initial_chunk_data) => { + if initial_chunk_data.total_data_size > self.payload_buf.len() { + self.command_parser = None; + } else { + self.command_parser = Self::parse_command(message.topic().unwrap()); - loop { - let (conn_state, app_state_change, app_data) = match select3( - MQTT_CONNECT_SIGNAL.wait(), - app_event.next_message_pure(), - app_data.next_message_pure(), - ) - .await - { - Either3::First(conn_state) => { - info!("send_task recv MQTT_CONNECT_SIGNAL"); - (Some(conn_state), None, None) - } - Either3::Second(app_state_change) => { - info!("send_task recv app_state_change"); - (None, Some(app_state_change), None) + self.payload_buf[..message.data().len()] + .copy_from_slice(message.data().as_ref()); + } + + None } - Either3::Third(app_data) => { - info!("send_task recv app_data"); - (None, None, Some(app_data)) + Details::SubsequentChunk(subsequent_chunk_data) => { + if let Some(command_parser) = self.command_parser.as_ref() { + self.payload_buf + [subsequent_chunk_data.current_data_offset..message.data().len()] + .copy_from_slice(message.data().as_ref()); + + if subsequent_chunk_data.total_data_size + == subsequent_chunk_data.current_data_offset + message.data().len() + { + command_parser(&self.payload_buf[0..subsequent_chunk_data.total_data_size]) + } else { + None + } + } else { + None + } } - }; + } + } - if let Some(new_conn_state) = conn_state { - if new_conn_state { - info!("send_task MQTT is now connected, subscribing"); + #[allow(clippy::type_complexity)] + fn parse_command(topic: &str) -> Option Option> { + if topic.ends_with("/commands/valve") { + Some(Self::parse_valve_command) + } else if topic.ends_with("/commands/flow_watch") { + Some(Self::parse_flow_watch_command) + } else if topic.ends_with("/commands/keep_alive") { + Some(Self::parse_keep_alive_command) + } else if topic.ends_with("/commands/system_update") { + Some(Self::parse_system_update_command) + } else { + None + } + } - mqtt.subscribe(topic_commands.as_str(), QoS::AtLeastOnce) - .await - .unwrap(); + fn parse_valve_command(data: &[u8]) -> Option { + Self::parse::(data).map(MqttCommand::Valve) + } - connected = true; - } else { - info!("send_task MQTT disconnected"); + fn parse_flow_watch_command(data: &[u8]) -> Option { + Self::parse::(data).map(MqttCommand::FlowWatch) + } - connected = false; - } - } + fn parse_keep_alive_command(data: &[u8]) -> Option { + Self::parse::(data).map(|secs| MqttCommand::KeepAlive(Duration::from_secs(secs as _))) + } - if let Some(ApplicationStateChange::OTAUpdateStarted) = app_state_change { - info!("send_task OTA Update started shutting down mqtt send_task"); - drop(mqtt); - break; - } + fn parse_system_update_command(data: &[u8]) -> Option { + Self::parse_empty(data).map(|_| MqttCommand::SystemUpdate) + } - if let Some(ApplicationDataChange::NewBatteryData(battery_data)) = app_data { - info!( - "send_task send new battery voltage data {}", - battery_data.voltage - ); + fn parse(data: &[u8]) -> Option + where + T: str::FromStr, + { + str::from_utf8(data) + .ok() + .and_then(|s| str::parse::(s).ok()) + } - if connected { - if let Ok(_msg_id) = super::error::check!( - mqtt.publish( - &topic_battery_voltage, - QoS::AtLeastOnce, - false, - format!("{}", battery_data.voltage).as_str().as_bytes() - ) - .await - ) { - info!("send_task published to {}", topic_battery_voltage); - } - } else { - info!( - "send_task client not connected, skipping publishment to {}", - topic_battery_voltage - ); - } + fn parse_empty(data: &[u8]) -> Option<()> { + if data.is_empty() { + Some(()) + } else { + None } } } diff --git a/rued-esp32/src/core/internal/ota.rs b/rued-esp32/src/core/internal/ota.rs index b3f6fde..003d6de 100644 --- a/rued-esp32/src/core/internal/ota.rs +++ b/rued-esp32/src/core/internal/ota.rs @@ -121,7 +121,7 @@ fn perform_update(firmware_url: &str) -> Result<(), OtaError> { // info!("no invalid slot found"); // } - let ota_update = match ota.initiate_update() { + let mut ota_update = match ota.initiate_update() { Ok(handle) => handle, Err(_) => return Err(OtaError::OtaApiError), }; @@ -260,7 +260,7 @@ fn add_firmware_info( update_summary.push_str(released.as_str()).unwrap(); if let Some(desc) = fw.description { update_summary.push_str(", ").unwrap(); - copy_truncated_string(&mut description, desc); + copy_truncated_string::<32, 128>(&mut description, desc); update_summary.push_str(description.as_str()).unwrap(); } } diff --git a/rued-esp32/src/core/internal/pulse_counter.rs b/rued-esp32/src/core/internal/pulse_counter.rs index f9053d7..1c44d3d 100644 --- a/rued-esp32/src/core/internal/pulse_counter.rs +++ b/rued-esp32/src/core/internal/pulse_counter.rs @@ -2,7 +2,8 @@ use core::convert::Infallible; use core::fmt::Debug; use core::future::Future; -use embedded_hal_0_2::digital::v2::InputPin; +use embedded_hal::digital::{ErrorType, InputPin}; +use embedded_hal_async::digital::Wait; use embassy_time::Duration; @@ -13,11 +14,7 @@ use super::button::{self, PressedLevel}; pub trait PulseCounter { type Error: Debug; - type TakePulsesFuture<'a>: Future> - where - Self: 'a; - - fn take_pulses(&mut self) -> Self::TakePulsesFuture<'_>; + async fn take_pulses(&mut self) -> Result; } impl PulseCounter for &mut T @@ -26,10 +23,8 @@ where { type Error = T::Error; - type TakePulsesFuture<'a> = T::TakePulsesFuture<'a> where Self: 'a; - - fn take_pulses(&mut self) -> Self::TakePulsesFuture<'_> { - (*self).take_pulses() + async fn take_pulses(&mut self) -> Result { + (*self).take_pulses().await } } @@ -50,54 +45,44 @@ where } } -pub struct CpuPulseCounter<'a, P> { +pub struct CpuPulseCounter

{ pin: P, pressed_level: PressedLevel, - pin_edge: &'a Notification, debounce_duration: Option, } -impl<'a, P> CpuPulseCounter<'a, P> { +impl

CpuPulseCounter

{ pub const fn new( pin: P, pressed_level: PressedLevel, - pin_edge: &'a Notification, debounce_duration: Option, ) -> Self { Self { pin, pressed_level, - pin_edge, debounce_duration, } } } -impl<'a, P> PulseCounter for CpuPulseCounter<'a, P> +impl

PulseCounter for CpuPulseCounter

where - P: InputPin, + P: InputPin + Wait, { - type Error = Infallible; - - type TakePulsesFuture<'b> = impl Future> + 'b where Self: 'b; + type Error = P::Error; - fn take_pulses(&mut self) -> Self::TakePulsesFuture<'_> { - async move { - button::wait_press( - &mut self.pin, - self.pressed_level, - &mut self.pin_edge, - self.debounce_duration, - ) - .await; + async fn take_pulses(&mut self) -> Result { + button::wait_press(&mut self.pin, self.pressed_level, self.debounce_duration).await?; - Ok(1) - } + Ok(1) } } -impl<'a, P> PulseWakeup for CpuPulseCounter<'a, P> { - type Error = Infallible; +impl

PulseWakeup for CpuPulseCounter

+where + P: ErrorType, +{ + type Error = P::Error; fn set_enabled(&mut self, _enabled: bool) -> Result<(), Self::Error> { Ok(()) diff --git a/rued-esp32/src/core/internal/pwm.rs b/rued-esp32/src/core/internal/pwm.rs index e20e081..8d2741a 100644 --- a/rued-esp32/src/core/internal/pwm.rs +++ b/rued-esp32/src/core/internal/pwm.rs @@ -4,6 +4,7 @@ use core::fmt::Debug; use channel_bridge::Receiver; use embedded_hal_0_2::PwmPin; use esp_idf_svc::hal::delay::FreeRtos; +use esp_idf_svc::hal::ledc::LedcDriver; use serde::{Deserialize, Serialize}; use log::trace; @@ -69,13 +70,13 @@ pub async fn process<'a>( impl PwmPin + 'a, )>, ) { - let mut pwm0; - let mut pwm1; - let mut pwm2; + let mut pwm0: LedcDriver<'a>; + let mut pwm1: LedcDriver<'a>; + let mut pwm2: LedcDriver<'a>; #[cfg(feature = "pwm")] { - let (mut pwm0, mut pwm1, mut pwm2) = pwm.expect("Unwraps pwm channels"); + let (pwm0, pwm1, pwm2) = pwm.expect("Unwraps pwm channels"); set_duty(&mut pwm0, DEFAULT_DUTY_CYCLE); set_duty(&mut pwm1, DEFAULT_DUTY_CYCLE); diff --git a/rued-esp32/src/core/internal/screen.rs b/rued-esp32/src/core/internal/screen.rs index 299af7b..9e01a7d 100644 --- a/rued-esp32/src/core/internal/screen.rs +++ b/rued-esp32/src/core/internal/screen.rs @@ -170,8 +170,9 @@ impl ScreenState { pub(crate) static BUTTON1_PRESSED_NOTIF: Notification = Notification::new(); pub(crate) static BUTTON2_PRESSED_NOTIF: Notification = Notification::new(); pub(crate) static BUTTON3_PRESSED_NOTIF: Notification = Notification::new(); -pub(crate) static WIFI_STATE_NOTIF: Notification = Notification::new(); pub(crate) static BATTERY_STATE_NOTIF: Notification = Notification::new(); +pub(crate) static MQTT_STATE_NOTIF: Notification = Notification::new(); +pub(crate) static WIFI_STATE_NOTIF: Notification = Notification::new(); pub(crate) static REMAINING_TIME_NOTIF: Notification = Notification::new(); pub(crate) static EXT_RTC_NOTIF: Notification = Notification::new(); pub(crate) static PWM_CHANGE_NOTIF: Notification = Notification::new(); diff --git a/rued-esp32/src/core/internal/spawn.rs b/rued-esp32/src/core/internal/spawn.rs index 16e6bd7..6e7cb91 100644 --- a/rued-esp32/src/core/internal/spawn.rs +++ b/rued-esp32/src/core/internal/spawn.rs @@ -6,7 +6,6 @@ use embedded_hal_0_2::{adc, PwmPin}; use embedded_hal_async::digital::Wait; use embedded_svc::mqtt::client::asynch::{Client, Connection, Publish}; -use embedded_svc::wifi::Wifi as WifiTrait; use embedded_svc::ws::asynch::server::Acceptor; use esp_idf_svc::handle::RawHandle; use esp_idf_svc::http::server::EspHttpServer; @@ -19,9 +18,9 @@ use edge_executor::*; use channel_bridge::asynch::*; +use crate::core::internal::mqtt::MqttCommand; use crate::core::internal::screen; use crate::models::rtc_external::RtcExternal; -use crate::mqtt_msg::MqttCommand; use crate::services::httpd::LazyInitHttpServer; use crate::MQTT_MAX_TOPIC_LEN; @@ -34,16 +33,11 @@ use super::{battery, mqtt, wifi}; pub fn high_prio<'a, const C: usize>( executor: &LocalExecutor<'a, C>, - button1_pin: impl InputPin + 'a, + button1_pin: impl InputPin + Wait + 'a, battery_voltage: impl crate::core::internal::battery::Adc + 'a, power_pin: impl InputPin + 'a, // display: D, - wifi: ( - impl embedded_svc::wifi::asynch::Wifi + 'a, - impl Receiver + 'a, - ), - httpd: &'a mut LazyInitHttpServer, - acceptor: Option, + // httpd: &'a mut LazyInitHttpServer<'a>, pwm: Option<( impl PwmPin + 'a, impl PwmPin + 'a, @@ -53,8 +47,6 @@ pub fn high_prio<'a, const C: usize>( pwm_flash: impl FnMut(crate::NvsDataState) + 'a, netif_notifier: impl Receiver + 'a, mqtt_topic_prefix: &'a str, - mqtt_client: impl Client + Publish + 'a, - mqtt_conn: impl Connection = Option> + 'a, ) { executor .spawn(button::button1_process(button1_pin, PressedLevel::Low)) @@ -63,10 +55,10 @@ pub fn high_prio<'a, const C: usize>( executor.spawn(super::keepalive::process()).detach(); // executor.spawn(screen::process()).detach(); // executor.spawn(screen::run_draw(display)).detach(); - executor - .spawn(super::wifi::process(wifi.0, wifi.1)) - .detach(); - executor.spawn(super::httpd::process(httpd)).detach(); + + // FIXME + // executor.spawn(super::httpd::process(httpd)).detach(); + executor.spawn(super::pwm::process(pwm)).detach(); executor.spawn(super::sntp::process()).detach(); executor.spawn(super::pwm::flash(pwm_flash)).detach(); @@ -79,16 +71,6 @@ pub fn high_prio<'a, const C: usize>( .detach(); // OTA executor.spawn(super::ota::ota_task()).detach(); - // MQTT - executor - .spawn(super::mqtt::receive_task(mqtt_conn)) - .detach(); - executor - .spawn(super::mqtt::send_task::( - mqtt_topic_prefix, - mqtt_client, - )) - .detach(); if let Some(rtc) = rtc { executor.spawn(super::external_rtc::process(rtc)).detach(); @@ -166,39 +148,29 @@ pub fn wifi<'a, const C: usize, D>( ) -> Result<(), SpawnError> where D: 'a, + WifiEvent: From, { executor.spawn(wifi::process(wifi, wifi_notif)).detach(); Ok(()) } -// FIXME This is MQTT based on ruwm -// pub fn mqtt_send<'a, const L: usize, const C: usize, M>( -// executor: &mut Executor<'a, C, M, Local>, -// tasks: &mut heapless::Vec, C>, -// mqtt_topic_prefix: &'a str, -// mqtt_client: impl Client + Publish + 'a, -// ) -> Result<(), SpawnError> -// where -// M: Monitor + Default, -// { -// executor.spawn_local_collect(mqtt::send::(mqtt_topic_prefix, mqtt_client), tasks)?; - -// Ok(()) -// } - -// pub fn mqtt_receive<'a, const C: usize, M>( -// executor: &mut Executor<'a, C, M, Local>, -// tasks: &mut heapless::Vec, C>, -// mqtt_conn: impl Connection> + 'a, -// ) -> Result<(), SpawnError> -// where -// M: Monitor + Default, -// { -// executor.spawn_local_collect(mqtt::receive(mqtt_conn), tasks)?; +pub fn mqtt_send<'a, const L: usize, const C: usize>( + executor: &LocalExecutor<'a, C>, + mqtt_topic_prefix: &'a str, + mqtt_client: impl Client + Publish + 'a, +) { + executor + .spawn(mqtt::send::(mqtt_topic_prefix, mqtt_client)) + .detach(); +} -// Ok(()) -// } +pub fn mqtt_receive( + executor: &LocalExecutor<'_, C>, + mqtt_conn: impl for<'a> Connection = Option> + 'static, +) { + executor.spawn(mqtt::receive(mqtt_conn)).detach(); +} pub fn ws<'a, const C: usize>( executor: &LocalExecutor<'a, C>, diff --git a/rued-esp32/src/core/internal/wifi.rs b/rued-esp32/src/core/internal/wifi.rs index 701cf86..e36800e 100644 --- a/rued-esp32/src/core/internal/wifi.rs +++ b/rued-esp32/src/core/internal/wifi.rs @@ -8,7 +8,7 @@ use embassy_futures::select::{select, Either}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::signal::Signal; -use embedded_svc::wifi::{Configuration, Wifi as WifiTrait}; +use embedded_svc::wifi::{asynch::Wifi, Configuration}; use channel_bridge::asynch::{Receiver, Sender}; @@ -50,10 +50,8 @@ pub static STATE: State> = State::new( pub(crate) static COMMAND: Signal = Signal::new(); -pub async fn process<'a, D>( - mut wifi: impl WifiTrait, - mut state_changed_source: impl Receiver, -) where +pub async fn process<'a, D>(mut wifi: impl Wifi, mut state_changed_source: impl Receiver) +where WifiEvent: From, { loop { @@ -63,7 +61,7 @@ pub async fn process<'a, D>( match event { WifiEvent::StaConnected => { log::info!("WifiEvent: STAConnected"); - if wifi.is_connected().unwrap() { + if wifi.is_connected().await.unwrap() { log::info!("WifiEvent: Connected"); } } @@ -78,7 +76,7 @@ pub async fn process<'a, D>( } } Either::Second(command) => match command { - WifiCommand::SetConfiguration(conf) => wifi.set_configuration(&conf).unwrap(), + WifiCommand::SetConfiguration(conf) => wifi.set_configuration(&conf).await.unwrap(), }, } } diff --git a/rued-esp32/src/httpd.rs b/rued-esp32/src/httpd.rs index 9ff1082..4863b06 100644 --- a/rued-esp32/src/httpd.rs +++ b/rued-esp32/src/httpd.rs @@ -24,7 +24,7 @@ use middleware::DefaultMiddleware; pub mod middleware; -pub fn configure_handlers<'a>(httpd: &mut RefMut<'_, EspHttpServer>) -> Result<()> { +pub fn configure_handlers<'a>(httpd: &mut RefMut<'a, EspHttpServer>) -> Result<()> { // HTTPd httpd.handler( "/health", @@ -137,21 +137,22 @@ pub fn configure_handlers<'a>(httpd: &mut RefMut<'_, EspHttpServer>) -> Result<( Ok(()) } -pub fn configure_websockets<'a>(server: &mut LazyInitHttpServer) -> Result { - let mut httpd = server.create(); +// FIXME Is this needed? +// pub fn configure_websockets<'a>(server: &mut LazyInitHttpServer<'a>) -> Result { +// let mut httpd = server.create(); - // Websockets - let (ws_processor, ws_acceptor) = - EspHttpWsProcessor::<{ ws::WS_MAX_CONNECTIONS }, { ws::WS_MAX_FRAME_LEN }>::new(()); +// // Websockets +// let (ws_processor, ws_acceptor) = +// EspHttpWsProcessor::<{ ws::WS_MAX_CONNECTIONS }, { ws::WS_MAX_FRAME_LEN }>::new(()); - let ws_processor = Mutex::::new(RefCell::new(ws_processor)); +// let ws_processor = Mutex::::new(RefCell::new(ws_processor)); - httpd.ws_handler("/ws", move |connection| { - ws_processor.lock(|ws_processor| ws_processor.borrow_mut().process(connection)) - })?; +// httpd.ws_handler("/ws", move |connection| { +// ws_processor.lock(|ws_processor| ws_processor.borrow_mut().process(connection)) +// })?; - Ok(ws_acceptor) -} +// Ok(ws_acceptor) +// } fn respond_err(conn: &mut EspHttpConnection, status: StatusCode, error: &str) -> Result<()> { conn.initiate_response( diff --git a/rued-esp32/src/main.rs b/rued-esp32/src/main.rs index 7f2688c..2c32195 100644 --- a/rued-esp32/src/main.rs +++ b/rued-esp32/src/main.rs @@ -137,43 +137,43 @@ mod mqtt_msg; mod peripherals; mod services; -/// -/// # Safety -pub unsafe extern "C" fn sntp_set_time_sync_notification_cb_custom( - tv: *mut esp_idf_svc::sys::timeval, -) { - let naive_dt_opt = NaiveDateTime::from_timestamp_opt((*tv).tv_sec as i64, 0); - let naive_dt = if let Some(value) = naive_dt_opt { - value - } else { - NaiveDateTime::default() - }; - let dt = DateTime::::from_utc(naive_dt, Utc); - - debug!( - "SNTP Sync Callback fired. Timestamp: {} / Year: {}", - dt.timestamp().to_string(), - dt.year().to_string() - ); - - if dt.year() < CURRENT_YEAR.into() { - debug!("SNTP Sync Callback: Falling back to RTC for sync."); - - // FIXME - todo!(); - } else { - debug!( - "SNTP Sync Callback: Update RTC from local time. sec: {}, usec: {}", - (*tv).tv_sec, - (*tv).tv_usec - ); - - external_rtc::COMMAND.signal(external_rtc::RtcExternalCommand::SntpSyncCallbackUpdateRtc); - - // FIXME simulating, battery status update - // keepalive::NOTIF.notify(); - } -} +// /// +// /// # Safety +// pub unsafe extern "C" fn sntp_set_time_sync_notification_cb_custom( +// tv: *mut esp_idf_svc::sys::timeval, +// ) { +// let naive_dt_opt = NaiveDateTime::from_timestamp_opt((*tv).tv_sec as i64, 0); +// let naive_dt = if let Some(value) = naive_dt_opt { +// value +// } else { +// NaiveDateTime::default() +// }; +// let dt = DateTime::::from_utc(naive_dt, Utc); + +// debug!( +// "SNTP Sync Callback fired. Timestamp: {} / Year: {}", +// dt.timestamp().to_string(), +// dt.year().to_string() +// ); + +// if dt.year() < CURRENT_YEAR.into() { +// debug!("SNTP Sync Callback: Falling back to RTC for sync."); + +// // FIXME +// todo!(); +// } else { +// debug!( +// "SNTP Sync Callback: Update RTC from local time. sec: {}, usec: {}", +// (*tv).tv_sec, +// (*tv).tv_usec +// ); + +// external_rtc::COMMAND.signal(external_rtc::RtcExternalCommand::SntpSyncCallbackUpdateRtc); + +// // FIXME simulating, battery status update +// // keepalive::NOTIF.notify(); +// } +// } pub fn sntp_sync_callback(time: ::core::time::Duration) {} @@ -256,7 +256,7 @@ fn run(wakeup_reason: WakeupReason) -> Result<(), InitError> { let i2c0_peripherals = peripherals.i2c0; let config = I2cConfig::new(); - let _ = config.baudrate(Hertz::from(400_u32)); + let _ = config.clone().baudrate(Hertz::from(400_u32)); let i2c0_driver = I2cDriver::new( i2c0_peripherals.i2c, @@ -367,8 +367,9 @@ fn run(wakeup_reason: WakeupReason) -> Result<(), InitError> { // Httpd - let mut httpd = services::httpd()?; - let ws_acceptor = httpd::configure_websockets(&mut httpd)?; + // FIXME + // let mut httpd = services::httpd()?; + // let ws_acceptor = httpd::configure_websockets(&mut httpd)?; // Mqtt @@ -466,9 +467,7 @@ fn run(wakeup_reason: WakeupReason) -> Result<(), InitError> { battery_voltage, PinDriver::input(peripherals.battery.power)?, // display, - (wifi, wifi_notif), - &mut httpd, - Some(ws_acceptor), + // &mut httpd, pwm, rtc_clock, move |_new_state| { @@ -477,8 +476,6 @@ fn run(wakeup_reason: WakeupReason) -> Result<(), InitError> { }, netif_notifier(sysloop.clone()).unwrap(), mqtt_topic_prefix, - mqtt_client, - mqtt_conn, ); // Mid-prio tasks @@ -507,8 +504,8 @@ fn run(wakeup_reason: WakeupReason) -> Result<(), InitError> { // }, ); - // spawn::wifi(&mut executor, &mut tasks, wifi, wifi_notif)?; - // spawn::mqtt_receive(&mut executor, &mut tasks, mqtt_conn)?; + spawn::wifi(&executor, wifi, wifi_notif).expect("Spawn Wifi in Executor"); + spawn::mqtt_receive(&executor, mqtt_conn); executor }); @@ -527,7 +524,7 @@ fn run(wakeup_reason: WakeupReason) -> Result<(), InitError> { let low_prio_execution = services::schedule::<4>(50000, quit::QUIT[2].wait(), move || { let executor = LocalExecutor::new(); - // spawn::mqtt_send::(&executor, mqtt_topic_prefix, mqtt_client); + spawn::mqtt_send::(&executor, mqtt_topic_prefix, mqtt_client); // spawn::ws(&executor, ws_acceptor); executor diff --git a/rued-esp32/src/models.rs b/rued-esp32/src/models.rs index 734000b..59e7672 100644 --- a/rued-esp32/src/models.rs +++ b/rued-esp32/src/models.rs @@ -5,11 +5,12 @@ use esp_idf_svc::sys::settimeofday; use esp_idf_svc::sys::time; use esp_idf_svc::sys::timeval; use esp_idf_svc::sys::timezone; +use heapless::String; use log::{debug, info, warn}; use rv8803::{i2c0::Bus as I2cBus, Rv8803, TIME_ARRAY_LENGTH}; -use serde::Deserialize; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use shared_bus::{BusManager, I2cProxy}; +use std::str::FromStr; use std::{env, error::Error as StdError, fmt, marker::PhantomData, ptr, sync::Mutex}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; @@ -144,7 +145,8 @@ where reading.seconds as u32, ) .unwrap(); - let datetime_utc = DateTime::::from_utc(naivedatetime_utc, crate::UTC_OFFSET_CHRONO); + let datetime_utc = + DateTime::::from_naive_utc_and_offset(naivedatetime_utc, crate::UTC_OFFSET_CHRONO); self.datetime = Some(datetime_utc); Ok(reading) @@ -265,10 +267,9 @@ pub struct RTCReading { } impl RTCReading { - pub fn to_s(&self) -> Result { + pub fn to_s(&self) -> Result> { let weekday: Weekday = self.weekday.into(); - - Ok(format!( + let text = format!( "{} {}-{:0>2}-{:0>2} {:0>2}:{:0>2}:{:0>2} {}", weekday, self.year, @@ -278,7 +279,11 @@ impl RTCReading { self.minutes, self.seconds, crate::UTC_OFFSET_CHRONO - )) + ); + + let resp: String<255> = String::from_str(text.as_str()).expect("Returns heapless String"); + + Ok(resp) } } @@ -294,8 +299,8 @@ pub struct SystemTimeBuffer { } impl SystemTimeBuffer { - pub fn to_s(&self) -> Result { - Ok(format!( + pub fn to_s(&self) -> Result> { + let text = format!( "{} {}-{:0>2}-{:0>2} {:0>2}:{:0>2}:{:0>2} {}", self.weekday().expect("Unwrapping weekday"), self.year, @@ -305,15 +310,26 @@ impl SystemTimeBuffer { self.minutes, self.seconds, crate::UTC_OFFSET_CHRONO - )) + ); + + let resp: String<255> = String::from_str(text.as_str()).expect("Returns heapless String"); + + Ok(resp) } fn to_timestamp(&self) -> Result { Ok(self.datetime.timestamp()) } - pub fn to_rfc3339(&self) -> Result { - Ok(self.datetime.to_rfc3339()) + pub fn to_rfc3339(&self) -> Result> { + // let bytes = self.datetime.to_rfc3339().into_bytes(); + // let mut heapless_vec: heapless::Vec = heapless::Vec::new(); + // heapless_vec.extend_from_slice(&bytes[..]); + + let resp: String<255> = + String::from_str(self.datetime.to_rfc3339().as_str()).expect("Returns heapless String"); + + Ok(resp) } pub fn weekday(&self) -> Result { @@ -386,7 +402,8 @@ pub(crate) mod rtc_external { )); }; - let datetime_utc = DateTime::::from_utc(naivedatetime_utc, UTC_OFFSET_CHRONO); + let datetime_utc = + DateTime::::from_naive_utc_and_offset(naivedatetime_utc, UTC_OFFSET_CHRONO); let buf = SystemTimeBuffer { date: datetime_utc.day() as u8, @@ -437,9 +454,11 @@ pub(crate) mod rtc_external { } // Returns the first 3-letters of the day of the week - pub fn as_short(&self) -> Result { + pub fn as_short(&self) -> Result> { + type HeaplessString = String<3>; + let day = self.as_str(); - let result: String = day.chars().take(3).collect(); + let result: HeaplessString = day.chars().take(3).collect(); Ok(result) } diff --git a/rued-esp32/src/mqtt_msg.rs b/rued-esp32/src/mqtt_msg.rs index e90ba70..a373df8 100644 --- a/rued-esp32/src/mqtt_msg.rs +++ b/rued-esp32/src/mqtt_msg.rs @@ -1,123 +1,123 @@ -use crate::models::OtaUrl; -use core::str; -use embedded_svc::mqtt::client::asynch::{Event, Message}; -use embedded_svc::mqtt::client::Details; -use log::*; -use serde::{Deserialize, Serialize}; +// use crate::models::OtaUrl; +// use core::str; +// use embedded_svc::mqtt::client::asynch::{Event, Message}; +// use embedded_svc::mqtt::client::Details; +// use log::*; +// use serde::{Deserialize, Serialize}; -pub const MQTT_TOPIC_POSTFIX_COMMAND: &str = "/command/#"; -pub const MQTT_TOPIC_POSTFIX_COMMAND_OTA_UPDATE: &str = "/command/ota_update"; -pub const MQTT_TOPIC_POSTFIX_COMMAND_SYSTEM_RESTART: &str = "/command/system_restart"; -pub const MQTT_TOPIC_POSTFIX_BATTERY_VOLTAGE: &str = "/battery/voltage"; +// pub const MQTT_TOPIC_POSTFIX_COMMAND: &str = "/command/#"; +// pub const MQTT_TOPIC_POSTFIX_COMMAND_OTA_UPDATE: &str = "/command/ota_update"; +// pub const MQTT_TOPIC_POSTFIX_COMMAND_SYSTEM_RESTART: &str = "/command/system_restart"; +// pub const MQTT_TOPIC_POSTFIX_BATTERY_VOLTAGE: &str = "/battery/voltage"; -#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] -pub enum MqttCommand { - ExecOTAUpdate(OtaUrl), - SystemRestart, -} +// #[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] +// pub enum MqttCommand { +// ExecOTAUpdate(OtaUrl), +// SystemRestart, +// } -pub struct MessageParser { - #[allow(clippy::type_complexity)] - command_parser: Option Option>, - payload_buf: [u8; 128], -} +// pub struct MessageParser { +// #[allow(clippy::type_complexity)] +// command_parser: Option Option>, +// payload_buf: [u8; 128], +// } -impl MessageParser { - pub fn new() -> Self { - MessageParser { - command_parser: None, - payload_buf: [0; 128], - } - } +// impl MessageParser { +// pub fn new() -> Self { +// MessageParser { +// command_parser: None, +// payload_buf: [0; 128], +// } +// } - pub fn convert( - &mut self, - event: &Result, E>, - ) -> Result>, E> - where - M: Message, - E: Clone, - { - event - .as_ref() - .map(|event| event.transform_received(|message| self.process(message))) - .map_err(|e| e.clone()) - } +// pub fn convert( +// &mut self, +// event: &Result, E>, +// ) -> Result>, E> +// where +// M: Message, +// E: Clone, +// { +// event +// .as_ref() +// .map(|event| event.transform_received(|message| self.process(message))) +// .map_err(|e| e.clone()) +// } - fn process(&mut self, message: &M) -> Option - where - M: Message, - { - info!("Message = {:?}", message.details()); - match message.details() { - Details::Complete => Self::parse_command(message.topic().unwrap()) - .and_then(|parser| parser(message.data())), - Details::InitialChunk(initial_chunk_data) => { - if initial_chunk_data.total_data_size > self.payload_buf.len() { - self.command_parser = None; - } else { - self.command_parser = Self::parse_command(message.topic().unwrap()); +// fn process(&mut self, message: &M) -> Option +// where +// M: Message, +// { +// info!("Message = {:?}", message.details()); +// match message.details() { +// Details::Complete => Self::parse_command(message.topic().unwrap()) +// .and_then(|parser| parser(message.data())), +// Details::InitialChunk(initial_chunk_data) => { +// if initial_chunk_data.total_data_size > self.payload_buf.len() { +// self.command_parser = None; +// } else { +// self.command_parser = Self::parse_command(message.topic().unwrap()); - self.payload_buf[..message.data().len()] - .copy_from_slice(message.data().as_ref()); - } +// self.payload_buf[..message.data().len()] +// .copy_from_slice(message.data().as_ref()); +// } - None - } - Details::SubsequentChunk(subsequent_chunk_data) => { - if let Some(command_parser) = self.command_parser.as_ref() { - self.payload_buf - [subsequent_chunk_data.current_data_offset..message.data().len()] - .copy_from_slice(message.data().as_ref()); +// None +// } +// Details::SubsequentChunk(subsequent_chunk_data) => { +// if let Some(command_parser) = self.command_parser.as_ref() { +// self.payload_buf +// [subsequent_chunk_data.current_data_offset..message.data().len()] +// .copy_from_slice(message.data().as_ref()); - if subsequent_chunk_data.total_data_size - == subsequent_chunk_data.current_data_offset + message.data().len() - { - command_parser(&self.payload_buf[0..subsequent_chunk_data.total_data_size]) - } else { - None - } - } else { - None - } - } - } - } +// if subsequent_chunk_data.total_data_size +// == subsequent_chunk_data.current_data_offset + message.data().len() +// { +// command_parser(&self.payload_buf[0..subsequent_chunk_data.total_data_size]) +// } else { +// None +// } +// } else { +// None +// } +// } +// } +// } - #[allow(clippy::type_complexity)] - fn parse_command(topic: &str) -> Option Option> { - info!("parse_command: {}", topic); - if topic.ends_with(MQTT_TOPIC_POSTFIX_COMMAND_OTA_UPDATE) { - Some(Self::parse_ota_update_command) - } else if topic.ends_with(MQTT_TOPIC_POSTFIX_COMMAND_SYSTEM_RESTART) { - Some(Self::parse_system_restart_command) - } else { - None - } - } +// #[allow(clippy::type_complexity)] +// fn parse_command(topic: &str) -> Option Option> { +// info!("parse_command: {}", topic); +// if topic.ends_with(MQTT_TOPIC_POSTFIX_COMMAND_OTA_UPDATE) { +// Some(Self::parse_ota_update_command) +// } else if topic.ends_with(MQTT_TOPIC_POSTFIX_COMMAND_SYSTEM_RESTART) { +// Some(Self::parse_system_restart_command) +// } else { +// None +// } +// } - fn parse_ota_update_command(data: &[u8]) -> Option { - Self::parse::(data).map(MqttCommand::ExecOTAUpdate) - } +// fn parse_ota_update_command(data: &[u8]) -> Option { +// Self::parse::(data).map(MqttCommand::ExecOTAUpdate) +// } - fn parse_system_restart_command(data: &[u8]) -> Option { - Self::parse_empty(data).map(|_| MqttCommand::SystemRestart) - } +// fn parse_system_restart_command(data: &[u8]) -> Option { +// Self::parse_empty(data).map(|_| MqttCommand::SystemRestart) +// } - fn parse(data: &[u8]) -> Option - where - T: str::FromStr, - { - str::from_utf8(data) - .ok() - .and_then(|s| str::parse::(s).ok()) - } +// fn parse(data: &[u8]) -> Option +// where +// T: str::FromStr, +// { +// str::from_utf8(data) +// .ok() +// .and_then(|s| str::parse::(s).ok()) +// } - fn parse_empty(data: &[u8]) -> Option<()> { - if data.is_empty() { - Some(()) - } else { - None - } - } -} +// fn parse_empty(data: &[u8]) -> Option<()> { +// if data.is_empty() { +// Some(()) +// } else { +// None +// } +// } +// } diff --git a/rued-esp32/src/peripherals.rs b/rued-esp32/src/peripherals.rs index 06e72b4..e45685e 100644 --- a/rued-esp32/src/peripherals.rs +++ b/rued-esp32/src/peripherals.rs @@ -1,8 +1,15 @@ use std::marker::PhantomData; use esp_idf_svc::hal::{ - adc::*, gpio::*, i2c::*, interrupt::InterruptType, ledc::*, modem::Modem, - peripherals::Peripherals, spi::*, units::Hertz, + adc::*, + gpio::*, + i2c::*, + interrupt::InterruptType, + ledc::*, + modem::Modem, + peripherals::Peripherals, + spi::{self, *}, + units::Hertz, }; use shared_bus::{BusManager, NullMutex}; @@ -178,15 +185,16 @@ impl SystemPeripherals { cs: Some(peripherals.pins.gpio15.into()), // HEADER_CS / G0-Processor }; + let spi_config = spi::SpiDriverConfig::new(); let driver = std::sync::Arc::new( SpiDriver::new( spi1.spi, spi1.sclk, // SCK spi1.sdo, // MOSI Some(spi1.sdi), // MISO / NOTE: Default value - Dma::Disabled, + &spi_config, ) - .unwrap(), + .expect("Initialise an instance of `SpiDriver`"), ); let spi1 = SpiBusPeripherals { diff --git a/rued-esp32/src/services.rs b/rued-esp32/src/services.rs index 081abd4..eb7b092 100644 --- a/rued-esp32/src/services.rs +++ b/rued-esp32/src/services.rs @@ -63,15 +63,13 @@ use gfx_xtra::draw_target::{Flushable, OwnedDrawTargetExt}; use edge_executor::*; use shared_bus::BusManager; -// FIXME This is MQTT based on ruwm -// use crate::core::internal::mqtt::{MessageParser, MqttCommand}; +use crate::core::internal::mqtt::{MessageParser, MqttCommand}; use crate::core::internal::pulse_counter::PulseCounter; use crate::core::internal::pulse_counter::PulseWakeup; use crate::core::internal::ws; use crate::core::internal::screen::Color; -use crate::mqtt_msg::{MessageParser, MqttCommand}; // use ruwm::button::PressedLevel; // use ruwm::pulse_counter::PulseCounter; // use ruwm::pulse_counter::PulseWakeup; @@ -221,7 +219,6 @@ pub fn pulse( let pulse_counter = crate::core::internal::pulse_counter::CpuPulseCounter::new( subscribe_pin(peripherals.pulse, || PULSE_SIGNAL.notify())?, crate::core::internal::button::PressedLevel::Low, - &PULSE_SIGNAL, Some(Duration::from_millis(50)), ); @@ -247,7 +244,8 @@ pub fn pulse( pub fn button<'d, P: InputPin + OutputPin>( pin: impl Peripheral

+ 'd, notification: &'static Notification, -) -> Result { +) -> Result +{ let resp = subscribe_pin(pin, move || notification.notify())?; Ok(resp) @@ -341,7 +339,6 @@ pub fn display<'a>( .with_display_size(240, 320) .with_framebuffer_size(240, 320) .with_color_order(mipidsi::ColorOrder::Bgr) - .with_invert_colors(true) .with_orientation(mipidsi::Orientation::PortraitInverted(true)) .init(&mut delay::Ets, Some(rst)) .unwrap() @@ -378,7 +375,7 @@ pub fn display<'a>( display.owned_cropped(display, &rect) }; - let display = display.owned_color_converted().owned_noop_flushing(); + let display = display.owned_noop_flushing().owned_color_converted(); Ok(display) } @@ -386,7 +383,7 @@ pub fn display<'a>( // TODO: Make it async pub fn wifi<'d>( modem: impl Peripheral

+ 'd, - sysloop: EspSystemEventLoop, + mut sysloop: EspSystemEventLoop, timer_service: EspTaskTimerService, partition: Option, auth_method: AuthMethod, @@ -422,7 +419,7 @@ pub fn wifi<'d>( bwifi.wait_netif_up()?; - let wifi = AsyncWifi::wrap(wifi, sysloop, timer_service)?; + let wifi = AsyncWifi::wrap(wifi, sysloop.clone(), timer_service)?; Ok(( wifi, @@ -430,7 +427,7 @@ pub fn wifi<'d>( )) } -pub fn httpd() -> Result, InitError> { +pub fn httpd<'a>() -> Result, InitError> { let server_certificate = tls::X509::pem_until_nul(include_bytes!( "/home/mike/esp/openssl-generate-rs/output/cert.pem" )); @@ -447,11 +444,11 @@ pub fn httpd() -> Result, InitError> { Ok(httpd) } -pub fn mqtt<'a>() -> Result< +pub fn mqtt() -> Result< ( &'static str, impl Client + Publish, - impl Connection = Option>, + impl for<'a> Connection = Option> + 'static, ), InitError, > { @@ -507,7 +504,8 @@ pub fn adc<'d, const A: adc_atten_t, ADC: Adc + 'd, P: ADCPin>( fn subscribe_pin<'d, P: InputPin + OutputPin>( pin: impl Peripheral

+ 'd, notify: impl Fn() + Send + 'static, -) -> Result { +) -> Result +{ let mut pin = PinDriver::input(pin)?; pin.set_interrupt_type(InterruptType::NegEdge)?; diff --git a/rued-esp32/src/services/httpd.rs b/rued-esp32/src/services/httpd.rs index 5726384..fd79345 100644 --- a/rued-esp32/src/services/httpd.rs +++ b/rued-esp32/src/services/httpd.rs @@ -8,14 +8,14 @@ pub struct LazyInitHttpServer<'a> { config: Configuration, } -impl LazyInitHttpServer<'_> { +impl<'a> LazyInitHttpServer<'a> { pub fn new(config: Configuration) -> Self { Self { data: Rc::new(RefCell::new(None)), config, } } - pub fn create(&self) -> RefMut<'_, EspHttpServer> { + pub fn create(&self) -> RefMut<'a, EspHttpServer> { if self.data.borrow().is_none() { *self.data.borrow_mut() = Some(EspHttpServer::new(&self.config).unwrap()); } @@ -24,7 +24,7 @@ impl LazyInitHttpServer<'_> { } #[allow(dead_code)] - pub fn get(&self) -> Option> { + pub fn get(&self) -> Option> { let m = self.data.borrow_mut(); if m.is_some() { Some(RefMut::map(m, |m| m.as_mut().unwrap())) From 92281bd12facc4a3b148429e3e9282d75ea0596d Mon Sep 17 00:00:00 2001 From: Michael de Silva Date: Thu, 14 Dec 2023 11:33:28 +0530 Subject: [PATCH 05/11] Use `rv8803` package on Crates.io --- rued-esp32/Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rued-esp32/Cargo.toml b/rued-esp32/Cargo.toml index 60646c5..29b127a 100644 --- a/rued-esp32/Cargo.toml +++ b/rued-esp32/Cargo.toml @@ -64,8 +64,7 @@ serde_json = "1.0.87" cstr_core = "0.2.6" uncased = { version = "0.9.7" } shared-bus = { version = "0.2", features = ["std"] } -# rv8803-rs = { git = "https://github.com/bsodmike/rv8803-rs" } -rv8803 = { path = "/home/mike/esp/rv8803-rs" } +rv8803 = { version = "0.3" } embedded-sdmmc = { git = "https://github.com/rust-embedded-community/embedded-sdmmc-rs", branch = "develop" } # optional dependencies From cefd4169b3a073833ed220e1acf5ae39db716ddb Mon Sep 17 00:00:00 2001 From: Michael de Silva Date: Sat, 16 Dec 2023 17:07:51 +0530 Subject: [PATCH 06/11] Initial patch for httpd as static --- rued-esp32/Cargo.toml | 4 +-- rued-esp32/src/core/internal/httpd.rs | 2 +- rued-esp32/src/core/internal/spawn.rs | 4 +-- rued-esp32/src/main.rs | 41 +++++++++++++++++++++++++-- rued-esp32/src/services.rs | 4 +-- rued-esp32/src/services/httpd.rs | 12 +++++--- sdkconfig.defaults | 3 ++ 7 files changed, 57 insertions(+), 13 deletions(-) diff --git a/rued-esp32/Cargo.toml b/rued-esp32/Cargo.toml index 29b127a..ae27c17 100644 --- a/rued-esp32/Cargo.toml +++ b/rued-esp32/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rued-esp32" -version = "4.0.0" +version = "5.0.0" authors = ["Michael de Silva "] edition = "2021" resolver = "2" @@ -36,7 +36,7 @@ log = { version = "0.4", features = [ "release_max_level_debug", ] } futures = {version = "0.3", features = ["async-await"] } -serde = { version = "1", default-features = false, features = ["derive"]} +serde = { version = "1", default-features = false, features = ["derive"] } postcard = "0.7" heapless = { version = "0.7", features = ["serde"] } critical-section = "1.1" diff --git a/rued-esp32/src/core/internal/httpd.rs b/rued-esp32/src/core/internal/httpd.rs index 0fe40e2..7f88ae3 100644 --- a/rued-esp32/src/core/internal/httpd.rs +++ b/rued-esp32/src/core/internal/httpd.rs @@ -40,7 +40,7 @@ pub enum HttpdCommand { pub(crate) static COMMAND: Signal = Signal::new(); -pub async fn process<'a>(httpd: &'a mut LazyInitHttpServer<'a>) { +pub async fn process(httpd: &mut LazyInitHttpServer<'static>) { const FIRMWARE_VERSION: &str = env!("CARGO_PKG_VERSION"); let mut network_event = NETWORK_EVENT_CHANNEL.subscriber().unwrap(); diff --git a/rued-esp32/src/core/internal/spawn.rs b/rued-esp32/src/core/internal/spawn.rs index 6e7cb91..b6679b5 100644 --- a/rued-esp32/src/core/internal/spawn.rs +++ b/rued-esp32/src/core/internal/spawn.rs @@ -37,7 +37,7 @@ pub fn high_prio<'a, const C: usize>( battery_voltage: impl crate::core::internal::battery::Adc + 'a, power_pin: impl InputPin + 'a, // display: D, - // httpd: &'a mut LazyInitHttpServer<'a>, + httpd: &'a mut LazyInitHttpServer<'static>, pwm: Option<( impl PwmPin + 'a, impl PwmPin + 'a, @@ -57,7 +57,7 @@ pub fn high_prio<'a, const C: usize>( // executor.spawn(screen::run_draw(display)).detach(); // FIXME - // executor.spawn(super::httpd::process(httpd)).detach(); + executor.spawn(super::httpd::process(httpd)).detach(); executor.spawn(super::pwm::process(pwm)).detach(); executor.spawn(super::sntp::process()).detach(); diff --git a/rued-esp32/src/main.rs b/rued-esp32/src/main.rs index 2c32195..33e5fca 100644 --- a/rued-esp32/src/main.rs +++ b/rued-esp32/src/main.rs @@ -368,9 +368,46 @@ fn run(wakeup_reason: WakeupReason) -> Result<(), InitError> { // Httpd // FIXME - // let mut httpd = services::httpd()?; + use esp_idf_svc::http::server::Middleware; + use esp_idf_svc::io::Write; + + // const FIRMWARE_VERSION: &str = env!("CARGO_PKG_VERSION"); + let mut httpd = services::httpd()?; + // let http_server = esp_idf_svc::http::server::EspHttpServer::new(&config); + // let ws_acceptor = httpd::configure_websockets(&mut httpd)?; + // let mut s = httpd; + + // // log::info!("http_server_task: starting httpd on address: {:?}", ip); + // if let Err(err) = s.handler( + // "/", + // embedded_svc::http::Method::Get, + // crate::httpd::middleware::DefaultMiddleware {}.compose( + // // + // esp_idf_svc::http::server::fn_handler(move |req| { + // let mut headers = embedded_svc::utils::http::Headers::<1>::new(); + // headers.set_cache_control("no-store"); + + // let mut resp = req.into_response(200, None, headers.as_slice())?; + // resp.write_all(FIRMWARE_VERSION.as_bytes())?; + + // log::info!("Processing '/' request"); + // Ok(()) + // }), + // ), + // ) { + // log::info!( + // "http_server_task: failed to register http handler /: {:?} - restarting device", + // err + // ); + // unsafe { + // esp_idf_svc::sys::esp_restart(); + // } + // } + + // crate::httpd::configure_handlers(&mut s).expect("Configure handlers for HTTPd server"); + // Mqtt let (mqtt_topic_prefix, mqtt_client, mqtt_conn) = services::mqtt()?; @@ -467,7 +504,7 @@ fn run(wakeup_reason: WakeupReason) -> Result<(), InitError> { battery_voltage, PinDriver::input(peripherals.battery.power)?, // display, - // &mut httpd, + &mut httpd, pwm, rtc_clock, move |_new_state| { diff --git a/rued-esp32/src/services.rs b/rued-esp32/src/services.rs index eb7b092..5493998 100644 --- a/rued-esp32/src/services.rs +++ b/rued-esp32/src/services.rs @@ -427,7 +427,7 @@ pub fn wifi<'d>( )) } -pub fn httpd<'a>() -> Result, InitError> { +pub fn httpd() -> Result, InitError> { let server_certificate = tls::X509::pem_until_nul(include_bytes!( "/home/mike/esp/openssl-generate-rs/output/cert.pem" )); @@ -439,7 +439,7 @@ pub fn httpd<'a>() -> Result, InitError> { config.server_certificate = Some(server_certificate); config.private_key = Some(server_private_key); - let httpd = LazyInitHttpServer::new(config); + let httpd: LazyInitHttpServer<'static> = LazyInitHttpServer::new(config); Ok(httpd) } diff --git a/rued-esp32/src/services/httpd.rs b/rued-esp32/src/services/httpd.rs index fd79345..f2b48f3 100644 --- a/rued-esp32/src/services/httpd.rs +++ b/rued-esp32/src/services/httpd.rs @@ -8,23 +8,27 @@ pub struct LazyInitHttpServer<'a> { config: Configuration, } -impl<'a> LazyInitHttpServer<'a> { +impl LazyInitHttpServer<'static> { pub fn new(config: Configuration) -> Self { Self { data: Rc::new(RefCell::new(None)), config, } } - pub fn create(&self) -> RefMut<'a, EspHttpServer> { + pub fn create(&self) -> RefMut<'_, EspHttpServer<'static>> { + // let server = EspHttpServer::new(&self.config).unwrap(); + if self.data.borrow().is_none() { *self.data.borrow_mut() = Some(EspHttpServer::new(&self.config).unwrap()); } let m = self.data.borrow_mut(); - RefMut::map(m, |m| m.as_mut().unwrap()) + + let resp = RefMut::map(m, |m| m.as_mut().unwrap()); + resp } #[allow(dead_code)] - pub fn get(&self) -> Option> { + pub fn get(&self) -> Option>> { let m = self.data.borrow_mut(); if m.is_some() { Some(RefMut::map(m, |m| m.as_mut().unwrap())) diff --git a/sdkconfig.defaults b/sdkconfig.defaults index bc58ff1..e85008a 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -29,6 +29,9 @@ CONFIG_HTTPD_WS_SUPPORT=y # Enable TLS CONFIG_ESP_HTTPS_SERVER_ENABLE=y +CONFIG_ESP_HTTP_CLIENT_ENABLED=y +CONFIG_ESP_HTTP_SERVER_ENABLED=y + # This is 10 by default. 16 is the maximum CONFIG_LWIP_MAX_SOCKETS=16 From 50644fb275f93809b49905e286b0413acb0e7450 Mon Sep 17 00:00:00 2001 From: Michael de Silva Date: Tue, 19 Dec 2023 17:31:22 +0530 Subject: [PATCH 07/11] Fixes for http and pwm --- rued-esp32/Cargo.toml | 5 ++-- rued-esp32/src/core/internal/httpd.rs | 3 ++- rued-esp32/src/core/internal/pwm.rs | 32 ++++++++++------------ rued-esp32/src/main.rs | 38 --------------------------- rued-esp32/src/peripherals.rs | 8 +++--- rued-esp32/src/services/httpd.rs | 6 +---- 6 files changed, 24 insertions(+), 68 deletions(-) diff --git a/rued-esp32/Cargo.toml b/rued-esp32/Cargo.toml index ae27c17..9e6f38f 100644 --- a/rued-esp32/Cargo.toml +++ b/rued-esp32/Cargo.toml @@ -11,7 +11,7 @@ rust-version = "1.71" [features] default = ["system", "experimental"] # system = ["display-i2c"] -system = ["display-spi", "nvs", "external-rtc", "board"] +system = ["display-spi", "nvs", "external-rtc", "board1"] external-rtc = [] nvs = [] @@ -21,7 +21,8 @@ display-binary-color = [] display-spi = ["profont", "ili9342"] ili9342 = ["profont", "mipidsi"] -board = ["micromod-data-logging-carrier"] +board1 = ["micromod-data-logging-carrier"] +board2 = ["micromod-qwiic-carrier-single", "micromod-main-board-single", "pwm"] micromod-qwiic-carrier-single = [] micromod-main-board-single = [] micromod-data-logging-carrier = [] diff --git a/rued-esp32/src/core/internal/httpd.rs b/rued-esp32/src/core/internal/httpd.rs index 7f88ae3..fd380be 100644 --- a/rued-esp32/src/core/internal/httpd.rs +++ b/rued-esp32/src/core/internal/httpd.rs @@ -5,6 +5,7 @@ use embedded_svc::io::{Read, Write as EmbeddedSvcIoWrite}; use log::trace; use serde::{Deserialize, Serialize}; use serde_json::json; +use std::borrow::BorrowMut; use std::fmt::Write; use std::ops::Deref; use std::primitive::u8; @@ -75,7 +76,7 @@ pub async fn process(httpd: &mut LazyInitHttpServer<'static>) { match network_state { Some(NetworkStateChange::IpAddressAssigned { ip }) => { - let mut s = httpd.create(); + let mut s: std::cell::RefMut<'_, EspHttpServer<'static>> = httpd.create(); log::info!("http_server_task: starting httpd on address: {:?}", ip); if let Err(err) = s.handler( diff --git a/rued-esp32/src/core/internal/pwm.rs b/rued-esp32/src/core/internal/pwm.rs index 8d2741a..50f1ac3 100644 --- a/rued-esp32/src/core/internal/pwm.rs +++ b/rued-esp32/src/core/internal/pwm.rs @@ -64,25 +64,12 @@ pub(crate) static COMMAND: Signal = Signal: pub const DEFAULT_DUTY_CYCLE: u32 = 50; pub async fn process<'a>( - pwm: Option<( + #[allow(unused_mut)] mut pwm: Option<( impl PwmPin + 'a, impl PwmPin + 'a, impl PwmPin + 'a, )>, ) { - let mut pwm0: LedcDriver<'a>; - let mut pwm1: LedcDriver<'a>; - let mut pwm2: LedcDriver<'a>; - - #[cfg(feature = "pwm")] - { - let (pwm0, pwm1, pwm2) = pwm.expect("Unwraps pwm channels"); - - set_duty(&mut pwm0, DEFAULT_DUTY_CYCLE); - set_duty(&mut pwm1, DEFAULT_DUTY_CYCLE); - set_duty(&mut pwm2, DEFAULT_DUTY_CYCLE); - } - loop { let (future, index) = select_array([COMMAND.wait()]).await; @@ -91,20 +78,29 @@ pub async fn process<'a>( match index { 0 => match future { PwmCommand::SetDutyCycle(percentage) => { + let (ref mut pwm0, ref mut pwm1, ref mut pwm2) = + pwm.as_mut().expect("Unwraps pwm channels"); log::info!("PwmCommand::SetDutyCycle: {}", percentage); if percentage > 100 { log::warn!("PWM duty-cycle cannot exceed 100%"); return; } else { - set_duty(&mut pwm0, percentage); - set_duty(&mut pwm1, percentage); - set_duty(&mut pwm2, percentage); + set_duty(pwm0, percentage); + set_duty(pwm1, percentage); + set_duty(pwm2, percentage); STATE.update(future); } } - PwmCommand::Initialised => {} + PwmCommand::Initialised => { + let (ref mut pwm0, ref mut pwm1, ref mut pwm2) = + pwm.as_mut().expect("Unwraps pwm channels"); + + set_duty(pwm0, DEFAULT_DUTY_CYCLE); + set_duty(pwm1, DEFAULT_DUTY_CYCLE); + set_duty(pwm2, DEFAULT_DUTY_CYCLE); + } }, _ => unreachable!(), } diff --git a/rued-esp32/src/main.rs b/rued-esp32/src/main.rs index 33e5fca..5c77f6c 100644 --- a/rued-esp32/src/main.rs +++ b/rued-esp32/src/main.rs @@ -367,47 +367,9 @@ fn run(wakeup_reason: WakeupReason) -> Result<(), InitError> { // Httpd - // FIXME - use esp_idf_svc::http::server::Middleware; - use esp_idf_svc::io::Write; - - // const FIRMWARE_VERSION: &str = env!("CARGO_PKG_VERSION"); let mut httpd = services::httpd()?; - // let http_server = esp_idf_svc::http::server::EspHttpServer::new(&config); - // let ws_acceptor = httpd::configure_websockets(&mut httpd)?; - // let mut s = httpd; - - // // log::info!("http_server_task: starting httpd on address: {:?}", ip); - // if let Err(err) = s.handler( - // "/", - // embedded_svc::http::Method::Get, - // crate::httpd::middleware::DefaultMiddleware {}.compose( - // // - // esp_idf_svc::http::server::fn_handler(move |req| { - // let mut headers = embedded_svc::utils::http::Headers::<1>::new(); - // headers.set_cache_control("no-store"); - - // let mut resp = req.into_response(200, None, headers.as_slice())?; - // resp.write_all(FIRMWARE_VERSION.as_bytes())?; - - // log::info!("Processing '/' request"); - // Ok(()) - // }), - // ), - // ) { - // log::info!( - // "http_server_task: failed to register http handler /: {:?} - restarting device", - // err - // ); - // unsafe { - // esp_idf_svc::sys::esp_restart(); - // } - // } - - // crate::httpd::configure_handlers(&mut s).expect("Configure handlers for HTTPd server"); - // Mqtt let (mqtt_topic_prefix, mqtt_client, mqtt_conn) = services::mqtt()?; diff --git a/rued-esp32/src/peripherals.rs b/rued-esp32/src/peripherals.rs index e45685e..f58edf3 100644 --- a/rued-esp32/src/peripherals.rs +++ b/rued-esp32/src/peripherals.rs @@ -60,7 +60,7 @@ pub struct SystemPeripherals< impl SystemPeripherals< Gpio33, - ADC1, + ADC2, Gpio2, Gpio32, Gpio0, @@ -92,7 +92,7 @@ impl spi1.sclk, // SCK spi1.sdo, // MOSI Some(spi1.sdi), // MISO / NOTE: Default value - Dma::Disabled, + &spi::SpiDriverConfig::new(), ) .unwrap(), ); @@ -116,7 +116,7 @@ impl battery: BatteryPeripherals { power: peripherals.pins.gpio35.into(), // A1 voltage: peripherals.pins.gpio2, - adc: peripherals.adc1, + adc: peripherals.adc2, }, buttons: ButtonsPeripherals { button1: peripherals.pins.gpio32, // G5 @@ -277,7 +277,7 @@ impl SystemPeripherals { spi1.sclk, // SCK spi1.sdo, // MOSI Some(spi1.sdi), // MISO / NOTE: Default value - Dma::Disabled, + &spi::SpiDriverConfig::new(), ) .unwrap(), ); diff --git a/rued-esp32/src/services/httpd.rs b/rued-esp32/src/services/httpd.rs index f2b48f3..e0af3c9 100644 --- a/rued-esp32/src/services/httpd.rs +++ b/rued-esp32/src/services/httpd.rs @@ -16,15 +16,11 @@ impl LazyInitHttpServer<'static> { } } pub fn create(&self) -> RefMut<'_, EspHttpServer<'static>> { - // let server = EspHttpServer::new(&self.config).unwrap(); - if self.data.borrow().is_none() { *self.data.borrow_mut() = Some(EspHttpServer::new(&self.config).unwrap()); } let m = self.data.borrow_mut(); - - let resp = RefMut::map(m, |m| m.as_mut().unwrap()); - resp + RefMut::map(m, |m| m.as_mut().unwrap()) } #[allow(dead_code)] From b921ec1c5e5621058526308da51e578ba4d41cc4 Mon Sep 17 00:00:00 2001 From: Michael de Silva Date: Wed, 20 Dec 2023 10:32:07 +0530 Subject: [PATCH 08/11] Add testing code for accessing SD Card --- rued-esp32/src/errors.rs | 14 +++++++++++ rued-esp32/src/main.rs | 51 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/rued-esp32/src/errors.rs b/rued-esp32/src/errors.rs index a3d735e..97bc2d0 100644 --- a/rued-esp32/src/errors.rs +++ b/rued-esp32/src/errors.rs @@ -5,6 +5,7 @@ use std::io::Error as IoError; // use edge_executor::SpawnError; use futures::task::SpawnError; +use embedded_sdmmc::SdCardError; use esp_idf_svc::hal::i2c::I2cError; use esp_idf_svc::io::EspIOError; use esp_idf_svc::sys::EspError; @@ -20,6 +21,7 @@ pub enum InitError { IoError(IoError), I2cError(I2cError), OtaError(OtaError), + SdCardError(embedded_sdmmc::Error), } impl From for InitError { @@ -64,6 +66,18 @@ impl From for InitError { } } +impl From> for InitError { + fn from(e: embedded_sdmmc::Error) -> Self { + Self::SdCardError(e) + } +} + +impl From for InitError { + fn from(e: SdCardError) -> Self { + Self::SdCardError(embedded_sdmmc::Error::DeviceError(e)) + } +} + // OTA #[derive(Debug)] diff --git a/rued-esp32/src/main.rs b/rued-esp32/src/main.rs index 5c77f6c..a165de0 100644 --- a/rued-esp32/src/main.rs +++ b/rued-esp32/src/main.rs @@ -433,8 +433,55 @@ fn run(wakeup_reason: WakeupReason) -> Result<(), InitError> { let sdmmc_cs = PinDriver::output(peripherals.sd_card.cs)?; // FIXME - // NOTE upgrade - // let sdmmc_spi = embedded_sdmmc::SdMmcSpi::new(sdmmc_spi, sdmmc_cs); + struct FakeDelayer(); + + impl embedded_hal_0_2::blocking::delay::DelayUs for FakeDelayer { + fn delay_us(&mut self, us: u8) { + std::thread::sleep(std::time::Duration::from_micros(u64::from(us))); + } + } + + struct FakeTimesource(); + + impl embedded_sdmmc::TimeSource for FakeTimesource { + fn get_timestamp(&self) -> embedded_sdmmc::Timestamp { + embedded_sdmmc::Timestamp { + year_since_1970: 0, + zero_indexed_month: 0, + zero_indexed_day: 0, + hours: 0, + minutes: 0, + seconds: 0, + } + } + } + + let delay = FakeDelayer(); + let time_source = FakeTimesource(); + // Build an SD Card interface out of an SPI device, a chip-select pin and the delay object + let sdcard = embedded_sdmmc::SdCard::new(sdmmc_spi, sdmmc_cs, delay); + // Get the card size (this also triggers card initialisation because it's not been done yet) + println!("Card size is {} bytes", sdcard.num_bytes()?); + // Now let's look for volumes (also known as partitions) on our block device. + // To do this we need a Volume Manager. It will take ownership of the block device. + let mut volume_mgr = embedded_sdmmc::VolumeManager::new(sdcard, time_source); + // Try and access Volume 0 (i.e. the first partition). + // The volume object holds information about the filesystem on that volume. + let mut volume0 = volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(0))?; + println!("Volume 0: {:?}", volume0); + // Open the root directory (mutably borrows from the volume). + let mut root_dir = volume0.open_root_dir()?; + // Open a file called "MY_FILE.TXT" in the root directory + // This mutably borrows the directory. + let mut my_file = root_dir.open_file_in_dir("MY_FILE.TXT", embedded_sdmmc::Mode::ReadOnly)?; + // Print the contents of the file + while !my_file.is_eof() { + let mut buffer = [0u8; 32]; + let num_read = my_file.read(&mut buffer)?; + for b in &buffer[0..num_read] { + print!("{}", *b as char); + } + } // High-prio tasks From 940857e074b3024d542e86bddb59d320daa5f411 Mon Sep 17 00:00:00 2001 From: Michael de Silva Date: Sun, 25 Feb 2024 16:30:39 +0530 Subject: [PATCH 09/11] FIXME upgrade for rv8803 changes --- rued-esp32/Cargo.toml | 30 ++++++++++++++++-------------- rued-esp32/src/main.rs | 21 +-------------------- rued-esp32/src/models.rs | 3 --- 3 files changed, 17 insertions(+), 37 deletions(-) diff --git a/rued-esp32/Cargo.toml b/rued-esp32/Cargo.toml index 9e6f38f..4082a70 100644 --- a/rued-esp32/Cargo.toml +++ b/rued-esp32/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" resolver = "2" license = "MIT OR Apache-2.0" readme = "README.md" -rust-version = "1.71" +rust-version = "1.75" [features] default = ["system", "experimental"] @@ -38,21 +38,21 @@ log = { version = "0.4", features = [ ] } futures = {version = "0.3", features = ["async-await"] } serde = { version = "1", default-features = false, features = ["derive"] } -postcard = "0.7" +postcard = { git = "https://github.com/jamesmunns/postcard" } heapless = { version = "0.7", features = ["serde"] } critical-section = "1.1" -embedded-hal = { version = "1.0.0-rc.1" } -embedded-hal-async = "1.0.0-rc.1" +embedded-hal = { version = "^1.0" } +embedded-hal-async = "^1.0" embedded-hal-0-2 = { package = "embedded-hal", version = "0.2", features = ["unproven"] } -embedded-svc = { version = "0.26", features = ["nightly"] } -esp-idf-svc = { version = "0.47", features = ["nightly", "critical-section", "embassy-time-driver", "embassy-time-isr-queue", "wake-from-isr"] } +embedded-svc = { version = "0.27.1", features = ["nightly"] } +esp-idf-svc = { version = "0.48.1", features = ["nightly", "critical-section", "embassy-time-driver", "wake-from-isr"] } embassy-futures = { version = "0.1" } -embassy-sync = { version = "0.3", features = ["std"] } -embassy-time = { version = "0.1" } +embassy-sync = { version = "^0.5", features = ["std"] } +# embassy-time = { version = "0.1.0" } static_cell = { version = "2" } edge-frame = { version = "0.7", default-features = false, features = ["dto"] } -edge-executor = { version = "0.4" } -channel-bridge = { version = "0.6", default-features = false, features = ["nightly", "embedded-svc"] } +edge-executor = { version = "^0.4" } +channel-bridge = { version = "0.8", default-features = false, features = ["embedded-svc"] } http = "0.2" # time = { version = "0.3.17", features = ["macros"] } @@ -64,15 +64,17 @@ gfx-xtra = "0.1" serde_json = "1.0.87" cstr_core = "0.2.6" uncased = { version = "0.9.7" } -shared-bus = { version = "0.2", features = ["std"] } -rv8803 = { version = "0.3" } -embedded-sdmmc = { git = "https://github.com/rust-embedded-community/embedded-sdmmc-rs", branch = "develop" } +rv8803 = { path = "../../rv8803" } + +# monkey patched to remove atomic-polyfill in favour of portable-atomic +embedded-sdmmc = { path = "../../embedded-sdmmc-rs_fork" } +shared-bus = { path = "../../shared-bus_fork", features = ["std"] } # optional dependencies profont = { version = "0.5", optional = true } ssd1306 = { version = "0.7", optional = true } ssd1351 = { version = "0.4", optional = true } -mipidsi = { version = "0.5", optional = true } +mipidsi = { version = "0.5", default-features = false, optional = true } [build-dependencies] embuild = { version = "0.31", features = ["espidf", "elf"] } diff --git a/rued-esp32/src/main.rs b/rued-esp32/src/main.rs index a165de0..8bf75a6 100644 --- a/rued-esp32/src/main.rs +++ b/rued-esp32/src/main.rs @@ -322,26 +322,7 @@ fn run(wakeup_reason: WakeupReason) -> Result<(), InitError> { let mut sntp_conf = SntpConf::default(); sntp_conf.servers = servers; - let sntp = sntp::EspSntp::new(&sntp_conf)?; - - // FIXME - // NOTE upgrade - // unsafe { - // // stop the sntp instance to redefine the callback - // // https://github.com/esp-rs/esp-idf-svc/blob/v0.42.5/src/sntp.rs#L155-L158 - // esp_idf_svc::sys::sntp_stop(); - - // // redefine and restart the callback. - // esp_idf_svc::sys::sntp_set_time_sync_notification_cb(Some( - // esp_idf_svc::sys::sntp_set_time_sync_notification_cb_custom, - // )); - - // esp_idf_svc::sys::sntp_init() - // }; - - // FIXME enable in v0.46.0 - // https://github.com/esp-rs/esp-idf-svc/pull/207 - // let sntp = sntp::EspSntp::new_with_callback(&sntp_conf, sntp_sync_callback)?; + let sntp: EspSntp<'_> = sntp::EspSntp::new_with_callback(&sntp_conf, sntp_sync_callback)?; // Wifi diff --git a/rued-esp32/src/models.rs b/rued-esp32/src/models.rs index 59e7672..caba87f 100644 --- a/rued-esp32/src/models.rs +++ b/rued-esp32/src/models.rs @@ -86,9 +86,6 @@ where + embedded_hal_0_2::blocking::i2c::WriteRead, { pub fn new(bus_manager: &'a BusManager>>) -> Result { - let address = rv8803::i2c0::Address::Default; - let rtc = Rv8803::from_i2c0(bus_manager.acquire_i2c(), address)?; - Ok(Self { datetime: None, bus_manager, From bee7fdd0c4ad3b75302a328f0b9df6c01a96f99e Mon Sep 17 00:00:00 2001 From: Michael de Silva Date: Thu, 29 Feb 2024 17:25:41 +0530 Subject: [PATCH 10/11] Upgrade monkey patched deps --- rued-esp32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rued-esp32/Cargo.toml b/rued-esp32/Cargo.toml index 4082a70..42b1fe5 100644 --- a/rued-esp32/Cargo.toml +++ b/rued-esp32/Cargo.toml @@ -67,8 +67,8 @@ uncased = { version = "0.9.7" } rv8803 = { path = "../../rv8803" } # monkey patched to remove atomic-polyfill in favour of portable-atomic -embedded-sdmmc = { path = "../../embedded-sdmmc-rs_fork" } -shared-bus = { path = "../../shared-bus_fork", features = ["std"] } +embedded-sdmmc = { git = "https://github.com/rust-embedded-community/embedded-sdmmc-rs", branch = "develop" } +shared-bus = { git = "https://github.com/bsodmike/shared-bus", branch = "upgrade_to_portable_atomic", features = ["std"] } # optional dependencies profont = { version = "0.5", optional = true } From 5ab4ba90052335a566cc2f2751a5f344f5871c50 Mon Sep 17 00:00:00 2001 From: Michael de Silva Date: Thu, 29 Feb 2024 17:33:23 +0530 Subject: [PATCH 11/11] Fix bee7fdd --- rued-esp32/src/main.rs | 5 ++++- rued-esp32/src/models.rs | 10 +++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/rued-esp32/src/main.rs b/rued-esp32/src/main.rs index 8bf75a6..6f9c37e 100644 --- a/rued-esp32/src/main.rs +++ b/rued-esp32/src/main.rs @@ -17,7 +17,10 @@ use chrono::{naive::NaiveDate, offset::Utc, DateTime, Datelike, NaiveDateTime, T use http::{header::SEC_WEBSOCKET_ACCEPT, StatusCode}; use log::{debug, error, info, warn}; use peripherals::{ButtonsPeripherals, PulseCounterPeripherals, SPI_BUS_FREQ}; -use rv8803::{i2c0::Bus as I2cBus, Rv8803, Rv8803Bus, TIME_ARRAY_LENGTH}; +use rv8803::{ + bus::Bus as I2cBus, + models::{Rv8803, TIME_ARRAY_LENGTH}, +}; use serde::{Deserialize, Serialize}; use serde_json::json; use shared_bus::{BusManager, I2cProxy}; diff --git a/rued-esp32/src/models.rs b/rued-esp32/src/models.rs index caba87f..3be4ba3 100644 --- a/rued-esp32/src/models.rs +++ b/rued-esp32/src/models.rs @@ -1,13 +1,13 @@ use anyhow::{Error, Result}; use chrono::{naive::NaiveDate, offset::Utc, DateTime, Datelike}; use esp_idf_svc::hal::i2c::{I2cDriver, I2cError}; -use esp_idf_svc::sys::settimeofday; -use esp_idf_svc::sys::time; -use esp_idf_svc::sys::timeval; -use esp_idf_svc::sys::timezone; +use esp_idf_svc::sys::{settimeofday, time, timeval, timezone}; use heapless::String; use log::{debug, info, warn}; -use rv8803::{i2c0::Bus as I2cBus, Rv8803, TIME_ARRAY_LENGTH}; +use rv8803::{ + bus::Bus as I2cBus, + models::{Rv8803, TIME_ARRAY_LENGTH}, +}; use serde::{Deserialize, Serialize}; use shared_bus::{BusManager, I2cProxy}; use std::str::FromStr;