Skip to main content

cyw43/
lib.rs

1#![no_std]
2#![no_main]
3#![allow(async_fn_in_trait)]
4#![allow(unsafe_op_in_unsafe_fn)]
5#![deny(unused_must_use)]
6#![doc = include_str!("../README.md")]
7#![warn(missing_docs)]
8
9// This mod MUST go first, so that the others see its macros.
10pub(crate) mod fmt;
11
12#[cfg(feature = "bluetooth")]
13/// Bluetooth module.
14pub mod bluetooth;
15mod consts;
16mod control;
17mod countries;
18mod events;
19mod ioctl;
20mod runner;
21mod sdio;
22mod spi;
23mod structs;
24mod util;
25
26use core::sync::atomic::AtomicBool;
27
28pub use aligned::{A4, Aligned};
29use embassy_net_driver_channel as ch;
30use embedded_hal_1::digital::OutputPin;
31use events::Events;
32use ioctl::IoctlState;
33
34pub use crate::control::{
35    AddMulticastAddressError, Control, JoinAuth, JoinError, JoinOptions, ScanOptions, ScanType, Scanner,
36};
37pub use crate::runner::Runner;
38pub use crate::sdio::{SdioBus, SdioBusCyw43};
39pub use crate::spi::{SpiBus, SpiBusCyw43};
40pub use crate::structs::BssInfo;
41
42const MTU: usize = 1514;
43
44#[allow(unused)]
45#[derive(Clone, Copy, PartialEq, Eq)]
46enum Core {
47    WLAN = 0,
48    SOCSRAM = 1,
49    SDIOD = 2,
50}
51
52impl Core {
53    fn base_addr(&self) -> u32 {
54        match self {
55            Self::WLAN => CHIP.arm_core_base_address,
56            Self::SOCSRAM => CHIP.socsram_wrapper_base_address,
57            Self::SDIOD => CHIP.sdiod_core_base_address,
58        }
59    }
60}
61
62#[allow(unused)]
63struct Chip {
64    arm_core_base_address: u32,
65    socsram_base_address: u32,
66    bluetooth_base_address: u32,
67    socsram_wrapper_base_address: u32,
68    sdiod_core_base_address: u32,
69    pmu_base_address: u32,
70    chip_ram_size: u32,
71    atcm_ram_base_address: u32,
72    socram_srmem_size: u32,
73    chanspec_band_mask: u32,
74    chanspec_band_2g: u32,
75    chanspec_band_5g: u32,
76    chanspec_band_shift: u32,
77    chanspec_bw_10: u32,
78    chanspec_bw_20: u32,
79    chanspec_bw_40: u32,
80    chanspec_bw_mask: u32,
81    chanspec_bw_shift: u32,
82    chanspec_ctl_sb_lower: u32,
83    chanspec_ctl_sb_upper: u32,
84    chanspec_ctl_sb_none: u32,
85    chanspec_ctl_sb_mask: u32,
86}
87
88const WRAPPER_REGISTER_OFFSET: u32 = 0x100000;
89
90// Data for CYW43439
91const CHIP: Chip = Chip {
92    arm_core_base_address: 0x18003000 + WRAPPER_REGISTER_OFFSET,
93    socsram_base_address: 0x18004000,
94    bluetooth_base_address: 0x19000000,
95    socsram_wrapper_base_address: 0x18004000 + WRAPPER_REGISTER_OFFSET,
96    sdiod_core_base_address: 0x18002000,
97    pmu_base_address: 0x18000000,
98    chip_ram_size: 512 * 1024,
99    atcm_ram_base_address: 0,
100    socram_srmem_size: 64 * 1024,
101    chanspec_band_mask: 0xc000,
102    chanspec_band_2g: 0x0000,
103    chanspec_band_5g: 0xc000,
104    chanspec_band_shift: 14,
105    chanspec_bw_10: 0x0800,
106    chanspec_bw_20: 0x1000,
107    chanspec_bw_40: 0x1800,
108    chanspec_bw_mask: 0x3800,
109    chanspec_bw_shift: 11,
110    chanspec_ctl_sb_lower: 0x0000,
111    chanspec_ctl_sb_upper: 0x0100,
112    chanspec_ctl_sb_none: 0x0000,
113    chanspec_ctl_sb_mask: 0x0700,
114};
115
116/// Driver state.
117pub struct State {
118    ioctl_state: IoctlState,
119    net: NetState,
120    #[cfg(feature = "bluetooth")]
121    bt: bluetooth::BtState,
122}
123
124struct NetState {
125    ch: ch::State<MTU, 4, 4>,
126    events: Events,
127    secure_network: AtomicBool,
128}
129
130impl State {
131    /// Create new driver state holder.
132    pub const fn new() -> Self {
133        Self {
134            ioctl_state: IoctlState::new(),
135            net: NetState {
136                ch: ch::State::new(),
137                events: Events::new(),
138                secure_network: AtomicBool::new(false),
139            },
140            #[cfg(feature = "bluetooth")]
141            bt: bluetooth::BtState::new(),
142        }
143    }
144}
145
146/// Power management modes.
147#[derive(Debug, Clone, Copy, PartialEq, Eq)]
148pub enum PowerManagementMode {
149    /// Custom, officially unsupported mode. Use at your own risk.
150    /// All power-saving features set to their max at only a marginal decrease in power consumption
151    /// as oppposed to `Aggressive`.
152    SuperSave,
153
154    /// Aggressive power saving mode.
155    Aggressive,
156
157    /// The default mode.
158    PowerSave,
159
160    /// Performance is prefered over power consumption but still some power is conserved as opposed to
161    /// `None`.
162    Performance,
163
164    /// Unlike all the other PM modes, this lowers the power consumption at all times at the cost of
165    /// a much lower throughput.
166    ThroughputThrottling,
167
168    /// No power management is configured. This consumes the most power.
169    None,
170}
171
172impl Default for PowerManagementMode {
173    fn default() -> Self {
174        Self::PowerSave
175    }
176}
177
178impl PowerManagementMode {
179    fn sleep_ret_ms(&self) -> u16 {
180        match self {
181            PowerManagementMode::SuperSave => 2000,
182            PowerManagementMode::Aggressive => 2000,
183            PowerManagementMode::PowerSave => 200,
184            PowerManagementMode::Performance => 20,
185            PowerManagementMode::ThroughputThrottling => 0, // value doesn't matter
186            PowerManagementMode::None => 0,                 // value doesn't matter
187        }
188    }
189
190    fn beacon_period(&self) -> u8 {
191        match self {
192            PowerManagementMode::SuperSave => 255,
193            PowerManagementMode::Aggressive => 1,
194            PowerManagementMode::PowerSave => 1,
195            PowerManagementMode::Performance => 1,
196            PowerManagementMode::ThroughputThrottling => 0, // value doesn't matter
197            PowerManagementMode::None => 0,                 // value doesn't matter
198        }
199    }
200
201    fn dtim_period(&self) -> u8 {
202        match self {
203            PowerManagementMode::SuperSave => 255,
204            PowerManagementMode::Aggressive => 1,
205            PowerManagementMode::PowerSave => 1,
206            PowerManagementMode::Performance => 1,
207            PowerManagementMode::ThroughputThrottling => 0, // value doesn't matter
208            PowerManagementMode::None => 0,                 // value doesn't matter
209        }
210    }
211
212    fn assoc(&self) -> u8 {
213        match self {
214            PowerManagementMode::SuperSave => 255,
215            PowerManagementMode::Aggressive => 10,
216            PowerManagementMode::PowerSave => 10,
217            PowerManagementMode::Performance => 1,
218            PowerManagementMode::ThroughputThrottling => 0, // value doesn't matter
219            PowerManagementMode::None => 0,                 // value doesn't matter
220        }
221    }
222
223    fn mode(&self) -> u32 {
224        match self {
225            PowerManagementMode::ThroughputThrottling => 1,
226            PowerManagementMode::None => 0,
227            _ => 2,
228        }
229    }
230}
231
232/// Embassy-net driver.
233pub type NetDriver<'a> = ch::Device<'a, MTU>;
234
235/// Create a new instance of the CYW43 driver.
236///
237/// Returns a handle to the network device, control handle and a runner for driving the low level
238/// stack.
239pub async fn new<'a, PWR, SPI>(
240    state: &'a mut State,
241    pwr: PWR,
242    spi: SPI,
243    firmware: &Aligned<A4, [u8]>,
244    nvram: &Aligned<A4, [u8]>,
245) -> (NetDriver<'a>, Control<'a>, Runner<'a, SpiBus<PWR, SPI>>)
246where
247    PWR: OutputPin,
248    SPI: SpiBusCyw43,
249{
250    let (ch_runner, device) = ch::new(&mut state.net.ch, ch::driver::HardwareAddress::Ethernet([0; 6]));
251    let state_ch = ch_runner.state_runner();
252
253    let mut runner = Runner::new(
254        ch_runner,
255        SpiBus::new(pwr, spi),
256        &state.ioctl_state,
257        &state.net.events,
258        &state.net.secure_network,
259        #[cfg(feature = "bluetooth")]
260        None,
261    );
262
263    runner.init(firmware, nvram, None).await.unwrap();
264    let control = Control::new(
265        state_ch,
266        &state.net.events,
267        &state.ioctl_state,
268        &state.net.secure_network,
269    );
270
271    (device, control, runner)
272}
273
274/// Create a new instance of the CYW43 driver.
275///
276/// Returns a handle to the network device, control handle and a runner for driving the low level
277/// stack.
278pub async fn new_sdio<'a, SDIO>(
279    state: &'a mut State,
280    sdio: SDIO,
281    firmware: &Aligned<A4, [u8]>,
282    nvram: &Aligned<A4, [u8]>,
283) -> (NetDriver<'a>, Control<'a>, Runner<'a, SdioBus<SDIO>>)
284where
285    SDIO: SdioBusCyw43<64>,
286{
287    let (ch_runner, device) = ch::new(&mut state.net.ch, ch::driver::HardwareAddress::Ethernet([0; 6]));
288    let state_ch = ch_runner.state_runner();
289
290    let mut runner = Runner::new(
291        ch_runner,
292        SdioBus::new(sdio),
293        &state.ioctl_state,
294        &state.net.events,
295        &state.net.secure_network,
296        #[cfg(feature = "bluetooth")]
297        None,
298    );
299
300    runner.init(firmware, nvram, None).await.unwrap();
301    let control = Control::new(
302        state_ch,
303        &state.net.events,
304        &state.ioctl_state,
305        &state.net.secure_network,
306    );
307
308    (device, control, runner)
309}
310
311/// Create a new instance of the CYW43 driver.
312///
313/// Returns a handle to the network device, control handle and a runner for driving the low level
314/// stack.
315#[cfg(feature = "bluetooth")]
316pub async fn new_with_bluetooth<'a, PWR, SPI>(
317    state: &'a mut State,
318    pwr: PWR,
319    spi: SPI,
320    wifi_firmware: &Aligned<A4, [u8]>,
321    bluetooth_firmware: &Aligned<A4, [u8]>,
322    nvram: &Aligned<A4, [u8]>,
323) -> (
324    NetDriver<'a>,
325    bluetooth::BtDriver<'a>,
326    Control<'a>,
327    Runner<'a, SpiBus<PWR, SPI>>,
328)
329where
330    PWR: OutputPin,
331    SPI: SpiBusCyw43,
332{
333    let (ch_runner, device) = ch::new(&mut state.net.ch, ch::driver::HardwareAddress::Ethernet([0; 6]));
334    let state_ch = ch_runner.state_runner();
335
336    let (bt_runner, bt_driver) = bluetooth::new(&mut state.bt);
337    let mut runner = Runner::new(
338        ch_runner,
339        SpiBus::new(pwr, spi),
340        &state.ioctl_state,
341        &state.net.events,
342        &state.net.secure_network,
343        #[cfg(feature = "bluetooth")]
344        Some(bt_runner),
345    );
346
347    runner
348        .init(wifi_firmware, nvram, Some(bluetooth_firmware))
349        .await
350        .unwrap();
351    let control = Control::new(
352        state_ch,
353        &state.net.events,
354        &state.ioctl_state,
355        &state.net.secure_network,
356    );
357
358    (device, bt_driver, control, runner)
359}
360
361/// Include bytes aligned to A4 in the binary
362#[macro_export]
363macro_rules! aligned_bytes {
364    ($path:expr) => {{
365        {
366            static BYTES: &cyw43::Aligned<cyw43::A4, [u8]> = &cyw43::Aligned(*include_bytes!($path));
367
368            BYTES
369        }
370    }};
371}