1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
use core::sync::atomic::Ordering;

use portable_atomic_enum::atomic_enum;

use super::WifiEvent;

/// Wifi interface state
#[atomic_enum]
#[derive(PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum WifiState {
    StaStarted,
    StaConnected,
    StaDisconnected,
    StaStopped,

    ApStarted,
    ApStopped,

    Invalid,
}

impl From<WifiEvent> for WifiState {
    fn from(event: WifiEvent) -> WifiState {
        match event {
            WifiEvent::StaStart => WifiState::StaStarted,
            WifiEvent::StaConnected => WifiState::StaConnected,
            WifiEvent::StaDisconnected => WifiState::StaDisconnected,
            WifiEvent::StaStop => WifiState::StaStopped,
            WifiEvent::ApStart => WifiState::ApStarted,
            WifiEvent::ApStop => WifiState::ApStopped,
            _ => WifiState::Invalid,
        }
    }
}

pub(crate) static STA_STATE: AtomicWifiState = AtomicWifiState::new(WifiState::Invalid);
pub(crate) static AP_STATE: AtomicWifiState = AtomicWifiState::new(WifiState::Invalid);

/// Get the current state of the AP
pub fn ap_state() -> WifiState {
    AP_STATE.load(Ordering::Relaxed)
}

/// Get the current state of the STA
pub fn sta_state() -> WifiState {
    STA_STATE.load(Ordering::Relaxed)
}

pub(crate) fn update_state(event: WifiEvent, handled: bool) {
    match event {
        WifiEvent::StaConnected
        | WifiEvent::StaDisconnected
        | WifiEvent::StaStart
        | WifiEvent::StaStop => STA_STATE.store(WifiState::from(event), Ordering::Relaxed),

        WifiEvent::ApStart | WifiEvent::ApStop => {
            AP_STATE.store(WifiState::from(event), Ordering::Relaxed)
        }

        other => {
            if !handled {
                debug!("Unhandled event: {:?}", other)
            }
        }
    }
}

pub(crate) fn reset_ap_state() {
    AP_STATE.store(WifiState::Invalid, Ordering::Relaxed)
}

pub(crate) fn reset_sta_state() {
    STA_STATE.store(WifiState::Invalid, Ordering::Relaxed)
}

/// Returns the current state of the WiFi stack.
///
/// This does not support AP-STA mode. Use one of `sta_state` or
/// `ap_state` instead.
pub fn wifi_state() -> WifiState {
    use super::WifiMode;
    match WifiMode::current() {
        Ok(WifiMode::Sta) => sta_state(),
        Ok(WifiMode::Ap) => ap_state(),
        _ => WifiState::Invalid,
    }
}