use crate::errors::CommError as Error;
use embedded_nal::nb;
use crate::manager::{
AccessPoint, AuthType, BootMode, BootState, Credentials, FirmwareInfo, HostName, IPConf,
MacAddress, ProvisioningInfo, ScanResult, SocketOptions, Ssid, TcpSockOpts, UdpSockOpts,
WifiChannel, WifiConnError,
};
#[cfg(feature = "ssl")]
use crate::manager::{SslSockConfig, SslSockOpts};
use crate::stack::{sock_holder::SocketStore, socket_callbacks::WifiModuleState};
use super::{Handle, PingResult, StackError, WincClient, Xfer};
use crate::{error, info};
const AP_CONNECT_TIMEOUT_MILLISECONDS: u32 = 60_000;
const AP_DISCONNECT_TIMEOUT_MILLISECONDS: u32 = 5_000;
#[cfg(not(test))]
const PROVISIONING_TIMEOUT: u32 = 60 * 1000;
#[cfg(test)]
const PROVISIONING_TIMEOUT: u32 = 1000;
impl<X: Xfer> WincClient<'_, X> {
pub fn heartbeat(&mut self) -> Result<(), StackError> {
self.dispatch_events()?;
Ok(())
}
fn start_wifi_module_impl(&mut self, boot_mode: BootMode) -> nb::Result<(), StackError> {
match self.callbacks.state {
WifiModuleState::Reset => {
self.callbacks.state = WifiModuleState::Starting;
self.manager.set_crc_state(true);
self.boot = Some(BootState::new(boot_mode));
Err(nb::Error::WouldBlock)
}
WifiModuleState::Starting => {
if let Some(state) = self.boot.as_mut() {
let result = self.manager.boot_the_chip(state)?;
if result {
self.callbacks.state = WifiModuleState::Unconnected;
self.boot = None;
return Ok(());
}
Err(nb::Error::WouldBlock)
} else {
Err(nb::Error::Other(StackError::InvalidState))
}
}
_ => Err(nb::Error::Other(StackError::InvalidState)),
}
}
pub fn start_wifi_module(&mut self) -> nb::Result<(), StackError> {
self.start_wifi_module_impl(BootMode::Normal)
}
#[cfg(feature = "ethernet")]
pub fn start_in_ethernet_mode(&mut self) -> nb::Result<(), StackError> {
self.start_wifi_module_impl(BootMode::Ethernet)
}
pub fn start_in_download_mode(&mut self) -> nb::Result<(), StackError> {
match self.callbacks.state {
WifiModuleState::Reset => {
self.manager.set_crc_state(true);
self.manager.chip_wake()?;
self.manager.chip_reset()?;
self.manager.chip_halt()?;
self.callbacks.state = WifiModuleState::Starting;
Err(nb::Error::WouldBlock)
}
WifiModuleState::Starting => {
self.manager.configure_spi_packetsize()?;
let chip_id = self.manager.chip_id()?;
let chip_rev = self.manager.chip_rev()?;
self.manager.disable_internal_interrupt()?;
self.manager.enable_interrupt_pins()?;
info!(
"Chip id: {:x} rev: {:x} booted into download mode.",
chip_id, chip_rev
);
self.callbacks.state = WifiModuleState::DownloadMode;
Ok(())
}
WifiModuleState::DownloadMode => {
info!("Chip is already in download mode.");
Ok(())
}
_ => Err(nb::Error::Other(StackError::InvalidState)),
}
}
fn connect_to_ap_impl(
&mut self,
connect_fn: impl FnOnce(&mut Self) -> Result<(), crate::errors::CommError>,
) -> nb::Result<(), StackError> {
match self.callbacks.state {
WifiModuleState::Unconnected => {
self.operation_countdown = AP_CONNECT_TIMEOUT_MILLISECONDS;
self.callbacks.state = WifiModuleState::ConnectingToAp;
connect_fn(self)?;
Err(nb::Error::WouldBlock)
}
WifiModuleState::ConnectingToAp => {
self.delay_us(self.poll_loop_delay_us); self.dispatch_events_may_wait()?;
self.operation_countdown -= 1;
if self.operation_countdown == 0 {
return Err(nb::Error::Other(StackError::GeneralTimeout));
}
Err(nb::Error::WouldBlock)
}
WifiModuleState::ConnectionFailed => {
self.callbacks.state = WifiModuleState::Unconnected;
Err(nb::Error::Other(StackError::ApJoinFailed(
self.callbacks
.connection_state
.conn_error
.take()
.unwrap_or(WifiConnError::Unhandled),
)))
}
WifiModuleState::ConnectedToAp => {
info!("connect_to_ap: got Connected to AP");
Ok(())
}
_ => Err(nb::Error::Other(StackError::InvalidState)),
}
}
pub fn connect_to_saved_ap(&mut self) -> nb::Result<(), StackError> {
self.connect_to_ap_impl(|inner_self: &mut Self| inner_self.manager.send_default_connect())
}
pub fn connect_to_ap(
&mut self,
ssid: &Ssid,
credentials: &Credentials,
channel: WifiChannel,
save_credentials: bool,
) -> nb::Result<(), StackError> {
self.connect_to_ap_impl(|inner_self: &mut Self| {
inner_self
.manager
.send_connect(ssid, credentials, channel, !save_credentials)
})
}
pub fn scan(&mut self) -> nb::Result<u8, StackError> {
match &mut self.callbacks.connection_state.scan_number_aps {
None => {
const PASSIVE_SCAN_TIME: u16 = 1000;
self.manager.send_scan(0xFF, PASSIVE_SCAN_TIME)?;
self.callbacks.connection_state.scan_number_aps = Some(None);
}
Some(num_aps) => {
if let Some(num_aps) = num_aps.take() {
if let Some(err) = self.callbacks.connection_state.conn_error.take() {
return Err(nb::Error::Other(StackError::ApScanFailed(err)));
}
self.callbacks.connection_state.scan_number_aps = None;
return Ok(num_aps);
}
}
}
self.dispatch_events_may_wait()?;
Err(nb::Error::WouldBlock)
}
pub fn get_scan_result(&mut self, index: u8) -> nb::Result<ScanResult, StackError> {
match &mut self.callbacks.connection_state.scan_results {
None => {
self.manager.send_get_scan_result(index)?;
self.callbacks.connection_state.scan_results = Some(None);
}
Some(result) => {
if let Some(result) = result.take() {
self.callbacks.connection_state.scan_results = None;
return Ok(result);
}
}
}
self.dispatch_events_may_wait()?;
Err(nb::Error::WouldBlock)
}
pub fn get_ip_settings(&mut self) -> nb::Result<IPConf, StackError> {
if let Some(ip_conf) = &self.callbacks.connection_state.ip_conf {
return Ok(ip_conf.clone());
}
self.dispatch_events_may_wait()?;
Err(nb::Error::WouldBlock)
}
pub fn get_current_rssi(&mut self) -> nb::Result<i8, StackError> {
match &mut self.callbacks.connection_state.rssi_level {
None => {
self.manager.send_get_current_rssi()?;
self.callbacks.connection_state.rssi_level = Some(None);
}
Some(rssi) => {
if let Some(rssi) = rssi.take() {
self.callbacks.connection_state.rssi_level = None;
return Ok(rssi);
}
}
}
self.dispatch_events_may_wait()?;
Err(nb::Error::WouldBlock)
}
pub fn get_connection_info(
&mut self,
) -> nb::Result<crate::manager::ConnectionInfo, StackError> {
match &mut self.callbacks.connection_state.conn_info {
None => {
self.manager.send_get_conn_info()?;
self.callbacks.connection_state.conn_info = Some(None);
}
Some(info) => {
if let Some(info) = info.take() {
self.callbacks.connection_state.conn_info = None;
return Ok(info);
}
}
}
self.dispatch_events_may_wait()?;
Err(nb::Error::WouldBlock)
}
pub fn get_firmware_version(&mut self) -> Result<FirmwareInfo, StackError> {
Ok(self.manager.get_firmware_ver_full()?)
}
pub fn send_ping(
&mut self,
dest_ip: core::net::Ipv4Addr,
ttl: u8,
count: u16,
) -> nb::Result<PingResult, StackError> {
match &mut self.callbacks.connection_state.ping_result {
None => {
info!("sending ping request");
let marker = 42; self.manager.send_ping_req(dest_ip, ttl, count, marker)?;
self.callbacks.connection_state.ping_result = Some(None);
}
Some(result) => {
if let Some(result) = result.take() {
self.callbacks.connection_state.ping_result = None;
return Ok(result);
}
}
}
self.dispatch_events_may_wait()?;
Err(nb::Error::WouldBlock)
}
pub fn disconnect_ap(&mut self) -> nb::Result<(), StackError> {
match &mut self.callbacks.state {
WifiModuleState::ConnectedToAp => {
self.operation_countdown = AP_DISCONNECT_TIMEOUT_MILLISECONDS;
self.callbacks.state = WifiModuleState::Disconnecting;
self.manager.send_disconnect()?;
Err(nb::Error::WouldBlock)
}
WifiModuleState::Disconnecting => {
self.delay_us(self.poll_loop_delay_us); self.dispatch_events_may_wait()?;
self.operation_countdown -= 1;
if self.operation_countdown == 0 {
return Err(nb::Error::Other(StackError::GeneralTimeout));
}
Err(nb::Error::WouldBlock)
}
_ => {
info!("disconnect_ap: got disconnected from AP");
Ok(())
}
}
}
pub fn provisioning_mode(
&mut self,
ap: &AccessPoint,
hostname: &HostName,
http_redirect: bool,
timeout: u32,
) -> nb::Result<ProvisioningInfo, StackError> {
match &mut self.callbacks.state {
WifiModuleState::Unconnected | WifiModuleState::ConnectedToAp => {
let auth = <Credentials as Into<AuthType>>::into(ap.key);
if auth == AuthType::S802_1X {
error!("Enterprise Security in provisioning mode is not supported");
return Err(nb::Error::Other(StackError::InvalidParameters));
}
self.manager
.send_start_provisioning(ap, hostname, http_redirect)?;
self.callbacks.state = WifiModuleState::Provisioning;
self.callbacks.provisioning_info = None;
}
WifiModuleState::Provisioning => match &mut self.callbacks.provisioning_info {
None => {
self.operation_countdown = timeout * PROVISIONING_TIMEOUT;
self.callbacks.provisioning_info = Some(None);
}
Some(result) => {
if let Some(info) = result.take() {
if info.status {
return Ok(info);
}
return Err(nb::Error::Other(StackError::WincWifiFail(Error::Failed)));
} else {
self.delay_us(self.poll_loop_delay_us);
self.operation_countdown -= 1;
if self.operation_countdown == 0 {
return Err(nb::Error::Other(StackError::GeneralTimeout));
}
}
}
},
_ => {
return Err(nb::Error::Other(StackError::InvalidState));
}
}
self.dispatch_events_may_wait()?;
Err(nb::Error::WouldBlock)
}
pub fn stop_provisioning_mode(&mut self) -> Result<(), StackError> {
if self.callbacks.state == WifiModuleState::Provisioning {
self.manager.send_stop_provisioning()?;
} else {
return Err(StackError::InvalidState);
}
self.callbacks.state = WifiModuleState::Unconnected;
Ok(())
}
pub fn enable_access_point(&mut self, ap: &AccessPoint) -> Result<(), StackError> {
if self.callbacks.state == WifiModuleState::Unconnected {
let auth: AuthType = ap.key.into();
if auth == AuthType::S802_1X {
error!("Enterprise Security is not supported in access point mode");
return Err(StackError::InvalidParameters);
}
self.manager.send_enable_access_point(ap)?;
self.callbacks.state = WifiModuleState::AccessPoint;
} else {
return Err(StackError::InvalidState);
}
Ok(())
}
pub fn disable_access_point(&mut self) -> Result<(), StackError> {
if self.callbacks.state == WifiModuleState::AccessPoint {
self.manager.send_disable_access_point()?;
self.callbacks.state = WifiModuleState::Unconnected;
} else {
return Err(StackError::InvalidState);
}
Ok(())
}
pub fn set_socket_option(
&mut self,
socket: &Handle,
option: &SocketOptions,
) -> Result<(), StackError> {
match option {
SocketOptions::Udp(opts) => {
let (sock, _) = self
.callbacks
.udp_sockets
.get(*socket)
.ok_or(StackError::SocketNotFound)?;
if let UdpSockOpts::ReceiveTimeout(timeout) = opts {
sock.set_recv_timeout(*timeout);
} else {
self.manager.send_setsockopt(*sock, opts)?;
}
}
SocketOptions::Tcp(opts) => {
let (sock, _) = self
.callbacks
.tcp_sockets
.get(*socket)
.ok_or(StackError::SocketNotFound)?;
match opts {
#[cfg(feature = "ssl")]
TcpSockOpts::Ssl(ssl_opts) => {
match *ssl_opts {
SslSockOpts::SetSni(_) => {
self.manager.send_ssl_setsockopt(*sock, ssl_opts)?;
}
SslSockOpts::Config(cfg, en) => {
if cfg == SslSockConfig::EnableSSL && en {
if (sock.get_ssl_cfg() & u8::from(cfg)) == cfg.into() {
return Ok(());
} else {
self.manager.send_ssl_sock_create(*sock)?;
}
}
sock.set_ssl_cfg(cfg.into(), en);
}
}
}
TcpSockOpts::ReceiveTimeout(timeout) => {
sock.set_recv_timeout(*timeout);
}
}
}
}
Ok(())
}
pub fn get_winc_mac_address(
&mut self,
#[cfg(test)] test_hook: bool,
) -> Result<MacAddress, StackError> {
Ok(self.manager.read_otp_mac_address(
#[cfg(test)]
test_hook,
)?)
}
}
#[cfg(test)]
mod tests {
use core::net::Ipv4Addr;
use super::*;
use crate::client::{test_shared::*, SocketCallbacks};
use crate::errors::CommError as Error;
use crate::manager::Ssid;
use crate::manager::{EventListener, PingError, WifiConnError, WifiConnState};
use crate::{ConnectionInfo, Credentials, S8Password, S8Username, WifiChannel, WpaKey};
#[cfg(feature = "wep")]
use crate::{WepKey, WepKeyIndex};
use embedded_nal::{TcpClientStack, UdpClientStack};
#[cfg(feature = "ssl")]
use crate::manager::SslSockConfig;
#[test]
fn test_heartbeat() {
assert_eq!(make_test_client().heartbeat(), Ok(()));
}
#[test]
fn test_start_wifi_module() {
let mut client = make_test_client();
let result = nb::block!(client.start_wifi_module());
assert_eq!(
result,
Err(StackError::WincWifiFail(Error::BootRomStart).into())
);
}
#[test]
fn test_connect_to_saved_ap_invalid_state() {
let mut client = make_test_client();
let result = nb::block!(client.connect_to_saved_ap());
assert_eq!(result, Err(StackError::InvalidState));
}
#[test]
fn test_connect_to_saved_ap_timeout() {
let mut client = make_test_client();
client.callbacks.state = WifiModuleState::Unconnected;
let result = nb::block!(client.connect_to_saved_ap());
assert_eq!(result, Err(StackError::GeneralTimeout));
}
#[test]
fn test_connect_to_saved_ap_success() {
let mut client = make_test_client();
client.callbacks.state = WifiModuleState::Unconnected;
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_connstate_changed(WifiConnState::Connected, WifiConnError::Unhandled);
};
client.debug_callback = Some(&mut my_debug);
let result = nb::block!(client.connect_to_saved_ap());
assert_eq!(result, Ok(()));
}
#[test]
fn test_connect_to_saved_ap_invalid_credentials() {
let mut client = make_test_client();
client.callbacks.state = WifiModuleState::Unconnected;
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_connstate_changed(WifiConnState::Disconnected, WifiConnError::AuthFail);
};
client.debug_callback = Some(&mut my_debug);
let result = nb::block!(client.connect_to_saved_ap());
assert_eq!(
result,
Err(StackError::ApJoinFailed(WifiConnError::AuthFail))
);
}
#[test]
fn test_connect_to_ap_success() {
let mut client = make_test_client();
let ssid = Ssid::from("test").unwrap();
let key = Credentials::WpaPSK(WpaKey::from("test").unwrap());
client.callbacks.state = WifiModuleState::Unconnected;
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_connstate_changed(WifiConnState::Connected, WifiConnError::Unhandled);
};
client.debug_callback = Some(&mut my_debug);
let result = nb::block!(client.connect_to_ap(&ssid, &key, WifiChannel::Channel1, false));
assert_eq!(result, Ok(()));
}
#[test]
fn test_scan_ok() {
let mut client = make_test_client();
client.callbacks.state = WifiModuleState::Unconnected;
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_scan_done(5, WifiConnError::NoError);
};
client.debug_callback = Some(&mut my_debug);
let result = nb::block!(client.scan());
assert_eq!(result, Ok(5));
}
#[test]
fn test_get_scan_result_ok() {
let mut client = make_test_client();
client.callbacks.state = WifiModuleState::Unconnected;
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_scan_result(ScanResult {
index: 0,
rssi: 0,
auth: AuthType::Open,
channel: 0,
bssid: [0; 6],
ssid: Ssid::from("test").unwrap(),
});
};
client.debug_callback = Some(&mut my_debug);
let result = nb::block!(client.get_scan_result(0));
assert_eq!(result.unwrap().ssid, Ssid::from("test").unwrap());
}
#[test]
fn test_get_current_rssi_ok() {
let mut client = make_test_client();
client.callbacks.state = WifiModuleState::Unconnected;
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_rssi(0);
};
client.debug_callback = Some(&mut my_debug);
let result = nb::block!(client.get_current_rssi());
assert_eq!(result, Ok(0));
}
#[test]
fn test_get_connection_info_ok() {
let mut client = make_test_client();
client.callbacks.state = WifiModuleState::Unconnected;
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_connection_info(ConnectionInfo {
ssid: Ssid::from("test").unwrap(),
auth: AuthType::Open,
ip: Ipv4Addr::new(192, 168, 1, 1),
mac: [0; 6],
rssi: 0,
});
};
client.debug_callback = Some(&mut my_debug);
let result = nb::block!(client.get_connection_info());
assert_eq!(result.unwrap().ssid, Ssid::from("test").unwrap());
}
#[test]
fn test_get_firmware_version_ok() {
let mut client = make_test_client();
client.callbacks.state = WifiModuleState::Unconnected;
let result = client.get_firmware_version();
assert_eq!(result.unwrap().chip_id, 0);
}
#[test]
fn test_send_ping_ok() {
let mut client = make_test_client();
client.callbacks.state = WifiModuleState::Unconnected;
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_ping(
Ipv4Addr::new(192, 168, 1, 1),
0,
42,
0,
0,
PingError::Unhandled,
);
};
client.debug_callback = Some(&mut my_debug);
let result = nb::block!(client.send_ping(Ipv4Addr::new(192, 168, 1, 1), 64, 1));
assert!(result.is_ok());
assert_eq!(result.unwrap().rtt, 42);
}
#[test]
fn test_disconnect_success() {
let mut client = make_test_client();
client.callbacks.state = WifiModuleState::ConnectedToAp;
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_connstate_changed(WifiConnState::Disconnected, WifiConnError::Unhandled);
};
client.debug_callback = Some(&mut my_debug);
let result = nb::block!(client.disconnect_ap());
assert!(result.is_ok());
}
#[test]
fn test_disconnect_timeout() {
let mut client = make_test_client();
client.callbacks.state = WifiModuleState::ConnectedToAp;
let result = nb::block!(client.disconnect_ap());
assert_eq!(result.err(), Some(StackError::GeneralTimeout));
}
#[test]
fn test_disconnect_while_not_connected() {
let mut client = make_test_client();
client.callbacks.state = WifiModuleState::Starting;
let result = nb::block!(client.disconnect_ap());
assert!(result.is_ok());
}
#[test]
fn test_provisioning_mode_open_success() {
let mut client = make_test_client();
let ap_ssid = Ssid::from("ssid").unwrap();
let ap = AccessPoint::open(&ap_ssid);
let hostname = HostName::from("admin").unwrap();
let test_ssid = Ssid::from("test_ssid").unwrap();
let test_key = WpaKey::new();
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_provisioning(test_ssid, test_key, AuthType::Open, true);
};
client.debug_callback = Some(&mut my_debug);
client.callbacks.state = WifiModuleState::Unconnected;
let result = nb::block!(client.provisioning_mode(&ap, &hostname, false, 1));
assert!(result.is_ok());
if let Ok(info) = result {
assert_eq!(info.key, Credentials::Open);
assert_eq!(info.ssid, test_ssid);
} else {
assert!(false);
}
}
#[test]
fn test_provisioning_mode_wpa_success() {
let mut client = make_test_client();
let ap_ssid = Ssid::from("ssid").unwrap();
let ap_key = WpaKey::from("wpa_key").unwrap();
let ap = AccessPoint::wpa(&ap_ssid, &ap_key);
let hostname = HostName::from("admin").unwrap();
let test_ssid = Ssid::from("test_ssid").unwrap();
let test_key = WpaKey::from("test_key").unwrap();
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_provisioning(test_ssid, test_key, AuthType::WpaPSK, true);
};
client.debug_callback = Some(&mut my_debug);
client.callbacks.state = WifiModuleState::Unconnected;
let result = nb::block!(client.provisioning_mode(&ap, &hostname, false, 1));
assert!(result.is_ok());
if let Ok(info) = result {
assert_eq!(info.key, Credentials::WpaPSK(test_key));
assert_eq!(info.ssid, test_ssid);
} else {
assert!(false);
}
}
#[cfg(feature = "wep")]
#[test]
fn test_provisioning_mode_wep_success() {
let mut client = make_test_client();
let ap_ssid = Ssid::from("ssid").unwrap();
let ap_key = WepKey::from("wep_key").unwrap();
let wep_key_index = WepKeyIndex::Key1;
let ap = AccessPoint::wep(&ap_ssid, &ap_key, wep_key_index);
let hostname = HostName::from("admin").unwrap();
let test_ssid = Ssid::from("test_ssid").unwrap();
let test_key = WpaKey::from("test_wep_key").unwrap();
let test_wep_key = WepKey::from("test_wep_key").unwrap();
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_provisioning(test_ssid, test_key, AuthType::WEP, true);
};
client.debug_callback = Some(&mut my_debug);
client.callbacks.state = WifiModuleState::Unconnected;
let result = nb::block!(client.provisioning_mode(&ap, &hostname, false, 1));
assert!(result.is_ok());
if let Ok(info) = result {
assert_eq!(info.key, Credentials::Wep(test_wep_key, wep_key_index));
assert_eq!(info.ssid, test_ssid);
} else {
assert!(false);
}
}
#[test]
fn test_provisioning_mode_enterprise_fail() {
let mut client = make_test_client();
let ap_ssid = Ssid::from("ssid").unwrap();
let s8_username = S8Username::from("username").unwrap();
let s8_password = S8Password::from("password").unwrap();
let ap_key = Credentials::S802_1X(s8_username, s8_password);
let ap = AccessPoint {
ssid: &ap_ssid,
key: ap_key,
channel: WifiChannel::Channel1,
ssid_hidden: false,
ip: Ipv4Addr::new(192, 168, 1, 1),
};
let hostname = HostName::from("admin").unwrap();
client.callbacks.state = WifiModuleState::Unconnected;
let result = nb::block!(client.provisioning_mode(&ap, &hostname, false, 1));
assert!(result.is_err());
if let Err(error) = result {
assert_eq!(error, StackError::InvalidParameters);
} else {
assert!(false);
}
}
#[test]
fn test_provisioning_invalid_state() {
let mut client = make_test_client();
let ap_ssid = Ssid::from("ssid").unwrap();
let ap = AccessPoint::open(&ap_ssid);
let hostname = HostName::from("admin").unwrap();
client.callbacks.state = WifiModuleState::ConnectingToAp;
let result = nb::block!(client.provisioning_mode(&ap, &hostname, false, 1));
assert!(result.is_err());
if let Err(err) = result {
assert_eq!(err, StackError::InvalidState);
} else {
assert!(false);
}
}
#[test]
fn test_provisioning_timeout() {
let mut client = make_test_client();
let ap_ssid = Ssid::from("ssid").unwrap();
let ap = AccessPoint::open(&ap_ssid);
let hostname = HostName::from("admin").unwrap();
client.callbacks.state = WifiModuleState::Unconnected;
let result = nb::block!(client.provisioning_mode(&ap, &hostname, false, 1500));
assert!(result.is_err());
if let Err(err) = result {
assert_eq!(err, StackError::GeneralTimeout);
} else {
assert!(false);
}
}
#[test]
fn test_provisioning_failed() {
let mut client = make_test_client();
let ap_ssid = Ssid::from("ssid").unwrap();
let ap = AccessPoint::open(&ap_ssid);
let hostname = HostName::from("admin").unwrap();
let test_ssid = Ssid::from("test_ssid").unwrap();
let test_key = WpaKey::new();
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_provisioning(test_ssid, test_key, AuthType::Open, false);
};
client.debug_callback = Some(&mut my_debug);
client.callbacks.state = WifiModuleState::Unconnected;
let result = nb::block!(client.provisioning_mode(&ap, &hostname, false, 1));
assert!(result.is_err());
if let Err(error) = result {
assert_eq!(error, StackError::WincWifiFail(Error::Failed));
} else {
assert!(false);
}
}
#[test]
fn test_stop_provisioning_success() {
let mut client = make_test_client();
client.callbacks.state = WifiModuleState::Provisioning;
let result = client.stop_provisioning_mode();
assert!(result.is_ok());
}
#[test]
fn test_stop_provisioning_state_error() {
let mut client = make_test_client();
client.callbacks.state = WifiModuleState::Unconnected;
let result = client.stop_provisioning_mode();
assert!(result.is_err());
}
#[test]
fn test_enable_access_point_success() {
let mut client = make_test_client();
client.callbacks.state = WifiModuleState::Unconnected;
let ssid = Ssid::from("ssid").unwrap();
let ap = AccessPoint::open(&ssid);
let result = client.enable_access_point(&ap);
assert!(result.is_ok());
assert_eq!(client.callbacks.state, WifiModuleState::AccessPoint);
}
#[test]
fn test_enable_access_point_invalid_security() {
let mut client = make_test_client();
client.callbacks.state = WifiModuleState::Unconnected;
let ssid = Ssid::from("ssid").unwrap();
let key = Credentials::from_s802("username", "password").unwrap();
let ap = AccessPoint {
ssid: &ssid,
key: key,
channel: WifiChannel::Channel1,
ssid_hidden: false,
ip: Ipv4Addr::new(192, 168, 1, 1),
};
let result = client.enable_access_point(&ap);
assert_eq!(result.err(), Some(StackError::InvalidParameters));
}
#[test]
fn test_enable_access_point_invalid_state() {
let mut client = make_test_client();
client.callbacks.state = WifiModuleState::Provisioning;
let ssid = Ssid::from("ssid").unwrap();
let ap = AccessPoint::open(&ssid);
let result = client.enable_access_point(&ap);
assert_eq!(result.err(), Some(StackError::InvalidState));
}
#[test]
fn test_disable_access_point_success() {
let mut client = make_test_client();
client.callbacks.state = WifiModuleState::AccessPoint;
let result = client.disable_access_point();
assert!(result.is_ok());
}
#[test]
fn test_disable_access_point_fail() {
let mut client = make_test_client();
client.callbacks.state = WifiModuleState::Unconnected;
let result = client.disable_access_point();
assert_eq!(result.err(), Some(StackError::InvalidState));
}
#[test]
fn test_udp_sock_opt_multicast() {
let mut client = make_test_client();
let socket = UdpClientStack::socket(&mut client).unwrap();
let addr = Ipv4Addr::new(192, 168, 1, 1);
let option = SocketOptions::join_multicast_v4(addr);
let result = client.set_socket_option(&socket, &option);
assert!(result.is_ok());
}
#[test]
fn test_udp_sock_opt_invalid_socket() {
let mut client = make_test_client();
let socket = TcpClientStack::socket(&mut client).unwrap();
let addr = Ipv4Addr::new(192, 168, 1, 1);
let option = SocketOptions::join_multicast_v4(addr);
let result = client.set_socket_option(&socket, &option);
assert_eq!(result.err(), Some(StackError::SocketNotFound));
}
#[test]
fn test_tcp_sock_opt_invalid_socket() {
let mut client = make_test_client();
let socket = UdpClientStack::socket(&mut client).unwrap();
let option = SocketOptions::set_tcp_receive_timeout(1500);
let result = client.set_socket_option(&socket, &option);
assert_eq!(result.err(), Some(StackError::SocketNotFound));
}
#[cfg(feature = "ssl")]
#[test]
fn test_tcp_sock_opt_set_sni() {
let mut client = make_test_client();
let socket = TcpClientStack::socket(&mut client).unwrap();
let option = SocketOptions::set_sni("hostname").unwrap();
let result = client.set_socket_option(&socket, &option);
assert!(result.is_ok());
}
#[test]
fn test_udp_set_socket_timeout() {
let mut client = make_test_client();
let timeout = 1500 as u32;
let socket = UdpClientStack::socket(&mut client).unwrap();
let options = SocketOptions::set_udp_receive_timeout(timeout);
let result = client.set_socket_option(&socket, &options);
assert!(result.is_ok());
let (sock, _) = client.callbacks.udp_sockets.get(socket).unwrap();
assert_eq!(sock.get_recv_timeout(), timeout);
}
#[test]
fn test_tcp_set_socket_timeout() {
let mut client = make_test_client();
let timeout = 150000 as u32;
let socket = TcpClientStack::socket(&mut client).unwrap();
let options = SocketOptions::set_tcp_receive_timeout(timeout);
let result = client.set_socket_option(&socket, &options);
assert!(result.is_ok());
let (sock, _) = client.callbacks.tcp_sockets.get(socket).unwrap();
assert_eq!(sock.get_recv_timeout(), timeout);
}
#[cfg(feature = "ssl")]
#[test]
fn test_tcp_ssl_cfg() {
let mut client = make_test_client();
let ssl_opt = SocketOptions::config_ssl(SslSockConfig::EnableSSL, true);
let socket = TcpClientStack::socket(&mut client).unwrap();
let result = client.set_socket_option(&socket, &ssl_opt);
assert!(result.is_ok());
let (sock, _) = client.callbacks.tcp_sockets.get(socket).unwrap();
assert_eq!(sock.get_ssl_cfg(), u8::from(SslSockConfig::EnableSSL));
}
#[cfg(feature = "ssl")]
#[test]
fn test_tcp_ssl_cfg_disable() {
let mut client = make_test_client();
let socket = TcpClientStack::socket(&mut client).unwrap();
let ssl_opt = SocketOptions::config_ssl(SslSockConfig::EnableSSL, true);
let result = client.set_socket_option(&socket, &ssl_opt);
assert!(result.is_ok());
let ssl_opt = SocketOptions::config_ssl(SslSockConfig::EnableSniValidation, true);
let result = client.set_socket_option(&socket, &ssl_opt);
assert!(result.is_ok());
{
let (sock, _) = client.callbacks.tcp_sockets.get(socket).unwrap();
assert_eq!(
sock.get_ssl_cfg(),
(u8::from(SslSockConfig::EnableSSL))
| (u8::from(SslSockConfig::EnableSniValidation))
);
}
let ssl_opt = SocketOptions::config_ssl(SslSockConfig::EnableSSL, false);
let result = client.set_socket_option(&socket, &ssl_opt);
assert!(result.is_ok());
let (sock, _) = client.callbacks.tcp_sockets.get(socket).unwrap();
assert_eq!(
sock.get_ssl_cfg(),
u8::from(SslSockConfig::EnableSniValidation)
);
}
#[test]
fn test_get_winc_mac_address_success() {
let mut client = make_test_client();
let mac = client.get_winc_mac_address(true);
assert!(mac.is_ok());
assert_eq!(mac.unwrap().octets(), [0u8; 6]);
}
#[test]
fn test_get_winc_mac_address_failure() {
let mut client = make_test_client();
let mac = client.get_winc_mac_address(false);
assert_eq!(
mac.err(),
Some(StackError::WincWifiFail(Error::BufferReadError))
);
}
}