rsiot/components/cmp_esp_wifi/
fn_process.rs

1use std::time::Duration;
2
3use embedded_svc::wifi::Wifi;
4use esp_idf_svc::hal::sys::EspError;
5use esp_idf_svc::{
6    netif::NetifStatus,
7    wifi::{AsyncWifi, ClientConfiguration, Configuration, EspWifi, NonBlocking},
8};
9use tokio::time::sleep;
10use tracing::{info, warn};
11
12use crate::{
13    executor::CmpInOut,
14    message::{system_messages, Message, MsgData, MsgDataBound},
15};
16
17use super::Config;
18
19pub async fn fn_process<TMsg>(config: Config, in_out: CmpInOut<TMsg>) -> super::Result<()>
20where
21    TMsg: MsgDataBound,
22{
23    let wifi_config = prepare_wifi_config(&config);
24
25    let driver = EspWifi::new(config.peripherals, config.event_loop.clone(), None).unwrap();
26
27    let mut wifi = AsyncWifi::wrap(driver, config.event_loop, config.timer_service).unwrap();
28
29    let mut state = ConnectionState::PreLaunch;
30
31    loop {
32        state = match state {
33            ConnectionState::PreLaunch => state_prelaunch(&mut wifi, &wifi_config).await,
34            ConnectionState::Connect => state_connect(&mut wifi, &in_out).await,
35            ConnectionState::Check => state_check(&mut wifi).await,
36            ConnectionState::Disconnect => state_disconnect(&mut wifi).await,
37            ConnectionState::OnlyAP => state_onlyap(&in_out).await,
38        };
39    }
40}
41
42// pub fn wifi_setup(
43//     wifi: &mut EspWifi<'static>,
44//     sys_loop: EspEventLoop<System>,
45//     configuration: Configuration,
46// ) {
47//     let mut wifi = BlockingWifi::wrap(wifi, sys_loop).unwrap();
48//     wifi.set_configuration(&configuration).unwrap();
49//     wifi.start().unwrap();
50//     info!("is wifi started: {:?}", wifi.is_started());
51//     info!("{:?}", wifi.get_capabilities());
52
53//     // Подключаемся к внешней точке Wi-Fi
54//     if matches!(configuration, Configuration::Client(_))
55//         || matches!(configuration, Configuration::Mixed(_, _))
56//     {
57//         wifi.connect().unwrap();
58
59//         info!("Wifi connected to external AP");
60
61//         wifi.wait_netif_up().unwrap();
62//         info!("Wifi netif up");
63//         let ip_info = wifi.wifi().sta_netif().get_ip_info().unwrap();
64//         info!("Wifi DHCP info: {:?}", ip_info);
65//     }
66// }
67
68// async fn start_wifi<TMsg>(config: Config, in_out: CmpInOut<TMsg>)
69// where
70//     TMsg: MsgDataBound,
71// {
72//     let wifi_config = prepare_wifi_config(&config);
73
74//     let driver = EspWifi::new(config.peripherals, config.event_loop.clone(), None).unwrap();
75
76//     let mut wifi = AsyncWifi::wrap(driver, config.event_loop, config.timer_service).unwrap();
77
78//     let mut state = ConnectionState::PreLaunch;
79
80//     loop {
81//         state = match state {
82//             ConnectionState::PreLaunch => state_prelaunch(&mut wifi, &wifi_config).await,
83//             ConnectionState::Connect => state_connect(&mut wifi, &in_out).await,
84//             ConnectionState::Check => state_check(&mut wifi).await,
85//             ConnectionState::Disconnect => state_disconnect(&mut wifi).await,
86//             // ConnectionState::OnlyAP => state_onlyap(&in_out).await,
87//             ConnectionState::OnlyAP => break,
88//         };
89//     }
90
91//     wifi_connected(&in_out).await.unwrap();
92// }
93
94fn prepare_wifi_config(config: &Config) -> Configuration {
95    let access_point_config =
96        config
97            .access_point
98            .as_ref()
99            .map(|ap| esp_idf_svc::wifi::AccessPointConfiguration {
100                ssid: heapless::String::try_from(ap.ssid.as_str()).unwrap(),
101                ..Default::default()
102            });
103
104    let client_config: Option<ClientConfiguration> =
105        config.client.as_ref().map(|cl| ClientConfiguration {
106            ssid: heapless::String::try_from(cl.ssid.as_str()).unwrap(),
107            password: heapless::String::try_from(cl.password.as_str()).unwrap(),
108            auth_method: cl.auth_method,
109            ..Default::default()
110        });
111
112    if let Some(apc) = access_point_config {
113        if let Some(cc) = client_config {
114            Configuration::Mixed(cc, apc)
115        } else {
116            Configuration::AccessPoint(apc)
117        }
118    } else if let Some(cc) = client_config {
119        Configuration::Client(cc)
120    } else {
121        todo!()
122    }
123}
124
125async fn state_prelaunch<T>(wifi: &mut AsyncWifi<T>, wifi_config: &Configuration) -> ConnectionState
126where
127    T: Wifi<Error = EspError> + NonBlocking,
128{
129    info!("Wifi state: prelaunch");
130    wifi.set_configuration(wifi_config).unwrap();
131    wifi.start().await.unwrap();
132    info!("is wifi started: {:?}", wifi.is_started());
133    info!("{:?}", wifi.get_capabilities());
134
135    if matches!(wifi_config, Configuration::Client(_))
136        || matches!(wifi_config, Configuration::Mixed(_, _))
137    {
138        ConnectionState::Connect
139    } else {
140        ConnectionState::OnlyAP
141    }
142}
143
144async fn state_connect<T, TMsg>(wifi: &mut AsyncWifi<T>, in_out: &CmpInOut<TMsg>) -> ConnectionState
145where
146    T: Wifi<Error = EspError> + NonBlocking + NetifStatus,
147    TMsg: MsgDataBound,
148{
149    info!("Wifi state: connect");
150    let res = wifi.connect().await;
151    if let Err(err) = res {
152        warn!("Wifi connect error: {}", err);
153        return ConnectionState::Disconnect;
154    }
155    info!("Wifi connected to external AP");
156    wifi.wait_netif_up().await.unwrap();
157    info!("Wifi netif up");
158
159    wifi_connected(in_out).await.unwrap();
160
161    ConnectionState::Check
162}
163
164async fn state_check<T>(wifi: &mut AsyncWifi<T>) -> ConnectionState
165where
166    T: Wifi<Error = EspError> + NonBlocking,
167{
168    info!("Wifi state: check");
169
170    loop {
171        let wifi_connected = wifi.is_connected().unwrap();
172        if !wifi_connected {
173            return ConnectionState::Disconnect;
174        } else {
175            sleep(Duration::from_secs(5)).await;
176        }
177    }
178}
179
180async fn state_disconnect<T>(wifi: &mut AsyncWifi<T>) -> ConnectionState
181where
182    T: Wifi<Error = EspError> + NonBlocking + NetifStatus,
183{
184    info!("Wifi state: disconnect");
185    wifi.disconnect().await.unwrap();
186    ConnectionState::Connect
187}
188
189async fn state_onlyap<TMsg>(in_out: &CmpInOut<TMsg>) -> ConnectionState
190where
191    TMsg: MsgDataBound,
192{
193    info!("Wifi state: only AP");
194    wifi_connected(in_out).await.unwrap();
195    loop {
196        sleep(Duration::from_secs(10)).await
197    }
198}
199
200/// Состояние соединения
201enum ConnectionState {
202    /// Подготовка. Запускает точку доступа, если настроена
203    PreLaunch,
204    /// Подключение к внешней точке доступа
205    Connect,
206    /// Проверка соединения
207    Check,
208    /// Отключение
209    Disconnect,
210    /// Настроен режим только точки доступа
211    OnlyAP,
212}
213
214async fn wifi_connected<TMsg>(in_out: &CmpInOut<TMsg>) -> super::Result<()>
215where
216    TMsg: MsgDataBound,
217{
218    // Рассылаем сообщение - wifi подключен
219    let msg = Message::new(MsgData::System(system_messages::System::EspWifiConnected));
220    in_out.send_output(msg).await.unwrap();
221
222    Ok(())
223}