working everything properly well

This commit is contained in:
Priec
2026-01-10 16:55:02 +01:00
parent fe4e48fbcc
commit 1cb6f3a3ee
13 changed files with 872 additions and 105 deletions

View File

@@ -8,90 +8,159 @@
)]
use embassy_executor::Spawner;
use embassy_futures::select::{select, Either};
use embassy_futures::select::{select3, Either3};
use embassy_net::{Runner, StackResources};
use embassy_time::{Duration, Timer};
use projekt_final::bus::I2cInner;
use esp_alloc as _;
use esp_backtrace as _;
use esp_hal::{clock::CpuClock, rng::Rng, timer::timg::TimerGroup};
use esp_hal::{
clock::CpuClock,
i2c::master::{Config as I2cConfig, I2c},
rng::Rng,
timer::timg::TimerGroup,
};
use esp_wifi::{
init,
wifi::{ClientConfiguration, Configuration, WifiController, WifiDevice, WifiEvent, WifiState},
EspWifiController,
};
use log::info;
use rust_mqtt::packet::v5::publish_packet::QualityOfService;
use projekt_final::mqtt::client::{
mqtt_events, mqtt_publish, mqtt_subscribe, mqtt_task, IncomingMsg,
use static_cell::StaticCell;
use core::cell::RefCell;
// Our crate
use projekt_final::{
bus,
display,
mpu,
mqtt::client::{mqtt_events, mqtt_publish, mqtt_subscribe, mqtt_task, IncomingMsg},
};
use projekt_final::i2c::com::i2c_check;
use projekt_final::i2c::com::display_task;
use defmt_rtt as _;
extern crate alloc;
use alloc::format;
esp_bootloader_esp_idf::esp_app_desc!();
static I2C_BUS: StaticCell<RefCell<I2cInner>> = StaticCell::new();
macro_rules! mk_static {
($t:ty,$val:expr) => {{
static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new();
#[deny(unused_attributes)]
let x = STATIC_CELL.uninit().write(($val));
x
($t:ty, $val:expr) => {{
static STATIC_CELL: StaticCell<$t> = StaticCell::new();
STATIC_CELL.init($val)
}};
}
const SSID: &str = env!("SSID");
const PASSWORD: &str = env!("PASSWORD");
const MQTT_PUBLISH_DIVIDER: u32 = 10;
esp_bootloader_esp_idf::esp_app_desc!();
#[esp_hal_embassy::main]
async fn main(spawner: Spawner) -> ! {
esp_println::logger::init_logger_from_env();
info!("═══════════════════════════════════════════════════════════");
info!(" ESP32 IoT Firmware Starting");
info!("═══════════════════════════════════════════════════════════");
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
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);
let esp_wifi_ctrl = &*mk_static!(
let esp_wifi_ctrl = mk_static!(
EspWifiController<'static>,
init(timg0.timer0, rng.clone()).unwrap()
esp_wifi::init(timg0.timer0, rng.clone()).unwrap()
);
let (controller, interfaces) =
esp_wifi::wifi::new(&esp_wifi_ctrl, peripherals.WIFI).unwrap();
esp_wifi::wifi::new(esp_wifi_ctrl, peripherals.WIFI).unwrap();
let wifi_interface = interfaces.sta;
let timg1 = TimerGroup::new(peripherals.TIMG1);
esp_hal_embassy::init(timg1.timer0);
let config = embassy_net::Config::dhcpv4(Default::default());
let net_config = embassy_net::Config::dhcpv4(Default::default());
let seed = (rng.random() as u64) << 32 | rng.random() as u64;
// Init network stack
let (stack, runner) = embassy_net::new(
wifi_interface,
config,
net_config,
mk_static!(StackResources<3>, StackResources::<3>::new()),
seed,
);
spawner.spawn(connection(controller)).ok();
spawner.spawn(net_task(runner)).ok();
spawner.spawn(connection_task(controller)).expect("spawn connection_task");
spawner.spawn(net_task(runner)).expect("spawn net_task");
wait_for_network(stack).await;
spawner.spawn(mqtt_task(stack)).expect("spawn mqtt_task");
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/cmd").await;
mqtt_publish("esp32/status", 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;
// Wait for link up
loop {
if stack.is_link_up() {
break;
match select3(
mqtt_rx.receive(),
imu_rx.receive(),
Timer::after(Duration::from_secs(30)),
).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(reading) => {
imu_reading_count += 1;
display::api::show_imu(reading).await;
if imu_reading_count % MQTT_PUBLISH_DIVIDER == 0 {
let payload = format!(
"{{\"ax\":{:.2},\"ay\":{:.2},\"az\":{:.2},\"t\":{:.1}}}",
reading.accel_g[0], reading.accel_g[1], reading.accel_g[2], reading.temp_c
);
mqtt_publish("esp32/imu", payload.as_bytes(), QualityOfService::QoS0, false).await;
}
}
Either3::Third(_) => {
info!("Heartbeat: {} IMU readings", imu_reading_count);
}
}
}
}
async fn wait_for_network(stack: embassy_net::Stack<'static>) {
loop {
if stack.is_link_up() { break; }
Timer::after(Duration::from_millis(500)).await;
}
info!("Waiting to get IP address...");
loop {
if let Some(config) = stack.config_v4() {
info!("Got IP: {}", config.address);
@@ -99,63 +168,24 @@ async fn main(spawner: Spawner) -> ! {
}
Timer::after(Duration::from_millis(500)).await;
}
}
spawner.spawn(mqtt_task(stack)).expect("failed to spawn MQTT task");
info!("MQTT task started");
spawner.spawn(display_task()).expect("failed to spawn Display task");
info!("I2C scan task started");
mqtt_publish("esp32/topic", b"hello from ESP32 (init)", QualityOfService::QoS1, false).await;
info!("Sent initial MQTT message");
mqtt_subscribe("esp32/topic").await;
// Get a receiver for incoming MQTT messages
let mqtt_rx = mqtt_events();
loop {
// Drive both: either process an MQTT message or publish periodically
match select(mqtt_rx.receive(), Timer::after(Duration::from_secs(5))).await
{
// Received inbound MQTT message (from broker)
Either::First(msg) => {
handle_incoming(msg);
}
// Time-based example publish
Either::Second(_) => {
// mqtt_publish(
// "esp32/topic",
// b"hello from main",
// QualityOfService::QoS1,
// false,
// )
// .await;
}
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; }
_ => {}
}
}
}
fn handle_incoming(msg: IncomingMsg) {
if let Ok(txt) = core::str::from_utf8(&msg.payload) {
info!("MAIN RX [{}]: {}", msg.topic.as_str(), txt);
info!("Received MQTT message -> topic: '{}', payload: '{}'", msg.topic.as_str(), txt);
} else {
info!("MAIN RX [{}]: {:?}", msg.topic.as_str(), msg.payload);
}
}
#[embassy_executor::task]
async fn connection(mut controller: WifiController<'static>) {
info!("start connection task");
info!("Device capabilities: {:?}", controller.capabilities());
async fn connection_task(mut controller: WifiController<'static>) {
loop {
match esp_wifi::wifi::wifi_state() {
WifiState::StaConnected => {
controller.wait_for_event(WifiEvent::StaDisconnected).await;
Timer::after(Duration::from_millis(5000)).await
}
_ => {}
if esp_wifi::wifi::wifi_state() == WifiState::StaConnected {
controller.wait_for_event(WifiEvent::StaDisconnected).await;
Timer::after(Duration::from_millis(5000)).await;
}
if !matches!(controller.is_started(), Ok(true)) {
let client_config = Configuration::Client(ClientConfiguration {
@@ -164,18 +194,13 @@ async fn connection(mut controller: WifiController<'static>) {
..Default::default()
});
controller.set_configuration(&client_config).unwrap();
info!("Starting wifi");
info!("Wi-Fi starting...");
controller.start_async().await.unwrap();
info!("Wifi started!");
}
info!("About to connect...");
match controller.connect_async().await {
Ok(_) => info!("Wifi connected!"),
Err(e) => {
info!("Failed to connect to wifi: {e:?}");
Timer::after(Duration::from_millis(5000)).await
}
if let Err(e) = controller.connect_async().await {
info!("Wi-Fi reconnect failed: {:?}", e);
} else {
info!("Wi-Fi connected.");
}
}
}