Allow for multiple connections at the same time
This commit is contained in:
parent
8603d6fab4
commit
03b6e01bd8
47
Cargo.lock
generated
47
Cargo.lock
generated
|
@ -133,9 +133,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.7.0"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be"
|
||||
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
|
@ -361,9 +361,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "data-encoding"
|
||||
version = "2.6.0"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2"
|
||||
checksum = "0e60eed09d8c01d3cee5b7d30acb059b76614c918fa0f992e0dd6eeb10daad6f"
|
||||
|
||||
[[package]]
|
||||
name = "debug-helper"
|
||||
|
@ -658,9 +658,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "embassy-sync"
|
||||
version = "0.6.1"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3899a6e39fa3f54bf8aaf00979f9f9c0145a522f7244810533abbb748be6ce82"
|
||||
checksum = "8d2c8cdff05a7a51ba0087489ea44b0b1d97a296ca6b1d6d1a33ea7423d34049"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"critical-section",
|
||||
|
@ -1018,9 +1018,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.7.0"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
|
||||
checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
|
@ -1028,13 +1028,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.13"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b"
|
||||
checksum = "3f187290c0ed3dfe3f7c85bedddd320949b68fc86ca0ceb71adfb05b3dc3af2a"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1095,7 +1095,7 @@ version = "0.1.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
||||
dependencies = [
|
||||
"bitflags 2.7.0",
|
||||
"bitflags 2.8.0",
|
||||
"libc",
|
||||
]
|
||||
|
||||
|
@ -1117,9 +1117,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.24"
|
||||
version = "0.4.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6ea2a48c204030ee31a7d7fc72c93294c92fe87ecb1789881c9543516e1a0d"
|
||||
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
||||
|
||||
[[package]]
|
||||
name = "managed"
|
||||
|
@ -1446,9 +1446,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.92"
|
||||
version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
||||
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
@ -1459,7 +1459,7 @@ version = "0.11.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625"
|
||||
dependencies = [
|
||||
"bitflags 2.7.0",
|
||||
"bitflags 2.8.0",
|
||||
"memchr",
|
||||
"unicase",
|
||||
]
|
||||
|
@ -1505,7 +1505,7 @@ version = "0.5.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
|
||||
dependencies = [
|
||||
"bitflags 2.7.0",
|
||||
"bitflags 2.8.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1971,7 +1971,7 @@ version = "0.1.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1980,15 +1980,6 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "air_filter_types"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bme280 = { workspace = true }
|
||||
|
|
210
src/main.rs
210
src/main.rs
|
@ -1,9 +1,11 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use core::{cell::RefCell, str::FromStr};
|
||||
|
||||
use approuter::{AppRouter, AppState};
|
||||
use bme280::i2c::AsyncBME280;
|
||||
use cyw43::{JoinOptions, PowerManagementMode};
|
||||
use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER};
|
||||
|
@ -11,13 +13,13 @@ use defmt::{debug, info, warn};
|
|||
use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig};
|
||||
use embassy_embedded_hal::flash::partition::BlockingPartition;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_net::{Config, DhcpConfig, StackResources};
|
||||
use embassy_net::{Config, DhcpConfig, Stack, StackResources};
|
||||
use embassy_rp::{
|
||||
bind_interrupts,
|
||||
clocks::RoscRng,
|
||||
flash::{Flash, WRITE_SIZE},
|
||||
gpio::{Flex, Input, Level, Output, Pin, Pull},
|
||||
i2c::{self, Async},
|
||||
i2c::{self},
|
||||
peripherals::{DMA_CH1, FLASH, I2C0, PIO0},
|
||||
pio::{self, Pio},
|
||||
Peripheral,
|
||||
|
@ -31,26 +33,19 @@ use embassy_sync::{
|
|||
};
|
||||
use embassy_time::{Delay, Duration, Timer};
|
||||
use heapless::String;
|
||||
use picoserve::{
|
||||
extract, make_static,
|
||||
routing::{get, PathRouter},
|
||||
Router,
|
||||
};
|
||||
use picoserve::{make_static, Router};
|
||||
use rand::{rngs::StdRng, RngCore, SeedableRng};
|
||||
use static_cell::StaticCell;
|
||||
use updater::firmware_router;
|
||||
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
use air_filter_types::{FanSpeed, FanState, SensorData, SetFanSpeed};
|
||||
use air_filter_types::{FanSpeed, FanState};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
PIO0_IRQ_0 => pio::InterruptHandler<PIO0>;
|
||||
I2C0_IRQ => i2c::InterruptHandler<I2C0>;
|
||||
});
|
||||
|
||||
const VERSION: &str = git_version::git_version!();
|
||||
const PUBLIC_SIGNING_KEY: &[u8; 32] = include_bytes!("../key.pub");
|
||||
const FLASH_SIZE: usize = 2 * 1024 * 1024;
|
||||
|
||||
struct Controller<'a> {
|
||||
|
@ -156,39 +151,94 @@ impl<'a> Controller<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct SharedController(&'static Mutex<CriticalSectionRawMutex, Controller<'static>>);
|
||||
// We need this because otherwise the compiler yells at us
|
||||
mod approuter {
|
||||
use air_filter_types::{SensorData, SetFanSpeed};
|
||||
use bme280::i2c::AsyncBME280;
|
||||
use defmt::debug;
|
||||
use embassy_boot::BlockingFirmwareUpdater;
|
||||
use embassy_rp::{
|
||||
i2c::{Async, I2c},
|
||||
peripherals::I2C0,
|
||||
};
|
||||
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex};
|
||||
use embassy_time::Delay;
|
||||
use picoserve::{
|
||||
extract, make_static,
|
||||
routing::{get, PathRouter},
|
||||
Router,
|
||||
};
|
||||
use updater::firmware_router;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct SharedBME280(
|
||||
&'static Mutex<CriticalSectionRawMutex, AsyncBME280<i2c::I2c<'static, I2C0, Async>>>,
|
||||
);
|
||||
use crate::{Controller, Partition};
|
||||
|
||||
struct AppState {
|
||||
shared_controller: SharedController,
|
||||
shared_bme280: SharedBME280,
|
||||
}
|
||||
const VERSION: &str = git_version::git_version!();
|
||||
const PUBLIC_SIGNING_KEY: &[u8; 32] = include_bytes!("../key.pub");
|
||||
|
||||
impl picoserve::extract::FromRef<AppState> for SharedController {
|
||||
fn from_ref(state: &AppState) -> Self {
|
||||
state.shared_controller
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SharedController(pub &'static Mutex<CriticalSectionRawMutex, Controller<'static>>);
|
||||
|
||||
impl SharedController {
|
||||
fn new(controller: Controller<'static>) -> Self {
|
||||
Self(
|
||||
make_static!(Mutex<CriticalSectionRawMutex, Controller<'static>>, Mutex::new(controller)),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl picoserve::extract::FromRef<AppState> for SharedBME280 {
|
||||
fn from_ref(state: &AppState) -> Self {
|
||||
state.shared_bme280
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SharedBME280(
|
||||
pub &'static Mutex<CriticalSectionRawMutex, AsyncBME280<I2c<'static, I2C0, Async>>>,
|
||||
);
|
||||
|
||||
impl SharedBME280 {
|
||||
fn new(bme280: AsyncBME280<I2c<'static, I2C0, Async>>) -> Self {
|
||||
Self(
|
||||
make_static!(Mutex<CriticalSectionRawMutex, AsyncBME280<I2c<'static, I2C0, Async>>>, Mutex::new(bme280)),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn state_router() -> Router<impl PathRouter<AppState>, AppState> {
|
||||
Router::new()
|
||||
#[derive(Clone)]
|
||||
pub struct AppState {
|
||||
pub shared_controller: SharedController,
|
||||
pub shared_bme280: SharedBME280,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
pub fn new(
|
||||
controller: Controller<'static>,
|
||||
bme280: AsyncBME280<I2c<'static, I2C0, Async>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
shared_controller: SharedController::new(controller),
|
||||
shared_bme280: SharedBME280::new(bme280),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl picoserve::extract::FromRef<AppState> for SharedController {
|
||||
fn from_ref(state: &AppState) -> Self {
|
||||
state.shared_controller
|
||||
}
|
||||
}
|
||||
|
||||
impl picoserve::extract::FromRef<AppState> for SharedBME280 {
|
||||
fn from_ref(state: &AppState) -> Self {
|
||||
state.shared_bme280
|
||||
}
|
||||
}
|
||||
|
||||
fn state_router() -> Router<impl PathRouter<AppState>, AppState> {
|
||||
Router::new()
|
||||
.route(
|
||||
"/fan",
|
||||
get(
|
||||
|extract::State(SharedController(controller)): extract::State<
|
||||
SharedController,
|
||||
>| async {
|
||||
debug!("Getting fan state");
|
||||
|
||||
let state = controller.lock().await.get_state();
|
||||
picoserve::response::Json(state)
|
||||
},
|
||||
|
@ -198,6 +248,8 @@ fn state_router() -> Router<impl PathRouter<AppState>, AppState> {
|
|||
SharedController,
|
||||
>,
|
||||
extract::Json(message): extract::Json<SetFanSpeed>| async move {
|
||||
debug!("Setting fan state");
|
||||
|
||||
let success = controller.lock().await.set_speed(message.speed());
|
||||
|
||||
if success {
|
||||
|
@ -212,6 +264,8 @@ fn state_router() -> Router<impl PathRouter<AppState>, AppState> {
|
|||
"/sensor",
|
||||
get(
|
||||
|extract::State(SharedBME280(bme280)): extract::State<SharedBME280>| async {
|
||||
debug!("Getting sensor state");
|
||||
|
||||
let measurement = bme280
|
||||
.lock()
|
||||
.await
|
||||
|
@ -224,6 +278,20 @@ fn state_router() -> Router<impl PathRouter<AppState>, AppState> {
|
|||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
pub type AppRouter = impl PathRouter<AppState>;
|
||||
pub fn make_app(
|
||||
updater: &'static Mutex<
|
||||
CriticalSectionRawMutex,
|
||||
BlockingFirmwareUpdater<'static, Partition, Partition>,
|
||||
>,
|
||||
) -> Router<AppRouter, AppState> {
|
||||
Router::new().nest("/state", state_router()).nest(
|
||||
"/firmware",
|
||||
firmware_router(VERSION, updater, PUBLIC_SIGNING_KEY),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the cyw43 firmware blobs
|
||||
|
@ -268,18 +336,39 @@ async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'sta
|
|||
runner.run().await
|
||||
}
|
||||
|
||||
type Thingy = BlockingPartition<
|
||||
type Partition = BlockingPartition<
|
||||
'static,
|
||||
NoopRawMutex,
|
||||
Flash<'static, FLASH, embassy_rp::flash::Blocking, FLASH_SIZE>,
|
||||
>;
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn fan_task(shared_controller: SharedController) -> ! {
|
||||
loop {
|
||||
shared_controller.0.lock().await.check_for_manual();
|
||||
Timer::after(Duration::from_millis(500)).await;
|
||||
}
|
||||
const WEB_TASK_POOL_SIZE: usize = 8;
|
||||
|
||||
#[embassy_executor::task(pool_size = WEB_TASK_POOL_SIZE)]
|
||||
async fn web_task(
|
||||
id: usize,
|
||||
stack: Stack<'static>,
|
||||
app: &'static Router<AppRouter, AppState>,
|
||||
config: &'static picoserve::Config<Duration>,
|
||||
state: AppState,
|
||||
) -> ! {
|
||||
let port = 80;
|
||||
let mut tcp_rx_buffer = [0; 1024];
|
||||
let mut tcp_tx_buffer = [0; 1024];
|
||||
let mut http_buffer = [0; 2048];
|
||||
|
||||
picoserve::listen_and_serve_with_state(
|
||||
id,
|
||||
app,
|
||||
config,
|
||||
stack,
|
||||
port,
|
||||
&mut tcp_rx_buffer,
|
||||
&mut tcp_tx_buffer,
|
||||
&mut http_buffer,
|
||||
&state,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[embassy_executor::main]
|
||||
|
@ -293,7 +382,7 @@ async fn main(spawner: Spawner) {
|
|||
let config = FirmwareUpdaterConfig::from_linkerfile_blocking(flash, flash);
|
||||
let aligned = make_static!(AlignedBuffer<WRITE_SIZE>, AlignedBuffer([0; WRITE_SIZE]));
|
||||
let updater = BlockingFirmwareUpdater::new(config, &mut aligned.0);
|
||||
let updater = make_static!(Mutex<CriticalSectionRawMutex, BlockingFirmwareUpdater<'static, Thingy, Thingy>>, Mutex::new(updater));
|
||||
let updater = make_static!(Mutex<CriticalSectionRawMutex, BlockingFirmwareUpdater<'static, Partition, Partition>>, Mutex::new(updater));
|
||||
|
||||
let controller = Controller::new(p.PIN_28, p.PIN_27, p.PIN_26, p.PIN_22);
|
||||
|
||||
|
@ -340,7 +429,7 @@ async fn main(spawner: Spawner) {
|
|||
// cryptographically secure PRNG
|
||||
let mut rng = StdRng::from_rng(&mut RoscRng).unwrap();
|
||||
|
||||
static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
|
||||
static RESOURCES: StaticCell<StackResources<16>> = StaticCell::new();
|
||||
let (stack, runner) = embassy_net::new(
|
||||
net_device,
|
||||
config,
|
||||
|
@ -392,39 +481,16 @@ async fn main(spawner: Spawner) {
|
|||
.keep_connection_alive()
|
||||
);
|
||||
|
||||
let app = Router::new().nest("/state", state_router()).nest(
|
||||
"/firmware",
|
||||
firmware_router(VERSION, updater, PUBLIC_SIGNING_KEY),
|
||||
);
|
||||
let app = make_static!(Router<AppRouter, AppState>, approuter::make_app(updater));
|
||||
|
||||
let shared_controller = SharedController(
|
||||
make_static!(Mutex<CriticalSectionRawMutex, Controller<'static>>, Mutex::new(controller)),
|
||||
);
|
||||
let shared_bme280 = SharedBME280(
|
||||
make_static!(Mutex<CriticalSectionRawMutex, AsyncBME280<i2c::I2c<'static, I2C0, Async>>>, Mutex::new(bme280)),
|
||||
);
|
||||
let state = AppState::new(controller, bme280);
|
||||
|
||||
let port = 80;
|
||||
let mut tcp_rx_buffer = [0; 1024];
|
||||
let mut tcp_tx_buffer = [0; 1024];
|
||||
let mut http_buffer = [0; 2048];
|
||||
for id in 0..WEB_TASK_POOL_SIZE {
|
||||
spawner.must_spawn(web_task(id, stack, app, config, state.clone()));
|
||||
}
|
||||
|
||||
spawner.must_spawn(fan_task(shared_controller));
|
||||
|
||||
// We can only handle one request at a time
|
||||
picoserve::listen_and_serve_with_state(
|
||||
0,
|
||||
&app,
|
||||
config,
|
||||
stack,
|
||||
port,
|
||||
&mut tcp_rx_buffer,
|
||||
&mut tcp_tx_buffer,
|
||||
&mut http_buffer,
|
||||
&AppState {
|
||||
shared_controller,
|
||||
shared_bme280,
|
||||
},
|
||||
)
|
||||
.await;
|
||||
loop {
|
||||
state.shared_controller.0.lock().await.check_for_manual();
|
||||
Timer::after(Duration::from_millis(500)).await;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user