diff options
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | examples/rpi-pico-w/Cargo.toml | 9 | ||||
| -rw-r--r-- | examples/rpi-pico-w/src/main.rs | 78 | ||||
| -rw-r--r-- | src/lib.rs | 168 | ||||
| -rw-r--r-- | src/structs.rs | 9 |
5 files changed, 255 insertions, 10 deletions
diff --git a/Cargo.toml b/Cargo.toml index bd27a48b8..31a14f96f 100644 --- a/Cargo.toml +++ b/Cargo.toml | |||
| @@ -9,6 +9,7 @@ log = ["dep:log"] | |||
| 9 | [dependencies] | 9 | [dependencies] |
| 10 | embassy = { version = "0.1.0" } | 10 | embassy = { version = "0.1.0" } |
| 11 | embassy-rp = { version = "0.1.0", features = ["unstable-traits", "nightly", "unstable-pac"] } | 11 | embassy-rp = { version = "0.1.0", features = ["unstable-traits", "nightly", "unstable-pac"] } |
| 12 | embassy-net = { version = "0.1.0" } | ||
| 12 | atomic-polyfill = "0.1.5" | 13 | atomic-polyfill = "0.1.5" |
| 13 | 14 | ||
| 14 | defmt = { version = "0.3", optional = true } | 15 | defmt = { version = "0.3", optional = true } |
diff --git a/examples/rpi-pico-w/Cargo.toml b/examples/rpi-pico-w/Cargo.toml index 8dbcb20d4..9e1d75470 100644 --- a/examples/rpi-pico-w/Cargo.toml +++ b/examples/rpi-pico-w/Cargo.toml | |||
| @@ -8,6 +8,7 @@ edition = "2021" | |||
| 8 | cyw43 = { path = "../../", features = ["defmt"]} | 8 | cyw43 = { path = "../../", features = ["defmt"]} |
| 9 | embassy = { version = "0.1.0", features = ["defmt", "defmt-timestamp-uptime"] } | 9 | embassy = { version = "0.1.0", features = ["defmt", "defmt-timestamp-uptime"] } |
| 10 | embassy-rp = { version = "0.1.0", features = ["defmt", "unstable-traits", "nightly", "unstable-pac"] } | 10 | embassy-rp = { version = "0.1.0", features = ["defmt", "unstable-traits", "nightly", "unstable-pac"] } |
| 11 | embassy-net = { version = "0.1.0", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } | ||
| 11 | atomic-polyfill = "0.1.5" | 12 | atomic-polyfill = "0.1.5" |
| 12 | 13 | ||
| 13 | defmt = "0.3" | 14 | defmt = "0.3" |
| @@ -20,13 +21,21 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa | |||
| 20 | 21 | ||
| 21 | embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" } | 22 | embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" } |
| 22 | embedded-hal-async = { version = "0.1.0-alpha.1" } | 23 | embedded-hal-async = { version = "0.1.0-alpha.1" } |
| 24 | embedded-io = { version = "0.3.0", features = ["async", "defmt"] } | ||
| 25 | heapless = "0.7.15" | ||
| 23 | 26 | ||
| 24 | 27 | ||
| 25 | [patch.crates-io] | 28 | [patch.crates-io] |
| 26 | embassy = { git = "https://github.com/embassy-rs/embassy", rev = "5f43c1d37e9db847c7861fe0bd821db62edba9f6" } | 29 | embassy = { git = "https://github.com/embassy-rs/embassy", rev = "5f43c1d37e9db847c7861fe0bd821db62edba9f6" } |
| 27 | embassy-rp = { git = "https://github.com/embassy-rs/embassy", rev = "5f43c1d37e9db847c7861fe0bd821db62edba9f6" } | 30 | embassy-rp = { git = "https://github.com/embassy-rs/embassy", rev = "5f43c1d37e9db847c7861fe0bd821db62edba9f6" } |
| 31 | embassy-net = { git = "https://github.com/embassy-rs/embassy", rev = "5f43c1d37e9db847c7861fe0bd821db62edba9f6" } | ||
| 28 | #embassy = { path = "/home/dirbaio/embassy/embassy/embassy" } | 32 | #embassy = { path = "/home/dirbaio/embassy/embassy/embassy" } |
| 29 | #embassy-rp = { path = "/home/dirbaio/embassy/embassy/embassy-rp" } | 33 | #embassy-rp = { path = "/home/dirbaio/embassy/embassy/embassy-rp" } |
| 34 | #embassy-net = { path = "/home/dirbaio/embassy/embassy/embassy-net" } | ||
| 35 | #smoltcp = { path = "./smoltcp" } | ||
| 36 | |||
| 37 | #[patch."https://github.com/smoltcp-rs/smoltcp"] | ||
| 38 | #smoltcp = { path = "./smoltcp" } | ||
| 30 | 39 | ||
| 31 | [profile.dev] | 40 | [profile.dev] |
| 32 | debug = 2 | 41 | debug = 2 |
diff --git a/examples/rpi-pico-w/src/main.rs b/examples/rpi-pico-w/src/main.rs index 6d1614147..e08ee8e95 100644 --- a/examples/rpi-pico-w/src/main.rs +++ b/examples/rpi-pico-w/src/main.rs | |||
| @@ -8,9 +8,13 @@ use defmt::{assert, assert_eq, panic, *}; | |||
| 8 | use embassy::executor::Spawner; | 8 | use embassy::executor::Spawner; |
| 9 | use embassy::time::{Duration, Timer}; | 9 | use embassy::time::{Duration, Timer}; |
| 10 | use embassy::util::Forever; | 10 | use embassy::util::Forever; |
| 11 | use embassy_net::tcp::TcpSocket; | ||
| 12 | use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; | ||
| 11 | use embassy_rp::gpio::{Flex, Level, Output, Pin}; | 13 | use embassy_rp::gpio::{Flex, Level, Output, Pin}; |
| 12 | use embassy_rp::peripherals::{PIN_23, PIN_24, PIN_25, PIN_29}; | 14 | use embassy_rp::peripherals::{PIN_23, PIN_24, PIN_25, PIN_29}; |
| 13 | use embassy_rp::Peripherals; | 15 | use embassy_rp::Peripherals; |
| 16 | use embedded_io::asynch::{Read, Write}; | ||
| 17 | use heapless::Vec; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | 18 | use {defmt_rtt as _, panic_probe as _}; |
| 15 | 19 | ||
| 16 | macro_rules! forever { | 20 | macro_rules! forever { |
| @@ -26,6 +30,11 @@ async fn wifi_task(runner: cyw43::Runner<'static, PIN_23, PIN_25, PIN_29, PIN_24 | |||
| 26 | runner.run().await | 30 | runner.run().await |
| 27 | } | 31 | } |
| 28 | 32 | ||
| 33 | #[embassy::task] | ||
| 34 | async fn net_task(stack: &'static Stack<cyw43::NetDevice<'static>>) -> ! { | ||
| 35 | stack.run().await | ||
| 36 | } | ||
| 37 | |||
| 29 | #[embassy::main] | 38 | #[embassy::main] |
| 30 | async fn main(spawner: Spawner, p: Peripherals) { | 39 | async fn main(spawner: Spawner, p: Peripherals) { |
| 31 | info!("Hello World!"); | 40 | info!("Hello World!"); |
| @@ -45,8 +54,71 @@ async fn main(spawner: Spawner, p: Peripherals) { | |||
| 45 | 54 | ||
| 46 | spawner.spawn(wifi_task(runner)).unwrap(); | 55 | spawner.spawn(wifi_task(runner)).unwrap(); |
| 47 | 56 | ||
| 48 | control.init().await; | 57 | let net_device = control.init().await; |
| 58 | |||
| 59 | control.join_open("MikroTik-951589").await; | ||
| 60 | //control.join_wpa2("MikroTik-951589", "asdfasdfasdfasdf").await; | ||
| 61 | |||
| 62 | let config = embassy_net::ConfigStrategy::Dhcp; | ||
| 63 | //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { | ||
| 64 | // address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), | ||
| 65 | // dns_servers: Vec::new(), | ||
| 66 | // gateway: Some(Ipv4Address::new(192, 168, 69, 1)), | ||
| 67 | //}); | ||
| 68 | |||
| 69 | // Generate random seed | ||
| 70 | let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. | ||
| 71 | |||
| 72 | // Init network stack | ||
| 73 | let stack = &*forever!(Stack::new( | ||
| 74 | net_device, | ||
| 75 | config, | ||
| 76 | forever!(StackResources::<1, 2, 8>::new()), | ||
| 77 | seed | ||
| 78 | )); | ||
| 79 | |||
| 80 | unwrap!(spawner.spawn(net_task(stack))); | ||
| 81 | |||
| 82 | // And now we can use it! | ||
| 83 | |||
| 84 | let mut rx_buffer = [0; 4096]; | ||
| 85 | let mut tx_buffer = [0; 4096]; | ||
| 86 | let mut buf = [0; 4096]; | ||
| 87 | |||
| 88 | loop { | ||
| 89 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); | ||
| 90 | socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10))); | ||
| 91 | |||
| 92 | info!("Listening on TCP:1234..."); | ||
| 93 | if let Err(e) = socket.accept(1234).await { | ||
| 94 | warn!("accept error: {:?}", e); | ||
| 95 | continue; | ||
| 96 | } | ||
| 97 | |||
| 98 | info!("Received connection from {:?}", socket.remote_endpoint()); | ||
| 99 | |||
| 100 | loop { | ||
| 101 | let n = match socket.read(&mut buf).await { | ||
| 102 | Ok(0) => { | ||
| 103 | warn!("read EOF"); | ||
| 104 | break; | ||
| 105 | } | ||
| 106 | Ok(n) => n, | ||
| 107 | Err(e) => { | ||
| 108 | warn!("read error: {:?}", e); | ||
| 109 | break; | ||
| 110 | } | ||
| 111 | }; | ||
| 112 | |||
| 113 | info!("rxd {:02x}", &buf[..n]); | ||
| 49 | 114 | ||
| 50 | //control.join_open("MikroTik-951589").await; | 115 | match socket.write_all(&buf[..n]).await { |
| 51 | control.join_wpa2("MikroTik-951589", "fasdfasdfasdf").await; | 116 | Ok(()) => {} |
| 117 | Err(e) => { | ||
| 118 | warn!("write error: {:?}", e); | ||
| 119 | break; | ||
| 120 | } | ||
| 121 | }; | ||
| 122 | } | ||
| 123 | } | ||
| 52 | } | 124 | } |
diff --git a/src/lib.rs b/src/lib.rs index e0c2c9312..dde9d9c34 100644 --- a/src/lib.rs +++ b/src/lib.rs | |||
| @@ -12,12 +12,19 @@ mod structs; | |||
| 12 | 12 | ||
| 13 | use core::cell::Cell; | 13 | use core::cell::Cell; |
| 14 | use core::slice; | 14 | use core::slice; |
| 15 | use core::sync::atomic::Ordering; | ||
| 16 | use core::task::Waker; | ||
| 15 | 17 | ||
| 18 | use atomic_polyfill::AtomicBool; | ||
| 19 | use embassy::blocking_mutex::raw::NoopRawMutex; | ||
| 20 | use embassy::channel::mpmc::Channel; | ||
| 16 | use embassy::time::{block_for, Duration, Timer}; | 21 | use embassy::time::{block_for, Duration, Timer}; |
| 17 | use embassy::util::yield_now; | 22 | use embassy::util::yield_now; |
| 23 | use embassy_net::{PacketBoxExt, PacketBuf}; | ||
| 18 | use embassy_rp::gpio::{Flex, Output, Pin}; | 24 | use embassy_rp::gpio::{Flex, Output, Pin}; |
| 19 | 25 | ||
| 20 | use self::structs::*; | 26 | use self::structs::*; |
| 27 | use crate::events::Event; | ||
| 21 | 28 | ||
| 22 | fn swap16(x: u32) -> u32 { | 29 | fn swap16(x: u32) -> u32 { |
| 23 | (x & 0xFF00FF00) >> 8 | (x & 0x00FF00FF) << 8 | 30 | (x & 0xFF00FF00) >> 8 | (x & 0x00FF00FF) << 8 |
| @@ -197,6 +204,10 @@ enum IoctlState { | |||
| 197 | pub struct State { | 204 | pub struct State { |
| 198 | ioctl_id: Cell<u16>, | 205 | ioctl_id: Cell<u16>, |
| 199 | ioctl_state: Cell<IoctlState>, | 206 | ioctl_state: Cell<IoctlState>, |
| 207 | |||
| 208 | tx_channel: Channel<NoopRawMutex, PacketBuf, 8>, | ||
| 209 | rx_channel: Channel<NoopRawMutex, PacketBuf, 8>, | ||
| 210 | link_up: AtomicBool, | ||
| 200 | } | 211 | } |
| 201 | 212 | ||
| 202 | impl State { | 213 | impl State { |
| @@ -204,6 +215,10 @@ impl State { | |||
| 204 | Self { | 215 | Self { |
| 205 | ioctl_id: Cell::new(0), | 216 | ioctl_id: Cell::new(0), |
| 206 | ioctl_state: Cell::new(IoctlState::Idle), | 217 | ioctl_state: Cell::new(IoctlState::Idle), |
| 218 | |||
| 219 | tx_channel: Channel::new(), | ||
| 220 | rx_channel: Channel::new(), | ||
| 221 | link_up: AtomicBool::new(true), // TODO set up/down as we join/deassociate | ||
| 207 | } | 222 | } |
| 208 | } | 223 | } |
| 209 | } | 224 | } |
| @@ -213,7 +228,7 @@ pub struct Control<'a> { | |||
| 213 | } | 228 | } |
| 214 | 229 | ||
| 215 | impl<'a> Control<'a> { | 230 | impl<'a> Control<'a> { |
| 216 | pub async fn init(&mut self) { | 231 | pub async fn init(&mut self) -> NetDevice<'a> { |
| 217 | const CHUNK_SIZE: usize = 1024; | 232 | const CHUNK_SIZE: usize = 1024; |
| 218 | 233 | ||
| 219 | let clm = unsafe { slice::from_raw_parts(0x10140000 as *const u8, 4752) }; | 234 | let clm = unsafe { slice::from_raw_parts(0x10140000 as *const u8, 4752) }; |
| @@ -253,6 +268,15 @@ impl<'a> Control<'a> { | |||
| 253 | self.set_iovar_u32("apsta", 1).await; | 268 | self.set_iovar_u32("apsta", 1).await; |
| 254 | //self.set_iovar("cur_etheraddr", &[02, 03, 04, 05, 06, 07]).await; | 269 | //self.set_iovar("cur_etheraddr", &[02, 03, 04, 05, 06, 07]).await; |
| 255 | 270 | ||
| 271 | // read MAC addr. | ||
| 272 | let mut mac_addr = [0; 6]; | ||
| 273 | assert_eq!(self.get_iovar("cur_etheraddr", &mut mac_addr).await, 6); | ||
| 274 | info!("mac addr: {:02x}", mac_addr); | ||
| 275 | |||
| 276 | // TODO get_iovar is broken, it returns all zeros. | ||
| 277 | // Harcdode our own MAC for now. | ||
| 278 | let mac_addr = [0x28, 0xCD, 0xC1, 0x00, 0x3F, 0x05]; | ||
| 279 | |||
| 256 | let country = countries::WORLD_WIDE_XX; | 280 | let country = countries::WORLD_WIDE_XX; |
| 257 | let country_info = CountryInfo { | 281 | let country_info = CountryInfo { |
| 258 | country_abbrev: [country.code[0], country.code[1], 0, 0], | 282 | country_abbrev: [country.code[0], country.code[1], 0, 0], |
| @@ -283,6 +307,15 @@ impl<'a> Control<'a> { | |||
| 283 | iface: 0, | 307 | iface: 0, |
| 284 | events: [0xFF; 24], | 308 | events: [0xFF; 24], |
| 285 | }; | 309 | }; |
| 310 | |||
| 311 | // Disable spammy uninteresting events. | ||
| 312 | evts.unset(Event::RADIO); | ||
| 313 | evts.unset(Event::IF); | ||
| 314 | evts.unset(Event::PROBREQ_MSG); | ||
| 315 | evts.unset(Event::PROBREQ_MSG_RX); | ||
| 316 | evts.unset(Event::PROBRESP_MSG); | ||
| 317 | evts.unset(Event::PROBRESP_MSG); | ||
| 318 | |||
| 286 | self.set_iovar("bsscfg:event_msgs", &evts.to_bytes()).await; | 319 | self.set_iovar("bsscfg:event_msgs", &evts.to_bytes()).await; |
| 287 | 320 | ||
| 288 | Timer::after(Duration::from_millis(100)).await; | 321 | Timer::after(Duration::from_millis(100)).await; |
| @@ -305,6 +338,11 @@ impl<'a> Control<'a> { | |||
| 305 | Timer::after(Duration::from_millis(100)).await; | 338 | Timer::after(Duration::from_millis(100)).await; |
| 306 | 339 | ||
| 307 | info!("INIT DONE"); | 340 | info!("INIT DONE"); |
| 341 | |||
| 342 | NetDevice { | ||
| 343 | state: self.state, | ||
| 344 | mac_addr, | ||
| 345 | } | ||
| 308 | } | 346 | } |
| 309 | 347 | ||
| 310 | pub async fn join_open(&mut self, ssid: &str) { | 348 | pub async fn join_open(&mut self, ssid: &str) { |
| @@ -387,6 +425,7 @@ impl<'a> Control<'a> { | |||
| 387 | self.ioctl(2, 263, 0, &mut buf).await; | 425 | self.ioctl(2, 263, 0, &mut buf).await; |
| 388 | } | 426 | } |
| 389 | 427 | ||
| 428 | // TODO this is not really working, it always returns all zeros. | ||
| 390 | async fn get_iovar(&mut self, name: &str, res: &mut [u8]) -> usize { | 429 | async fn get_iovar(&mut self, name: &str, res: &mut [u8]) -> usize { |
| 391 | info!("get {}", name); | 430 | info!("get {}", name); |
| 392 | 431 | ||
| @@ -395,7 +434,7 @@ impl<'a> Control<'a> { | |||
| 395 | buf[name.len()] = 0; | 434 | buf[name.len()] = 0; |
| 396 | 435 | ||
| 397 | let total_len = name.len() + 1 + res.len(); | 436 | let total_len = name.len() + 1 + res.len(); |
| 398 | let res_len = self.ioctl(2, 262, 0, &mut buf[..total_len]).await - name.len() - 1; | 437 | let res_len = self.ioctl(0, 262, 0, &mut buf[..total_len]).await - name.len() - 1; |
| 399 | res[..res_len].copy_from_slice(&buf[name.len() + 1..][..res_len]); | 438 | res[..res_len].copy_from_slice(&buf[name.len() + 1..][..res_len]); |
| 400 | res_len | 439 | res_len |
| 401 | } | 440 | } |
| @@ -408,9 +447,6 @@ impl<'a> Control<'a> { | |||
| 408 | async fn ioctl(&mut self, kind: u32, cmd: u32, iface: u32, buf: &mut [u8]) -> usize { | 447 | async fn ioctl(&mut self, kind: u32, cmd: u32, iface: u32, buf: &mut [u8]) -> usize { |
| 409 | // TODO cancel ioctl on future drop. | 448 | // TODO cancel ioctl on future drop. |
| 410 | 449 | ||
| 411 | // snail mode 🐌 | ||
| 412 | Timer::after(Duration::from_millis(100)).await; | ||
| 413 | |||
| 414 | while !matches!(self.state.ioctl_state.get(), IoctlState::Idle) { | 450 | while !matches!(self.state.ioctl_state.get(), IoctlState::Idle) { |
| 415 | yield_now().await; | 451 | yield_now().await; |
| 416 | } | 452 | } |
| @@ -434,6 +470,50 @@ impl<'a> Control<'a> { | |||
| 434 | } | 470 | } |
| 435 | } | 471 | } |
| 436 | 472 | ||
| 473 | pub struct NetDevice<'a> { | ||
| 474 | state: &'a State, | ||
| 475 | mac_addr: [u8; 6], | ||
| 476 | } | ||
| 477 | |||
| 478 | impl<'a> embassy_net::Device for NetDevice<'a> { | ||
| 479 | fn register_waker(&mut self, waker: &Waker) { | ||
| 480 | // loopy loopy wakey wakey | ||
| 481 | waker.wake_by_ref() | ||
| 482 | } | ||
| 483 | |||
| 484 | fn link_state(&mut self) -> embassy_net::LinkState { | ||
| 485 | match self.state.link_up.load(Ordering::Relaxed) { | ||
| 486 | true => embassy_net::LinkState::Up, | ||
| 487 | false => embassy_net::LinkState::Down, | ||
| 488 | } | ||
| 489 | } | ||
| 490 | |||
| 491 | fn capabilities(&self) -> embassy_net::DeviceCapabilities { | ||
| 492 | let mut caps = embassy_net::DeviceCapabilities::default(); | ||
| 493 | caps.max_transmission_unit = 1514; // 1500 IP + 14 ethernet header | ||
| 494 | caps.medium = embassy_net::Medium::Ethernet; | ||
| 495 | caps | ||
| 496 | } | ||
| 497 | |||
| 498 | fn is_transmit_ready(&mut self) -> bool { | ||
| 499 | true | ||
| 500 | } | ||
| 501 | |||
| 502 | fn transmit(&mut self, pkt: PacketBuf) { | ||
| 503 | if self.state.tx_channel.try_send(pkt).is_err() { | ||
| 504 | warn!("TX failed") | ||
| 505 | } | ||
| 506 | } | ||
| 507 | |||
| 508 | fn receive(&mut self) -> Option<PacketBuf> { | ||
| 509 | self.state.rx_channel.try_recv().ok() | ||
| 510 | } | ||
| 511 | |||
| 512 | fn ethernet_address(&self) -> [u8; 6] { | ||
| 513 | self.mac_addr | ||
| 514 | } | ||
| 515 | } | ||
| 516 | |||
| 437 | pub struct Runner<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> { | 517 | pub struct Runner<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> { |
| 438 | state: &'a State, | 518 | state: &'a State, |
| 439 | 519 | ||
| @@ -576,7 +656,10 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Runner<'a, PWR, CS, CLK, DIO> { | |||
| 576 | while self.read32(FUNC_BUS, REG_BUS_STATUS) & STATUS_F2_RX_READY == 0 {} | 656 | while self.read32(FUNC_BUS, REG_BUS_STATUS) & STATUS_F2_RX_READY == 0 {} |
| 577 | 657 | ||
| 578 | // Some random configs related to sleep. | 658 | // Some random configs related to sleep. |
| 579 | // I think they're not needed if we don't want sleep...??? | 659 | // These aren't needed if we don't want to sleep the bus. |
| 660 | // TODO do we need to sleep the bus to read the irq line, due to | ||
| 661 | // being on the same pin as MOSI/MISO? | ||
| 662 | |||
| 580 | /* | 663 | /* |
| 581 | let mut val = self.read8(FUNC_BACKPLANE, REG_BACKPLANE_WAKEUP_CTRL); | 664 | let mut val = self.read8(FUNC_BACKPLANE, REG_BACKPLANE_WAKEUP_CTRL); |
| 582 | val |= 0x02; // WAKE_TILL_HT_AVAIL | 665 | val |= 0x02; // WAKE_TILL_HT_AVAIL |
| @@ -606,11 +689,16 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Runner<'a, PWR, CS, CLK, DIO> { | |||
| 606 | let mut buf = [0; 2048]; | 689 | let mut buf = [0; 2048]; |
| 607 | loop { | 690 | loop { |
| 608 | // Send stuff | 691 | // Send stuff |
| 692 | // TODO flow control | ||
| 609 | if let IoctlState::Pending { kind, cmd, iface, buf } = self.state.ioctl_state.get() { | 693 | if let IoctlState::Pending { kind, cmd, iface, buf } = self.state.ioctl_state.get() { |
| 610 | self.send_ioctl(kind, cmd, iface, unsafe { &*buf }, self.state.ioctl_id.get()); | 694 | self.send_ioctl(kind, cmd, iface, unsafe { &*buf }, self.state.ioctl_id.get()); |
| 611 | self.state.ioctl_state.set(IoctlState::Sent { buf }); | 695 | self.state.ioctl_state.set(IoctlState::Sent { buf }); |
| 612 | } | 696 | } |
| 613 | 697 | ||
| 698 | if let Ok(p) = self.state.tx_channel.try_recv() { | ||
| 699 | self.send_packet(&p); | ||
| 700 | } | ||
| 701 | |||
| 614 | // Receive stuff | 702 | // Receive stuff |
| 615 | let irq = self.read16(FUNC_BUS, REG_BUS_INTERRUPT); | 703 | let irq = self.read16(FUNC_BUS, REG_BUS_INTERRUPT); |
| 616 | 704 | ||
| @@ -646,6 +734,52 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Runner<'a, PWR, CS, CLK, DIO> { | |||
| 646 | } | 734 | } |
| 647 | } | 735 | } |
| 648 | 736 | ||
| 737 | fn send_packet(&mut self, packet: &[u8]) { | ||
| 738 | trace!("tx pkt {:02x}", &packet[..packet.len().min(48)]); | ||
| 739 | |||
| 740 | let mut buf = [0; 2048]; | ||
| 741 | |||
| 742 | let total_len = SdpcmHeader::SIZE + BcdHeader::SIZE + packet.len(); | ||
| 743 | |||
| 744 | let seq = self.ioctl_seq; | ||
| 745 | self.ioctl_seq = self.ioctl_seq.wrapping_add(1); | ||
| 746 | |||
| 747 | let sdpcm_header = SdpcmHeader { | ||
| 748 | len: total_len as u16, // TODO does this len need to be rounded up to u32? | ||
| 749 | len_inv: !total_len as u16, | ||
| 750 | sequence: seq, | ||
| 751 | channel_and_flags: 2, // data channel | ||
| 752 | next_length: 0, | ||
| 753 | header_length: SdpcmHeader::SIZE as _, | ||
| 754 | wireless_flow_control: 0, | ||
| 755 | bus_data_credit: 0, | ||
| 756 | reserved: [0, 0], | ||
| 757 | }; | ||
| 758 | |||
| 759 | let bcd_header = BcdHeader { | ||
| 760 | flags: 0x20, | ||
| 761 | priority: 0, | ||
| 762 | flags2: 0, | ||
| 763 | data_offset: 0, | ||
| 764 | }; | ||
| 765 | trace!("tx {:?}", sdpcm_header); | ||
| 766 | trace!(" {:?}", bcd_header); | ||
| 767 | |||
| 768 | buf[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes()); | ||
| 769 | buf[SdpcmHeader::SIZE..][..BcdHeader::SIZE].copy_from_slice(&bcd_header.to_bytes()); | ||
| 770 | buf[SdpcmHeader::SIZE + BcdHeader::SIZE..][..packet.len()].copy_from_slice(packet); | ||
| 771 | |||
| 772 | let total_len = (total_len + 3) & !3; // round up to 4byte | ||
| 773 | |||
| 774 | trace!(" {:02x}", &buf[..total_len.min(48)]); | ||
| 775 | |||
| 776 | let cmd = cmd_word(true, true, FUNC_WLAN, 0, total_len as _); | ||
| 777 | self.cs.set_low(); | ||
| 778 | self.spi_write(&cmd.to_le_bytes()); | ||
| 779 | self.spi_write(&buf[..total_len]); | ||
| 780 | self.cs.set_high(); | ||
| 781 | } | ||
| 782 | |||
| 649 | fn rx(&mut self, packet: &[u8]) { | 783 | fn rx(&mut self, packet: &[u8]) { |
| 650 | if packet.len() < SdpcmHeader::SIZE { | 784 | if packet.len() < SdpcmHeader::SIZE { |
| 651 | warn!("packet too short, len={}", packet.len()); | 785 | warn!("packet too short, len={}", packet.len()); |
| @@ -683,6 +817,8 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Runner<'a, PWR, CS, CLK, DIO> { | |||
| 683 | assert_eq!(cdc_header.status, 0); // todo propagate error instead | 817 | assert_eq!(cdc_header.status, 0); // todo propagate error instead |
| 684 | 818 | ||
| 685 | let resp_len = cdc_header.len as usize; | 819 | let resp_len = cdc_header.len as usize; |
| 820 | info!("IOCTL Response: {:02x}", &payload[CdcHeader::SIZE..][..resp_len]); | ||
| 821 | |||
| 686 | (unsafe { &mut *buf }[..resp_len]).copy_from_slice(&payload[CdcHeader::SIZE..][..resp_len]); | 822 | (unsafe { &mut *buf }[..resp_len]).copy_from_slice(&payload[CdcHeader::SIZE..][..resp_len]); |
| 687 | self.state.ioctl_state.set(IoctlState::Done { resp_len }); | 823 | self.state.ioctl_state.set(IoctlState::Done { resp_len }); |
| 688 | } | 824 | } |
| @@ -703,14 +839,32 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Runner<'a, PWR, CS, CLK, DIO> { | |||
| 703 | let mut evt = EventHeader::from_bytes(&packet[24..][..EventHeader::SIZE].try_into().unwrap()); | 839 | let mut evt = EventHeader::from_bytes(&packet[24..][..EventHeader::SIZE].try_into().unwrap()); |
| 704 | evt.byteswap(); | 840 | evt.byteswap(); |
| 705 | let evt_data = &packet[24 + EventHeader::SIZE..][..evt.datalen as usize]; | 841 | let evt_data = &packet[24 + EventHeader::SIZE..][..evt.datalen as usize]; |
| 706 | info!( | 842 | debug!( |
| 707 | "=== EVENT {}: {} {:02x}", | 843 | "=== EVENT {}: {} {:02x}", |
| 708 | events::Event::from(evt.event_type as u8), | 844 | events::Event::from(evt.event_type as u8), |
| 709 | evt, | 845 | evt, |
| 710 | evt_data | 846 | evt_data |
| 711 | ); | 847 | ); |
| 712 | } | 848 | } |
| 849 | 2 => { | ||
| 850 | let bcd_header = BcdHeader::from_bytes(&payload[..BcdHeader::SIZE].try_into().unwrap()); | ||
| 851 | trace!(" {:?}", bcd_header); | ||
| 713 | 852 | ||
| 853 | let packet_start = BcdHeader::SIZE + 4 * bcd_header.data_offset as usize; | ||
| 854 | if packet_start > payload.len() { | ||
| 855 | warn!("packet start out of range."); | ||
| 856 | return; | ||
| 857 | } | ||
| 858 | let packet = &payload[packet_start..]; | ||
| 859 | trace!("rx pkt {:02x}", &packet[..(packet.len() as usize).min(48)]); | ||
| 860 | |||
| 861 | let mut p = unwrap!(embassy_net::PacketBox::new(embassy_net::Packet::new())); | ||
| 862 | p[..packet.len()].copy_from_slice(packet); | ||
| 863 | |||
| 864 | if let Err(_) = self.state.rx_channel.try_send(p.slice(0..packet.len())) { | ||
| 865 | warn!("failed to push rxd packet to the channel.") | ||
| 866 | } | ||
| 867 | } | ||
| 714 | _ => {} | 868 | _ => {} |
| 715 | } | 869 | } |
| 716 | } | 870 | } |
diff --git a/src/structs.rs b/src/structs.rs index dd2c0cfe9..060c2b060 100644 --- a/src/structs.rs +++ b/src/structs.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | use crate::events::Event; | ||
| 2 | |||
| 1 | macro_rules! impl_bytes { | 3 | macro_rules! impl_bytes { |
| 2 | ($t:ident) => { | 4 | ($t:ident) => { |
| 3 | impl $t { | 5 | impl $t { |
| @@ -157,3 +159,10 @@ pub struct EventMask { | |||
| 157 | pub events: [u8; 24], | 159 | pub events: [u8; 24], |
| 158 | } | 160 | } |
| 159 | impl_bytes!(EventMask); | 161 | impl_bytes!(EventMask); |
| 162 | |||
| 163 | impl EventMask { | ||
| 164 | pub fn unset(&mut self, evt: Event) { | ||
| 165 | let evt = evt as u8 as usize; | ||
| 166 | self.events[evt / 8] &= !(1 << (evt % 8)); | ||
| 167 | } | ||
| 168 | } | ||
