clean + minify

This commit is contained in:
Arkitu 2025-08-10 03:14:11 +02:00
parent 23d03920ae
commit fc6423ad44
17 changed files with 61 additions and 261 deletions

86
Cargo.lock generated
View File

@ -290,48 +290,6 @@ version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f578e8e2c440e7297e008bb5486a3a8a194775224bbc23729b0dbdfaeebf162e" checksum = "f578e8e2c440e7297e008bb5486a3a8a194775224bbc23729b0dbdfaeebf162e"
[[package]]
name = "defmt"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f6162c53f659f65d00619fe31f14556a6e9f8752ccc4a41bd177ffcf3d6130"
dependencies = [
"bitflags 1.3.2",
"defmt-macros",
]
[[package]]
name = "defmt-macros"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d135dd939bad62d7490b0002602d35b358dce5fd9233a709d3c1ef467d4bde6"
dependencies = [
"defmt-parser",
"proc-macro-error2",
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]]
name = "defmt-parser"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3983b127f13995e68c1e29071e5d115cd96f215ccb5e6812e3728cd6f92653b3"
dependencies = [
"thiserror",
]
[[package]]
name = "defmt-rtt"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab697b3dbbc1750b7c8b821aa6f6e7f2480b47a99bc057a2ed7b170ebef0c51"
dependencies = [
"critical-section",
"defmt",
]
[[package]] [[package]]
name = "dhcparse" name = "dhcparse"
version = "1.0.0" version = "1.0.0"
@ -399,7 +357,6 @@ source = "git+https://github.com/embassy-rs/embassy#cae954a87ec3c5ece520b6a44168
dependencies = [ dependencies = [
"cortex-m", "cortex-m",
"critical-section", "critical-section",
"defmt",
"document-features", "document-features",
"embassy-executor-macros", "embassy-executor-macros",
] ]
@ -427,7 +384,6 @@ source = "git+https://github.com/embassy-rs/embassy#cae954a87ec3c5ece520b6a44168
dependencies = [ dependencies = [
"cortex-m", "cortex-m",
"critical-section", "critical-section",
"defmt",
"num-traits", "num-traits",
] ]
@ -436,7 +392,6 @@ name = "embassy-net"
version = "0.7.0" version = "0.7.0"
source = "git+https://github.com/embassy-rs/embassy#cae954a87ec3c5ece520b6a44168b36e79f3f86a" source = "git+https://github.com/embassy-rs/embassy#cae954a87ec3c5ece520b6a44168b36e79f3f86a"
dependencies = [ dependencies = [
"defmt",
"document-features", "document-features",
"embassy-net-driver", "embassy-net-driver",
"embassy-sync", "embassy-sync",
@ -452,9 +407,6 @@ dependencies = [
name = "embassy-net-driver" name = "embassy-net-driver"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/embassy-rs/embassy#cae954a87ec3c5ece520b6a44168b36e79f3f86a" source = "git+https://github.com/embassy-rs/embassy#cae954a87ec3c5ece520b6a44168b36e79f3f86a"
dependencies = [
"defmt",
]
[[package]] [[package]]
name = "embassy-net-driver-channel" name = "embassy-net-driver-channel"
@ -476,7 +428,6 @@ dependencies = [
"cortex-m", "cortex-m",
"cortex-m-rt", "cortex-m-rt",
"critical-section", "critical-section",
"defmt",
"document-features", "document-features",
"embassy-embedded-hal", "embassy-embedded-hal",
"embassy-futures", "embassy-futures",
@ -567,9 +518,6 @@ dependencies = [
name = "embassy-usb-driver" name = "embassy-usb-driver"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/embassy-rs/embassy#cae954a87ec3c5ece520b6a44168b36e79f3f86a" source = "git+https://github.com/embassy-rs/embassy#cae954a87ec3c5ece520b6a44168b36e79f3f86a"
dependencies = [
"defmt",
]
[[package]] [[package]]
name = "embassy-usb-logger" name = "embassy-usb-logger"
@ -834,7 +782,6 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
dependencies = [ dependencies = [
"defmt",
"hash32", "hash32",
"serde", "serde",
"stable_deref_trait", "stable_deref_trait",
@ -1031,15 +978,6 @@ version = "1.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
[[package]]
name = "panic-probe"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4047d9235d1423d66cc97da7d07eddb54d4f154d6c13805c6d0793956f4f25b0"
dependencies = [
"cortex-m",
]
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.12.3" version = "0.12.3"
@ -1109,8 +1047,6 @@ dependencies = [
"cortex-m-rt", "cortex-m-rt",
"cyw43", "cyw43",
"cyw43-pio", "cyw43-pio",
"defmt",
"defmt-rtt",
"dhcparse", "dhcparse",
"dnsparse", "dnsparse",
"embassy-executor", "embassy-executor",
@ -1122,7 +1058,6 @@ dependencies = [
"embedded-io-async", "embedded-io-async",
"heapless", "heapless",
"log", "log",
"panic-probe",
"percent-encoding", "percent-encoding",
"portable-atomic", "portable-atomic",
"rand_core", "rand_core",
@ -1494,7 +1429,6 @@ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"byteorder", "byteorder",
"cfg-if", "cfg-if",
"defmt",
"heapless", "heapless",
"managed", "managed",
] ]
@ -1583,26 +1517,6 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "thiserror"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.18.0" version = "1.18.0"

View File

@ -16,14 +16,12 @@ default = ["dhcp", "dns", "ttt"]
[dependencies] [dependencies]
embassy-executor = { git = "https://github.com/embassy-rs/embassy", features = [ embassy-executor = { git = "https://github.com/embassy-rs/embassy", features = [
"defmt",
"nightly", "nightly",
"arch-cortex-m", "arch-cortex-m",
"executor-thread", "executor-thread",
"executor-interrupt", "executor-interrupt",
] } ] }
embassy-rp = { git = "https://github.com/embassy-rs/embassy", features = [ embassy-rp = { git = "https://github.com/embassy-rs/embassy", features = [
"defmt",
"unstable-pac", "unstable-pac",
"rp2040", "rp2040",
"time-driver", "time-driver",
@ -32,7 +30,6 @@ embassy-rp = { git = "https://github.com/embassy-rs/embassy", features = [
embassy-time = { git = "https://github.com/embassy-rs/embassy" } embassy-time = { git = "https://github.com/embassy-rs/embassy" }
embassy-usb-logger = { git = "https://github.com/embassy-rs/embassy" } embassy-usb-logger = { git = "https://github.com/embassy-rs/embassy" }
embassy-net = { git = "https://github.com/embassy-rs/embassy", features = [ embassy-net = { git = "https://github.com/embassy-rs/embassy", features = [
"defmt",
"proto-ipv4", "proto-ipv4",
"tcp", "tcp",
"udp", "udp",
@ -43,9 +40,6 @@ cyw43-pio = { git = "https://github.com/embassy-rs/embassy" }
cyw43 = { git = "https://github.com/embassy-rs/embassy" } cyw43 = { git = "https://github.com/embassy-rs/embassy" }
embedded-io-async = "*" embedded-io-async = "*"
defmt = "*"
defmt-rtt = "*"
panic-probe = "*"
cortex-m = { version = "*", features = ["inline-asm"] } cortex-m = { version = "*", features = ["inline-asm"] }
cortex-m-rt = "*" cortex-m-rt = "*"
static_cell = "*" static_cell = "*"

View File

@ -32,5 +32,5 @@ fn main() {
println!("cargo:rustc-link-arg-bins=--nmagic"); println!("cargo:rustc-link-arg-bins=--nmagic");
println!("cargo:rustc-link-arg-bins=-Tlink.x"); println!("cargo:rustc-link-arg-bins=-Tlink.x");
println!("cargo:rustc-link-arg-bins=-Tlink-rp.x"); println!("cargo:rustc-link-arg-bins=-Tlink-rp.x");
println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); // println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
} }

View File

@ -1,15 +1,10 @@
<!doctype html> <!doctype html>
<head>
<script>
var ws = new WebSocket("/chat");
</script>
</head>
<html> <html>
<body> <body>
<h1>Apps</h1> <h1>Apps</h1>
<ul> <ul>
<li><a href="http://pico.wifi:8080">Tic Tac Toe</a> (team blue)</li> <li><a href="/ttt?team=0">Tic Tac Toe</a> (team blue)</li>
<li><a href="http://pico.wifi:8081">Tic Tac Toe</a> (team red)</li> <li><a href="/ttt?team=1">Tic Tac Toe</a> (team red)</li>
</ul> </ul>
</body> </body>
</html> </html>

View File

@ -23,7 +23,18 @@ impl App for IndexApp {
"/" | "/index" | "/index.html" => ( "/" | "/index" | "/index.html" => (
HttpResCode::Ok, HttpResCode::Ok,
"html", "html",
Some(include_str!("./index.html").into()), #[cfg(debug_assertions)]
Some(include_str!("index.html").into()),
#[cfg(not(debug_assertions))]
Some(include_str!("../../static/index.min.html").into()),
),
"/htmx.js" => (
HttpResCode::Ok,
"javascript",
#[cfg(debug_assertions)]
Some(include_str!("../../static/htmx.js").into()),
#[cfg(not(debug_assertions))]
Some(include_str!("../../static/htmx.min.js").into()),
), ),
path => { path => {
let (path, args) = path.split_once('?').unwrap_or((path, "")); let (path, args) = path.split_once('?').unwrap_or((path, ""));
@ -39,7 +50,11 @@ impl App for IndexApp {
let Some(team) = team else { let Some(team) = team else {
return (HttpResCode::BadRequest, "", None); return (HttpResCode::BadRequest, "", None);
}; };
#[cfg(debug_assertions)]
let html = include_str!("ttt.html"); let html = include_str!("ttt.html");
#[cfg(not(debug_assertions))]
let html = include_str!("../../static/ttt.min.html");
let mut content = Vec::new(); let mut content = Vec::new();
let r: Result<(), &str> = try { let r: Result<(), &str> = try {
let (html1, html2) = html.split_once("/ttt.js").ok_or("")?; let (html1, html2) = html.split_once("/ttt.js").ok_or("")?;
@ -60,8 +75,11 @@ impl App for IndexApp {
let r: Result<(), &str> = try { let r: Result<(), &str> = try {
content.push("const team = ")?; content.push("const team = ")?;
content.push(team)?; content.push(team)?;
content.push(";\n")?; content.push(";")?;
#[cfg(debug_assertions)]
content.push(include_str!("ttt.js"))?; content.push(include_str!("ttt.js"))?;
#[cfg(not(debug_assertions))]
content.push(include_str!("../../static/ttt.min.js"))?;
}; };
unwrap(r).await; unwrap(r).await;
(HttpResCode::Ok, "javascript", Some(Content(content))) (HttpResCode::Ok, "javascript", Some(Content(content)))

View File

@ -31,12 +31,6 @@ pub trait App {
pub struct Content<'a>(pub Vec<&'a str, 8>); pub struct Content<'a>(pub Vec<&'a str, 8>);
// pub enum Content<'a> {
// Str(&'a str),
// /// Return the number of bytes written
// /// (fn that writes content, length)
// Fn(fn(&mut [u8]) -> usize, usize),
// }
impl<'a> From<&'a str> for Content<'a> { impl<'a> From<&'a str> for Content<'a> {
fn from(value: &'a str) -> Self { fn from(value: &'a str) -> Self {
let mut v = Vec::new(); let mut v = Vec::new();

View File

@ -1,6 +1,5 @@
<!doctype html> <!doctype html>
<head> <head>
<!-- <script src="./htmx.js"></script> -->
<style type="text/css"> <style type="text/css">
body { body {
#grid { #grid {

View File

@ -27,7 +27,6 @@ const ws = new WebSocket(
); );
ws.onmessage = (event) => { ws.onmessage = (event) => {
console.log(event.data);
if (typeof event.data == "string") { if (typeof event.data == "string") {
let msg = JSON.parse(event.data); let msg = JSON.parse(event.data);
let cells = []; let cells = [];
@ -46,18 +45,12 @@ ws.onmessage = (event) => {
if (tagName === "button") { if (tagName === "button") {
cell.addEventListener("click", (event) => { cell.addEventListener("click", (event) => {
console.log(i);
ws.send(new Uint8Array([i])); ws.send(new Uint8Array([i]));
}); });
} }
cell.setAttribute("team", owner); cell.setAttribute("team", owner);
// if (msg.board & (1 << i != 0) || msg.board & (1 << (i + 9))) {
// if (msg.board & (1 << (i + 9) != 0)) {
// col = "firebrick";
// }
// }
cells.push(cell); cells.push(cell);
} }
document.getElementById("grid").replaceChildren(...cells); document.getElementById("grid").replaceChildren(...cells);

View File

@ -1,9 +1,8 @@
use core::ops::Not;
use core::str::from_utf8_unchecked; use core::str::from_utf8_unchecked;
use core::{ops::Not, sync::atomic::Ordering};
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
use embassy_sync::mutex::Mutex; use embassy_sync::mutex::Mutex;
use embassy_time::{Duration, Instant, Timer}; use embassy_time::{Duration, Instant, Timer};
use heapless::{String, Vec};
use log::{info, warn}; use log::{info, warn};
use pico_website::{unwrap, unwrap_opt}; use pico_website::{unwrap, unwrap_opt};
use serde::Serialize; use serde::Serialize;
@ -60,8 +59,6 @@ impl Game {
static GAME: Mutex<ThreadModeRawMutex, Game> = Mutex::new(Game::default()); static GAME: Mutex<ThreadModeRawMutex, Game> = Mutex::new(Game::default());
// {"board"=[null,null,null,null,null,null,null,null,null],"turn"=null,"winner":null}
pub struct TttApp { pub struct TttApp {
team: Team, team: Team,
last_game: Game, last_game: Game,
@ -82,67 +79,17 @@ impl TttApp {
json_buf: [0; 128], json_buf: [0; 128],
} }
} }
// pub fn is_ended(&self, board: u32) -> (bool, Option<Team>) {
// if let Some((_, t)) = self.end {
// return (true, t);
// }
// for (t, m) in [(Team::Zero, 0), (Team::One, 9)] {
// for w in [
// 0b111000000,
// 0b000111000,
// 0b000000111,
// 0b100100100,
// 0b010010010,
// 0b001001001,
// 0b100010001,
// 0b001010100,
// ] {
// if board & (w << m) == (w << m) {
// return (true, Some(t));
// }
// }
// }
// if ((board | (board >> 9)) & 0b111111111) == 0b111111111 {
// return (true, None);
// }
// (false, None)
// }
// pub fn update_end_state(&mut self, board: &mut u32) {
// if let Some((i, _)) = self.end {
// if i + Duration::from_secs(7) < Instant::now() {
// self.end = None;
// // BOARD.store(0, Ordering::Release);
// *board = 0;
// }
// } else {
// if let (true, t) = self.is_ended(*board) {
// self.end = Some((Instant::now(), t));
// }
// }
// }
} }
impl App for TttApp { impl App for TttApp {
fn socket_name(&self) -> &'static str { fn socket_name(&self) -> &'static str {
self.team.name() match self.team {
} Team::Zero => "ttt0",
async fn handle_request<'a>( Team::One => "ttt1",
&'a mut self,
path: &str,
_req_type: HttpRequestType,
_content: &str,
) -> (HttpResCode, &'static str, Option<Content<'a>>) {
match path {
"/" | "/index" | "/index.html" | "/ttt" | "/ttt.html" => (
HttpResCode::Ok,
"html",
Some(include_str!("ttt.html").into()),
),
_ => (HttpResCode::NotFound, "", None),
} }
} }
fn accept_ws(&self, path: &str) -> bool { fn accept_ws(&self, path: &str) -> bool {
matches!(path, "/blue" | "/red") (self.team == Team::Zero && path == "/blue") || (self.team == Team::One && path == "/red")
} }
async fn handle_ws<'a, const BUF_SIZE: usize, const RES_HEAD_BUF_SIZE: usize>( async fn handle_ws<'a, const BUF_SIZE: usize, const RES_HEAD_BUF_SIZE: usize>(
&'a mut self, &'a mut self,
@ -154,22 +101,18 @@ impl App for TttApp {
loop { loop {
Timer::after_millis(1).await; Timer::after_millis(1).await;
let Ok(mut game) = GAME.try_lock() else { let Ok(mut game) = GAME.try_lock() else {
info!("locked"); info!("game locked");
continue; continue;
}; };
// match GAME.try_lock() ;
if self.last_game != *game { if self.last_game != *game {
// let json = unwrap(serde_json_core::to_string::<Game, 128>(&game)).await;
let n = unwrap(serde_json_core::to_slice(&(*game), &mut self.json_buf)).await; let n = unwrap(serde_json_core::to_slice(&(*game), &mut self.json_buf)).await;
let json = let json =
unsafe { from_utf8_unchecked(&unwrap_opt(self.json_buf.get(..n)).await) }; unsafe { from_utf8_unchecked(&unwrap_opt(self.json_buf.get(..n)).await) };
info!("{:?}", json);
ws.send(WsMsg::Text(json)).await?; ws.send(WsMsg::Text(json)).await?;
self.last_game = game.clone(); self.last_game = game.clone();
} }
if ws.last_msg.elapsed() >= Duration::from_secs(5) { if ws.last_msg.elapsed() >= Duration::from_secs(5) {
ws.send(WsMsg::Ping(&[])).await?; ws.send(WsMsg::Ping(&[])).await?;
info!("ping");
} }
if self.end.map(|e| e.elapsed()).unwrap_or_default() > Duration::from_secs(5) { if self.end.map(|e| e.elapsed()).unwrap_or_default() > Duration::from_secs(5) {
self.end = None; self.end = None;
@ -179,17 +122,15 @@ impl App for TttApp {
}; };
} }
while let Some(r) = ws.rcv().await? { while let Some(r) = ws.rcv().await? {
info!("{:?}", r);
if let WsMsg::Bytes([c]) = r { if let WsMsg::Bytes([c]) = r {
let c = *c as usize; let c = *c as usize;
info!("c={}", c);
if c >= game.board.len() { if c >= game.board.len() {
warn!("Cell played is too big!"); warn!("Cell played is too big!");
return; continue;
} }
if game.board[c].is_some() { if game.board[c].is_some() {
warn!("Cell is already taken!"); warn!("Cell is already taken!");
return; continue;
} }
if game.turn == Some(self.team) { if game.turn == Some(self.team) {
game.board[c] = Some(self.team); game.board[c] = Some(self.team);
@ -199,17 +140,18 @@ impl App for TttApp {
} }
} else { } else {
warn!("It's not your turn!"); warn!("It's not your turn!");
return; continue;
} }
info!("{:#?}", game);
} }
} }
// Timer::after_secs(1).await;
} }
}; };
warn!("error: {:?}", r); if r.is_err() {
Timer::after_micros(100).await; warn!(
"Socket {}: error in ws, terminating connection",
self.socket_name()
);
}
} }
} }

View File

@ -36,6 +36,7 @@ pub async fn dhcp_server(stack: Stack<'static>) {
info!("Starting DHCP server"); info!("Starting DHCP server");
loop { loop {
Timer::after_secs(0).await;
let (n, _) = unwrap(socket.recv_from(&mut buf).await).await; let (n, _) = unwrap(socket.recv_from(&mut buf).await).await;
let msg = unwrap_opt(buf.get(..n)).await; let msg = unwrap_opt(buf.get(..n)).await;
@ -54,7 +55,6 @@ pub async fn dhcp_server(stack: Stack<'static>) {
rapid_commit = true; rapid_commit = true;
} }
info!("Dhcp: received {:?} message", msg_type); info!("Dhcp: received {:?} message", msg_type);
Timer::after_secs(0).await;
match msg_type { match msg_type {
DhcpMsgType::DISCOVER | DhcpMsgType::REQUEST => { DhcpMsgType::DISCOVER | DhcpMsgType::REQUEST => {
@ -127,7 +127,6 @@ pub async fn dhcp_server(stack: Stack<'static>) {
) )
.await; .await;
info!("Dhcp: offer/ack sent for ip 192.254.0.{}", current_ip); info!("Dhcp: offer/ack sent for ip 192.254.0.{}", current_ip);
Timer::after_secs(0).await;
if msg_type == DhcpMsgType::REQUEST || rapid_commit { if msg_type == DhcpMsgType::REQUEST || rapid_commit {
current_ip += 1; current_ip += 1;
@ -161,8 +160,7 @@ async fn write_dhcp_opts<const N: usize>(buf: &mut Vec<u8, N>, op_codes: &[u8])
59 => (4, &3500_u32.to_be_bytes()), // rebinding time 59 => (4, &3500_u32.to_be_bytes()), // rebinding time
80 => (0, &[]), 80 => (0, &[]),
_ => { _ => {
info!("Dhcp: unhandled requested option {}", o); warn!("Dhcp: unhandled requested option {}", o);
Timer::after_secs(0).await;
continue; continue;
} }
}; };

View File

@ -2,13 +2,13 @@
use core::{fmt::Debug, panic::PanicInfo}; use core::{fmt::Debug, panic::PanicInfo};
use embassy_time::Timer; use embassy_time::Timer;
use log::info; use log::error;
pub async fn unwrap<T, E: Debug>(res: Result<T, E>) -> T { pub async fn unwrap<T, E: Debug>(res: Result<T, E>) -> T {
match res { match res {
Ok(v) => v, Ok(v) => v,
Err(e) => loop { Err(e) => loop {
info!("FATAL ERROR : {:?}", e); error!("FATAL ERROR : {:?}", e);
Timer::after_secs(5).await; Timer::after_secs(5).await;
}, },
} }
@ -24,9 +24,9 @@ pub async fn assert(condition: bool) {
} }
} }
// Doesn't work // TODO: make this log work
#[panic_handler] #[panic_handler]
fn panic(info: &PanicInfo) -> ! { fn panic(info: &PanicInfo) -> ! {
info!("PANIC: {}", info); error!("PANIC: {}", info);
loop {} loop {}
} }

View File

@ -1,12 +1,6 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![allow(async_fn_in_trait)] #![allow(async_fn_in_trait)]
#![deny(
// clippy::unwrap_used,
// clippy::expect_used,
clippy::panic,
clippy::indexing_slicing
)]
#![feature(impl_trait_in_assoc_type)] #![feature(impl_trait_in_assoc_type)]
#![feature(slice_split_once)] #![feature(slice_split_once)]
#![feature(try_blocks)] #![feature(try_blocks)]
@ -16,8 +10,6 @@
use core::net::Ipv4Addr; use core::net::Ipv4Addr;
use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi}; use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi};
use defmt::warn;
use defmt_rtt as _;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_net::{Config, StackResources}; use embassy_net::{Config, StackResources};
use embassy_rp::bind_interrupts; use embassy_rp::bind_interrupts;
@ -70,13 +62,6 @@ async fn main(spawner: Spawner) {
spawner.spawn(logger_task(driver)).unwrap(); spawner.spawn(logger_task(driver)).unwrap();
let mut rng = RoscRng; let mut rng = RoscRng;
// let mut i = 0;
// loop {
// info!("test{}", i);
// Timer::after_secs(1).await;
// i += 1;
// }
let fw = include_bytes!("../cyw43-firmware/43439A0.bin"); let fw = include_bytes!("../cyw43-firmware/43439A0.bin");
let clm = include_bytes!("../cyw43-firmware/43439A0_clm.bin"); let clm = include_bytes!("../cyw43-firmware/43439A0_clm.bin");
let pwr = Output::new(p.PIN_23, Level::Low); let pwr = Output::new(p.PIN_23, Level::Low);
@ -171,9 +156,6 @@ async fn main(spawner: Spawner) {
// Wait for DHCP, not necessary when using static IP // Wait for DHCP, not necessary when using static IP
info!("waiting for DHCP..."); info!("waiting for DHCP...");
stack.wait_config_up().await; stack.wait_config_up().await;
// while !stack.is_config_up() {
// Timer::after_millis(100).await;
// }
info!("DHCP is now up!"); info!("DHCP is now up!");
info!( info!(
"ip : {}", "ip : {}",
@ -182,12 +164,6 @@ async fn main(spawner: Spawner) {
.address .address
) )
} }
// embassy_time::Timer::after_secs(5).await;
// info!("test0");
// embassy_time::Timer::after_secs(3).await;
// panic!("test");
#[cfg(feature = "dhcp")] #[cfg(feature = "dhcp")]
unwrap(spawner.spawn(dhcp::dhcp_server(stack))).await; unwrap(spawner.spawn(dhcp::dhcp_server(stack))).await;

View File

@ -32,10 +32,6 @@ pub async fn chat_listen_task(stack: embassy_net::Stack<'static>, port: u16) {
} }
pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps::App, port: u16) { pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps::App, port: u16) {
// loop {
// info!("team:{:?}", team);
// Timer::after_millis(0).await;
// }
let mut rx_buffer = [0; 1024]; let mut rx_buffer = [0; 1024];
let mut tx_buffer = [0; 2048]; let mut tx_buffer = [0; 2048];
let mut buf = [0; 1024]; let mut buf = [0; 1024];
@ -84,9 +80,6 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
} }
}; };
// info!("\n{:?}\n", headers);
// Timer::after_micros(100).await;
let mut hl = headers.lines(); let mut hl = headers.lines();
let (request_type, path) = match hl.next() { let (request_type, path) = match hl.next() {
None => { None => {
@ -147,7 +140,6 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
host, host,
path, path,
); );
Timer::after_micros(100).await;
head_buf.clear(); head_buf.clear();
let res_content: Result<Option<Content>, core::fmt::Error> = try { let res_content: Result<Option<Content>, core::fmt::Error> = try {
@ -182,24 +174,14 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
Upgrade: websocket\r\n\ Upgrade: websocket\r\n\
Connection: Upgrade\r\n\ Connection: Upgrade\r\n\
Sec-WebSocket-Accept: {}\r\n\r\n", Sec-WebSocket-Accept: {}\r\n\r\n",
// Sec-WebSocket-Protocol: chat\r\n
Into::<&str>::into(HttpResCode::SwitchingProtocols), Into::<&str>::into(HttpResCode::SwitchingProtocols),
accept accept
)?; )?;
None None
} }
} else { } else {
let (code, res_type, res_content) = match path { let (code, res_type, res_content) =
"/htmx.js" => ( app.handle_request(path, request_type, content).await;
HttpResCode::Ok,
"javascript",
#[cfg(debug_assertions)]
Some(include_str!("../static/htmx.js").into()),
#[cfg(not(debug_assertions))]
Some(include_bytes!("../static/htmx.min.js").into()),
),
_ => app.handle_request(path, request_type, content).await,
};
write!(&mut head_buf, "{}", Into::<&str>::into(code))?; write!(&mut head_buf, "{}", Into::<&str>::into(code))?;
if let Some(ref c) = res_content { if let Some(ref c) = res_content {
@ -225,9 +207,6 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
} }
}; };
info!("\n{}\n", unwrap(from_utf8(&head_buf)).await);
Timer::after_micros(1000).await;
let w: Result<(), embassy_net::tcp::Error> = try { let w: Result<(), embassy_net::tcp::Error> = try {
socket.write_all(&head_buf).await?; socket.write_all(&head_buf).await?;
if let Some(ref c) = res_content { if let Some(ref c) = res_content {
@ -248,8 +227,6 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
} }
} }
if let Some(path) = ws_path { if let Some(path) = ws_path {
info!("handle ws");
Timer::after_micros(200).await;
app.handle_ws( app.handle_ws(
&path, &path,
Ws::new(&mut socket, &mut buf, &mut head_buf, app.socket_name()), Ws::new(&mut socket, &mut buf, &mut head_buf, app.socket_name()),
@ -297,7 +274,6 @@ impl Into<&str> for HttpResCode {
async fn compute_ws_accept(key: &str) -> Result<String<28>, EncodeSliceError> { async fn compute_ws_accept(key: &str) -> Result<String<28>, EncodeSliceError> {
let mut res = Vec::<u8, 28>::new(); let mut res = Vec::<u8, 28>::new();
Timer::after_micros(10).await;
res.extend_from_slice(&[0; 28]).unwrap(); res.extend_from_slice(&[0; 28]).unwrap();
let mut hasher = Sha1::new(); let mut hasher = Sha1::new();
hasher.update(key.as_bytes()); hasher.update(key.as_bytes());

View File

@ -1,7 +1,7 @@
use core::str::from_utf8; use core::str::from_utf8;
use embassy_net::tcp::{TcpReader, TcpSocket, TcpWriter}; use embassy_net::tcp::{TcpReader, TcpSocket, TcpWriter};
use embassy_time::{Instant, Timer}; use embassy_time::Instant;
use embedded_io_async::{ErrorType, ReadReady, Write}; use embedded_io_async::{ErrorType, ReadReady, Write};
use heapless::Vec; use heapless::Vec;
use log::{info, warn}; use log::{info, warn};
@ -58,7 +58,6 @@ impl<'a, const HEAD_BUF_SIZE: usize> WsTx<'a, HEAD_BUF_SIZE> {
.extend_from_slice(&(msg.len() as u16).to_le_bytes()), .extend_from_slice(&(msg.len() as u16).to_le_bytes()),
) )
.await; .await;
// self.head_buf.extend_from_slice(msg.as_bytes()).unwrap();
} }
let w: Result<(), <TcpSocket<'_> as ErrorType>::Error> = try { let w: Result<(), <TcpSocket<'_> as ErrorType>::Error> = try {
self.socket.write_all(&self.head_buf).await?; self.socket.write_all(&self.head_buf).await?;
@ -66,7 +65,6 @@ impl<'a, const HEAD_BUF_SIZE: usize> WsTx<'a, HEAD_BUF_SIZE> {
}; };
w.map_err(|e| { w.map_err(|e| {
warn!("write error: {:?}", e); warn!("write error: {:?}", e);
()
}) })
} }
} }
@ -99,7 +97,7 @@ impl<'a, const BUF_SIZE: usize, const HEAD_BUF_SIZE: usize> Ws<'a, BUF_SIZE, HEA
name, name,
} }
} }
// Do this often to respond to pings /// Do this often to respond to pings
pub async fn rcv(&mut self) -> Result<Option<WsMsg>, ()> { pub async fn rcv(&mut self) -> Result<Option<WsMsg>, ()> {
let n = match self.rx.msg_in_buf.take() { let n = match self.rx.msg_in_buf.take() {
Some(n) => { Some(n) => {
@ -108,12 +106,12 @@ impl<'a, const BUF_SIZE: usize, const HEAD_BUF_SIZE: usize> Ws<'a, BUF_SIZE, HEA
if unwrap(self.rx.socket.read_ready()).await { if unwrap(self.rx.socket.read_ready()).await {
let n_rcv = match self.rx.socket.read(&mut self.rx.buf[n.1..]).await { let n_rcv = match self.rx.socket.read(&mut self.rx.buf[n.1..]).await {
Ok(0) => { Ok(0) => {
info!("read EOF"); warn!("read EOF");
return Err(()); return Err(());
} }
Ok(n) => n, Ok(n) => n,
Err(e) => { Err(e) => {
info!("Socket {}: read error: {:?}", self.name, e); warn!("Socket {}: read error: {:?}", self.name, e);
return Err(()); return Err(());
} }
}; };
@ -126,12 +124,12 @@ impl<'a, const BUF_SIZE: usize, const HEAD_BUF_SIZE: usize> Ws<'a, BUF_SIZE, HEA
if unwrap(self.rx.socket.read_ready()).await { if unwrap(self.rx.socket.read_ready()).await {
match self.rx.socket.read(self.rx.buf).await { match self.rx.socket.read(self.rx.buf).await {
Ok(0) => { Ok(0) => {
info!("read EOF"); warn!("read EOF");
return Err(()); return Err(());
} }
Ok(n) => n, Ok(n) => n,
Err(e) => { Err(e) => {
info!("Socket {}: read error: {:?}", self.name, e); warn!("Socket {}: read error: {:?}", self.name, e);
return Err(()); return Err(());
} }
} }
@ -142,11 +140,11 @@ impl<'a, const BUF_SIZE: usize, const HEAD_BUF_SIZE: usize> Ws<'a, BUF_SIZE, HEA
}; };
if self.rx.buf[0] & 0b1000_0000 == 0 { if self.rx.buf[0] & 0b1000_0000 == 0 {
info!("Fragmented ws messages are not supported!"); warn!("Fragmented ws messages are not supported!");
return Err(()); return Err(());
} }
if self.rx.buf[0] & 0b0111_0000 != 0 { if self.rx.buf[0] & 0b0111_0000 != 0 {
info!( warn!(
"Reserved ws bits are set : {}", "Reserved ws bits are set : {}",
(self.rx.buf[0] >> 4) & 0b0111 (self.rx.buf[0] >> 4) & 0b0111
); );
@ -164,14 +162,14 @@ impl<'a, const BUF_SIZE: usize, const HEAD_BUF_SIZE: usize> Ws<'a, BUF_SIZE, HEA
l => (l as u64, 2), l => (l as u64, 2),
}; };
if length > 512 { if length > 512 {
info!("ws payload bigger than 512!"); warn!("ws payload bigger than 512!");
return Err(()); return Err(());
} }
let content = if self.rx.buf[1] & 0b1000_0000 != 0 { let content = if self.rx.buf[1] & 0b1000_0000 != 0 {
// masked message // masked message
if n_after_length + 4 + length as usize > n { if n_after_length + 4 + length as usize > n {
info!("ws payload smaller than length"); warn!("ws payload smaller than length");
return Err(()); return Err(());
} }
let mask_key: [u8; 4] = self.rx.buf[n_after_length..n_after_length + 4] let mask_key: [u8; 4] = self.rx.buf[n_after_length..n_after_length + 4]
@ -192,7 +190,7 @@ impl<'a, const BUF_SIZE: usize, const HEAD_BUF_SIZE: usize> Ws<'a, BUF_SIZE, HEA
&self.rx.buf[n_after_length + 4..n_after_length + 4 + length as usize] &self.rx.buf[n_after_length + 4..n_after_length + 4 + length as usize]
} else { } else {
if n_after_length + length as usize > n { if n_after_length + length as usize > n {
info!("ws payload smaller than length"); warn!("ws payload smaller than length");
return Err(()); return Err(());
} }
if n_after_length + (length as usize) < n { if n_after_length + (length as usize) < n {
@ -220,7 +218,7 @@ impl<'a, const BUF_SIZE: usize, const HEAD_BUF_SIZE: usize> Ws<'a, BUF_SIZE, HEA
// Pong // Pong
10 => Ok(Some(WsMsg::Pong(&content))), 10 => Ok(Some(WsMsg::Pong(&content))),
c => { c => {
info!("Unknown ws op code (ignoring) : {}", c); warn!("Unknown ws op code (ignoring) : {}", c);
Ok(Some(WsMsg::Unknown(c, &content))) Ok(Some(WsMsg::Unknown(c, &content)))
} }
} }

1
static/index.min.html Normal file
View File

@ -0,0 +1 @@
<!doctype html><html><body><h1>Apps</h1><ul><li><a href="/ttt?team=0">Tic Tac Toe</a>(team blue)</li><li><a href="/ttt?team=1">Tic Tac Toe</a>(team red)</li></ul></body></html>

1
static/ttt.min.html Normal file
View File

@ -0,0 +1 @@
<!doctype html><head><style type="text/css"> body { #grid { .cell { border: 1px dotted black; padding: 33%; } .cell[team="0"] { background-color: dodgerblue; } .cell[team="1"] { background-color: firebrick; } display: grid; border: 1px solid black; grid-template-rows: 1fr 1fr 1fr; grid-template-columns: 1fr 1fr 1fr; } } </style><script src="/ttt.js" defer></script></head><html><body><h1>TicTacToe</h1><h3 id="team"></h3><h3 id="winner"></h3><div id="grid"></div></body></html>

1
static/ttt.min.js vendored Normal file
View File

@ -0,0 +1 @@
if(0!=team&&1!=team)throw"team is not 0 or 1! team="+team;const teams=[{name:"blue",color:"dodgerblue",port:"8080"},{name:"red",color:"firebrick",port:"8081"}];document.getElementById("team").innerHTML='Team : <span style="color:'+teams[team].color+'">'+teams[team].name+"</span>";const ws=new WebSocket("ws://192.254.0.2:"+teams[team].port+"/"+teams[team].name);ws.onmessage=e=>{if("string"==typeof e.data){let t=JSON.parse(e.data),n=[];for(let e=0;e<9;e++){let a,r=t.board[e];a=t.turn==team&&null===r?"button":"div";let m=document.createElement(a);m.classList.add("cell"),"button"===a&&m.addEventListener("click",(t=>{ws.send(new Uint8Array([e]))})),m.setAttribute("team",r),n.push(m)}document.getElementById("grid").replaceChildren(...n),null==t.turn?null==t.winner?document.getElementById("winner").innerHTML="Draw!":document.getElementById("winner").innerHTML='Winner : <span style="color:'+teams[t.winner].color+'">'+teams[t.winner].name+"</span>":document.getElementById("winner").innerHTML=""}};