From b542fb02a271401d826755ba3e05f83df2c2a110 Mon Sep 17 00:00:00 2001 From: Priec Date: Sun, 3 May 2026 12:58:49 +0200 Subject: [PATCH] vykostene --- tprais_semestralka1/src/bin/main.rs | 185 ++++++++++++------------- tprais_semestralka1/src/mqtt/client.rs | 62 +++------ 2 files changed, 107 insertions(+), 140 deletions(-) diff --git a/tprais_semestralka1/src/bin/main.rs b/tprais_semestralka1/src/bin/main.rs index 7c9f8a5..e924a11 100644 --- a/tprais_semestralka1/src/bin/main.rs +++ b/tprais_semestralka1/src/bin/main.rs @@ -9,20 +9,19 @@ // TODO WARNING core 1 should be logic, core 0 wifi, its flipped now use embassy_executor::Spawner; -use embassy_futures::select::{select, Either, select3, Either3}; +use embassy_futures::select::{select, select3, Either, Either3}; use embassy_net::{Runner, StackResources}; -use embassy_sync::signal::Signal; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use embassy_time::{Duration, Timer, Instant}; -use projekt_final::bus::I2cInner; +use embassy_sync::signal::Signal; +use embassy_time::{Duration, Instant, Timer}; use projekt_final::mqtt::client; use esp_alloc as _; use esp_backtrace as _; use esp_hal::{ - gpio::InputConfig, clock::CpuClock, + gpio::InputConfig, gpio::{Input, Pull}, i2c::master::{Config as I2cConfig, I2c}, rng::Rng, @@ -34,25 +33,21 @@ use esp_wifi::{ EspWifiController, }; -use pages_tui::input::Key; +use core::cell::RefCell; +use core::fmt::Write; +use heapless::String; use log::info; +use pages_tui::input::Key; use rust_mqtt::packet::v5::publish_packet::QualityOfService; use static_cell::StaticCell; -use core::cell::RefCell; -use heapless::String; -use core::fmt::Write; -use projekt_final::{ - bus, - display, - mpu, - mqtt::client::{mqtt_events, mqtt_try_publish, mqtt_publish, mqtt_subscribe, mqtt_task, IncomingMsg}, +use projekt_final::mqtt::client::{ + mqtt_events, mqtt_publish, mqtt_subscribe, mqtt_task, mqtt_try_publish, IncomingMsg, }; extern crate alloc; use alloc::format; -static I2C_BUS: StaticCell> = StaticCell::new(); static APP_CORE_STACK: StaticCell> = StaticCell::new(); static EXECUTOR_CORE1: StaticCell = StaticCell::new(); static NETWORK_READY: Signal = Signal::new(); @@ -83,17 +78,6 @@ async fn main(spawner: Spawner) -> ! { let peripherals = esp_hal::init(config); esp_alloc::heap_allocator!(size: 72 * 1024); - info!("Initializing I2C bus..."); - let i2c = I2c::new(peripherals.I2C0, I2cConfig::default()) - .expect("Failed to create I2C instance") - .with_sda(peripherals.GPIO21) - .with_scl(peripherals.GPIO22) - .into_async(); - - let i2c_bus = I2C_BUS.init(RefCell::new(i2c)); - let display_i2c = bus::new_device(i2c_bus); - let mpu_i2c = bus::new_device(i2c_bus); - info!("Initializing WiFi..."); let timg0 = TimerGroup::new(peripherals.TIMG0); let mut rng = Rng::new(peripherals.RNG); @@ -103,8 +87,7 @@ async fn main(spawner: Spawner) -> ! { esp_wifi::init(timg0.timer0, rng.clone()).unwrap() ); - let (controller, interfaces) = - esp_wifi::wifi::new(esp_wifi_ctrl, peripherals.WIFI).unwrap(); + let (controller, interfaces) = esp_wifi::wifi::new(esp_wifi_ctrl, peripherals.WIFI).unwrap(); let wifi_interface = interfaces.sta; let timg1 = TimerGroup::new(peripherals.TIMG1); @@ -114,15 +97,21 @@ async fn main(spawner: Spawner) -> ! { // Start core 1 for WiFi and MQTT (network stack created there) let mut cpu_control = CpuControl::new(peripherals.CPU_CTRL); - let _guard = cpu_control.start_app_core( - APP_CORE_STACK.init(Stack::new()), - move || { + let _guard = cpu_control + .start_app_core(APP_CORE_STACK.init(Stack::new()), move || { let executor = EXECUTOR_CORE1.init(esp_hal_embassy::Executor::new()); executor.run(|spawner| { - spawner.spawn(core1_network_task(spawner, controller, wifi_interface, seed)).ok(); + spawner + .spawn(core1_network_task( + spawner, + controller, + wifi_interface, + seed, + )) + .ok(); }); - } - ).unwrap(); + }) + .unwrap(); // Wait for network to be ready (signaled from core 1) NETWORK_READY.wait().await; @@ -131,63 +120,60 @@ async fn main(spawner: Spawner) -> ! { let config = InputConfig::default().with_pull(Pull::Down); let button_select = Input::new(peripherals.GPIO32, config); let button_next = Input::new(peripherals.GPIO35, config); - spawner.spawn(button_detection_task(button_select, button_next)).unwrap(); + spawner + .spawn(button_detection_task(button_select, button_next)) + .unwrap(); - // Core 0: display and MPU tasks - spawner.spawn(display::task::display_task(display_i2c)).expect("spawn display_task"); - spawner.spawn(mpu::task::mpu_task(mpu_i2c)).expect("spawn mpu_task"); - - display::api::set_status("Booting...").await; mqtt_subscribe("esp32/read").await; mqtt_publish("esp32/imu", b"online", QualityOfService::QoS1, false).await; - display::api::set_status("Running").await; - display::api::set_mqtt_status(true, 0).await; - let mqtt_rx = mqtt_events(); - let imu_rx = mpu::api::events(); - let mut imu_reading_count: u32 = 0; let mut mqtt_msg_count: u32 = 0; let mut mqtt_publish_drops: u32 = 0; let mut last_mqtt_publish = Instant::now(); let mqtt_publish_interval = Duration::from_secs(3); - loop { - match select3( - mqtt_rx.receive(), - imu_rx.receive(), - Timer::after(Duration::from_secs(5)), - ).await { - Either3::First(msg) => { - mqtt_msg_count += 1; - handle_mqtt_message(msg).await; - display::api::set_mqtt_status(true, mqtt_msg_count).await; - } - Either3::Second(mut reading) => { - // Drain zabezpečuje, že 'reading' je najčerstvejšia možná hodnota - let mut drained = 0; - while let Ok(next) = imu_rx.try_receive() { - reading = next; - drained += 1; - } - - imu_reading_count += 1; - display::api::show_imu(reading); + // loop { + // match select3( + // mqtt_rx.receive(), + // // imu_rx.receive(), + // Timer::after(Duration::from_secs(5)), + // ) + // .await + // { + // Either3::First(msg) => { + // mqtt_msg_count += 1; + // handle_mqtt_message(msg).await; + // display::api::set_mqtt_status(true, mqtt_msg_count).await; + // } + // Either3::Second(mut reading) => { + // // Drain zabezpečuje, že 'reading' je najčerstvejšia možná hodnota + // let mut drained = 0; + // while let Ok(next) = imu_rx.try_receive() { + // reading = next; + // drained += 1; + // } - // 3. Nahraďte pôvodnú podmienku týmto časovým zámkom - if last_mqtt_publish.elapsed() >= mqtt_publish_interval { - let payload = client::encode_imu_json(&reading); - client::mqtt_set_imu_payload(payload); - last_mqtt_publish = Instant::now(); - } - } - Either3::Third(_) => { - crate::mpu::api::IMU_CHANNEL.clear(); - info!("IMU heartbeat: force-cleared queue, {} readings total, {} mqtt drops", - imu_reading_count, mqtt_publish_drops); - } - } - } + // imu_reading_count += 1; + // display::api::show_imu(reading); + + // // 3. Nahraďte pôvodnú podmienku týmto časovým zámkom + // if last_mqtt_publish.elapsed() >= mqtt_publish_interval { + // let payload = client::encode_imu_json(&reading); + // client::mqtt_set_imu_payload(payload); + // last_mqtt_publish = Instant::now(); + // } + // } + // Either3::Third(_) => { + // crate::mpu::api::IMU_CHANNEL.clear(); + // info!( + // "IMU heartbeat: force-cleared queue, {} readings total, {} mqtt drops", + // imu_reading_count, mqtt_publish_drops + // ); + // } + // } + // } + loop {} } // Runs on core 1 - creates and owns the network stack @@ -212,7 +198,9 @@ async fn core1_network_task( // Wait for network loop { - if stack.is_link_up() { break; } + if stack.is_link_up() { + break; + } Timer::after(Duration::from_millis(500)).await; } loop { @@ -232,9 +220,10 @@ async fn core1_network_task( async fn handle_mqtt_message(msg: IncomingMsg) { if let Ok(txt) = core::str::from_utf8(&msg.payload) { match txt { - "clear" => { display::api::clear().await; } - "status" => { mqtt_publish("esp32/status", b"running", QualityOfService::QoS1, false).await; } - _ => { display::api::add_chat_message(txt).await; } + "status" => { + mqtt_publish("esp32/status", b"running", QualityOfService::QoS1, false).await; + } + _ => {} } } } @@ -274,19 +263,21 @@ async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) { #[embassy_executor::task] async fn button_detection_task(mut select_btn: Input<'static>, mut next_btn: Input<'static>) { loop { - match select( - select_btn.wait_for_rising_edge(), - next_btn.wait_for_rising_edge(), - ).await { - Either::First(_) => { - info!("Detection: GPIO 32 (Select) triggered!"); - display::api::push_key(Key::enter()).await; - } - Either::Second(_) => { - info!("Detection: GPIO 35 (Next) triggered!"); - display::api::push_key(Key::tab()).await - } - } + // match select( + // select_btn.wait_for_rising_edge(), + // next_btn.wait_for_rising_edge(), + // ) + // .await + // { + // Either::First(_) => { + // info!("Detection: GPIO 32 (Select) triggered!"); + // display::api::push_key(Key::enter()).await; + // } + // Either::Second(_) => { + // info!("Detection: GPIO 35 (Next) triggered!"); + // display::api::push_key(Key::tab()).await + // } + // } // Debounce: prevent mechanical bouncing from double-triggering embassy_time::Timer::after(embassy_time::Duration::from_millis(200)).await; } diff --git a/tprais_semestralka1/src/mqtt/client.rs b/tprais_semestralka1/src/mqtt/client.rs index a7d2f8b..6d63e08 100644 --- a/tprais_semestralka1/src/mqtt/client.rs +++ b/tprais_semestralka1/src/mqtt/client.rs @@ -1,25 +1,24 @@ // src/mqtt/client.rs -use embassy_net::{tcp::TcpSocket, Stack}; -use embassy_time::{Duration, Timer, Instant}; use embassy_futures::select::{select, Either}; +use embassy_net::{tcp::TcpSocket, Stack}; +use embassy_time::{Duration, Instant, Timer}; use rust_mqtt::client::client::MqttClient; use rust_mqtt::client::client_config::{ClientConfig, MqttVersion}; use rust_mqtt::packet::v5::publish_packet::QualityOfService; use rust_mqtt::packet::v5::reason_codes::ReasonCode; use rust_mqtt::utils::rng_generator::CountingRng; +use core::fmt::Write; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use embassy_sync::mutex::Mutex; use embassy_sync::channel::{Channel, Receiver}; +use embassy_sync::mutex::Mutex; use embassy_sync::signal::Signal; use heapless::{String, Vec}; -use static_cell::ConstStaticCell; -use core::fmt::Write; use log::{info, warn}; +use static_cell::ConstStaticCell; use crate::mqtt::config::mqtt_broker_endpoint; -use crate::contracts::ImuReading; const RECONNECT_DELAY_SECS: u64 = 5; const KEEPALIVE_SECS: u64 = 60; @@ -102,31 +101,6 @@ pub fn mqtt_try_publish(topic: &str, payload: &[u8], qos: QualityOfService, reta .is_ok() } -pub fn mqtt_set_imu(reading: ImuReading) { - // Encode JSON into a bounded buffer (no alloc::format!) - let payload = encode_imu_json(&reading); - IMU_SIG.signal(payload); -} - -pub fn mqtt_set_imu_payload(payload: Vec) { - IMU_SIG.signal(payload); -} - -pub fn encode_imu_json(reading: &ImuReading) -> Vec { - let mut s: String<256> = String::new(); - let _ = write!( - &mut s, - "{{\"ax\":{:.2},\"ay\":{:.2},\"az\":{:.2},\"gx\":{:.1},\"gy\":{:.1},\"gz\":{:.1},\"t\":{:.1},\"ts\":{}}}", - reading.accel_g[0], reading.accel_g[1], reading.accel_g[2], - reading.gyro_dps[0], reading.gyro_dps[1], reading.gyro_dps[2], - reading.temp_c, - reading.timestamp_ms - ); - let mut v: Vec = Vec::new(); - let _ = v.extend_from_slice(s.as_bytes()); - v -} - pub async fn mqtt_subscribe(topic: &str) { let t = truncate_str::(topic); { @@ -139,8 +113,7 @@ pub async fn mqtt_subscribe(topic: &str) { CMD_CHAN.send(Command::Subscribe(t)).await; } -pub fn mqtt_events( -) -> Receiver<'static, CriticalSectionRawMutex, IncomingMsg, EVENT_QUEUE> { +pub fn mqtt_events() -> Receiver<'static, CriticalSectionRawMutex, IncomingMsg, EVENT_QUEUE> { EVT_CHAN.receiver() } @@ -221,8 +194,7 @@ async fn run_one_session( cfg.keep_alive = KEEPALIVE_SECS as u16; cfg.add_client_id("esp32-client"); - let mut client = - MqttClient::new(socket, mqtt_tx, mqtt_tx.len(), mqtt_rx, mqtt_rx.len(), cfg); + let mut client = MqttClient::new(socket, mqtt_tx, mqtt_tx.len(), mqtt_rx, mqtt_rx.len(), cfg); match client.connect_to_broker().await { Ok(_) => info!("MQTT CONNACK received"), @@ -260,8 +232,8 @@ async fn run_one_session( let mut tx_err: u32 = 0; let mut rx_ok: u32 = 0; let mut ping_ok: u32 = 0; - let mut last_ok = Instant::now(); // last successful MQTT I/O (tx/rx/ping) - let mut last_imu_sig = Instant::now(); // last time we received IMU_SIG in MQTT task + let mut last_ok = Instant::now(); // last successful MQTT I/O (tx/rx/ping) + let mut last_imu_sig = Instant::now(); // last time we received IMU_SIG in MQTT task loop { let now = Instant::now(); @@ -284,7 +256,11 @@ async fn run_one_session( last_imu_sig = now; } - let ping_in = if next_ping_at > now { next_ping_at - now } else { Duration::from_secs(0) }; + let ping_in = if next_ping_at > now { + next_ping_at - now + } else { + Duration::from_secs(0) + }; // Timebox receive_message() even if lower layers misbehave. let recv_fut = async { @@ -326,11 +302,11 @@ async fn run_one_session( client.send_message("esp32/imu", &payload, QualityOfService::QoS0, false), Timer::after(Duration::from_secs(5)), ) - .await - { - Either::First(res) => res, - Either::Second(_) => Err(ReasonCode::NetworkError), - }; + .await + { + Either::First(res) => res, + Either::Second(_) => Err(ReasonCode::NetworkError), + }; match send_res { Ok(_) => {