mirror of
https://github.com/Djeeberjr/fw-anwesenheit.git
synced 2026-05-01 02:59:09 +00:00
Compare commits
4 Commits
2e6094ea11
...
23bb1126a6
| Author | SHA1 | Date | |
|---|---|---|---|
| 23bb1126a6 | |||
| a97e9c8080 | |||
| 4b39529a65 | |||
| c91d2f070f |
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -426,6 +426,7 @@ dependencies = [
|
|||||||
"futures-sink",
|
"futures-sink",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"heapless",
|
"heapless",
|
||||||
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -974,6 +975,7 @@ dependencies = [
|
|||||||
"edge-nal-embassy",
|
"edge-nal-embassy",
|
||||||
"embassy-executor",
|
"embassy-executor",
|
||||||
"embassy-net",
|
"embassy-net",
|
||||||
|
"embassy-sync 0.7.0",
|
||||||
"embassy-time",
|
"embassy-time",
|
||||||
"embedded-io",
|
"embedded-io",
|
||||||
"embedded-io-async",
|
"embedded-io-async",
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ edge-dhcp = { version = "0.6.0", features = ["log"] }
|
|||||||
edge-nal = "0.5.0"
|
edge-nal = "0.5.0"
|
||||||
edge-nal-embassy = { version = "0.6.0", features = ["log"] }
|
edge-nal-embassy = { version = "0.6.0", features = ["log"] }
|
||||||
picoserve = { version = "0.16.0", features = ["embassy", "log"] }
|
picoserve = { version = "0.16.0", features = ["embassy", "log"] }
|
||||||
|
embassy-sync = { version = "0.7.0", features = ["log"] }
|
||||||
|
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
|
|||||||
61
src/bin/init/mod.rs
Normal file
61
src/bin/init/mod.rs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_net::Stack;
|
||||||
|
use esp_hal::peripherals::{GPIO1, GPIO2, UART1};
|
||||||
|
use esp_hal::{
|
||||||
|
Async,
|
||||||
|
clock::CpuClock,
|
||||||
|
timer::{systimer::SystemTimer, timg::TimerGroup},
|
||||||
|
uart::Uart,
|
||||||
|
};
|
||||||
|
use esp_println::logger::init_logger;
|
||||||
|
use log::error;
|
||||||
|
|
||||||
|
mod network;
|
||||||
|
mod wifi;
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(_: &core::panic::PanicInfo) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_bootloader_esp_idf::esp_app_desc!();
|
||||||
|
|
||||||
|
pub async fn hardware_init(spawner: &mut Spawner) -> (Uart<'static, Async>, Stack<'static>) {
|
||||||
|
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
|
||||||
|
let peripherals = esp_hal::init(config);
|
||||||
|
|
||||||
|
esp_alloc::heap_allocator!(size: 72 * 1024);
|
||||||
|
|
||||||
|
let timer0 = SystemTimer::new(peripherals.SYSTIMER);
|
||||||
|
esp_hal_embassy::init(timer0.alarm0);
|
||||||
|
|
||||||
|
init_logger(log::LevelFilter::Debug);
|
||||||
|
|
||||||
|
let timer1 = TimerGroup::new(peripherals.TIMG0);
|
||||||
|
let mut rng = esp_hal::rng::Rng::new(peripherals.RNG);
|
||||||
|
let network_seed = (rng.random() as u64) << 32 | rng.random() as u64;
|
||||||
|
|
||||||
|
wifi::set_antenna_mode(peripherals.GPIO3, peripherals.GPIO14).await;
|
||||||
|
let interfaces = wifi::setup_wifi(timer1.timer0, rng, peripherals.WIFI, spawner);
|
||||||
|
let stack = network::setup_network(network_seed, interfaces.ap, spawner);
|
||||||
|
|
||||||
|
let uart_devie = setup_uart(peripherals.UART1, peripherals.GPIO1, peripherals.GPIO2);
|
||||||
|
|
||||||
|
(uart_devie, stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_uart(
|
||||||
|
uart1: UART1<'static>,
|
||||||
|
gpio1: GPIO1<'static>,
|
||||||
|
gpio2: GPIO2<'static>,
|
||||||
|
) -> Uart<'static, Async> {
|
||||||
|
let uard_device = Uart::new(uart1, esp_hal::uart::Config::default().with_baudrate(9600));
|
||||||
|
|
||||||
|
match uard_device {
|
||||||
|
Ok(block) => block.with_rx(gpio1).with_tx(gpio2).into_async(),
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to initialize UART: {e}");
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
72
src/bin/init/network.rs
Normal file
72
src/bin/init/network.rs
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
use core::{net::Ipv4Addr, str::FromStr};
|
||||||
|
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_net::{Ipv4Cidr, Runner, Stack, StackResources, StaticConfigV4};
|
||||||
|
use embassy_time::{Duration, Timer};
|
||||||
|
use esp_wifi::wifi::WifiDevice;
|
||||||
|
use static_cell::make_static;
|
||||||
|
|
||||||
|
|
||||||
|
pub fn setup_network<'a>(seed: u64, wifi: WifiDevice<'static>, spawner: &mut Spawner) -> Stack<'a> {
|
||||||
|
let gw_ip_addr_str = "192.168.2.1";
|
||||||
|
let gw_ip_addr = Ipv4Addr::from_str(gw_ip_addr_str).expect("failed to parse gateway ip");
|
||||||
|
let config = embassy_net::Config::ipv4_static(StaticConfigV4 {
|
||||||
|
address: Ipv4Cidr::new(gw_ip_addr, 24),
|
||||||
|
gateway: Some(gw_ip_addr),
|
||||||
|
dns_servers: Default::default(),
|
||||||
|
});
|
||||||
|
|
||||||
|
let (stack, runner) =
|
||||||
|
embassy_net::new(wifi, config, make_static!(StackResources::<3>::new()), seed);
|
||||||
|
|
||||||
|
spawner.must_spawn(net_task(runner));
|
||||||
|
spawner.must_spawn(run_dhcp(stack, gw_ip_addr_str));
|
||||||
|
|
||||||
|
stack
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn run_dhcp(stack: Stack<'static>, gw_ip_addr: &'static str) {
|
||||||
|
use core::net::{Ipv4Addr, SocketAddrV4};
|
||||||
|
|
||||||
|
use edge_dhcp::{
|
||||||
|
io::{self, DEFAULT_SERVER_PORT},
|
||||||
|
server::{Server, ServerOptions},
|
||||||
|
};
|
||||||
|
use edge_nal::UdpBind;
|
||||||
|
use edge_nal_embassy::{Udp, UdpBuffers};
|
||||||
|
|
||||||
|
let ip = Ipv4Addr::from_str(gw_ip_addr).expect("dhcp task failed to parse gw ip");
|
||||||
|
|
||||||
|
let mut buf = [0u8; 1500];
|
||||||
|
|
||||||
|
let mut gw_buf = [Ipv4Addr::UNSPECIFIED];
|
||||||
|
|
||||||
|
let buffers = UdpBuffers::<3, 1024, 1024, 10>::new();
|
||||||
|
let unbound_socket = Udp::new(stack, &buffers);
|
||||||
|
let mut bound_socket = unbound_socket
|
||||||
|
.bind(core::net::SocketAddr::V4(SocketAddrV4::new(
|
||||||
|
Ipv4Addr::UNSPECIFIED,
|
||||||
|
DEFAULT_SERVER_PORT,
|
||||||
|
)))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
_ = io::server::run(
|
||||||
|
&mut Server::<_, 64>::new_with_et(ip),
|
||||||
|
&ServerOptions::new(ip, Some(&mut gw_buf)),
|
||||||
|
&mut bound_socket,
|
||||||
|
&mut buf,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.inspect_err(|e| log::warn!("DHCP server error: {e:?}"));
|
||||||
|
Timer::after(Duration::from_millis(500)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) {
|
||||||
|
runner.run().await;
|
||||||
|
}
|
||||||
|
|
||||||
56
src/bin/init/wifi.rs
Normal file
56
src/bin/init/wifi.rs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_time::{Duration, Timer};
|
||||||
|
use esp_hal::gpio::{Output, OutputConfig};
|
||||||
|
use esp_hal::peripherals::{GPIO3, GPIO14, WIFI};
|
||||||
|
use esp_wifi::wifi::{AccessPointConfiguration, Configuration, WifiController, WifiEvent, WifiState};
|
||||||
|
use esp_wifi::{EspWifiRngSource, EspWifiTimerSource, wifi::Interfaces};
|
||||||
|
use static_cell::make_static;
|
||||||
|
|
||||||
|
pub async fn set_antenna_mode(gpio3: GPIO3<'static>, gpio14: GPIO14<'static>) {
|
||||||
|
let mut rf_switch = Output::new(gpio3, esp_hal::gpio::Level::Low, OutputConfig::default());
|
||||||
|
|
||||||
|
rf_switch.set_low();
|
||||||
|
|
||||||
|
Timer::after_millis(150).await;
|
||||||
|
|
||||||
|
let mut antenna_mode = Output::new(gpio14, esp_hal::gpio::Level::Low, OutputConfig::default());
|
||||||
|
|
||||||
|
antenna_mode.set_low();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup_wifi<'d: 'static>(
|
||||||
|
timer: impl EspWifiTimerSource + 'd,
|
||||||
|
rng: impl EspWifiRngSource + 'd,
|
||||||
|
wifi: WIFI<'static>,
|
||||||
|
spawner: &mut Spawner,
|
||||||
|
) -> Interfaces<'d> {
|
||||||
|
let esp_wifi_ctrl = make_static!(esp_wifi::init(timer, rng).unwrap());
|
||||||
|
|
||||||
|
let (controller, interfaces) = esp_wifi::wifi::new(esp_wifi_ctrl, wifi).unwrap();
|
||||||
|
|
||||||
|
spawner.must_spawn(connection(controller));
|
||||||
|
|
||||||
|
interfaces
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn connection(mut controller: WifiController<'static>) {
|
||||||
|
loop {
|
||||||
|
match esp_wifi::wifi::wifi_state() {
|
||||||
|
WifiState::ApStarted => {
|
||||||
|
// wait until we're no longer connected
|
||||||
|
controller.wait_for_event(WifiEvent::ApStop).await;
|
||||||
|
Timer::after(Duration::from_millis(5000)).await
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
if !matches!(controller.is_started(), Ok(true)) {
|
||||||
|
let client_config = Configuration::AccessPoint(AccessPointConfiguration {
|
||||||
|
ssid: "esp-wifi".try_into().unwrap(),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
controller.set_configuration(&client_config).unwrap();
|
||||||
|
controller.start_async().await.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
266
src/bin/main.rs
266
src/bin/main.rs
@@ -3,115 +3,56 @@
|
|||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
#![feature(impl_trait_in_assoc_type)]
|
#![feature(impl_trait_in_assoc_type)]
|
||||||
|
|
||||||
use core::net::Ipv4Addr;
|
|
||||||
use core::str::FromStr;
|
|
||||||
|
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_net::{Ipv4Cidr, Runner, Stack, StackResources, StaticConfigV4};
|
use embassy_net::Stack;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_sync::{
|
||||||
use esp_hal::clock::CpuClock;
|
blocking_mutex::raw::NoopRawMutex,
|
||||||
use esp_hal::gpio::{Output, OutputConfig};
|
pubsub::{
|
||||||
use esp_hal::peripherals::{GPIO1, GPIO2, UART1};
|
PubSubChannel, Publisher,
|
||||||
use esp_hal::timer::systimer::SystemTimer;
|
WaitResult::{Lagged, Message},
|
||||||
use esp_hal::timer::timg::TimerGroup;
|
},
|
||||||
use esp_hal::uart::{Config, Uart};
|
|
||||||
use esp_println::logger::init_logger;
|
|
||||||
use esp_wifi::wifi::{
|
|
||||||
AccessPointConfiguration, Configuration, WifiController, WifiDevice, WifiEvent, WifiState,
|
|
||||||
};
|
};
|
||||||
|
use embassy_time::{Duration, Timer};
|
||||||
|
use esp_alloc::psram_allocator;
|
||||||
|
use esp_hal::Async;
|
||||||
|
use esp_hal::uart::Uart;
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use picoserve::routing::get;
|
|
||||||
use picoserve::{AppBuilder, AppRouter};
|
|
||||||
use static_cell::make_static;
|
use static_cell::make_static;
|
||||||
|
|
||||||
#[panic_handler]
|
use crate::{store::TallyID, webserver::start_webserver};
|
||||||
fn panic(_: &core::panic::PanicInfo) -> ! {
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern crate alloc;
|
mod init;
|
||||||
|
mod store;
|
||||||
|
mod webserver;
|
||||||
|
|
||||||
esp_bootloader_esp_idf::esp_app_desc!();
|
type TallyChannel = PubSubChannel<NoopRawMutex, TallyID, 8, 2, 1>;
|
||||||
|
type TallyPublisher = Publisher<'static, NoopRawMutex, TallyID, 8, 2, 1>;
|
||||||
|
|
||||||
#[esp_hal_embassy::main]
|
#[esp_hal_embassy::main]
|
||||||
async fn main(spawner: Spawner) {
|
async fn main(mut spawner: Spawner) {
|
||||||
// ------------------- init ---------------------------
|
let (uart_device, stack) = init::hardware_init(&mut spawner).await;
|
||||||
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
|
|
||||||
let peripherals = esp_hal::init(config);
|
|
||||||
|
|
||||||
info!("starting up...");
|
wait_for_stack_up(stack).await;
|
||||||
|
|
||||||
esp_alloc::heap_allocator!(size: 72 * 1024);
|
let chan: &'static mut TallyChannel = make_static!(PubSubChannel::new());
|
||||||
|
|
||||||
let timer0 = SystemTimer::new(peripherals.SYSTIMER);
|
start_webserver(&mut spawner, stack);
|
||||||
esp_hal_embassy::init(timer0.alarm0);
|
|
||||||
|
|
||||||
init_logger(log::LevelFilter::Debug);
|
let publisher = chan.publisher().unwrap();
|
||||||
|
|
||||||
let timer1 = TimerGroup::new(peripherals.TIMG0);
|
spawner.must_spawn(rfid_reader_task(uart_device, publisher));
|
||||||
let mut rng = esp_hal::rng::Rng::new(peripherals.RNG);
|
|
||||||
|
|
||||||
debug!("set wlan antenna..");
|
let mut sub = chan.subscriber().unwrap();
|
||||||
let mut rf_switch = Output::new(
|
loop {
|
||||||
peripherals.GPIO3,
|
let wait_result = sub.next_message().await;
|
||||||
esp_hal::gpio::Level::Low,
|
match wait_result {
|
||||||
OutputConfig::default(),
|
Lagged(_) => debug!("Lagged"),
|
||||||
);
|
Message(msg) => debug!("Got message: {msg:?}"),
|
||||||
|
}
|
||||||
rf_switch.set_low();
|
}
|
||||||
|
}
|
||||||
Timer::after_secs(1).await;
|
|
||||||
|
|
||||||
let mut antenna_mode = Output::new(
|
|
||||||
peripherals.GPIO14,
|
|
||||||
esp_hal::gpio::Level::Low,
|
|
||||||
OutputConfig::default(),
|
|
||||||
);
|
|
||||||
|
|
||||||
antenna_mode.set_low();
|
|
||||||
|
|
||||||
Timer::after_secs(1).await;
|
|
||||||
|
|
||||||
// Setup wifi deivce
|
|
||||||
debug!("setup wifi..");
|
|
||||||
let esp_wifi_ctrl =
|
|
||||||
make_static!(esp_wifi::init(timer1.timer0, rng).unwrap());
|
|
||||||
let (controller, interfaces) = esp_wifi::wifi::new(esp_wifi_ctrl, peripherals.WIFI).unwrap();
|
|
||||||
// let wifi_interface = interfaces.sta;
|
|
||||||
let wifi_ap = interfaces.ap;
|
|
||||||
|
|
||||||
let gw_ip_addr_str = "192.168.2.1";
|
|
||||||
let gw_ip_addr = Ipv4Addr::from_str(gw_ip_addr_str).expect("failed to parse gateway ip");
|
|
||||||
|
|
||||||
let config = embassy_net::Config::ipv4_static(StaticConfigV4 {
|
|
||||||
address: Ipv4Cidr::new(gw_ip_addr, 24),
|
|
||||||
gateway: Some(gw_ip_addr),
|
|
||||||
dns_servers: Default::default(),
|
|
||||||
});
|
|
||||||
|
|
||||||
let seed = (rng.random() as u64) << 32 | rng.random() as u64;
|
|
||||||
|
|
||||||
// Init network stack
|
|
||||||
let (stack, runner) = embassy_net::new(
|
|
||||||
wifi_ap,
|
|
||||||
config,
|
|
||||||
make_static!(StackResources::<3>::new()),
|
|
||||||
seed,
|
|
||||||
);
|
|
||||||
|
|
||||||
debug!("Setup complete. Running network tasks");
|
|
||||||
|
|
||||||
spawner.spawn(connection(controller)).ok();
|
|
||||||
spawner.spawn(net_task(runner)).ok();
|
|
||||||
spawner.spawn(run_dhcp(stack, gw_ip_addr_str)).ok();
|
|
||||||
spawner
|
|
||||||
.spawn(rfid_reader_task(
|
|
||||||
peripherals.UART1,
|
|
||||||
peripherals.GPIO1,
|
|
||||||
peripherals.GPIO2,
|
|
||||||
))
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
|
async fn wait_for_stack_up(stack: Stack<'static>) {
|
||||||
loop {
|
loop {
|
||||||
if stack.is_link_up() {
|
if stack.is_link_up() {
|
||||||
break;
|
break;
|
||||||
@@ -122,154 +63,25 @@ async fn main(spawner: Spawner) {
|
|||||||
}
|
}
|
||||||
Timer::after(Duration::from_millis(500)).await;
|
Timer::after(Duration::from_millis(500)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Starting webserver");
|
|
||||||
|
|
||||||
let app = make_static!(AppProps.build_app());
|
|
||||||
|
|
||||||
let config = make_static!(picoserve::Config::new(picoserve::Timeouts {
|
|
||||||
start_read_request: Some(Duration::from_secs(5)),
|
|
||||||
persistent_start_read_request: Some(Duration::from_secs(1)),
|
|
||||||
read_request: Some(Duration::from_secs(1)),
|
|
||||||
write: Some(Duration::from_secs(1)),
|
|
||||||
}));
|
|
||||||
|
|
||||||
let _ = spawner.spawn(webserver_task(0, stack, app, config));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AppProps;
|
|
||||||
|
|
||||||
impl AppBuilder for AppProps {
|
|
||||||
type PathRouter = impl picoserve::routing::PathRouter;
|
|
||||||
|
|
||||||
fn build_app(self) -> picoserve::Router<Self::PathRouter> {
|
|
||||||
picoserve::Router::new().route("/", get(|| async move { "Hello World" }))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn webserver_task(
|
async fn rfid_reader_task(mut uart_device: Uart<'static, Async>, chan: TallyPublisher) {
|
||||||
id: usize,
|
|
||||||
stack: embassy_net::Stack<'static>,
|
|
||||||
app: &'static AppRouter<AppProps>,
|
|
||||||
config: &'static picoserve::Config<Duration>,
|
|
||||||
) -> ! {
|
|
||||||
let mut tcp_rx_buffer = [0u8; 1024];
|
|
||||||
let mut tcp_tx_buffer = [0u8; 1024];
|
|
||||||
let mut http_buffer = [0u8; 2048];
|
|
||||||
|
|
||||||
picoserve::listen_and_serve(
|
|
||||||
id,
|
|
||||||
app,
|
|
||||||
config,
|
|
||||||
stack,
|
|
||||||
80,
|
|
||||||
&mut tcp_rx_buffer,
|
|
||||||
&mut tcp_tx_buffer,
|
|
||||||
&mut http_buffer,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[embassy_executor::task]
|
|
||||||
async fn run_dhcp(stack: Stack<'static>, gw_ip_addr: &'static str) {
|
|
||||||
debug!("start dhcp");
|
|
||||||
use core::net::{Ipv4Addr, SocketAddrV4};
|
|
||||||
|
|
||||||
use edge_dhcp::{
|
|
||||||
io::{self, DEFAULT_SERVER_PORT},
|
|
||||||
server::{Server, ServerOptions},
|
|
||||||
};
|
|
||||||
use edge_nal::UdpBind;
|
|
||||||
use edge_nal_embassy::{Udp, UdpBuffers};
|
|
||||||
|
|
||||||
let ip = Ipv4Addr::from_str(gw_ip_addr).expect("dhcp task failed to parse gw ip");
|
|
||||||
|
|
||||||
let mut buf = [0u8; 1500];
|
|
||||||
|
|
||||||
let mut gw_buf = [Ipv4Addr::UNSPECIFIED];
|
|
||||||
|
|
||||||
let buffers = UdpBuffers::<3, 1024, 1024, 10>::new();
|
|
||||||
let unbound_socket = Udp::new(stack, &buffers);
|
|
||||||
let mut bound_socket = unbound_socket
|
|
||||||
.bind(core::net::SocketAddr::V4(SocketAddrV4::new(
|
|
||||||
Ipv4Addr::UNSPECIFIED,
|
|
||||||
DEFAULT_SERVER_PORT,
|
|
||||||
)))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
_ = io::server::run(
|
|
||||||
&mut Server::<_, 64>::new_with_et(ip),
|
|
||||||
&ServerOptions::new(ip, Some(&mut gw_buf)),
|
|
||||||
&mut bound_socket,
|
|
||||||
&mut buf,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.inspect_err(|e| log::warn!("DHCP server error: {e:?}"));
|
|
||||||
Timer::after(Duration::from_millis(500)).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[embassy_executor::task]
|
|
||||||
async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) {
|
|
||||||
runner.run().await;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[embassy_executor::task]
|
|
||||||
async fn connection(mut controller: WifiController<'static>) {
|
|
||||||
debug!("start connection task");
|
|
||||||
debug!("Device capabilities: {:?}", controller.capabilities());
|
|
||||||
loop {
|
|
||||||
match esp_wifi::wifi::wifi_state() {
|
|
||||||
WifiState::ApStarted => {
|
|
||||||
// wait until we're no longer connected
|
|
||||||
controller.wait_for_event(WifiEvent::ApStop).await;
|
|
||||||
Timer::after(Duration::from_millis(5000)).await
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
if !matches!(controller.is_started(), Ok(true)) {
|
|
||||||
let client_config = Configuration::AccessPoint(AccessPointConfiguration {
|
|
||||||
ssid: "esp-wifi".try_into().unwrap(),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
controller.set_configuration(&client_config).unwrap();
|
|
||||||
debug!("Starting wifi");
|
|
||||||
controller.start_async().await.unwrap();
|
|
||||||
debug!("Wifi started!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[embassy_executor::task]
|
|
||||||
async fn rfid_reader_task(uart1: UART1<'static>, gpio1: GPIO1<'static>, gpio2: GPIO2<'static>) {
|
|
||||||
debug!("init rfid reader..");
|
|
||||||
|
|
||||||
let uart1_block_result = Uart::new(uart1, Config::default().with_baudrate(9600));
|
|
||||||
let mut nfc_reader = match uart1_block_result {
|
|
||||||
Ok(block) => block.with_rx(gpio1).with_tx(gpio2).into_async(),
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Failed to initialize UART: {:?}", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut uart_buffer = [0u8; 64];
|
let mut uart_buffer = [0u8; 64];
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
debug!("Looking for NFC...");
|
debug!("Looking for NFC...");
|
||||||
match nfc_reader.read_async(&mut uart_buffer).await {
|
match uart_device.read_async(&mut uart_buffer).await {
|
||||||
Ok(n) => {
|
Ok(n) => {
|
||||||
let mut hex_str = heapless::String::<128>::new();
|
let mut hex_str = heapless::String::<128>::new();
|
||||||
for byte in &uart_buffer[..n] {
|
for byte in &uart_buffer[..n] {
|
||||||
core::fmt::Write::write_fmt(&mut hex_str, format_args!("{:02X} ", byte)).ok();
|
core::fmt::Write::write_fmt(&mut hex_str, format_args!("{:02X} ", byte)).ok();
|
||||||
}
|
}
|
||||||
info!("Read {} bytes from UART: {}", n, hex_str);
|
info!("Read {n} bytes from UART: {hex_str}");
|
||||||
|
chan.publish([1, 0, 2, 5, 0, 8, 12, 15]).await;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Error reading from UART: {:?}", e);
|
log::error!("Error reading from UART: {e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Timer::after(Duration::from_millis(200)).await;
|
Timer::after(Duration::from_millis(200)).await;
|
||||||
|
|||||||
31
src/bin/store/id_mapping.rs
Normal file
31
src/bin/store/id_mapping.rs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
use super::TallyID;
|
||||||
|
use alloc::collections::BTreeMap;
|
||||||
|
use alloc::string::String;
|
||||||
|
|
||||||
|
pub struct Name {
|
||||||
|
pub first: String,
|
||||||
|
pub last: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IDMapping {
|
||||||
|
id_map: BTreeMap<TallyID, Name>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IDMapping {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
IDMapping {
|
||||||
|
id_map: BTreeMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map(&self, id: &TallyID) -> Option<&Name> {
|
||||||
|
self.id_map.get(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_mapping(&mut self, id: TallyID, name: Name) {
|
||||||
|
self.id_map.insert(id, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
71
src/bin/store/id_store.rs
Normal file
71
src/bin/store/id_store.rs
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
use super::Date;
|
||||||
|
use super::IDMapping;
|
||||||
|
use super::TallyID;
|
||||||
|
use alloc::collections::BTreeMap;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
pub struct AttendanceDay {
|
||||||
|
date: Date,
|
||||||
|
ids: Vec<TallyID>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AttendanceDay {
|
||||||
|
fn new(date: Date) -> Self {
|
||||||
|
Self {
|
||||||
|
date,
|
||||||
|
ids: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add an ID to the day.
|
||||||
|
// Returns false if ID was already present
|
||||||
|
fn add_id(&mut self, id: TallyID) -> bool {
|
||||||
|
if self.ids.contains(&id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
self.ids.push(id);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IDStore {
|
||||||
|
days: BTreeMap<Date, AttendanceDay>,
|
||||||
|
mapping: IDMapping,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IDStore {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
IDStore {
|
||||||
|
days: BTreeMap::new(),
|
||||||
|
mapping: IDMapping::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_from_storage() -> Self {
|
||||||
|
// TODO: implement
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a new id for the current day
|
||||||
|
/// Returns false if ID is already present at the current day.
|
||||||
|
pub fn add_id(&mut self, id: TallyID) -> bool {
|
||||||
|
self.get_current_day().add_id(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the `AttendanceDay` of the current day
|
||||||
|
/// Creates a new if not exists
|
||||||
|
pub fn get_current_day(&mut self) -> &mut AttendanceDay {
|
||||||
|
let current_day: Date = 1;
|
||||||
|
|
||||||
|
if self.days.contains_key(¤t_day) {
|
||||||
|
return self.days.get_mut(¤t_day).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.days
|
||||||
|
.insert(current_day, AttendanceDay::new(current_day));
|
||||||
|
|
||||||
|
self.days.get_mut(¤t_day.clone()).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/bin/store/mod.rs
Normal file
8
src/bin/store/mod.rs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
mod id_mapping;
|
||||||
|
mod id_store;
|
||||||
|
|
||||||
|
pub use id_mapping::{IDMapping, Name};
|
||||||
|
pub use id_store::IDStore;
|
||||||
|
|
||||||
|
pub type TallyID = [u8; 8];
|
||||||
|
pub type Date = u64;
|
||||||
52
src/bin/webserver/mod.rs
Normal file
52
src/bin/webserver/mod.rs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_net::Stack;
|
||||||
|
use embassy_time::Duration;
|
||||||
|
use picoserve::{AppBuilder, AppRouter, routing::get};
|
||||||
|
use static_cell::make_static;
|
||||||
|
|
||||||
|
pub fn start_webserver(spawner: &mut Spawner, stack: Stack<'static>) {
|
||||||
|
let app = make_static!(AppProps.build_app());
|
||||||
|
|
||||||
|
let config = make_static!(picoserve::Config::new(picoserve::Timeouts {
|
||||||
|
start_read_request: Some(Duration::from_secs(5)),
|
||||||
|
persistent_start_read_request: Some(Duration::from_secs(1)),
|
||||||
|
read_request: Some(Duration::from_secs(1)),
|
||||||
|
write: Some(Duration::from_secs(1)),
|
||||||
|
}));
|
||||||
|
|
||||||
|
let _ = spawner.spawn(webserver_task(0, stack, app, config));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AppProps;
|
||||||
|
|
||||||
|
impl AppBuilder for AppProps {
|
||||||
|
type PathRouter = impl picoserve::routing::PathRouter;
|
||||||
|
|
||||||
|
fn build_app(self) -> picoserve::Router<Self::PathRouter> {
|
||||||
|
picoserve::Router::new().route("/", get(|| async move { "Hello World" }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn webserver_task(
|
||||||
|
id: usize,
|
||||||
|
stack: embassy_net::Stack<'static>,
|
||||||
|
app: &'static AppRouter<AppProps>,
|
||||||
|
config: &'static picoserve::Config<Duration>,
|
||||||
|
) -> ! {
|
||||||
|
let mut tcp_rx_buffer = [0u8; 1024];
|
||||||
|
let mut tcp_tx_buffer = [0u8; 1024];
|
||||||
|
let mut http_buffer = [0u8; 2048];
|
||||||
|
|
||||||
|
picoserve::listen_and_serve(
|
||||||
|
id,
|
||||||
|
app,
|
||||||
|
config,
|
||||||
|
stack,
|
||||||
|
80,
|
||||||
|
&mut tcp_rx_buffer,
|
||||||
|
&mut tcp_tx_buffer,
|
||||||
|
&mut http_buffer,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user