The Pico W now serves a basic HTML page.
This has not been so simple. The only way I could find to make picoserve and embassy compatible was to get a local copy of picoserve and change its embassy dependencies to use git as their source. Otherwise there are conflicts about embassy-timer-driver versions. Using picoserve also required changing my Rust "channel" to "nightly". A bunch of stuff I am not keen on, but necessary to progress rather than get bogged down in build system meta. Meanwhile also I've changed this to use a static IP at 192.168.3.14 for now. For currently unknownr reasons the loop waiting for the DHCP lease to work isn't exiting. I have rebooted the DHCP server and that didn't help and given the WiFi on the Pico W is working I don't really know whats up.
This commit is contained in:
parent
f5ce5e7958
commit
bd9389cfd5
7 changed files with 1039 additions and 323 deletions
1210
Cargo.lock
generated
1210
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -7,6 +7,8 @@ version = "0.1.0"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
# web server
|
||||||
|
picoserve = { version = "0.15.0", path = "../picoserve/picoserve/", features = ["embassy"] }
|
||||||
embassy-embedded-hal = { version = "0.3.0", git = "https://github.com/embassy-rs/embassy.git", features = ["defmt"] }
|
embassy-embedded-hal = { version = "0.3.0", git = "https://github.com/embassy-rs/embassy.git", features = ["defmt"] }
|
||||||
embassy-sync = { version = "0.6.2", git = "https://github.com/embassy-rs/embassy.git", features = ["defmt"] }
|
embassy-sync = { version = "0.6.2", git = "https://github.com/embassy-rs/embassy.git", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.7.0", git = "https://github.com/embassy-rs/embassy.git", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
|
embassy-executor = { version = "0.7.0", git = "https://github.com/embassy-rs/embassy.git", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
|
||||||
|
|
@ -25,13 +27,14 @@ defmt-rtt = "0.4"
|
||||||
fixed = "1.23.1"
|
fixed = "1.23.1"
|
||||||
fixed-macro = "1.2"
|
fixed-macro = "1.2"
|
||||||
|
|
||||||
|
|
||||||
# for web request example
|
# for web request example
|
||||||
#reqwless = { version = "0.13.0", features = ["defmt"] }
|
#reqwless = { version = "0.13.0", features = ["defmt"] }
|
||||||
#serde = { version = "1.0.203", default-features = false, features = ["derive"] }
|
#serde = { version = "1.0.203", default-features = false, features = ["derive"] }
|
||||||
#serde-json-core = "0.5.1"
|
#serde-json-core = "0.5.1"
|
||||||
|
|
||||||
# for assign resources example
|
# for assign resources example
|
||||||
#assign-resources = { git = "https://github.com/adamgreig/assign-resources", rev = "94ad10e2729afdf0fd5a77cd12e68409a982f58a" }
|
#assign-resources = { rev = "94ad10e2729afdf0fd5a77cd12e68409a982f58a" }
|
||||||
|
|
||||||
#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
|
#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
|
||||||
cortex-m = { version = "0.7.6", features = ["inline-asm"] }
|
cortex-m = { version = "0.7.6", features = ["inline-asm"] }
|
||||||
|
|
|
||||||
12
memory.x
12
memory.x
|
|
@ -1,17 +1,5 @@
|
||||||
MEMORY {
|
MEMORY {
|
||||||
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
|
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
|
||||||
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
|
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
|
||||||
|
|
||||||
/* Pick one of the two options for RAM layout */
|
|
||||||
|
|
||||||
/* OPTION A: Use all RAM banks as one big block */
|
|
||||||
/* Reasonable, unless you are doing something */
|
|
||||||
/* really particular with DMA or other concurrent */
|
|
||||||
/* access that would benefit from striping */
|
|
||||||
RAM : ORIGIN = 0x20000000, LENGTH = 264K
|
RAM : ORIGIN = 0x20000000, LENGTH = 264K
|
||||||
|
|
||||||
/* OPTION B: Keep the unstriped sections separate */
|
|
||||||
/* RAM: ORIGIN = 0x20000000, LENGTH = 256K */
|
|
||||||
/* SCRATCH_A: ORIGIN = 0x20040000, LENGTH = 4K */
|
|
||||||
/* SCRATCH_B: ORIGIN = 0x20041000, LENGTH = 4K */
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "1.84"
|
channel = "nightly"
|
||||||
components = [ "rust-src", "rustfmt", "llvm-tools" ]
|
components = [ "rust-src", "rustfmt", "llvm-tools" ]
|
||||||
targets = [
|
targets = [
|
||||||
"thumbv6m-none-eabi",
|
"thumbv6m-none-eabi",
|
||||||
|
|
|
||||||
12
src/html/index.html
Normal file
12
src/html/index.html
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Meat-Pi</title>
|
||||||
|
<link rel="stylesheet" href="main.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Meat-Pi 🍖🌡️</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
19
src/html/main.css
Normal file
19
src/html/main.css
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
:root {
|
||||||
|
color-scheme: light dark;
|
||||||
|
--light-bg: #ddffdd;
|
||||||
|
--light-color: #002200;
|
||||||
|
--dark-bg: #002200;
|
||||||
|
--dark-color: #ddffdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
background-color: light-dark(var(--light-bg), var(--dark-bg));
|
||||||
|
color: light-dark(var(--light-color), var(--dark-color));
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
align-items: center;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
}
|
||||||
98
src/main.rs
98
src/main.rs
|
|
@ -1,17 +1,14 @@
|
||||||
//! This example test the RP Pico W on board LED.
|
//! Raspberry Pi Pico W meat thermometer
|
||||||
//!
|
|
||||||
//! It does not work with the RP Pico board. See blinky.rs.
|
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
// required for impl in AppProps code for picoserve
|
||||||
use core::str::from_utf8;
|
#![feature(impl_trait_in_assoc_type)]
|
||||||
|
|
||||||
use cyw43::JoinOptions;
|
use cyw43::JoinOptions;
|
||||||
use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER};
|
use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER};
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_net::{Config, StackResources};
|
use embassy_net::{Config, StackResources, Ipv4Cidr, Ipv4Address};
|
||||||
use embassy_net::tcp::TcpSocket;
|
|
||||||
use embassy_rp::bind_interrupts;
|
use embassy_rp::bind_interrupts;
|
||||||
use embassy_rp::clocks::RoscRng;
|
use embassy_rp::clocks::RoscRng;
|
||||||
use embassy_rp::gpio::{Level, Output};
|
use embassy_rp::gpio::{Level, Output};
|
||||||
|
|
@ -20,7 +17,13 @@ use embassy_rp::peripherals::USB;
|
||||||
use embassy_rp::pio::{InterruptHandler, Pio};
|
use embassy_rp::pio::{InterruptHandler, Pio};
|
||||||
use embassy_rp::usb::{Driver, InterruptHandler as USBInterruptHandler};
|
use embassy_rp::usb::{Driver, InterruptHandler as USBInterruptHandler};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use embedded_io_async::Write;
|
use heapless::Vec;
|
||||||
|
use picoserve::{
|
||||||
|
make_static,
|
||||||
|
routing::{get_service, PathRouter},
|
||||||
|
AppBuilder, AppRouter
|
||||||
|
};
|
||||||
|
use picoserve::response::File;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
@ -51,6 +54,54 @@ async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'sta
|
||||||
runner.run().await
|
runner.run().await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// picoserve HTTP code kicked off using: https://github.com/sammhicks/picoserve/blob/main/examples/embassy/hello_world/src/main.rs
|
||||||
|
struct AppProps;
|
||||||
|
|
||||||
|
impl AppBuilder for AppProps {
|
||||||
|
type PathRouter = impl PathRouter;
|
||||||
|
|
||||||
|
fn build_app(self) -> picoserve::Router<Self::PathRouter> {
|
||||||
|
picoserve::Router::new()
|
||||||
|
.route(
|
||||||
|
"/",
|
||||||
|
get_service(File::html(include_str!("html/index.html")))
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/main.css",
|
||||||
|
get_service(File::css(include_str!("html/main.css")))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2 is plenty of a little IoT thermometer, right?
|
||||||
|
const WEB_TASK_POOL_SIZE: usize = 2;
|
||||||
|
|
||||||
|
#[embassy_executor::task(pool_size = WEB_TASK_POOL_SIZE)]
|
||||||
|
async fn web_task(
|
||||||
|
id: usize,
|
||||||
|
stack: embassy_net::Stack<'static>,
|
||||||
|
app: &'static AppRouter<AppProps>,
|
||||||
|
config: &'static picoserve::Config<Duration>,
|
||||||
|
) -> ! {
|
||||||
|
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(
|
||||||
|
id,
|
||||||
|
app,
|
||||||
|
config,
|
||||||
|
stack,
|
||||||
|
port,
|
||||||
|
&mut tcp_rx_buffer,
|
||||||
|
&mut tcp_tx_buffer,
|
||||||
|
&mut http_buffer,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(spawner: Spawner) {
|
async fn main(spawner: Spawner) {
|
||||||
let p = embassy_rp::init(Default::default());
|
let p = embassy_rp::init(Default::default());
|
||||||
|
|
@ -102,7 +153,12 @@ async fn main(spawner: Spawner) {
|
||||||
.set_power_management(cyw43::PowerManagementMode::PowerSave)
|
.set_power_management(cyw43::PowerManagementMode::PowerSave)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let config = Config::dhcpv4(Default::default());
|
//let config = Config::dhcpv4(Default::default());
|
||||||
|
let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
|
||||||
|
address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 3, 14), 24),
|
||||||
|
dns_servers: Vec::new(),
|
||||||
|
gateway: Some(Ipv4Address::new(192, 168, 3, 1)),
|
||||||
|
});
|
||||||
|
|
||||||
// Generate random seed
|
// Generate random seed
|
||||||
let seed = rng.next_u64();
|
let seed = rng.next_u64();
|
||||||
|
|
@ -126,18 +182,35 @@ async fn main(spawner: Spawner) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for DHCP, not necessary when using static IP
|
// Wait for DHCP, not necessary when using static IP
|
||||||
log::info!("waiting for DHCP...");
|
/*log::info!("waiting for DHCP...");
|
||||||
while !stack.is_config_up() {
|
while !stack.is_config_up() {
|
||||||
Timer::after_millis(100).await;
|
Timer::after_millis(100).await;
|
||||||
}
|
}
|
||||||
log::info!("DHCP is now up!");
|
log::info!("DHCP is now up!");*/
|
||||||
|
|
||||||
// And now we can use it!
|
// And now we can use it!
|
||||||
|
let app = make_static!(AppRouter<AppProps>, AppProps.build_app());
|
||||||
|
|
||||||
|
let config = make_static!(
|
||||||
|
picoserve::Config<Duration>,
|
||||||
|
picoserve::Config::new(picoserve::Timeouts {
|
||||||
|
start_read_request: Some(Duration::from_secs(5)),
|
||||||
|
read_request: Some(Duration::from_secs(1)),
|
||||||
|
write: Some(Duration::from_secs(1)),
|
||||||
|
})
|
||||||
|
.keep_connection_alive()
|
||||||
|
);
|
||||||
|
|
||||||
|
for id in 0..WEB_TASK_POOL_SIZE {
|
||||||
|
spawner.must_spawn(web_task(id, stack, app, config));
|
||||||
|
}
|
||||||
|
/*
|
||||||
let mut rx_buffer = [0; 4096];
|
let mut rx_buffer = [0; 4096];
|
||||||
let mut tx_buffer = [0; 4096];
|
let mut tx_buffer = [0; 4096];
|
||||||
let mut buf = [0; 4096];
|
let mut buf = [0; 4096];
|
||||||
|
|
||||||
|
let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
|
||||||
|
|
||||||
//let delay = Duration::from_secs(1);
|
//let delay = Duration::from_secs(1);
|
||||||
log::info!("main: pre-loop");
|
log::info!("main: pre-loop");
|
||||||
loop {
|
loop {
|
||||||
|
|
@ -145,7 +218,7 @@ async fn main(spawner: Spawner) {
|
||||||
socket.set_timeout(Some(Duration::from_secs(10)));
|
socket.set_timeout(Some(Duration::from_secs(10)));
|
||||||
|
|
||||||
control.gpio_set(0, false).await;
|
control.gpio_set(0, false).await;
|
||||||
log::info!("Listening on TCP:1234...");
|
log::info!("Listening on TCP:00...");
|
||||||
if let Err(e) = socket.accept(1234).await {
|
if let Err(e) = socket.accept(1234).await {
|
||||||
log::warn!("accept error: {:?}", e);
|
log::warn!("accept error: {:?}", e);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -183,4 +256,5 @@ async fn main(spawner: Spawner) {
|
||||||
log::info!("LED off!");
|
log::info!("LED off!");
|
||||||
control.gpio_set(0, false).await;
|
control.gpio_set(0, false).await;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue