access_point.rs
1 #![no_std] 2 #![no_main] 3 4 use defmt::info; 5 use embassy_executor::Spawner; 6 use embassy_net::{Ipv4Cidr, Runner, Stack, StackResources, StaticConfigV4}; 7 use embassy_time::{Duration, Timer}; 8 use esp_hal::{ 9 clock::CpuClock, 10 interrupt::software::SoftwareInterruptControl, 11 rng::Rng, 12 timer::timg::TimerGroup, 13 }; 14 use esp_radio::wifi::{Config, ControllerConfig, Interface, WifiController, ap::AccessPointConfig}; 15 use panic_rtt_target as _; 16 use picoserve::routing::get; 17 use static_cell::StaticCell; 18 19 use firmware::config::app; 20 21 const AP_SSID: &str = env!("WIFI_SSID"); 22 const AP_PASSWORD: &str = env!("WIFI_PSK"); 23 const AP_CHANNEL: u8 = 6; 24 25 esp_bootloader_esp_idf::esp_app_desc!(); 26 27 macro_rules! mk_static { 28 ($type:ty, $value:expr) => {{ 29 static STATIC_CELL: StaticCell<$type> = StaticCell::new(); 30 STATIC_CELL.uninit().write($value) 31 }}; 32 } 33 34 fn random_seed(random_number_generator: &mut Rng) -> u64 { 35 (u64::from(random_number_generator.random()) << 32) 36 | u64::from(random_number_generator.random()) 37 } 38 39 #[embassy_executor::task] 40 async fn wifi_ap_task(wifi_controller: WifiController<'static>) { 41 let _ = wifi_controller; 42 loop { 43 Timer::after(Duration::from_secs(60)).await; 44 } 45 } 46 47 #[embassy_executor::task] 48 async fn wifi_net_task(mut runner: Runner<'static, Interface<'static>>) { 49 runner.run().await; 50 } 51 52 #[embassy_executor::task] 53 async fn http_server_task(stack: Stack<'static>) { 54 let app = picoserve::Router::new().route( 55 "/", 56 get(|| async { 57 ( 58 ("Content-Type", "text/html; charset=utf-8"), 59 concat!( 60 "<!DOCTYPE html><html><head><title>Ceratina Setup</title></head><body>", 61 "<h1>Ceratina Device Setup</h1>", 62 "<p>Connect this device to your Wi-Fi network.</p>", 63 "</body></html>", 64 ), 65 ) 66 }), 67 ); 68 69 let config = mk_static!( 70 picoserve::Config, 71 picoserve::Config::new(picoserve::Timeouts { 72 start_read_request: Duration::from_secs(5), 73 persistent_start_read_request: Duration::from_secs(5), 74 read_request: Duration::from_secs(2), 75 write: Duration::from_secs(2), 76 }) 77 .keep_connection_alive() 78 ); 79 80 let mut tcp_rx_buffer = [0u8; 2048]; 81 let mut tcp_tx_buffer = [0u8; 2048]; 82 let mut http_buffer = [0u8; 4096]; 83 84 loop { 85 picoserve::Server::new(&app, config, &mut http_buffer) 86 .listen_and_serve(0usize, stack, app::http::PORT, &mut tcp_rx_buffer, &mut tcp_tx_buffer) 87 .await; 88 } 89 } 90 91 #[esp_rtos::main] 92 async fn main(spawner: Spawner) -> ! { 93 rtt_target::rtt_init_defmt!(); 94 95 let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); 96 let peripherals = esp_hal::init(config); 97 98 esp_alloc::heap_allocator!(#[esp_hal::ram(reclaimed)] size: 73744); 99 esp_alloc::heap_allocator!(size: 64 * 1024); 100 101 let timg0 = TimerGroup::new(peripherals.TIMG0); 102 let sw_ints = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); 103 esp_rtos::start(timg0.timer0, sw_ints.software_interrupt0); 104 105 info!("Embassy initialized!"); 106 107 let ap_config = Config::AccessPoint( 108 AccessPointConfig::default() 109 .with_ssid(AP_SSID) 110 .with_password(AP_PASSWORD.into()) 111 .with_channel(AP_CHANNEL), 112 ); 113 114 info!("starting Wi-Fi in AP mode"); 115 let (wifi_controller, interfaces) = esp_radio::wifi::new( 116 peripherals.WIFI, 117 ControllerConfig::default().with_initial_config(ap_config), 118 ) 119 .expect("Failed to initialize Wi-Fi controller"); 120 121 info!("AP '{}' started on channel {}", AP_SSID, AP_CHANNEL); 122 info!("AP IP: 192.168.4.1"); 123 124 let mut random_number_generator = Rng::new(); 125 let seed = random_seed(&mut random_number_generator); 126 127 let ap_network_config = embassy_net::Config::ipv4_static(StaticConfigV4 { 128 address: Ipv4Cidr::new( 129 core::net::Ipv4Addr::new(192, 168, 4, 1), 130 24, 131 ), 132 gateway: Some(core::net::Ipv4Addr::new(192, 168, 4, 1)), 133 dns_servers: Default::default(), 134 }); 135 136 let (stack, runner) = embassy_net::new( 137 interfaces.access_point, 138 ap_network_config, 139 mk_static!(StackResources<3>, StackResources::<3>::new()), 140 seed, 141 ); 142 143 spawner.spawn(wifi_ap_task(wifi_controller).unwrap()); 144 spawner.spawn(wifi_net_task(runner).unwrap()); 145 146 stack.wait_config_up().await; 147 148 spawner.spawn(http_server_task(stack).unwrap()); 149 150 info!("HTTP server listening on port {}", app::http::PORT); 151 152 loop { 153 Timer::after(Duration::from_secs(60)).await; 154 } 155 }