wifi scan ioctl
This commit is contained in:
parent
c19de29847
commit
2c5d94493c
6 changed files with 165 additions and 10 deletions
|
@ -143,4 +143,3 @@ async fn main(spawner: Spawner) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,11 +6,11 @@ use embassy_time::{Duration, Timer};
|
|||
|
||||
pub use crate::bus::SpiBusCyw43;
|
||||
use crate::consts::*;
|
||||
use crate::events::{Event, Events};
|
||||
use crate::events::{Event, EventSubscriber, Events};
|
||||
use crate::fmt::Bytes;
|
||||
use crate::ioctl::{IoctlState, IoctlType};
|
||||
use crate::structs::*;
|
||||
use crate::{countries, PowerManagementMode};
|
||||
use crate::{countries, events, PowerManagementMode};
|
||||
|
||||
pub struct Control<'a> {
|
||||
state_ch: ch::StateRunner<'a>,
|
||||
|
@ -245,9 +245,13 @@ impl<'a> Control<'a> {
|
|||
}
|
||||
|
||||
async fn set_iovar(&mut self, name: &str, val: &[u8]) {
|
||||
self.set_iovar_v::<64>(name, val).await
|
||||
}
|
||||
|
||||
async fn set_iovar_v<const BUFSIZE: usize>(&mut self, name: &str, val: &[u8]) {
|
||||
info!("set {} = {:02x}", name, Bytes(val));
|
||||
|
||||
let mut buf = [0; 64];
|
||||
let mut buf = [0; BUFSIZE];
|
||||
buf[..name.len()].copy_from_slice(name.as_bytes());
|
||||
buf[name.len()] = 0;
|
||||
buf[name.len() + 1..][..val.len()].copy_from_slice(val);
|
||||
|
@ -304,4 +308,61 @@ impl<'a> Control<'a> {
|
|||
|
||||
resp_len
|
||||
}
|
||||
|
||||
pub async fn scan(&mut self) -> Scanner<'_> {
|
||||
const SCANTYPE_PASSIVE: u8 = 1;
|
||||
|
||||
let scan_params = ScanParams {
|
||||
version: 1,
|
||||
action: 1,
|
||||
sync_id: 1,
|
||||
ssid_len: 0,
|
||||
ssid: [0; 32],
|
||||
bssid: [0xff; 6],
|
||||
bss_type: 2,
|
||||
scan_type: SCANTYPE_PASSIVE,
|
||||
nprobes: !0,
|
||||
active_time: !0,
|
||||
passive_time: !0,
|
||||
home_time: !0,
|
||||
channel_num: 0,
|
||||
channel_list: [0; 1],
|
||||
};
|
||||
|
||||
self.events.mask.enable(&[Event::ESCAN_RESULT]);
|
||||
let subscriber = self.events.queue.subscriber().unwrap();
|
||||
self.set_iovar_v::<256>("escan", &scan_params.to_bytes()).await;
|
||||
|
||||
Scanner {
|
||||
subscriber,
|
||||
events: &self.events,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Scanner<'a> {
|
||||
subscriber: EventSubscriber<'a>,
|
||||
events: &'a Events,
|
||||
}
|
||||
|
||||
impl Scanner<'_> {
|
||||
pub async fn next(&mut self) -> Option<BssInfo> {
|
||||
let event = self.subscriber.next_message_pure().await;
|
||||
if event.header.status != EStatus::PARTIAL {
|
||||
self.events.mask.disable_all();
|
||||
return None;
|
||||
}
|
||||
|
||||
if let events::Payload::BssInfo(bss) = event.payload {
|
||||
Some(bss)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Scanner<'_> {
|
||||
fn drop(&mut self) {
|
||||
self.events.mask.disable_all();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#![allow(unused)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use core::cell::RefCell;
|
||||
|
||||
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
||||
use embassy_sync::pubsub::{PubSubChannel, Publisher, Subscriber};
|
||||
use embassy_sync::pubsub::{PubSubChannel, Subscriber};
|
||||
|
||||
use crate::structs::BssInfo;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, num_enum::FromPrimitive)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
|
@ -286,7 +288,6 @@ pub enum Event {
|
|||
|
||||
// TODO this PubSub can probably be replaced with shared memory to make it a bit more efficient.
|
||||
pub type EventQueue = PubSubChannel<NoopRawMutex, Message, 2, 1, 1>;
|
||||
pub type EventPublisher<'a> = Publisher<'a, NoopRawMutex, Message, 2, 1, 1>;
|
||||
pub type EventSubscriber<'a> = Subscriber<'a, NoopRawMutex, Message, 2, 1, 1>;
|
||||
|
||||
pub struct Events {
|
||||
|
@ -313,6 +314,7 @@ pub struct Status {
|
|||
#[derive(Clone, Copy)]
|
||||
pub enum Payload {
|
||||
None,
|
||||
BssInfo(BssInfo),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
|
@ -344,7 +346,7 @@ impl EventMask {
|
|||
let word = n / u32::BITS;
|
||||
let bit = n % u32::BITS;
|
||||
|
||||
self.mask[word as usize] |= (1 << bit);
|
||||
self.mask[word as usize] |= 1 << bit;
|
||||
}
|
||||
|
||||
fn disable(&mut self, event: Event) {
|
||||
|
@ -378,6 +380,7 @@ impl SharedEventMask {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn disable(&self, events: &[Event]) {
|
||||
let mut mask = self.mask.borrow_mut();
|
||||
for event in events {
|
||||
|
|
|
@ -29,6 +29,7 @@ use crate::bus::Bus;
|
|||
pub use crate::bus::SpiBusCyw43;
|
||||
pub use crate::control::Control;
|
||||
pub use crate::runner::Runner;
|
||||
pub use crate::structs::BssInfo;
|
||||
|
||||
const MTU: usize = 1514;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use embedded_hal_1::digital::OutputPin;
|
|||
use crate::bus::Bus;
|
||||
pub use crate::bus::SpiBusCyw43;
|
||||
use crate::consts::*;
|
||||
use crate::events::{Events, Status};
|
||||
use crate::events::{Event, Events, Status};
|
||||
use crate::fmt::Bytes;
|
||||
use crate::ioctl::{IoctlState, IoctlType, PendingIoctl};
|
||||
use crate::nvram::NVRAM;
|
||||
|
@ -351,6 +351,8 @@ where
|
|||
panic!("IOCTL error {}", cdc_header.status as i32);
|
||||
}
|
||||
|
||||
info!("IOCTL Response: {:02x}", Bytes(response));
|
||||
|
||||
self.ioctl_state.ioctl_done(response);
|
||||
}
|
||||
}
|
||||
|
@ -404,7 +406,15 @@ where
|
|||
|
||||
if self.events.mask.is_enabled(evt_type) {
|
||||
let status = event_packet.msg.status;
|
||||
let event_payload = events::Payload::None;
|
||||
let event_payload = match evt_type {
|
||||
Event::ESCAN_RESULT if status == EStatus::PARTIAL => {
|
||||
let Some((_, bss_info)) = ScanResults::parse(evt_data) else { return };
|
||||
let Some(bss_info) = BssInfo::parse(bss_info) else { return };
|
||||
events::Payload::BssInfo(*bss_info)
|
||||
}
|
||||
Event::ESCAN_RESULT => events::Payload::None,
|
||||
_ => events::Payload::None,
|
||||
};
|
||||
|
||||
// this intentionally uses the non-blocking publish immediate
|
||||
// publish() is a deadlock risk in the current design as awaiting here prevents ioctls
|
||||
|
|
|
@ -404,3 +404,84 @@ impl EventMask {
|
|||
self.events[evt / 8] &= !(1 << (evt % 8));
|
||||
}
|
||||
}
|
||||
|
||||
/// Parameters for a wifi scan
|
||||
#[derive(Clone, Copy)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(C)]
|
||||
pub struct ScanParams {
|
||||
pub version: u32,
|
||||
pub action: u16,
|
||||
pub sync_id: u16,
|
||||
pub ssid_len: u32,
|
||||
pub ssid: [u8; 32],
|
||||
pub bssid: [u8; 6],
|
||||
pub bss_type: u8,
|
||||
pub scan_type: u8,
|
||||
pub nprobes: u32,
|
||||
pub active_time: u32,
|
||||
pub passive_time: u32,
|
||||
pub home_time: u32,
|
||||
pub channel_num: u32,
|
||||
pub channel_list: [u16; 1],
|
||||
}
|
||||
impl_bytes!(ScanParams);
|
||||
|
||||
/// Wifi Scan Results Header, followed by `bss_count` `BssInfo`
|
||||
#[derive(Clone, Copy)]
|
||||
// #[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(C, packed(2))]
|
||||
pub struct ScanResults {
|
||||
pub buflen: u32,
|
||||
pub version: u32,
|
||||
pub sync_id: u16,
|
||||
pub bss_count: u16,
|
||||
}
|
||||
impl_bytes!(ScanResults);
|
||||
|
||||
impl ScanResults {
|
||||
pub fn parse(packet: &mut [u8]) -> Option<(&mut ScanResults, &mut [u8])> {
|
||||
if packet.len() < ScanResults::SIZE {
|
||||
return None;
|
||||
}
|
||||
|
||||
let (scan_results, bssinfo) = packet.split_at_mut(ScanResults::SIZE);
|
||||
let scan_results = ScanResults::from_bytes_mut(scan_results.try_into().unwrap());
|
||||
|
||||
if scan_results.bss_count > 0 && bssinfo.len() < BssInfo::SIZE {
|
||||
warn!("Scan result, incomplete BssInfo");
|
||||
return None;
|
||||
}
|
||||
|
||||
Some((scan_results, bssinfo))
|
||||
}
|
||||
}
|
||||
|
||||
/// Wifi Scan Result
|
||||
#[derive(Clone, Copy)]
|
||||
// #[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(C, packed(2))]
|
||||
#[non_exhaustive]
|
||||
pub struct BssInfo {
|
||||
pub version: u32,
|
||||
pub length: u32,
|
||||
pub bssid: [u8; 6],
|
||||
pub beacon_period: u16,
|
||||
pub capability: u16,
|
||||
pub ssid_len: u8,
|
||||
pub ssid: [u8; 32],
|
||||
// there will be more stuff here
|
||||
}
|
||||
impl_bytes!(BssInfo);
|
||||
|
||||
impl BssInfo {
|
||||
pub fn parse(packet: &mut [u8]) -> Option<&mut Self> {
|
||||
if packet.len() < BssInfo::SIZE {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(BssInfo::from_bytes_mut(
|
||||
packet[..BssInfo::SIZE].as_mut().try_into().unwrap(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue