nonsense, nothing is fixed
This commit is contained in:
@@ -150,14 +150,23 @@ async fn main(spawner: Spawner) -> ! {
|
|||||||
match select3(
|
match select3(
|
||||||
mqtt_rx.receive(),
|
mqtt_rx.receive(),
|
||||||
imu_rx.receive(),
|
imu_rx.receive(),
|
||||||
Timer::after(Duration::from_secs(30)),
|
Timer::after(Duration::from_secs(5)),
|
||||||
).await {
|
).await {
|
||||||
Either3::First(msg) => {
|
Either3::First(msg) => {
|
||||||
mqtt_msg_count += 1;
|
mqtt_msg_count += 1;
|
||||||
handle_mqtt_message(msg).await;
|
handle_mqtt_message(msg).await;
|
||||||
display::api::set_mqtt_status(true, mqtt_msg_count).await;
|
display::api::set_mqtt_status(true, mqtt_msg_count).await;
|
||||||
}
|
}
|
||||||
Either3::Second(reading) => {
|
Either3::Second(mut reading) => {
|
||||||
|
// Drain any queued IMU messages and keep only the latest
|
||||||
|
let mut drained = 0;
|
||||||
|
while let Ok(next) = imu_rx.try_receive() {
|
||||||
|
reading = next;
|
||||||
|
drained += 1;
|
||||||
|
}
|
||||||
|
if drained > 0 {
|
||||||
|
log::info!("IMU drained {} stale readings before display", drained);
|
||||||
|
}
|
||||||
imu_reading_count += 1;
|
imu_reading_count += 1;
|
||||||
display::api::show_imu(reading).await;
|
display::api::show_imu(reading).await;
|
||||||
if imu_reading_count % MQTT_PUBLISH_DIVIDER == 0 {
|
if imu_reading_count % MQTT_PUBLISH_DIVIDER == 0 {
|
||||||
@@ -169,7 +178,9 @@ async fn main(spawner: Spawner) -> ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Either3::Third(_) => {
|
Either3::Third(_) => {
|
||||||
info!("Heartbeat: {} IMU readings", imu_reading_count);
|
crate::mpu::api::IMU_CHANNEL.clear();
|
||||||
|
info!("IMU heartbeat: force-cleared queue, {} readings total", imu_reading_count);
|
||||||
|
// info!("Heartbeat: {} IMU readings", imu_reading_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -259,7 +270,6 @@ async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) {
|
|||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn button_detection_task(mut select_btn: Input<'static>, mut next_btn: Input<'static>) {
|
async fn button_detection_task(mut select_btn: Input<'static>, mut next_btn: Input<'static>) {
|
||||||
use embassy_futures::select::Either;
|
|
||||||
loop {
|
loop {
|
||||||
match select(
|
match select(
|
||||||
select_btn.wait_for_rising_edge(),
|
select_btn.wait_for_rising_edge(),
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
// src/bus/mod.rs
|
// src/bus/mod.rs
|
||||||
|
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
|
||||||
use embassy_sync::mutex::Mutex;
|
|
||||||
use embedded_hal_bus::i2c::RefCellDevice;
|
use embedded_hal_bus::i2c::RefCellDevice;
|
||||||
use esp_hal::i2c::master::I2c;
|
use esp_hal::i2c::master::I2c;
|
||||||
use esp_hal::Async;
|
use esp_hal::Async;
|
||||||
|
|||||||
@@ -136,8 +136,7 @@ impl Component for Screen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============ PAGE ORDER ============
|
// PAGE ORDER
|
||||||
|
|
||||||
const PAGE_ORDER: &[&str] = &["menu", "imu", "chat"];
|
const PAGE_ORDER: &[&str] = &["menu", "imu", "chat"];
|
||||||
|
|
||||||
pub fn next_page_id(current: &str) -> &'static str {
|
pub fn next_page_id(current: &str) -> &'static str {
|
||||||
@@ -150,9 +149,7 @@ pub fn prev_page_id(current: &str) -> &'static str {
|
|||||||
if idx == 0 { PAGE_ORDER[PAGE_ORDER.len() - 1] } else { PAGE_ORDER[idx - 1] }
|
if idx == 0 { PAGE_ORDER[PAGE_ORDER.len() - 1] } else { PAGE_ORDER[idx - 1] }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============ RENDERING - NO LAYOUT, DIRECT RECTS ============
|
// RENDERING
|
||||||
// 128x32 display = 21 chars x 4 rows (6x8 font)
|
|
||||||
|
|
||||||
/// Get row rect (0-3) for 128x32 display
|
/// Get row rect (0-3) for 128x32 display
|
||||||
#[inline]
|
#[inline]
|
||||||
fn row(area: Rect, n: u16) -> Rect {
|
fn row(area: Rect, n: u16) -> Rect {
|
||||||
@@ -169,7 +166,7 @@ pub fn render_frame<B: ratatui::backend::Backend>(
|
|||||||
let area = f.area();
|
let area = f.area();
|
||||||
|
|
||||||
if let Some(ref err) = state.last_error {
|
if let Some(ref err) = state.last_error {
|
||||||
f.render_widget(Paragraph::new(format!("ERR:{}", err.as_str())).red().bold(), area);
|
f.render_widget(Paragraph::new(format!("ERR:{}", err.as_str())).white().bold(), area);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,10 +206,10 @@ fn render_menu(f: &mut ratatui::Frame, area: Rect, focused: Option<&PageFocus>,
|
|||||||
fn render_imu(f: &mut ratatui::Frame, area: Rect, focused: Option<&PageFocus>, state: &DisplayState) {
|
fn render_imu(f: &mut ratatui::Frame, area: Rect, focused: Option<&PageFocus>, state: &DisplayState) {
|
||||||
if let Some(ref imu) = state.last_imu {
|
if let Some(ref imu) = state.last_imu {
|
||||||
// Row 0 Gyro
|
// Row 0 Gyro
|
||||||
// f.render_widget(
|
f.render_widget(
|
||||||
// Paragraph::new(format!("G:{:+5.0}{:+5.0}{:+5.0}", imu.gyro_dps[0], imu.gyro_dps[1], imu.gyro_dps[2])).cyan(),
|
Paragraph::new(format!("G:{:+5.0}{:+5.0}{:+5.0}", imu.gyro_dps[0], imu.gyro_dps[1], imu.gyro_dps[2])).cyan(),
|
||||||
// row(area, 0),
|
row(area, 0),
|
||||||
// );
|
);
|
||||||
// Row 1 Accel
|
// Row 1 Accel
|
||||||
f.render_widget(
|
f.render_widget(
|
||||||
Paragraph::new(format!("A:{:+.1} {:+.1} {:+.1}", imu.accel_g[0], imu.accel_g[1], imu.accel_g[2])).green(),
|
Paragraph::new(format!("A:{:+.1} {:+.1} {:+.1}", imu.accel_g[0], imu.accel_g[1], imu.accel_g[2])).green(),
|
||||||
@@ -228,7 +225,7 @@ fn render_imu(f: &mut ratatui::Frame, area: Rect, focused: Option<&PageFocus>, s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Row 3 Nav bar
|
// Row 3 Nav bar
|
||||||
render_nav_bar(f, row(area, 2), focused);
|
// render_nav_bar(f, row(area, 3), focused);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_chat(f: &mut ratatui::Frame, area: Rect, focused: Option<&PageFocus>, state: &DisplayState) {
|
fn render_chat(f: &mut ratatui::Frame, area: Rect, focused: Option<&PageFocus>, state: &DisplayState) {
|
||||||
@@ -245,7 +242,7 @@ fn render_chat(f: &mut ratatui::Frame, area: Rect, focused: Option<&PageFocus>,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Row 3 Nav bar
|
// Row 3 Nav bar
|
||||||
render_nav_bar(f, row(area, 3), focused);
|
render_nav_bar(f, row(area, 2), focused);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Nav bar: --[<]-------[>]--
|
/// Nav bar: --[<]-------[>]--
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
|||||||
use embassy_sync::channel::{Channel, Receiver, Sender};
|
use embassy_sync::channel::{Channel, Receiver, Sender};
|
||||||
use crate::contracts::ImuReading;
|
use crate::contracts::ImuReading;
|
||||||
|
|
||||||
const QUEUE_SIZE: usize = 4;
|
const QUEUE_SIZE: usize = 16;
|
||||||
|
|
||||||
pub(crate) static IMU_CHANNEL: Channel<CriticalSectionRawMutex, ImuReading, QUEUE_SIZE> = Channel::new();
|
pub static IMU_CHANNEL: Channel<CriticalSectionRawMutex, ImuReading, QUEUE_SIZE> = Channel::new();
|
||||||
|
|
||||||
pub fn events() -> Receiver<'static, CriticalSectionRawMutex, ImuReading, QUEUE_SIZE> {
|
pub fn events() -> Receiver<'static, CriticalSectionRawMutex, ImuReading, QUEUE_SIZE> {
|
||||||
IMU_CHANNEL.receiver()
|
IMU_CHANNEL.receiver()
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use crate::mpu::api::sender;
|
|||||||
use crate::mpu::driver::Mpu6050;
|
use crate::mpu::driver::Mpu6050;
|
||||||
|
|
||||||
/// Sampling interval in milliseconds.
|
/// Sampling interval in milliseconds.
|
||||||
/// 50ms = 20Hz, reasonable for display updates.
|
/// 50ms = 20Hz
|
||||||
const SAMPLE_INTERVAL_MS: u64 = 50;
|
const SAMPLE_INTERVAL_MS: u64 = 50;
|
||||||
|
|
||||||
/// MPU6050 I2C address (0x68 with AD0 low, 0x69 with AD0 high)
|
/// MPU6050 I2C address (0x68 with AD0 low, 0x69 with AD0 high)
|
||||||
@@ -52,7 +52,7 @@ pub async fn mpu_task(i2c: I2cDevice) {
|
|||||||
Timer::after(Duration::from_secs(2)).await;
|
Timer::after(Duration::from_secs(2)).await;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Err(_e) => {
|
Err(_) => {
|
||||||
warn!(
|
warn!(
|
||||||
"I2C error verifying MPU6050 (attempt {})",
|
"I2C error verifying MPU6050 (attempt {})",
|
||||||
init_attempts
|
init_attempts
|
||||||
@@ -68,7 +68,7 @@ pub async fn mpu_task(i2c: I2cDevice) {
|
|||||||
info!("MPU6050 initialized successfully");
|
info!("MPU6050 initialized successfully");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Err(_e) => {
|
Err(_) => {
|
||||||
error!("MPU6050 init failed (attempt {})", init_attempts);
|
error!("MPU6050 init failed (attempt {})", init_attempts);
|
||||||
Timer::after(Duration::from_secs(2)).await;
|
Timer::after(Duration::from_secs(2)).await;
|
||||||
continue;
|
continue;
|
||||||
@@ -78,11 +78,14 @@ pub async fn mpu_task(i2c: I2cDevice) {
|
|||||||
|
|
||||||
// Allow sensor to stabilize after wake-up
|
// Allow sensor to stabilize after wake-up
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
Timer::after(Duration::from_millis(100)).await;
|
||||||
|
info!(
|
||||||
info!("MPU task entering sampling loop ({}ms interval)", SAMPLE_INTERVAL_MS);
|
"MPU task entering sampling loop ({}ms interval)",
|
||||||
|
SAMPLE_INTERVAL_MS
|
||||||
|
);
|
||||||
|
|
||||||
let tx = sender();
|
let tx = sender();
|
||||||
let mut consecutive_errors = 0u32;
|
let mut consecutive_errors = 0u32;
|
||||||
|
let mut sent_count: u32 = 0;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
@@ -98,13 +101,20 @@ pub async fn mpu_task(i2c: I2cDevice) {
|
|||||||
timestamp_ms: start.as_millis(),
|
timestamp_ms: start.as_millis(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Try to send; if queue is full, drop oldest by using try_send
|
sent_count = sent_count.wrapping_add(1);
|
||||||
// This ensures we never block the sampling loop
|
if tx.try_send(reading).is_ok() {
|
||||||
if tx.try_send(reading).is_err() {
|
if sent_count % 20 == 0 {
|
||||||
// Queue full - that's okay, main will get the next one
|
info!(
|
||||||
|
"IMU send#{} ax:{:.2} ay:{:.2} az:{:.2} t:{:.1}",
|
||||||
|
sent_count, accel_g[0], accel_g[1], accel_g[2], temp_c
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if sent_count % 20 == 0 {
|
||||||
|
info!("IMU drop: channel full ({} sent)", sent_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_e) => {
|
|
||||||
|
Err(_) => {
|
||||||
consecutive_errors += 1;
|
consecutive_errors += 1;
|
||||||
if consecutive_errors == 1 || consecutive_errors % 10 == 0 {
|
if consecutive_errors == 1 || consecutive_errors % 10 == 0 {
|
||||||
warn!("MPU read error (consecutive: {})", consecutive_errors);
|
warn!("MPU read error (consecutive: {})", consecutive_errors);
|
||||||
@@ -122,7 +132,7 @@ pub async fn mpu_task(i2c: I2cDevice) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sleep for remainder of interval
|
// Maintain a steady period
|
||||||
let elapsed = start.elapsed();
|
let elapsed = start.elapsed();
|
||||||
let target = Duration::from_millis(SAMPLE_INTERVAL_MS);
|
let target = Duration::from_millis(SAMPLE_INTERVAL_MS);
|
||||||
if elapsed < target {
|
if elapsed < target {
|
||||||
|
|||||||
Reference in New Issue
Block a user