#![no_std]
#![no_main]
#![allow(async_fn_in_trait)]
#![allow(unsafe_op_in_unsafe_fn)]
#![deny(unused_must_use)]
#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
pub(crate) mod fmt;
#[cfg(feature = "bluetooth")]
pub mod bluetooth;
mod consts;
mod control;
mod countries;
mod events;
mod ioctl;
mod runner;
mod sdio;
mod spi;
mod structs;
mod util;
use core::sync::atomic::AtomicBool;
pub use aligned::{A4, Aligned};
use embassy_net_driver_channel as ch;
use embedded_hal_1::digital::OutputPin;
use events::Events;
use ioctl::IoctlState;
pub use crate::control::{
AddMulticastAddressError, Control, JoinAuth, JoinError, JoinOptions, ScanOptions, ScanType, Scanner,
};
pub use crate::runner::Runner;
pub use crate::sdio::{SdioBus, SdioBusCyw43};
pub use crate::spi::{SpiBus, SpiBusCyw43};
pub use crate::structs::BssInfo;
const MTU: usize = 1514;
#[allow(unused)]
#[derive(Clone, Copy, PartialEq, Eq)]
enum Core {
WLAN = 0,
SOCSRAM = 1,
SDIOD = 2,
}
impl Core {
fn base_addr(&self) -> u32 {
match self {
Self::WLAN => CHIP.arm_core_base_address,
Self::SOCSRAM => CHIP.socsram_wrapper_base_address,
Self::SDIOD => CHIP.sdiod_core_base_address,
}
}
}
#[allow(unused)]
struct Chip {
arm_core_base_address: u32,
socsram_base_address: u32,
bluetooth_base_address: u32,
socsram_wrapper_base_address: u32,
sdiod_core_base_address: u32,
pmu_base_address: u32,
chip_ram_size: u32,
atcm_ram_base_address: u32,
socram_srmem_size: u32,
chanspec_band_mask: u32,
chanspec_band_2g: u32,
chanspec_band_5g: u32,
chanspec_band_shift: u32,
chanspec_bw_10: u32,
chanspec_bw_20: u32,
chanspec_bw_40: u32,
chanspec_bw_mask: u32,
chanspec_bw_shift: u32,
chanspec_ctl_sb_lower: u32,
chanspec_ctl_sb_upper: u32,
chanspec_ctl_sb_none: u32,
chanspec_ctl_sb_mask: u32,
}
const WRAPPER_REGISTER_OFFSET: u32 = 0x100000;
const CHIP: Chip = Chip {
arm_core_base_address: 0x18003000 + WRAPPER_REGISTER_OFFSET,
socsram_base_address: 0x18004000,
bluetooth_base_address: 0x19000000,
socsram_wrapper_base_address: 0x18004000 + WRAPPER_REGISTER_OFFSET,
sdiod_core_base_address: 0x18002000,
pmu_base_address: 0x18000000,
chip_ram_size: 512 * 1024,
atcm_ram_base_address: 0,
socram_srmem_size: 64 * 1024,
chanspec_band_mask: 0xc000,
chanspec_band_2g: 0x0000,
chanspec_band_5g: 0xc000,
chanspec_band_shift: 14,
chanspec_bw_10: 0x0800,
chanspec_bw_20: 0x1000,
chanspec_bw_40: 0x1800,
chanspec_bw_mask: 0x3800,
chanspec_bw_shift: 11,
chanspec_ctl_sb_lower: 0x0000,
chanspec_ctl_sb_upper: 0x0100,
chanspec_ctl_sb_none: 0x0000,
chanspec_ctl_sb_mask: 0x0700,
};
pub struct State {
ioctl_state: IoctlState,
net: NetState,
#[cfg(feature = "bluetooth")]
bt: bluetooth::BtState,
}
struct NetState {
ch: ch::State<MTU, 4, 4>,
events: Events,
secure_network: AtomicBool,
}
impl State {
pub const fn new() -> Self {
Self {
ioctl_state: IoctlState::new(),
net: NetState {
ch: ch::State::new(),
events: Events::new(),
secure_network: AtomicBool::new(false),
},
#[cfg(feature = "bluetooth")]
bt: bluetooth::BtState::new(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PowerManagementMode {
SuperSave,
Aggressive,
PowerSave,
Performance,
ThroughputThrottling,
None,
}
impl Default for PowerManagementMode {
fn default() -> Self {
Self::PowerSave
}
}
impl PowerManagementMode {
fn sleep_ret_ms(&self) -> u16 {
match self {
PowerManagementMode::SuperSave => 2000,
PowerManagementMode::Aggressive => 2000,
PowerManagementMode::PowerSave => 200,
PowerManagementMode::Performance => 20,
PowerManagementMode::ThroughputThrottling => 0, PowerManagementMode::None => 0, }
}
fn beacon_period(&self) -> u8 {
match self {
PowerManagementMode::SuperSave => 255,
PowerManagementMode::Aggressive => 1,
PowerManagementMode::PowerSave => 1,
PowerManagementMode::Performance => 1,
PowerManagementMode::ThroughputThrottling => 0, PowerManagementMode::None => 0, }
}
fn dtim_period(&self) -> u8 {
match self {
PowerManagementMode::SuperSave => 255,
PowerManagementMode::Aggressive => 1,
PowerManagementMode::PowerSave => 1,
PowerManagementMode::Performance => 1,
PowerManagementMode::ThroughputThrottling => 0, PowerManagementMode::None => 0, }
}
fn assoc(&self) -> u8 {
match self {
PowerManagementMode::SuperSave => 255,
PowerManagementMode::Aggressive => 10,
PowerManagementMode::PowerSave => 10,
PowerManagementMode::Performance => 1,
PowerManagementMode::ThroughputThrottling => 0, PowerManagementMode::None => 0, }
}
fn mode(&self) -> u32 {
match self {
PowerManagementMode::ThroughputThrottling => 1,
PowerManagementMode::None => 0,
_ => 2,
}
}
}
pub type NetDriver<'a> = ch::Device<'a, MTU>;
pub async fn new<'a, PWR, SPI>(
state: &'a mut State,
pwr: PWR,
spi: SPI,
firmware: &Aligned<A4, [u8]>,
nvram: &Aligned<A4, [u8]>,
) -> (NetDriver<'a>, Control<'a>, Runner<'a, SpiBus<PWR, SPI>>)
where
PWR: OutputPin,
SPI: SpiBusCyw43,
{
let (ch_runner, device) = ch::new(&mut state.net.ch, ch::driver::HardwareAddress::Ethernet([0; 6]));
let state_ch = ch_runner.state_runner();
let mut runner = Runner::new(
ch_runner,
SpiBus::new(pwr, spi),
&state.ioctl_state,
&state.net.events,
&state.net.secure_network,
#[cfg(feature = "bluetooth")]
None,
);
runner.init(firmware, nvram, None).await.unwrap();
let control = Control::new(
state_ch,
&state.net.events,
&state.ioctl_state,
&state.net.secure_network,
);
(device, control, runner)
}
pub async fn new_sdio<'a, SDIO>(
state: &'a mut State,
sdio: SDIO,
firmware: &Aligned<A4, [u8]>,
nvram: &Aligned<A4, [u8]>,
) -> (NetDriver<'a>, Control<'a>, Runner<'a, SdioBus<SDIO>>)
where
SDIO: SdioBusCyw43<64>,
{
let (ch_runner, device) = ch::new(&mut state.net.ch, ch::driver::HardwareAddress::Ethernet([0; 6]));
let state_ch = ch_runner.state_runner();
let mut runner = Runner::new(
ch_runner,
SdioBus::new(sdio),
&state.ioctl_state,
&state.net.events,
&state.net.secure_network,
#[cfg(feature = "bluetooth")]
None,
);
runner.init(firmware, nvram, None).await.unwrap();
let control = Control::new(
state_ch,
&state.net.events,
&state.ioctl_state,
&state.net.secure_network,
);
(device, control, runner)
}
#[cfg(feature = "bluetooth")]
pub async fn new_with_bluetooth<'a, PWR, SPI>(
state: &'a mut State,
pwr: PWR,
spi: SPI,
wifi_firmware: &Aligned<A4, [u8]>,
bluetooth_firmware: &Aligned<A4, [u8]>,
nvram: &Aligned<A4, [u8]>,
) -> (
NetDriver<'a>,
bluetooth::BtDriver<'a>,
Control<'a>,
Runner<'a, SpiBus<PWR, SPI>>,
)
where
PWR: OutputPin,
SPI: SpiBusCyw43,
{
let (ch_runner, device) = ch::new(&mut state.net.ch, ch::driver::HardwareAddress::Ethernet([0; 6]));
let state_ch = ch_runner.state_runner();
let (bt_runner, bt_driver) = bluetooth::new(&mut state.bt);
let mut runner = Runner::new(
ch_runner,
SpiBus::new(pwr, spi),
&state.ioctl_state,
&state.net.events,
&state.net.secure_network,
#[cfg(feature = "bluetooth")]
Some(bt_runner),
);
runner
.init(wifi_firmware, nvram, Some(bluetooth_firmware))
.await
.unwrap();
let control = Control::new(
state_ch,
&state.net.events,
&state.ioctl_state,
&state.net.secure_network,
);
(device, bt_driver, control, runner)
}
#[macro_export]
macro_rules! aligned_bytes {
($path:expr) => {{
{
static BYTES: &cyw43::Aligned<cyw43::A4, [u8]> = &cyw43::Aligned(*include_bytes!($path));
BYTES
}
}};
}