Compare commits
1 Commits
v0.2.1
...
273bf2f946
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
273bf2f946 |
@@ -6,10 +6,13 @@
|
|||||||
clippy::mem_forget,
|
clippy::mem_forget,
|
||||||
reason = "mem::forget is generally not safe to do with esp_hal types"
|
reason = "mem::forget is generally not safe to do with esp_hal types"
|
||||||
)]
|
)]
|
||||||
|
// TODO WARNING core 1 should be logic, core 0 wifi, its flipped now
|
||||||
|
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_futures::select::{select3, Either3};
|
use embassy_futures::select::{select3, Either3};
|
||||||
use embassy_net::{Runner, StackResources};
|
use embassy_net::{Runner, StackResources};
|
||||||
|
use embassy_sync::signal::Signal;
|
||||||
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use projekt_final::bus::I2cInner;
|
use projekt_final::bus::I2cInner;
|
||||||
|
|
||||||
@@ -20,6 +23,7 @@ use esp_hal::{
|
|||||||
clock::CpuClock,
|
clock::CpuClock,
|
||||||
i2c::master::{Config as I2cConfig, I2c},
|
i2c::master::{Config as I2cConfig, I2c},
|
||||||
rng::Rng,
|
rng::Rng,
|
||||||
|
system::{CpuControl, Stack},
|
||||||
timer::timg::TimerGroup,
|
timer::timg::TimerGroup,
|
||||||
};
|
};
|
||||||
use esp_wifi::{
|
use esp_wifi::{
|
||||||
@@ -43,6 +47,9 @@ extern crate alloc;
|
|||||||
use alloc::format;
|
use alloc::format;
|
||||||
|
|
||||||
static I2C_BUS: StaticCell<RefCell<I2cInner>> = StaticCell::new();
|
static I2C_BUS: StaticCell<RefCell<I2cInner>> = StaticCell::new();
|
||||||
|
static APP_CORE_STACK: StaticCell<Stack<8192>> = StaticCell::new();
|
||||||
|
static EXECUTOR_CORE1: StaticCell<esp_hal_embassy::Executor> = StaticCell::new();
|
||||||
|
static NETWORK_READY: Signal<CriticalSectionRawMutex, ()> = Signal::new();
|
||||||
|
|
||||||
macro_rules! mk_static {
|
macro_rules! mk_static {
|
||||||
($t:ty,$val:expr) => {{
|
($t:ty,$val:expr) => {{
|
||||||
@@ -97,21 +104,25 @@ async fn main(spawner: Spawner) -> ! {
|
|||||||
let timg1 = TimerGroup::new(peripherals.TIMG1);
|
let timg1 = TimerGroup::new(peripherals.TIMG1);
|
||||||
esp_hal_embassy::init(timg1.timer0);
|
esp_hal_embassy::init(timg1.timer0);
|
||||||
|
|
||||||
let net_config = embassy_net::Config::dhcpv4(Default::default());
|
|
||||||
let seed = (rng.random() as u64) << 32 | rng.random() as u64;
|
let seed = (rng.random() as u64) << 32 | rng.random() as u64;
|
||||||
|
|
||||||
let (stack, runner) = embassy_net::new(
|
// Start core 1 for WiFi and MQTT (network stack created there)
|
||||||
wifi_interface,
|
let mut cpu_control = CpuControl::new(peripherals.CPU_CTRL);
|
||||||
net_config,
|
let _guard = cpu_control.start_app_core(
|
||||||
mk_static!(StackResources<3>, StackResources::<3>::new()),
|
APP_CORE_STACK.init(Stack::new()),
|
||||||
seed,
|
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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
spawner.spawn(connection_task(controller)).expect("spawn connection_task");
|
// Wait for network to be ready (signaled from core 1)
|
||||||
spawner.spawn(net_task(runner)).expect("spawn net_task");
|
NETWORK_READY.wait().await;
|
||||||
wait_for_network(stack).await;
|
info!("Network ready, starting core 0 tasks");
|
||||||
|
|
||||||
spawner.spawn(mqtt_task(stack)).expect("spawn mqtt_task");
|
// Core 0: display and MPU tasks
|
||||||
spawner.spawn(display::task::display_task(display_i2c)).expect("spawn display_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");
|
spawner.spawn(mpu::task::mpu_task(mpu_i2c)).expect("spawn mpu_task");
|
||||||
|
|
||||||
@@ -156,7 +167,27 @@ async fn main(spawner: Spawner) -> ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn wait_for_network(stack: embassy_net::Stack<'static>) {
|
// Runs on core 1 - creates and owns the network stack
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn core1_network_task(
|
||||||
|
spawner: Spawner,
|
||||||
|
controller: WifiController<'static>,
|
||||||
|
wifi_interface: WifiDevice<'static>,
|
||||||
|
seed: u64,
|
||||||
|
) {
|
||||||
|
spawner.spawn(connection_task(controller)).ok();
|
||||||
|
|
||||||
|
let net_config = embassy_net::Config::dhcpv4(Default::default());
|
||||||
|
let (stack, runner) = embassy_net::new(
|
||||||
|
wifi_interface,
|
||||||
|
net_config,
|
||||||
|
mk_static!(StackResources<3>, StackResources::<3>::new()),
|
||||||
|
seed,
|
||||||
|
);
|
||||||
|
|
||||||
|
spawner.spawn(net_task(runner)).ok();
|
||||||
|
|
||||||
|
// Wait for network
|
||||||
loop {
|
loop {
|
||||||
if stack.is_link_up() { break; }
|
if stack.is_link_up() { break; }
|
||||||
Timer::after(Duration::from_millis(500)).await;
|
Timer::after(Duration::from_millis(500)).await;
|
||||||
@@ -168,6 +199,12 @@ async fn wait_for_network(stack: embassy_net::Stack<'static>) {
|
|||||||
}
|
}
|
||||||
Timer::after(Duration::from_millis(500)).await;
|
Timer::after(Duration::from_millis(500)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Signal core 0 that network is ready
|
||||||
|
NETWORK_READY.signal(());
|
||||||
|
|
||||||
|
// Start MQTT on this core (it needs the stack)
|
||||||
|
spawner.spawn(mqtt_task(stack)).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_mqtt_message(msg: IncomingMsg) {
|
async fn handle_mqtt_message(msg: IncomingMsg) {
|
||||||
|
|||||||
@@ -7,17 +7,16 @@ 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;
|
||||||
|
|
||||||
/// The underlying I2C peripheral type for esp-hal 1.0.0-rc.0
|
/// The underlying I2C peripheral type
|
||||||
pub type I2cInner = I2c<'static, Async>;
|
pub type I2cInner = I2c<'static, Async>;
|
||||||
|
|
||||||
/// We use RefCell to share the bus on a single core.
|
/// RefCell to share the bus on a single core.
|
||||||
/// It's zero-overhead and safe because Embassy tasks don't preempt each other.
|
|
||||||
pub type SharedI2c = RefCell<I2cInner>;
|
pub type SharedI2c = RefCell<I2cInner>;
|
||||||
|
|
||||||
/// A handle to a shared I2C device.
|
/// A handle to a shared I2C device.
|
||||||
pub type I2cDevice = RefCellDevice<'static, I2cInner>;
|
pub type I2cDevice = RefCellDevice<'static, I2cInner>;
|
||||||
|
|
||||||
/// Create a new I2C device handle from the shared bus.
|
/// New I2C device handle from the shared bus.
|
||||||
pub fn new_device(bus: &'static SharedI2c) -> I2cDevice {
|
pub fn new_device(bus: &'static SharedI2c) -> I2cDevice {
|
||||||
RefCellDevice::new(bus)
|
RefCellDevice::new(bus)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
use embassy_sync::channel::{Channel, Receiver, TrySendError};
|
use embassy_sync::channel::{Channel, Receiver, TrySendError};
|
||||||
use heapless::String as HString;
|
use heapless::String;
|
||||||
|
|
||||||
use crate::contracts::{DisplayCommand, ImuReading};
|
use crate::contracts::{DisplayCommand, ImuReading};
|
||||||
|
|
||||||
@@ -58,14 +58,14 @@ pub async fn show_imu(reading: ImuReading) {
|
|||||||
|
|
||||||
/// Set the status line.
|
/// Set the status line.
|
||||||
pub async fn set_status(text: &str) {
|
pub async fn set_status(text: &str) {
|
||||||
let mut s = HString::<32>::new();
|
let mut s = String::<32>::new();
|
||||||
let _ = s.push_str(&text[..text.len().min(32)]);
|
let _ = s.push_str(&text[..text.len().min(32)]);
|
||||||
send(DisplayCommand::SetStatus(s)).await;
|
send(DisplayCommand::SetStatus(s)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Show an error message.
|
/// Show an error message.
|
||||||
pub async fn show_error(text: &str) {
|
pub async fn show_error(text: &str) {
|
||||||
let mut s = HString::<64>::new();
|
let mut s = String::<64>::new();
|
||||||
let _ = s.push_str(&text[..text.len().min(64)]);
|
let _ = s.push_str(&text[..text.len().min(64)]);
|
||||||
send(DisplayCommand::ShowError(s)).await;
|
send(DisplayCommand::ShowError(s)).await;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use log::{error, info};
|
|||||||
|
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use alloc::format;
|
use alloc::format;
|
||||||
use heapless::String as HString;
|
use heapless::String;
|
||||||
use mousefood::{EmbeddedBackend, EmbeddedBackendConfig};
|
use mousefood::{EmbeddedBackend, EmbeddedBackendConfig};
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
layout::{Constraint, Direction, Layout},
|
layout::{Constraint, Direction, Layout},
|
||||||
@@ -27,9 +27,9 @@ const REFRESH_INTERVAL_MS: u64 = 100;
|
|||||||
|
|
||||||
/// Internal state for what to render.
|
/// Internal state for what to render.
|
||||||
struct DisplayState {
|
struct DisplayState {
|
||||||
status: HString<32>,
|
status: String<32>,
|
||||||
last_imu: Option<ImuReading>,
|
last_imu: Option<ImuReading>,
|
||||||
last_error: Option<HString<64>>,
|
last_error: Option<String<64>>,
|
||||||
mqtt_connected: bool,
|
mqtt_connected: bool,
|
||||||
mqtt_msg_count: u32,
|
mqtt_msg_count: u32,
|
||||||
}
|
}
|
||||||
@@ -37,7 +37,7 @@ struct DisplayState {
|
|||||||
impl Default for DisplayState {
|
impl Default for DisplayState {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
status: HString::new(),
|
status: String::new(),
|
||||||
last_imu: None,
|
last_imu: None,
|
||||||
last_error: None,
|
last_error: None,
|
||||||
mqtt_connected: false,
|
mqtt_connected: false,
|
||||||
@@ -66,7 +66,7 @@ impl DisplayState {
|
|||||||
DisplayCommand::Clear => {
|
DisplayCommand::Clear => {
|
||||||
self.last_imu = None;
|
self.last_imu = None;
|
||||||
self.last_error = None;
|
self.last_error = None;
|
||||||
self.status = HString::new();
|
self.status = String::new();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// src/i2c/com.rs
|
// src/i2c/com.rs
|
||||||
|
|
||||||
use embassy_executor::task;
|
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use esp_hal::{
|
use esp_hal::{
|
||||||
i2c::master::{Config, I2c},
|
i2c::master::{Config, I2c},
|
||||||
@@ -9,7 +8,7 @@ use esp_hal::{
|
|||||||
use ssd1306::mode::BufferedGraphicsMode;
|
use ssd1306::mode::BufferedGraphicsMode;
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
#[task]
|
#[embassy_executor::task]
|
||||||
pub async fn display_task() {
|
pub async fn display_task() {
|
||||||
use mousefood::{EmbeddedBackend, EmbeddedBackendConfig};
|
use mousefood::{EmbeddedBackend, EmbeddedBackendConfig};
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
@@ -73,7 +72,7 @@ pub async fn display_task() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task]
|
#[embassy_executor::task]
|
||||||
pub async fn i2c_check() {
|
pub async fn i2c_check() {
|
||||||
let peripherals = unsafe { Peripherals::steal() };
|
let peripherals = unsafe { Peripherals::steal() };
|
||||||
let mut i2c = I2c::new(peripherals.I2C0, Config::default())
|
let mut i2c = I2c::new(peripherals.I2C0, Config::default())
|
||||||
|
|||||||
Reference in New Issue
Block a user