Working http server

This commit is contained in:
Arkitu 2025-03-26 20:52:54 +01:00
parent bb7f643134
commit ef8d06b516
2 changed files with 130 additions and 11 deletions

2
rust-toolchain.toml Normal file
View File

@ -0,0 +1,2 @@
[toolchain]
channel = "nightly"

View File

@ -1,25 +1,29 @@
#![no_std]
#![no_main]
#![allow(async_fn_in_trait)]
#![feature(slice_split_once)]
use core::fmt::{Debug, Write};
use core::str::from_utf8;
use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER};
use log::{info, warn};
use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi};
use defmt::println;
use embassy_executor::Spawner;
use embassy_net::tcp::TcpSocket;
use embassy_net::{Config, StackResources};
use embassy_rp::bind_interrupts;
use embassy_rp::clocks::RoscRng;
use embassy_rp::gpio::{Level, Output};
use embassy_rp::peripherals::USB;
use embassy_rp::peripherals::{DMA_CH0, PIO0};
use embassy_rp::pio::{InterruptHandler as PioInterruptHandler, Pio};
use embassy_rp::usb::{Driver, InterruptHandler as UsbInterruptHandler};
use embassy_time::Duration;
use embedded_io_async::Write;
use embassy_time::Timer;
use embedded_io_async::Write as _;
use heapless::{String, Vec};
use log::{info, warn};
use rand_core::RngCore;
use static_cell::StaticCell;
use embassy_rp::peripherals::USB;
use embassy_rp::usb::{Driver, InterruptHandler as UsbInterruptHandler};
use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
@ -33,7 +37,9 @@ async fn logger_task(driver: Driver<'static, USB>) {
}
#[embassy_executor::task]
async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
async fn cyw43_task(
runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>,
) -> ! {
runner.run().await
}
@ -87,7 +93,12 @@ async fn main(spawner: Spawner) {
// Init network stack
static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed);
let (stack, runner) = embassy_net::new(
net_device,
config,
RESOURCES.init(StackResources::new()),
seed,
);
spawner.spawn(net_task(runner)).unwrap();
@ -97,10 +108,11 @@ async fn main(spawner: Spawner) {
let mut rx_buffer = [0; 4096];
let mut tx_buffer = [0; 4096];
let mut buf = [0; 4096];
let mut res_buf = Vec::<u8, 4096>::new();
loop {
let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
socket.set_timeout(Some(Duration::from_secs(10)));
socket.set_timeout(Some(Duration::from_secs(30)));
control.gpio_set(0, false).await;
info!("Listening on TCP:1234...");
@ -125,9 +137,95 @@ async fn main(spawner: Spawner) {
}
};
info!("rxd {}", from_utf8(&buf[..n]).unwrap());
info!("request :\n{}", from_utf8(&buf[..n]).unwrap());
match socket.write_all(&buf[..n]).await {
let mut headers: &[u8] = &buf[..n];
let mut content: &[u8] = &[];
for i in 0..(n - 1) {
if &buf[i..i + 1] == b"\r\n" {
headers = &buf[0..i];
if i + 2 < n {
content = &buf[i + 2..n];
}
}
}
let mut headers = headers.split(|x| *x == b'\n');
let (request_type, path) = match headers.next() {
None => {
warn!("Empty request");
break;
}
Some(l1) => {
let mut l1 = l1.split(|x| *x == b' ');
(
match l1.next() {
Some(b"GET") => HttpRequestType::Get,
Some(b"POST") => HttpRequestType::Post,
Some(t) => {
warn!("Unknown request type : {}", from_utf8(t).unwrap());
break;
}
None => {
warn!("No request type");
break;
}
},
match l1.next() {
Some(path) => path,
None => {
warn!("No path");
break;
}
},
)
}
};
let (code, res): (HttpResCode, &str) = match path {
b"/" => (
HttpResCode::Ok,
"<!DOCTYPE html>\r\n\
<html>\r\n\
<body>\r\n\
<h1>Titre</h1>\r\n\
<p>contenu</p>\r\n\
</body>\r\n\
</html>",
),
_ => (HttpResCode::NotFound, ""),
};
//b"HTTP/1.1 200 OK\r\n\
// Content-Type: text/html\r\n\
// Content-Length: 81\r\n\r\n\
// <!DOCTYPE html>\r\n\
// <html>\r\n\
// <body>\r\n\
// <h1>Titre</h1>\r\n\
// <p>contenu</p>\r\n\
// </body>\r\n\
// </html>"
// Write response to buf
res_buf.clear();
if let Err(e) = write!(
&mut res_buf,
"{}\r\n\
Content-Type: text/html\r\n\
Content-Length: {}\r\n\r\n\
{}",
Into::<&str>::into(code),
res.len(),
res
) {
warn!("write error: {:?}", e);
break;
}
info!("response :\n{}", from_utf8(&res_buf).unwrap());
match socket.write_all(&res_buf).await {
Ok(()) => {}
Err(e) => {
warn!("write error: {:?}", e);
@ -137,3 +235,22 @@ async fn main(spawner: Spawner) {
}
}
}
enum HttpRequestType {
Get,
Post,
}
#[derive(Debug, Clone, Copy)]
enum HttpResCode {
Ok,
NotFound,
}
impl Into<&str> for HttpResCode {
fn into(self) -> &'static str {
match self {
HttpResCode::Ok => "HTTP/1.1 200 OK",
HttpResCode::NotFound => "HTTP/1.1 404 NOT FOUND",
}
}
}