Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions esp-radio/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `connect_async` now returns `Ok(ConnectedStationInfo)` on success, providing detailed information about the connection. (#4898)
- `disconnect_async` now returns `Ok(DisconnectedStationInfo)`. (#4898)
- `WifiError::Disconnected` is now a tuple-like enum variant `WifiError::Disconnected(DisconnectedStationInfo)` containing details about the disconnection. (#4898)
- Various structs now use the `Ssid` type to represent SSIDs instead of `String` (#4953)

### Fixed

Expand Down
25 changes: 25 additions & 0 deletions esp-radio/MIGRATING-0.17.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,28 @@ Previously, you would wait for `AccessPointStationConnected` or `AccessPointStat
+ }
+ }
```

## SSID Type Change

The API has been updated to use a dedicated SSID type instead of String for SSID values.

Builders now take `Into<Ssid>` instead of a String.

e.g.

```diff
let station_config = Config::Station(
StationConfig::default()
- .with_ssid("MyNetwork".into()) // Used .into() to convert to String
+ .with_ssid("MyNetwork") // Ssid implements From<&str>
.with_password("password".into()),
);
```

Migration Steps

1. Remove `.into()` calls: Remove .into() calls when passing SSIDs to configuration methods:
- Change .with_ssid("network".into()) to .with_ssid("network")

2. Update SSID access: When retrieving SSIDs from structs or events, use .as_str() to get the string representation:
- Change ssid_value to ssid_value.as_str() when you need a string slice
20 changes: 12 additions & 8 deletions esp-radio/src/wifi/ap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use core::fmt;
use enumset::EnumSet;
use procmacros::BuilderLite;

use super::{AuthenticationMethod, CountryInfo, Protocol, SecondaryChannel};
use super::{AuthenticationMethod, CountryInfo, Protocol, SecondaryChannel, Ssid};
use crate::{WifiError, sys::include::wifi_ap_record_t};

/// Information about a detected Wi-Fi access point.
Expand All @@ -15,9 +15,7 @@ use crate::{WifiError, sys::include::wifi_ap_record_t};
#[non_exhaustive]
pub struct AccessPointInfo {
/// The SSID of the access point.
// TODO: we can use the `alloc` feature once we have `defmt` 1.0.2
#[cfg_attr(feature = "defmt", defmt(Debug2Format))]
pub ssid: String,
pub ssid: Ssid,
/// The BSSID (MAC address) of the access point.
pub bssid: [u8; 6],
/// The channel the access point is operating on.
Expand All @@ -36,8 +34,8 @@ pub struct AccessPointInfo {
#[derive(Clone, PartialEq, Eq, BuilderLite, Hash)]
pub struct AccessPointConfig {
/// The SSID of the access point.
#[builder_lite(reference)]
pub(crate) ssid: String,
#[builder_lite(skip_setter)]
pub(crate) ssid: Ssid,
/// Whether the SSID is hidden or visible.
pub(crate) ssid_hidden: bool,
/// The channel the access point will operate on.
Expand All @@ -61,6 +59,12 @@ pub struct AccessPointConfig {
}

impl AccessPointConfig {
/// Set the SSID of the access point.
pub fn with_ssid(mut self, ssid: impl Into<Ssid>) -> Self {
self.ssid = ssid.into();
self
}

pub(crate) fn validate(&self) -> Result<(), WifiError> {
if self.ssid.len() > 32 {
return Err(WifiError::InvalidArguments);
Expand All @@ -81,7 +85,7 @@ impl AccessPointConfig {
impl Default for AccessPointConfig {
fn default() -> Self {
Self {
ssid: String::from("iot-device"),
ssid: "iot-device".into(),
ssid_hidden: false,
channel: 1,
secondary_channel: None,
Expand Down Expand Up @@ -149,7 +153,7 @@ pub(crate) fn convert_ap_info(record: &wifi_ap_record_t) -> AccessPointInfo {
.iter()
.position(|&c| c == 0)
.unwrap_or(record.ssid.len());
let ssid = alloc::string::String::from_utf8_lossy(&record.ssid[..str_len]).into_owned();
let ssid = Ssid::from(&record.ssid[..str_len]);

AccessPointInfo {
ssid,
Expand Down
21 changes: 9 additions & 12 deletions esp-radio/src/wifi/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use esp_config::esp_config_int;
use esp_sync::NonReentrantMutex;
use num_derive::FromPrimitive;

use super::Ssid;
use crate::wifi::include::{
wifi_event_sta_wps_er_success_t__bindgen_ty_1,
wifi_ftm_report_entry_t,
Expand Down Expand Up @@ -801,7 +802,7 @@ pub struct FineTimingMeasurementReportInfo {
#[instability::unstable]
pub struct CredentialsInfo {
/// SSID of AP
pub ssid: [u8; 32usize],
pub ssid: Ssid,
/// Passphrase for the AP
pub passphrase: [u8; 64usize],
}
Expand Down Expand Up @@ -853,9 +854,7 @@ pub enum EventInfo {
/// Station connected to a network.
StationConnected {
/// SSID of connected AP
ssid: [u8; 32usize],
/// SSID length of connected AP
ssid_len: u8,
ssid: Ssid,
/// BSSID of connected AP
bssid: [u8; 6usize],
/// Channel of connected AP
Expand All @@ -869,9 +868,7 @@ pub enum EventInfo {
/// Station disconnected from a network.
StationDisconnected {
/// SSID of disconnected AP
ssid: [u8; 32usize],
/// SSID length of disconnected AP
ssid_len: u8,
ssid: Ssid,
/// BSSID of disconnected AP
bssid: [u8; 6usize],
/// Disconnection reason
Expand Down Expand Up @@ -1079,8 +1076,7 @@ impl EventInfo {
let ev = unsafe { StationConnected::from_raw_event_data(payload) };

Some(EventInfo::StationConnected {
ssid: ev.ssid().try_into().unwrap(),
ssid_len: ev.ssid_len(),
ssid: Ssid::from_raw(ev.ssid(), ev.ssid_len()),
bssid: ev.bssid().try_into().unwrap(),
channel: ev.channel(),
authmode: ev.authmode(),
Expand All @@ -1090,8 +1086,7 @@ impl EventInfo {
WifiEvent::StationDisconnected => {
let ev = unsafe { StationDisconnected::from_raw_event_data(payload) };
Some(EventInfo::StationDisconnected {
ssid: ev.ssid().try_into().unwrap(),
ssid_len: ev.ssid_len(),
ssid: Ssid::from_raw(ev.ssid(), ev.ssid_len()),
bssid: ev.bssid().try_into().unwrap(),
reason: ev.reason() as u16,
rssi: ev.rssi(),
Expand Down Expand Up @@ -1131,7 +1126,7 @@ impl EventInfo {
credentials: Collection(ev
.access_point_cred()[..ev.access_point_cred_cnt() as usize].iter()
.map(|cred| CredentialsInfo {
ssid: cred.ssid().try_into().unwrap(),
ssid: cred.ssid().into(),
passphrase: cred.passphrase().try_into().unwrap(),
})
.collect()),
Expand Down Expand Up @@ -1295,6 +1290,8 @@ pub fn enable_wifi_events(events: EnumSet<WifiEvent>) {
/// - [WifiEvent::StationDisconnected]
/// - [WifiEvent::AccessPointStart]
/// - [WifiEvent::AccessPointStop]
/// - [WifiEvent::AccessPointStationConnected]
/// - [WifiEvent::AccessPointStationDisconnected]
/// - [WifiEvent::ScanDone]
///
/// [crate::wifi::new] always enables these events, even if they were disabled beforehand.
Expand Down
76 changes: 55 additions & 21 deletions esp-radio/src/wifi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#![deny(missing_docs)]

use alloc::{collections::vec_deque::VecDeque, vec::Vec};
use alloc::{borrow::ToOwned, collections::vec_deque::VecDeque, str, vec::Vec};
use core::{
fmt::{Debug, Write},
marker::PhantomData,
Expand Down Expand Up @@ -595,7 +595,7 @@ impl DisconnectReason {
}

/// Information about a connected station.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Ssid {
ssid: [u8; 32],
Expand All @@ -609,10 +609,7 @@ impl Ssid {
let len = usize::min(32, bytes.len());
ssid_bytes[..len].copy_from_slice(bytes);

Self {
ssid: ssid_bytes,
len: len as u8,
}
Self::from_raw(&ssid_bytes, len as u8)
}

pub(crate) fn from_raw(ssid: &[u8], len: u8) -> Self {
Expand All @@ -621,14 +618,35 @@ impl Ssid {
ssid_bytes[..len].copy_from_slice(&ssid[..len]);

Self {
ssid: ssid.try_into().unwrap(),
ssid: ssid_bytes,
len: len as u8,
}
}

pub(crate) fn as_bytes(&self) -> &[u8] {
&self.ssid[..self.len as usize]
}

/// The length (in bytes) of the SSID.
pub fn len(&self) -> usize {
self.len as usize
}

/// Returns true if the SSID is empty.
pub fn is_empty(&self) -> bool {
self.len == 0
}

/// The SSID as a string slice.
pub fn as_str(&self) -> &str {
unsafe { str::from_utf8_unchecked(&self.ssid[..self.len as usize]) }
let part = &self.ssid[..self.len as usize];
match str::from_utf8(part) {
Ok(s) => s,
Err(e) => {
let (valid, _) = part.split_at(e.valid_up_to());
unsafe { str::from_utf8_unchecked(valid) }
}
}
}
}

Expand All @@ -640,6 +658,24 @@ impl Debug for Ssid {
}
}

impl From<alloc::string::String> for Ssid {
fn from(ssid: alloc::string::String) -> Self {
Self::new(&ssid)
}
}

impl From<&str> for Ssid {
fn from(ssid: &str) -> Self {
Self::new(ssid)
}
}

impl From<&[u8]> for Ssid {
fn from(ssid: &[u8]) -> Self {
Self::from_raw(ssid, ssid.len() as u8)
}
}

/// Information about a connected station.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
Expand Down Expand Up @@ -1059,7 +1095,7 @@ pub(crate) fn wifi_start_scan(
show_hidden,
scan_type,
..
}: ScanConfig<'_>,
}: ScanConfig,
) -> i32 {
scan_type.validate();
let (scan_time, scan_type) = match scan_type {
Expand All @@ -1083,7 +1119,7 @@ pub(crate) fn wifi_start_scan(
};

let mut ssid_buf = ssid.map(|m| {
let mut buf = Vec::from_iter(m.bytes());
let mut buf = Vec::from_iter(m.as_bytes().to_owned());
buf.push(b'\0');
buf
});
Expand Down Expand Up @@ -2051,6 +2087,8 @@ pub fn new<'d>(
| WifiEvent::StationDisconnected
| WifiEvent::AccessPointStart
| WifiEvent::AccessPointStop
| WifiEvent::AccessPointStationConnected
| WifiEvent::AccessPointStationDisconnected
| WifiEvent::ScanDone,
);

Expand Down Expand Up @@ -2196,7 +2234,7 @@ impl WifiController<'_> {
/// esp_radio::wifi::new(peripherals.WIFI, Default::default())?;
///
/// wifi_controller.set_config(&Config::AccessPoint(
/// AccessPointConfig::default().with_ssid("esp-radio".into()),
/// AccessPointConfig::default().with_ssid("esp-radio"),
/// ))?;
///
/// wifi_controller.set_protocol(Protocol::P802D11BGNLR.into());
Expand Down Expand Up @@ -2365,7 +2403,7 @@ impl WifiController<'_> {
/// # esp_radio::wifi::new(peripherals.WIFI, Default::default())?;
/// let station_config = Config::Station(
/// StationConfig::default()
/// .with_ssid("SSID".into())
/// .with_ssid("SSID")
/// .with_password("PASSWORD".into()),
/// );
///
Expand Down Expand Up @@ -2630,7 +2668,7 @@ impl WifiController<'_> {
/// ```
pub async fn scan_with_config_async(
&mut self,
config: ScanConfig<'_>,
config: ScanConfig,
) -> Result<Vec<AccessPointInfo>, WifiError> {
let mut subscriber = EVENT_CHANNEL
.subscriber()
Expand Down Expand Up @@ -2854,26 +2892,24 @@ impl WifiController<'_> {
match result {
event::EventInfo::StationConnected {
ssid,
ssid_len,
bssid,
channel,
authmode,
aid,
} => Ok(ConnectedStationInfo {
ssid: Ssid::from_raw(&ssid, ssid_len),
ssid,
bssid,
channel,
authmode: AuthenticationMethod::from_raw(authmode),
aid,
}),
event::EventInfo::StationDisconnected {
ssid,
ssid_len,
bssid,
reason,
rssi,
} => Err(WifiError::Disconnected(DisconnectedStationInfo {
ssid: Ssid::from_raw(&ssid, ssid_len),
ssid,
bssid,
reason: DisconnectReason::from_raw(reason),
rssi,
Expand Down Expand Up @@ -2922,14 +2958,13 @@ impl WifiController<'_> {

if let event::EventInfo::StationDisconnected {
ssid,
ssid_len,
bssid,
reason,
rssi,
} = event
{
break Ok(DisconnectedStationInfo {
ssid: Ssid::from_raw(&ssid, ssid_len),
ssid,
bssid,
reason: DisconnectReason::from_raw(reason),
rssi,
Expand All @@ -2955,14 +2990,13 @@ impl WifiController<'_> {

if let event::EventInfo::StationDisconnected {
ssid,
ssid_len,
bssid,
reason,
rssi,
} = event
{
break Ok(DisconnectedStationInfo {
ssid: Ssid::from_raw(&ssid, ssid_len),
ssid,
bssid,
reason: DisconnectReason::from_raw(reason),
rssi,
Expand Down
Loading