aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-04-30 15:05:16 +0000
committerGitHub <[email protected]>2023-04-30 15:05:16 +0000
commit5659269c8fb2f7d03d4a903e4ad48c8268668f0a (patch)
treee35e59f37d50791029c2f88b3014b409ea802d39
parentc19de2984751ba6fa2972ee66cfa2a6310d5f0c1 (diff)
parent76b967a966677e570cc0a2942ed3ccd29b2d1017 (diff)
Merge pull request #70 from kbleeke/wifi-scanning-ioctl
Wifi scanning ioctl
-rw-r--r--examples/rpi-pico-w/src/main.rs1
-rw-r--r--src/control.rs75
-rw-r--r--src/events.rs11
-rw-r--r--src/lib.rs1
-rw-r--r--src/runner.rs14
-rw-r--r--src/structs.rs81
6 files changed, 173 insertions, 10 deletions
diff --git a/examples/rpi-pico-w/src/main.rs b/examples/rpi-pico-w/src/main.rs
index d075aec2a..944beaac0 100644
--- a/examples/rpi-pico-w/src/main.rs
+++ b/examples/rpi-pico-w/src/main.rs
@@ -143,4 +143,3 @@ async fn main(spawner: Spawner) {
143 } 143 }
144 } 144 }
145} 145}
146
diff --git a/src/control.rs b/src/control.rs
index 0c06009b9..934bade23 100644
--- a/src/control.rs
+++ b/src/control.rs
@@ -6,11 +6,11 @@ use embassy_time::{Duration, Timer};
6 6
7pub use crate::bus::SpiBusCyw43; 7pub use crate::bus::SpiBusCyw43;
8use crate::consts::*; 8use crate::consts::*;
9use crate::events::{Event, Events}; 9use crate::events::{Event, EventSubscriber, Events};
10use crate::fmt::Bytes; 10use crate::fmt::Bytes;
11use crate::ioctl::{IoctlState, IoctlType}; 11use crate::ioctl::{IoctlState, IoctlType};
12use crate::structs::*; 12use crate::structs::*;
13use crate::{countries, PowerManagementMode}; 13use crate::{countries, events, PowerManagementMode};
14 14
15pub struct Control<'a> { 15pub struct Control<'a> {
16 state_ch: ch::StateRunner<'a>, 16 state_ch: ch::StateRunner<'a>,
@@ -245,9 +245,13 @@ impl<'a> Control<'a> {
245 } 245 }
246 246
247 async fn set_iovar(&mut self, name: &str, val: &[u8]) { 247 async fn set_iovar(&mut self, name: &str, val: &[u8]) {
248 self.set_iovar_v::<64>(name, val).await
249 }
250
251 async fn set_iovar_v<const BUFSIZE: usize>(&mut self, name: &str, val: &[u8]) {
248 info!("set {} = {:02x}", name, Bytes(val)); 252 info!("set {} = {:02x}", name, Bytes(val));
249 253
250 let mut buf = [0; 64]; 254 let mut buf = [0; BUFSIZE];
251 buf[..name.len()].copy_from_slice(name.as_bytes()); 255 buf[..name.len()].copy_from_slice(name.as_bytes());
252 buf[name.len()] = 0; 256 buf[name.len()] = 0;
253 buf[name.len() + 1..][..val.len()].copy_from_slice(val); 257 buf[name.len() + 1..][..val.len()].copy_from_slice(val);
@@ -304,4 +308,69 @@ impl<'a> Control<'a> {
304 308
305 resp_len 309 resp_len
306 } 310 }
311
312 /// Start a wifi scan
313 ///
314 /// Returns a `Stream` of networks found by the device
315 ///
316 /// # Note
317 /// Device events are currently implemented using a bounded queue.
318 /// To not miss any events, you should make sure to always await the stream.
319 pub async fn scan(&mut self) -> Scanner<'_> {
320 const SCANTYPE_PASSIVE: u8 = 1;
321
322 let scan_params = ScanParams {
323 version: 1,
324 action: 1,
325 sync_id: 1,
326 ssid_len: 0,
327 ssid: [0; 32],
328 bssid: [0xff; 6],
329 bss_type: 2,
330 scan_type: SCANTYPE_PASSIVE,
331 nprobes: !0,
332 active_time: !0,
333 passive_time: !0,
334 home_time: !0,
335 channel_num: 0,
336 channel_list: [0; 1],
337 };
338
339 self.events.mask.enable(&[Event::ESCAN_RESULT]);
340 let subscriber = self.events.queue.subscriber().unwrap();
341 self.set_iovar_v::<256>("escan", &scan_params.to_bytes()).await;
342
343 Scanner {
344 subscriber,
345 events: &self.events,
346 }
347 }
348}
349
350pub struct Scanner<'a> {
351 subscriber: EventSubscriber<'a>,
352 events: &'a Events,
353}
354
355impl Scanner<'_> {
356 /// wait for the next found network
357 pub async fn next(&mut self) -> Option<BssInfo> {
358 let event = self.subscriber.next_message_pure().await;
359 if event.header.status != EStatus::PARTIAL {
360 self.events.mask.disable_all();
361 return None;
362 }
363
364 if let events::Payload::BssInfo(bss) = event.payload {
365 Some(bss)
366 } else {
367 None
368 }
369 }
370}
371
372impl Drop for Scanner<'_> {
373 fn drop(&mut self) {
374 self.events.mask.disable_all();
375 }
307} 376}
diff --git a/src/events.rs b/src/events.rs
index d6f114ed9..a94c49a0c 100644
--- a/src/events.rs
+++ b/src/events.rs
@@ -1,10 +1,12 @@
1#![allow(unused)] 1#![allow(dead_code)]
2#![allow(non_camel_case_types)] 2#![allow(non_camel_case_types)]
3 3
4use core::cell::RefCell; 4use core::cell::RefCell;
5 5
6use embassy_sync::blocking_mutex::raw::NoopRawMutex; 6use embassy_sync::blocking_mutex::raw::NoopRawMutex;
7use embassy_sync::pubsub::{PubSubChannel, Publisher, Subscriber}; 7use embassy_sync::pubsub::{PubSubChannel, Subscriber};
8
9use crate::structs::BssInfo;
8 10
9#[derive(Debug, Clone, Copy, PartialEq, Eq, num_enum::FromPrimitive)] 11#[derive(Debug, Clone, Copy, PartialEq, Eq, num_enum::FromPrimitive)]
10#[cfg_attr(feature = "defmt", derive(defmt::Format))] 12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -286,7 +288,6 @@ pub enum Event {
286 288
287// TODO this PubSub can probably be replaced with shared memory to make it a bit more efficient. 289// TODO this PubSub can probably be replaced with shared memory to make it a bit more efficient.
288pub type EventQueue = PubSubChannel<NoopRawMutex, Message, 2, 1, 1>; 290pub type EventQueue = PubSubChannel<NoopRawMutex, Message, 2, 1, 1>;
289pub type EventPublisher<'a> = Publisher<'a, NoopRawMutex, Message, 2, 1, 1>;
290pub type EventSubscriber<'a> = Subscriber<'a, NoopRawMutex, Message, 2, 1, 1>; 291pub type EventSubscriber<'a> = Subscriber<'a, NoopRawMutex, Message, 2, 1, 1>;
291 292
292pub struct Events { 293pub struct Events {
@@ -313,6 +314,7 @@ pub struct Status {
313#[derive(Clone, Copy)] 314#[derive(Clone, Copy)]
314pub enum Payload { 315pub enum Payload {
315 None, 316 None,
317 BssInfo(BssInfo),
316} 318}
317 319
318#[derive(Clone, Copy)] 320#[derive(Clone, Copy)]
@@ -344,7 +346,7 @@ impl EventMask {
344 let word = n / u32::BITS; 346 let word = n / u32::BITS;
345 let bit = n % u32::BITS; 347 let bit = n % u32::BITS;
346 348
347 self.mask[word as usize] |= (1 << bit); 349 self.mask[word as usize] |= 1 << bit;
348 } 350 }
349 351
350 fn disable(&mut self, event: Event) { 352 fn disable(&mut self, event: Event) {
@@ -378,6 +380,7 @@ impl SharedEventMask {
378 } 380 }
379 } 381 }
380 382
383 #[allow(dead_code)]
381 pub fn disable(&self, events: &[Event]) { 384 pub fn disable(&self, events: &[Event]) {
382 let mut mask = self.mask.borrow_mut(); 385 let mut mask = self.mask.borrow_mut();
383 for event in events { 386 for event in events {
diff --git a/src/lib.rs b/src/lib.rs
index f9244bddb..d437a882e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -29,6 +29,7 @@ use crate::bus::Bus;
29pub use crate::bus::SpiBusCyw43; 29pub use crate::bus::SpiBusCyw43;
30pub use crate::control::Control; 30pub use crate::control::Control;
31pub use crate::runner::Runner; 31pub use crate::runner::Runner;
32pub use crate::structs::BssInfo;
32 33
33const MTU: usize = 1514; 34const MTU: usize = 1514;
34 35
diff --git a/src/runner.rs b/src/runner.rs
index 806ddfc49..9b99e174f 100644
--- a/src/runner.rs
+++ b/src/runner.rs
@@ -7,7 +7,7 @@ use embedded_hal_1::digital::OutputPin;
7use crate::bus::Bus; 7use crate::bus::Bus;
8pub use crate::bus::SpiBusCyw43; 8pub use crate::bus::SpiBusCyw43;
9use crate::consts::*; 9use crate::consts::*;
10use crate::events::{Events, Status}; 10use crate::events::{Event, Events, Status};
11use crate::fmt::Bytes; 11use crate::fmt::Bytes;
12use crate::ioctl::{IoctlState, IoctlType, PendingIoctl}; 12use crate::ioctl::{IoctlState, IoctlType, PendingIoctl};
13use crate::nvram::NVRAM; 13use crate::nvram::NVRAM;
@@ -351,6 +351,8 @@ where
351 panic!("IOCTL error {}", cdc_header.status as i32); 351 panic!("IOCTL error {}", cdc_header.status as i32);
352 } 352 }
353 353
354 info!("IOCTL Response: {:02x}", Bytes(response));
355
354 self.ioctl_state.ioctl_done(response); 356 self.ioctl_state.ioctl_done(response);
355 } 357 }
356 } 358 }
@@ -404,7 +406,15 @@ where
404 406
405 if self.events.mask.is_enabled(evt_type) { 407 if self.events.mask.is_enabled(evt_type) {
406 let status = event_packet.msg.status; 408 let status = event_packet.msg.status;
407 let event_payload = events::Payload::None; 409 let event_payload = match evt_type {
410 Event::ESCAN_RESULT if status == EStatus::PARTIAL => {
411 let Some((_, bss_info)) = ScanResults::parse(evt_data) else { return };
412 let Some(bss_info) = BssInfo::parse(bss_info) else { return };
413 events::Payload::BssInfo(*bss_info)
414 }
415 Event::ESCAN_RESULT => events::Payload::None,
416 _ => events::Payload::None,
417 };
408 418
409 // this intentionally uses the non-blocking publish immediate 419 // this intentionally uses the non-blocking publish immediate
410 // publish() is a deadlock risk in the current design as awaiting here prevents ioctls 420 // publish() is a deadlock risk in the current design as awaiting here prevents ioctls
diff --git a/src/structs.rs b/src/structs.rs
index f54ec7fcf..d01d5a65c 100644
--- a/src/structs.rs
+++ b/src/structs.rs
@@ -404,3 +404,84 @@ impl EventMask {
404 self.events[evt / 8] &= !(1 << (evt % 8)); 404 self.events[evt / 8] &= !(1 << (evt % 8));
405 } 405 }
406} 406}
407
408/// Parameters for a wifi scan
409#[derive(Clone, Copy)]
410#[cfg_attr(feature = "defmt", derive(defmt::Format))]
411#[repr(C)]
412pub struct ScanParams {
413 pub version: u32,
414 pub action: u16,
415 pub sync_id: u16,
416 pub ssid_len: u32,
417 pub ssid: [u8; 32],
418 pub bssid: [u8; 6],
419 pub bss_type: u8,
420 pub scan_type: u8,
421 pub nprobes: u32,
422 pub active_time: u32,
423 pub passive_time: u32,
424 pub home_time: u32,
425 pub channel_num: u32,
426 pub channel_list: [u16; 1],
427}
428impl_bytes!(ScanParams);
429
430/// Wifi Scan Results Header, followed by `bss_count` `BssInfo`
431#[derive(Clone, Copy)]
432// #[cfg_attr(feature = "defmt", derive(defmt::Format))]
433#[repr(C, packed(2))]
434pub struct ScanResults {
435 pub buflen: u32,
436 pub version: u32,
437 pub sync_id: u16,
438 pub bss_count: u16,
439}
440impl_bytes!(ScanResults);
441
442impl ScanResults {
443 pub fn parse(packet: &mut [u8]) -> Option<(&mut ScanResults, &mut [u8])> {
444 if packet.len() < ScanResults::SIZE {
445 return None;
446 }
447
448 let (scan_results, bssinfo) = packet.split_at_mut(ScanResults::SIZE);
449 let scan_results = ScanResults::from_bytes_mut(scan_results.try_into().unwrap());
450
451 if scan_results.bss_count > 0 && bssinfo.len() < BssInfo::SIZE {
452 warn!("Scan result, incomplete BssInfo");
453 return None;
454 }
455
456 Some((scan_results, bssinfo))
457 }
458}
459
460/// Wifi Scan Result
461#[derive(Clone, Copy)]
462// #[cfg_attr(feature = "defmt", derive(defmt::Format))]
463#[repr(C, packed(2))]
464#[non_exhaustive]
465pub struct BssInfo {
466 pub version: u32,
467 pub length: u32,
468 pub bssid: [u8; 6],
469 pub beacon_period: u16,
470 pub capability: u16,
471 pub ssid_len: u8,
472 pub ssid: [u8; 32],
473 // there will be more stuff here
474}
475impl_bytes!(BssInfo);
476
477impl BssInfo {
478 pub fn parse(packet: &mut [u8]) -> Option<&mut Self> {
479 if packet.len() < BssInfo::SIZE {
480 return None;
481 }
482
483 Some(BssInfo::from_bytes_mut(
484 packet[..BssInfo::SIZE].as_mut().try_into().unwrap(),
485 ))
486 }
487}