diff --git a/.cargo/config.toml b/.cargo/config.toml
index 292a084c5761876f8aae9bfe037775753cc38bf9..7125c6c1b0ede70e163e4d74b9b781b263b5854d 100644
--- a/.cargo/config.toml
+++ b/.cargo/config.toml
@@ -5,6 +5,7 @@ runner = "espflash flash --monitor"
 rustflags = [
   "-C", "link-arg=-Tlinkall.x",
   "-C", "link-arg=-nostartfiles",
+  "-C", "link-arg=-Trom_functions.x",
 ]
 
 target = "xtensa-esp32s3-none-elf"
diff --git a/Cargo.lock b/Cargo.lock
index 5f71d30d523e4b5d5267330b869a27fa1b14f423..7e79ce7d6bb4236dd75c3b81d5be7e39b08581ec 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -89,6 +89,12 @@ dependencies = [
  "stable_deref_trait",
 ]
 
+[[package]]
+name = "atomic-waker"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3"
+
 [[package]]
 name = "autocfg"
 version = "1.1.0"
@@ -116,6 +122,12 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "bit_field"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
+
 [[package]]
 name = "bitfield"
 version = "0.14.0"
@@ -528,6 +540,20 @@ dependencies = [
  "no-std-net 0.6.0",
 ]
 
+[[package]]
+name = "embedded-svc"
+version = "0.25.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adb928fd4f8e71dee7628bbab86b25df74c503fc5209cfeeb174a9806bb4fd11"
+dependencies = [
+ "atomic-waker",
+ "embedded-io",
+ "enumset",
+ "heapless",
+ "no-std-net 0.5.0",
+ "serde",
+]
+
 [[package]]
 name = "enum-as-inner"
 version = "0.4.0"
@@ -540,6 +566,27 @@ dependencies = [
  "syn 1.0.109",
 ]
 
+[[package]]
+name = "enumset"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e875f1719c16de097dee81ed675e2d9bb63096823ed3f0ca827b7dea3028bbbb"
+dependencies = [
+ "enumset_derive",
+]
+
+[[package]]
+name = "enumset_derive"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af"
+dependencies = [
+ "darling 0.20.3",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.28",
+]
+
 [[package]]
 name = "equivalent"
 version = "1.0.1"
@@ -576,13 +623,20 @@ dependencies = [
  "embedded-hal-async",
  "embedded-hal-nb",
  "esp-hal-procmacros",
+ "esp-riscv-rt",
  "esp-synopsys-usb-otg",
+ "esp32",
+ "esp32c2",
+ "esp32c3",
+ "esp32c6",
+ "esp32s2",
  "esp32s3",
  "fugit",
  "lock_api",
  "log",
  "nb 1.1.0",
  "paste",
+ "riscv-atomic-emulation-trap",
  "serde",
  "strum 0.25.0",
  "usb-device",
@@ -625,6 +679,16 @@ dependencies = [
  "critical-section",
 ]
 
+[[package]]
+name = "esp-riscv-rt"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb1008d28898f6dc8bab1c01f14826399b93f7e5f910c83062fc1d19eb5b5f28"
+dependencies = [
+ "riscv",
+ "riscv-rt-macros",
+]
+
 [[package]]
 name = "esp-synopsys-usb-otg"
 version = "0.3.2"
@@ -637,6 +701,151 @@ dependencies = [
  "vcell",
 ]
 
+[[package]]
+name = "esp-wifi"
+version = "0.1.0"
+source = "git+https://github.com/esp-rs/esp-wifi.git?rev=6b53683586e29bcec7af23309d788fed4fb49f2c#6b53683586e29bcec7af23309d788fed4fb49f2c"
+dependencies = [
+ "atomic-polyfill 1.0.3",
+ "critical-section",
+ "embassy-futures",
+ "embassy-net-driver",
+ "embassy-sync",
+ "embedded-hal 0.2.7",
+ "embedded-io",
+ "embedded-svc",
+ "enumset",
+ "esp-hal-common",
+ "esp-wifi-sys",
+ "esp32-hal",
+ "esp32c2-hal",
+ "esp32c3-hal",
+ "esp32c6-hal",
+ "esp32s2-hal",
+ "esp32s3-hal",
+ "fugit",
+ "heapless",
+ "linked_list_allocator",
+ "log",
+ "num-derive",
+ "num-traits",
+ "smoltcp",
+ "toml-cfg",
+]
+
+[[package]]
+name = "esp-wifi-sys"
+version = "0.1.0"
+source = "git+https://github.com/esp-rs/esp-wifi.git?rev=6b53683586e29bcec7af23309d788fed4fb49f2c#6b53683586e29bcec7af23309d788fed4fb49f2c"
+dependencies = [
+ "anyhow",
+]
+
+[[package]]
+name = "esp32"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52d8411f8deda48029d8df126448f1a892f04684d0bfec85795d65d312fe4906"
+dependencies = [
+ "critical-section",
+ "vcell",
+ "xtensa-lx",
+]
+
+[[package]]
+name = "esp32-hal"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "646349d80b3d5c5613137efe63eec2b85c4625e7d48f4ba0aaa9dc9f08016d39"
+dependencies = [
+ "embedded-hal 0.2.7",
+ "esp-hal-common",
+]
+
+[[package]]
+name = "esp32c2"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e8ecbc7773a65dfe8731f4732fbb7c366d7652062ef53bb5498fe79cd08253d"
+dependencies = [
+ "critical-section",
+ "vcell",
+]
+
+[[package]]
+name = "esp32c2-hal"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e96025b9a7b6da60edcf8f68d1ebbaa053ac957ce1e65f18d30f7c0d8bb6269"
+dependencies = [
+ "embedded-hal 0.2.7",
+ "esp-hal-common",
+]
+
+[[package]]
+name = "esp32c3"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e3775bd92a673d2c96e40ada5ad5f93448c02ce77a3f7a635b386d59e9b2880"
+dependencies = [
+ "critical-section",
+ "vcell",
+]
+
+[[package]]
+name = "esp32c3-hal"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8cccbc1d35013f062ae0330651d000736200692d4fdc9e1146eff540af907240"
+dependencies = [
+ "cfg-if",
+ "embedded-hal 0.2.7",
+ "esp-hal-common",
+]
+
+[[package]]
+name = "esp32c6"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c17de7bcc3ec3966ccb60a271968125d471bee348da445a80b970efca1db8b4f"
+dependencies = [
+ "critical-section",
+ "vcell",
+]
+
+[[package]]
+name = "esp32c6-hal"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79e3a6aa9d32a90bf6b673c046e8bb04a564c40ee4f367bb1d3df1fb45802c22"
+dependencies = [
+ "cfg-if",
+ "embedded-hal 0.2.7",
+ "esp-hal-common",
+]
+
+[[package]]
+name = "esp32s2"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf5cc09343866e8868d2e8b2dc3681fc0050aae83ce5cbe2617f2d5d98da27a9"
+dependencies = [
+ "critical-section",
+ "vcell",
+ "xtensa-lx",
+]
+
+[[package]]
+name = "esp32s2-hal"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "911d665dde2de5bef1e72b15c7dc889e331dccf800c2753f3165648e8dcfe660"
+dependencies = [
+ "embedded-hal 0.2.7",
+ "esp-hal-common",
+ "xtensa-atomic-emulation-trap",
+]
+
 [[package]]
 name = "esp32s3"
 version = "0.20.0"
@@ -697,9 +906,11 @@ dependencies = [
  "embedded-hal 1.0.0-alpha.11",
  "embedded-hal-async",
  "embedded-hal-bus",
+ "embedded-svc",
  "esp-backtrace",
  "esp-hal-smartled",
  "esp-println",
+ "esp-wifi",
  "esp32s3-hal",
  "gc9a01",
  "heapless",
@@ -894,6 +1105,12 @@ dependencies = [
  "hashbrown",
 ]
 
+[[package]]
+name = "linked_list_allocator"
+version = "0.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286"
+
 [[package]]
 name = "lock_api"
 version = "0.4.10"
@@ -970,6 +1187,17 @@ version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65"
 
+[[package]]
+name = "num-derive"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
 [[package]]
 name = "num-traits"
 version = "0.2.16"
@@ -1109,6 +1337,34 @@ dependencies = [
  "bytemuck",
 ]
 
+[[package]]
+name = "riscv"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa3145d2fae3778b1e31ec2e827b228bdc6abd9b74bb5705ba46dcb82069bc4f"
+dependencies = [
+ "bit_field",
+ "critical-section",
+ "embedded-hal 0.2.7",
+]
+
+[[package]]
+name = "riscv-atomic-emulation-trap"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da39f4a5642a62e8e16bb438c37e6f90ea388ca0b7960fe875ea39887155d6ba"
+
+[[package]]
+name = "riscv-rt-macros"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f38509d7b17c2f604ceab3e5ff8ac97bb8cd2f544688c512be75c715edaf4daf"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
 [[package]]
 name = "rustc_version"
 version = "0.4.0"
@@ -1307,6 +1563,29 @@ dependencies = [
  "embedded-graphics",
 ]
 
+[[package]]
+name = "toml"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml-cfg"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91dbf509587452b781d208257bfe9923808873290d99505ee0eb0e6599540bdf"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "syn 1.0.109",
+ "toml",
+]
+
 [[package]]
 name = "toml_datetime"
 version = "0.6.3"
@@ -1369,6 +1648,12 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "xtensa-atomic-emulation-trap"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8cd1632531f5d8ba78dabeff8b006a0d675560f436727479138a3dd194f0582b"
+
 [[package]]
 name = "xtensa-lx"
 version = "0.8.0"
diff --git a/Cargo.toml b/Cargo.toml
index 7012879e956bd60a02f32b4fae1169913c2ac42f..706c3f8986444de396457fff39c88cb3d2772c98 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,7 +12,7 @@ byte-slice-cast = { version = "1.2.2", default-features = false }
 display-interface = { path = "./display-interface", features = ["nightly", "async", "dma"] }
 embassy-executor = { version = "0.2.0", features = ["nightly", "arch-xtensa", "executor-thread", "integrated-timers"] }
 embassy-futures = "0.1.0"
-embassy-net = { version = "0.1.0", features = ["medium-ethernet", "udp", "proto-ipv6", "nightly", "unstable-traits"] }
+embassy-net = { version = "0.1.0", features = ["medium-ethernet", "udp", "proto-ipv6", "nightly", "unstable-traits", "dhcpv4"] }
 embassy-net-badgelink = { path = "./embassy-net-badgelink" }
 embassy-sync = "0.2.0"
 embassy-time = { version = "=0.1.2", features = ["nightly", "unstable-traits"] }
@@ -35,3 +35,13 @@ smart-leds = "0.3.0"
 smoltcp = { version = "0.10.0", default-features = false }
 static_cell = "1.2.0"
 tinybmp = "0.5.0"
+esp-wifi = { git = "https://github.com/esp-rs/esp-wifi.git", rev = "6b53683586e29bcec7af23309d788fed4fb49f2c", features = ["esp32s3", "wifi", "ipv6", "phy-enable-usb", "embassy-net"] }
+embedded-svc = { version = "0.25.3", default-features = false }
+
+[profile.dev.package.esp-wifi]
+opt-level = 3
+
+[profile.dev]
+lto = "off"
+[profile.release]
+lto = "off"
diff --git a/src/demo_tasks.rs b/src/demo_tasks.rs
index d4282c8be4c7986330bedeb5448c7c0712121b49..633e65f60d9df41e2967565faff0d8c6727e5970 100644
--- a/src/demo_tasks.rs
+++ b/src/demo_tasks.rs
@@ -1,7 +1,7 @@
-use crate::flow3r::{captouch::CaptouchHandler, display::Display, imu::ImuHandler, badgelink::{BadgeLink, badgenet::{BadgenetUartLeft, BadgenetUartRight, start_badgenet_left, start_badgenet_right}}};
+use crate::flow3r::{captouch::CaptouchHandler, display::Display, imu::ImuHandler, badgelink::{BadgeLink, badgenet::{BadgenetUartLeft, BadgenetUartRight, start_badgenet_left, start_badgenet_right, get_link_local_address}}, wifi::start_wifi};
 use embassy_executor::Spawner;
 use embassy_futures::select::{select, select3, Either, Either3};
-use embassy_net::{udp::{UdpSocket, PacketMetadata}, Ipv6Address, Stack, StaticConfigV6, Config, Ipv6Cidr};
+use embassy_net::{udp::{UdpSocket, PacketMetadata}, Ipv6Address, Stack, StaticConfigV6, Config, Ipv6Cidr, Ipv4Address};
 use embassy_net_badgelink::Device;
 use embassy_time::{Duration, Timer};
 use embedded_graphics::{
@@ -14,7 +14,8 @@ use embedded_graphics::{
 };
 use esp_backtrace as _;
 use esp_println::println;
-use hal::{Rng, uart};
+use esp_wifi::EspWifiInitialization;
+use hal::{Rng, uart, radio::Wifi};
 use heapless::Vec;
 use smoltcp::wire::IpEndpoint;
 use tinybmp::Bmp;
@@ -277,13 +278,45 @@ pub async fn captouch_demo(display: &mut Display) {
     }
 }
 
-pub async fn badgelink_demo(badgelink: &mut BadgeLink, uart0: BadgenetUartLeft, uart1: BadgenetUartRight, rng: &'static mut Rng) -> (&'static mut BadgenetUartLeft, &'static mut BadgenetUartRight,  &'static mut Rng) {
+pub async fn wifi_demo(wifi: Wifi, init: EspWifiInitialization, mut rng: Rng) {
+    let config = Config::dhcpv4(Default::default());
+    let wifi = start_wifi(wifi, init, config, rng.random().into(), "zm!Wireless", "DidPWfdWN25").await;
+    let mut rx_buffer = [0; 4096];
+    let mut tx_buffer = [0; 4096];
+
+    loop {
+        if wifi.is_link_up() {
+            break;
+        }
+        Timer::after(Duration::from_millis(500)).await;
+    }
+
+    println!("Waiting to get IP address...");
+    loop {
+        if let Some(config) = wifi.config_v4() {
+            println!("Got IP: {}", config.address);
+            break;
+        }
+        Timer::after(Duration::from_millis(500)).await;
+    }
+    println!("got ip!");
+
+    loop {
+        Timer::after(Duration::from_secs(1)).await;
+    }
+}
+
+pub async fn badgelink_demo(badgelink: &mut BadgeLink, uart0: BadgenetUartLeft, uart1: BadgenetUartRight, mut rng: Rng) -> (&'static mut BadgenetUartLeft, &'static mut BadgenetUartRight,  &'static mut Rng) {
     badgelink.left_badgelink().unwrap();
     badgelink.right_badgelink().unwrap();
 
     let addr_left = Ipv6Address::new(0xfe80, 0x00, 0x00, 0x00, 0x5686, 0x8cff, 0xfe5c, 0x278d);
     let addr_right = Ipv6Address::new(0xfe80, 0x00, 0x00, 0x00, 0x5686, 0x8cfa, 0xfe5c, 0x278d);
 
+    /*let addr_left = get_link_local_address();
+    println!("slaac addr {}", addr_left);
+    let addr_right = get_link_local_address();*/
+
     let config_left = Config::ipv6_static(StaticConfigV6 {
         address: Ipv6Cidr::new(addr_left, 10),
         gateway: None,
@@ -298,40 +331,44 @@ pub async fn badgelink_demo(badgelink: &mut BadgeLink, uart0: BadgenetUartLeft,
 
 
     let network_stack_left = start_badgenet_left(uart0, rng.random().into(), config_left).await;
-    let network_stack_right = start_badgenet_right(uart1, rng.random().into(), config_right).await;
+    //let network_stack_right = start_badgenet_right(uart1, rng.random().into(), config_right).await;
 
     Timer::after(Duration::from_millis(10)).await;
 
     let spawner = Spawner::for_current_executor().await;
-    spawner.spawn(listen_task(network_stack_right)).unwrap();
+    //spawner.spawn(listen_task(network_stack_right)).unwrap();
+    Timer::after(Duration::from_millis(10)).await;
     spawner.spawn(send_task(network_stack_left, addr_right)).unwrap();
 
+    //spawner.spawn(listen_task_uart(uart1)).unwrap();
+    //spawner.spawn(send_task_uart(uart0)).unwrap();
+
     loop {
         Timer::after(Duration::from_secs(10)).await;
     }
 }
 
-/* 
+
 #[embassy_executor::task]
-async fn listen_task(mut uart: BadgenetUartRight) {
+async fn listen_task_uart(mut uart: BadgenetUartRight) {
     let mut data = [0u8;100];
     println!("ready to recv");
     loop {
-        uart.read(&mut data).await.unwrap();
-        println!("recvd");
+        let bytes = uart.read(&mut data).await.unwrap();
+        println!("recvd {} bytes", bytes);
     }
 }
 
 #[embassy_executor::task]
-async fn send_task(mut uart: BadgenetUartLeft) {
-    let data = [0;128];
+async fn send_task_uart(mut uart: BadgenetUartLeft) {
+    let data = [40;128];
     loop {
         uart.write_bytes(&data).unwrap();
         println!("sent");
         Timer::after(Duration::from_secs(1)).await;
     }
 }
-*/
+
 
 #[embassy_executor::task]
 async fn listen_task(network_stack: &'static Stack<Device<'static>>) {
@@ -381,10 +418,10 @@ async fn send_task(network_stack: &'static Stack<Device<'static>>, addr_left: Ip
     socket_right.bind(2345).unwrap();
 
     let endpoint = IpEndpoint::new(addr_left.into_address(), 1234);
-    let send_data = [0;128];
+    let send_data = "Hello World!";
 
     loop {
-        socket_right.send_to(&send_data, endpoint).await.unwrap();
+        socket_right.send_to(send_data.as_bytes(), endpoint).await.unwrap();
         println!("data sent");
 
         Timer::after(Duration::from_secs(1)).await;
diff --git a/src/flow3r/badgelink/badgenet.rs b/src/flow3r/badgelink/badgenet.rs
index 42c2fe117f41e3521e550931d69cd80c7928fb3d..5b293e004b436cbe47483c700c7503447b58bace 100644
--- a/src/flow3r/badgelink/badgenet.rs
+++ b/src/flow3r/badgelink/badgenet.rs
@@ -83,3 +83,12 @@ pub async fn stack_task_1(stack: &'static Stack<Device<'static>>) -> ! {
     println!("right badgenet stack started");
     stack.run().await
 }
+
+pub fn get_link_local_address() -> Ipv6Address {
+    let mac = Efuse::get_mac_address();
+    generate_link_local_addr(mac)
+}
+
+fn generate_link_local_addr(mac: [u8;6]) -> Ipv6Address {
+    Ipv6Address::from_bytes(&[0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, mac[0] ^ 2, mac[1], mac[2], 0xff, 0xfe, mac[3], mac[4], mac[5]])
+}
\ No newline at end of file
diff --git a/src/flow3r/mod.rs b/src/flow3r/mod.rs
index 39f820ecba487970308fa5029d718c4c0a5b7ddd..06a30a9147290e211694600524f9769aa8875f77 100644
--- a/src/flow3r/mod.rs
+++ b/src/flow3r/mod.rs
@@ -1,3 +1,5 @@
+use esp_wifi::EspWifiInitialization;
+use hal::radio::Wifi;
 use hal::{Uart, Rng};
 use hal::peripherals::{UART0, UART1};
 
@@ -17,6 +19,7 @@ pub mod input;
 pub mod leds;
 pub mod sdcard;
 pub mod ui;
+pub mod wifi;
 
 pub struct Flow3r {
     pub badgelink: BadgeLink,
@@ -27,7 +30,9 @@ pub struct Flow3r {
     pub leds: Leds,
     pub uart0: BadgenetUartLeft,
     pub uart1: BadgenetUartRight,
-    pub rng: &'static mut Rng,
+    pub rng: Rng,
+    pub wifi: Wifi,
+    pub wifi_init: EspWifiInitialization,
 }
 
 impl Flow3r {
@@ -40,7 +45,9 @@ impl Flow3r {
         leds: Leds,
         uart0: BadgenetUartLeft,
         uart1: BadgenetUartRight,
-        rng: &'static mut Rng,
+        rng: Rng,
+        wifi: Wifi,
+        wifi_init: EspWifiInitialization,
     ) -> Self {
         Self {
             badgelink,
@@ -51,7 +58,9 @@ impl Flow3r {
             leds,
             uart0,
             uart1,
-            rng
+            rng,
+            wifi,
+            wifi_init
         }
     }
 }
diff --git a/src/flow3r/wifi.rs b/src/flow3r/wifi.rs
new file mode 100644
index 0000000000000000000000000000000000000000..77812f650f9d4ad300fa6fe0107d9ff8a1bd443e
--- /dev/null
+++ b/src/flow3r/wifi.rs
@@ -0,0 +1,68 @@
+use embassy_executor::Spawner;
+use embassy_net::{Stack, StackResources, Config};
+use embassy_time::{Timer, Duration};
+use embedded_svc::wifi::{Wifi, Configuration, ClientConfiguration};
+use esp_println::println;
+use esp_wifi::{EspWifiInitialization, wifi::{WifiMode, WifiDevice, WifiController, WifiState, WifiEvent}};
+use static_cell::StaticCell;
+
+static STACK: StaticCell<Stack<WifiDevice<'static>>> = StaticCell::new();
+static STACK_RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
+
+pub async fn start_wifi(wifi: hal::radio::Wifi, init: EspWifiInitialization, config: Config, seed: u64, ssid: &'static str, password: &'static str) -> &'static Stack<WifiDevice<'static>> {
+    let (wifi_interface, controller) = esp_wifi::wifi::new_with_mode(&init, wifi, WifiMode::Sta).unwrap();
+    let stack = STACK.init(Stack::new(
+        wifi_interface,
+        config,
+        STACK_RESOURCES.init(StackResources::new()),
+        seed,
+    ));
+
+    let spawner = Spawner::for_current_executor().await;
+    spawner.spawn(connection(controller, ssid, password)).ok();
+    spawner.spawn(stack_task(stack)).ok();
+
+    stack
+}
+
+#[embassy_executor::task]
+async fn connection(mut controller: WifiController<'static>, ssid: &'static str, password: &'static str) {
+    println!("start connection task");
+    println!("Device capabilities: {:?}", controller.get_capabilities());
+    loop {
+        match esp_wifi::wifi::get_wifi_state() {
+            WifiState::StaConnected => {
+                // wait until we're no longer connected
+                controller.wait_for_event(WifiEvent::StaDisconnected).await;
+                Timer::after(Duration::from_millis(5000)).await
+            }
+            _ => {}
+        }
+        if !matches!(controller.is_started(), Ok(true)) {
+            let client_config = Configuration::Client(ClientConfiguration {
+                ssid: ssid.into(),
+                password: password.into(),
+                ..Default::default()
+            });
+            controller.set_configuration(&client_config).unwrap();
+            println!("Starting wifi");
+            controller.start().await.unwrap();
+            println!("Wifi started!");
+        }
+        println!("About to connect...");
+
+        match controller.connect().await {
+            Ok(_) => println!("Wifi connected!"),
+            Err(e) => {
+                println!("Failed to connect to wifi: {e:?}");
+                Timer::after(Duration::from_millis(5000)).await
+            }
+        }
+    }
+}
+
+#[embassy_executor::task]
+pub async fn stack_task(stack: &'static Stack<WifiDevice<'static>>) -> ! {
+    println!("wifi stack started");
+    stack.run().await
+}
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 82b4d3a03f27dea41c18b81668639d8b6668bf1f..9741d1ce33f5b855d99a3fd8a843e42f3716b128 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -8,7 +8,7 @@ mod demo_tasks;
 mod flow3r;
 mod runtime;
 
-use demo_tasks::{draw_start_screen, badgelink_demo};
+use demo_tasks::{draw_start_screen, badgelink_demo, wifi_demo};
 use embassy_executor::Spawner;
 use embassy_time::{Duration, Timer};
 
@@ -32,7 +32,8 @@ async fn main(mut flow3r: Flow3r) -> ! {
 
     //Timer::after(Duration::from_secs(3)).await;
 
-    badgelink_demo(&mut flow3r.badgelink, flow3r.uart0, flow3r.uart1, flow3r.rng).await;
+    //badgelink_demo(&mut flow3r.badgelink, flow3r.uart0, flow3r.uart1, flow3r.rng).await;
+    wifi_demo(flow3r.wifi, flow3r.wifi_init, flow3r.rng).await;
 
     loop {}
 
diff --git a/src/runtime.rs b/src/runtime.rs
index f4811823f27d8d87f3e41b326d5ad782769d634b..4f3d5ad9f3605ba1eed20ccb22c49060f92fa557 100644
--- a/src/runtime.rs
+++ b/src/runtime.rs
@@ -1,8 +1,9 @@
 use embassy_executor::{Executor, Spawner};
 use embassy_time::{Duration, Timer};
 use esp_println::println;
+use esp_wifi::EspWifiInitFor;
 use hal::{
-    clock::{ClockControl, Clocks},
+    clock::{ClockControl, Clocks, CpuClock},
     cpu_control::CpuControl,
     embassy,
     gdma::Gdma,
@@ -59,7 +60,7 @@ async fn init_runtime() {
     esp_println::println!("Init!");
     let peripherals = Peripherals::take();
     let mut system = peripherals.SYSTEM.split();
-    let clocks = CLOCKS.init(ClockControl::boot_defaults(system.clock_control).freeze());
+    let clocks = CLOCKS.init(ClockControl::configure(system.clock_control, CpuClock::Clock240MHz).freeze());
 
     let mut rtc = Rtc::new(peripherals.RTC_CNTL);
     let timer_group0 = TimerGroup::new(
@@ -160,7 +161,7 @@ async fn init_runtime() {
     // Init uart
 
     let uart0_config = uart::config::Config {
-        baudrate: 9600, //115200,
+        baudrate: 115200,
         data_bits: uart::config::DataBits::DataBits8,
         parity: uart::config::Parity::ParityNone,
         stop_bits: uart::config::StopBits::STOP1
@@ -176,7 +177,7 @@ async fn init_runtime() {
     .unwrap();
 
     let uart1_config = uart::config::Config {
-        baudrate: 9600, //115200,
+        baudrate: 115200,
         data_bits: uart::config::DataBits::DataBits8,
         parity: uart::config::Parity::ParityNone,
         stop_bits: uart::config::StopBits::STOP1
@@ -191,7 +192,18 @@ async fn init_runtime() {
     )
     .unwrap();
 
-    let rng = RNG.init(Rng::new(peripherals.RNG));
+    let rng = Rng::new(peripherals.RNG);
+
+    let wifi_init = esp_wifi::initialize(
+        EspWifiInitFor::Wifi,
+        timer_group1.timer0,
+        rng.clone(),
+        system.radio_clock_control,
+        &clocks,
+    )
+    .unwrap();
+
+    let (wifi, _) = peripherals.RADIO.split();
 
     // Init Flow3r components
 
@@ -201,7 +213,7 @@ async fn init_runtime() {
     let captouch = CaptouchHandler;
     let leds = init_leds(rmt, io.pins.gpio14);
 
-    let flow3r = Flow3r::new(badgelink, captouch, display, imu, inputs, leds, uart0, uart1, rng);
+    let flow3r = Flow3r::new(badgelink, captouch, display, imu, inputs, leds, uart0, uart1, rng, wifi, wifi_init);
 
     // Spawn background tasks