use alloc::string::ToString; use embassy_executor::Spawner; use embassy_sync::pubsub::DynSubscriber; use esp_wifi::{EspWifiController, wifi::{ClientConfiguration, WifiDevice}}; use log::*; use alloc::format; use embassy_net::dns::DnsSocket; use embassy_net::tcp::client::{TcpClient, TcpClientState}; use embassy_net::{Config, StackResources}; use nalgebra::Vector2; use reqwless::client::{HttpClient, TlsConfig}; use static_cell::StaticCell; use crate::{backoff::Backoff, events::{Prediction, Telemetry}}; #[embassy_executor::task] async fn net_task(mut runner: embassy_net::Runner<'static, WifiDevice<'static>>) { info!("Network stack is running"); runner.run().await } static RESOURCES: StaticCell> = StaticCell::new(); // TODO: Wifi task needs to know when there is data to upload, so it only connects when needed. #[embassy_executor::task] pub async fn wireless_task(mut telemetry: DynSubscriber<'static, Telemetry>, wifi_init: &'static mut EspWifiController<'static>, wifi_device: esp_hal::peripherals::WIFI<'static>) { let (mut wifi, interfaces) = esp_wifi::wifi::new(wifi_init, wifi_device) .expect("Failed to initialize WIFI!"); wifi.set_configuration(&esp_wifi::wifi::Configuration::Client( ClientConfiguration { ssid: "The Frequency".to_string(), auth_method: esp_wifi::wifi::AuthMethod::WPA2Personal, password: "thepasswordkenneth".to_string(), ..Default::default() } )).unwrap(); wifi.set_mode(esp_wifi::wifi::WifiMode::Sta).unwrap(); wifi.set_power_saving(esp_wifi::config::PowerSaveMode::Maximum).unwrap(); wifi.start_async().await.unwrap(); let device = interfaces.sta; // TODO: Somehow grab a real random seed from main() let seed = 0; let config = Config::dhcpv4(Default::default()); let (stack, runner) = embassy_net::new(device, config, RESOURCES.init_with(|| { StackResources::new() }), seed as u64); info!("Launching network task"); Spawner::for_current_executor().await.must_spawn(net_task(runner)); loop { Backoff::from_secs(3).forever().attempt(async || { info!("Connecting to wifi..."); match wifi.connect_async().await { Ok(_) => Ok(()), Err(e) => { error!("Wifi error: {e:?}"); Err(()) } } }).await.unwrap(); info!("Waiting for DHCP"); stack.wait_config_up().await; info!("Online!"); let ip_cfg = stack.config_v4().unwrap(); info!("ip={ip_cfg:?}"); let mut rx_buf = [0; 4096]; let mut tx_buf = [0; 4096]; let dns = DnsSocket::new(stack); let tcp_state = TcpClientState::<1, 4096, 4096>::new(); let tcp = TcpClient::new(stack, &tcp_state); let tls = TlsConfig::new( seed as u64, &mut rx_buf, &mut tx_buf, reqwless::client::TlsVerify::None, ); let mut client = HttpClient::new_with_tls(&tcp, &dns, tls); loop { if let Telemetry::Prediction(Prediction::Location(coords)) = telemetry.next_message_pure().await { if let Err(e) = push_location(&mut client, coords).await { error!("HTTP error in publishing location: {e:?}"); break } } } } } async fn push_location(client: &mut HttpClient<'_, TcpClient<'_, 1, 4096, 4096>, DnsSocket<'_>>, location: Vector2) -> Result<(), reqwless::Error> { let mut buffer = [0u8; 4096]; let base = "https://nextcloud.malloc.hackerbots.net/nextcloud/index.php/apps/phonetrack/logGet/a062000067304e9dee6590f1b8f9e0db/renderbug"; let url = format!("{base}?lat={}&lon={}", location.y, location.x); info!("Pushing to {url}"); let mut http_req = client .request( reqwless::request::Method::GET, &url, ) .await?; let response = http_req.send(&mut buffer).await?; info!("Got response"); let res = response.body().read_to_end().await?; let content = core::str::from_utf8(res).unwrap(); info!("{content}"); Ok(()) }