rsiot/components/cmp_esp_wifi/
fn_process.rs1use 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
42fn 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
200enum ConnectionState {
202 PreLaunch,
204 Connect,
206 Check,
208 Disconnect,
210 OnlyAP,
212}
213
214async fn wifi_connected<TMsg>(in_out: &CmpInOut<TMsg>) -> super::Result<()>
215where
216 TMsg: MsgDataBound,
217{
218 let msg = Message::new(MsgData::System(system_messages::System::EspWifiConnected));
220 in_out.send_output(msg).await.unwrap();
221
222 Ok(())
223}