wifi scan ioctl
This commit is contained in:
parent
c19de29847
commit
2c5d94493c
@ -143,4 +143,3 @@ async fn main(spawner: Spawner) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,11 +6,11 @@ use embassy_time::{Duration, Timer};
|
|||||||
|
|
||||||
pub use crate::bus::SpiBusCyw43;
|
pub use crate::bus::SpiBusCyw43;
|
||||||
use crate::consts::*;
|
use crate::consts::*;
|
||||||
use crate::events::{Event, Events};
|
use crate::events::{Event, EventSubscriber, Events};
|
||||||
use crate::fmt::Bytes;
|
use crate::fmt::Bytes;
|
||||||
use crate::ioctl::{IoctlState, IoctlType};
|
use crate::ioctl::{IoctlState, IoctlType};
|
||||||
use crate::structs::*;
|
use crate::structs::*;
|
||||||
use crate::{countries, PowerManagementMode};
|
use crate::{countries, events, PowerManagementMode};
|
||||||
|
|
||||||
pub struct Control<'a> {
|
pub struct Control<'a> {
|
||||||
state_ch: ch::StateRunner<'a>,
|
state_ch: ch::StateRunner<'a>,
|
||||||
@ -245,9 +245,13 @@ impl<'a> Control<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn set_iovar(&mut self, name: &str, val: &[u8]) {
|
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));
|
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()].copy_from_slice(name.as_bytes());
|
||||||
buf[name.len()] = 0;
|
buf[name.len()] = 0;
|
||||||
buf[name.len() + 1..][..val.len()].copy_from_slice(val);
|
buf[name.len() + 1..][..val.len()].copy_from_slice(val);
|
||||||
@ -304,4 +308,61 @@ impl<'a> Control<'a> {
|
|||||||
|
|
||||||
resp_len
|
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)]
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
|
|
||||||
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
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)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, num_enum::FromPrimitive)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[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.
|
// 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 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 type EventSubscriber<'a> = Subscriber<'a, NoopRawMutex, Message, 2, 1, 1>;
|
||||||
|
|
||||||
pub struct Events {
|
pub struct Events {
|
||||||
@ -313,6 +314,7 @@ pub struct Status {
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum Payload {
|
pub enum Payload {
|
||||||
None,
|
None,
|
||||||
|
BssInfo(BssInfo),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
@ -344,7 +346,7 @@ impl EventMask {
|
|||||||
let word = n / u32::BITS;
|
let word = n / u32::BITS;
|
||||||
let bit = 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) {
|
fn disable(&mut self, event: Event) {
|
||||||
@ -378,6 +380,7 @@ impl SharedEventMask {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn disable(&self, events: &[Event]) {
|
pub fn disable(&self, events: &[Event]) {
|
||||||
let mut mask = self.mask.borrow_mut();
|
let mut mask = self.mask.borrow_mut();
|
||||||
for event in events {
|
for event in events {
|
||||||
|
@ -29,6 +29,7 @@ use crate::bus::Bus;
|
|||||||
pub use crate::bus::SpiBusCyw43;
|
pub use crate::bus::SpiBusCyw43;
|
||||||
pub use crate::control::Control;
|
pub use crate::control::Control;
|
||||||
pub use crate::runner::Runner;
|
pub use crate::runner::Runner;
|
||||||
|
pub use crate::structs::BssInfo;
|
||||||
|
|
||||||
const MTU: usize = 1514;
|
const MTU: usize = 1514;
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ use embedded_hal_1::digital::OutputPin;
|
|||||||
use crate::bus::Bus;
|
use crate::bus::Bus;
|
||||||
pub use crate::bus::SpiBusCyw43;
|
pub use crate::bus::SpiBusCyw43;
|
||||||
use crate::consts::*;
|
use crate::consts::*;
|
||||||
use crate::events::{Events, Status};
|
use crate::events::{Event, Events, Status};
|
||||||
use crate::fmt::Bytes;
|
use crate::fmt::Bytes;
|
||||||
use crate::ioctl::{IoctlState, IoctlType, PendingIoctl};
|
use crate::ioctl::{IoctlState, IoctlType, PendingIoctl};
|
||||||
use crate::nvram::NVRAM;
|
use crate::nvram::NVRAM;
|
||||||
@ -351,6 +351,8 @@ where
|
|||||||
panic!("IOCTL error {}", cdc_header.status as i32);
|
panic!("IOCTL error {}", cdc_header.status as i32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info!("IOCTL Response: {:02x}", Bytes(response));
|
||||||
|
|
||||||
self.ioctl_state.ioctl_done(response);
|
self.ioctl_state.ioctl_done(response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -404,7 +406,15 @@ where
|
|||||||
|
|
||||||
if self.events.mask.is_enabled(evt_type) {
|
if self.events.mask.is_enabled(evt_type) {
|
||||||
let status = event_packet.msg.status;
|
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
|
// this intentionally uses the non-blocking publish immediate
|
||||||
// publish() is a deadlock risk in the current design as awaiting here prevents ioctls
|
// 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));
|
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 New Issue
Block a user