aboutsummaryrefslogtreecommitdiff
path: root/src/control.rs
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-03-27 03:17:30 +0200
committerGitHub <[email protected]>2023-03-27 03:17:30 +0200
commitbb90bb8c563a02d314ba574f45816d5d3c79be38 (patch)
treeb30e9545302fa9ef68dfa25748602877f838f722 /src/control.rs
parent8b24fe3df02862991b2574f9d5c9ada7bd27706b (diff)
parent20923080e6ea313278b5f3aa8ec21055c6208527 (diff)
Merge pull request #46 from kbleeke/split-lib-rs
split lib.rs into multiple files
Diffstat (limited to 'src/control.rs')
-rw-r--r--src/control.rs299
1 files changed, 299 insertions, 0 deletions
diff --git a/src/control.rs b/src/control.rs
new file mode 100644
index 000000000..7f1c9fe86
--- /dev/null
+++ b/src/control.rs
@@ -0,0 +1,299 @@
1use core::cell::Cell;
2use core::cmp::{max, min};
3
4use ch::driver::LinkState;
5use embassy_futures::yield_now;
6use embassy_net_driver_channel as ch;
7use embassy_time::{Duration, Timer};
8
9pub use crate::bus::SpiBusCyw43;
10use crate::consts::*;
11use crate::events::{Event, EventQueue};
12use crate::structs::*;
13use crate::{countries, IoctlState, IoctlType, PowerManagementMode};
14
15pub struct Control<'a> {
16 state_ch: ch::StateRunner<'a>,
17 event_sub: &'a EventQueue,
18 ioctl_state: &'a Cell<IoctlState>,
19}
20
21impl<'a> Control<'a> {
22 pub(crate) fn new(
23 state_ch: ch::StateRunner<'a>,
24 event_sub: &'a EventQueue,
25 ioctl_state: &'a Cell<IoctlState>,
26 ) -> Self {
27 Self {
28 state_ch,
29 event_sub,
30 ioctl_state,
31 }
32 }
33
34 pub async fn init(&mut self, clm: &[u8]) {
35 const CHUNK_SIZE: usize = 1024;
36
37 info!("Downloading CLM...");
38
39 let mut offs = 0;
40 for chunk in clm.chunks(CHUNK_SIZE) {
41 let mut flag = DOWNLOAD_FLAG_HANDLER_VER;
42 if offs == 0 {
43 flag |= DOWNLOAD_FLAG_BEGIN;
44 }
45 offs += chunk.len();
46 if offs == clm.len() {
47 flag |= DOWNLOAD_FLAG_END;
48 }
49
50 let header = DownloadHeader {
51 flag,
52 dload_type: DOWNLOAD_TYPE_CLM,
53 len: chunk.len() as _,
54 crc: 0,
55 };
56 let mut buf = [0; 8 + 12 + CHUNK_SIZE];
57 buf[0..8].copy_from_slice(b"clmload\x00");
58 buf[8..20].copy_from_slice(&header.to_bytes());
59 buf[20..][..chunk.len()].copy_from_slice(&chunk);
60 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..8 + 12 + chunk.len()])
61 .await;
62 }
63
64 // check clmload ok
65 assert_eq!(self.get_iovar_u32("clmload_status").await, 0);
66
67 info!("Configuring misc stuff...");
68
69 // Disable tx gloming which transfers multiple packets in one request.
70 // 'glom' is short for "conglomerate" which means "gather together into
71 // a compact mass".
72 self.set_iovar_u32("bus:txglom", 0).await;
73 self.set_iovar_u32("apsta", 1).await;
74
75 // read MAC addr.
76 let mut mac_addr = [0; 6];
77 assert_eq!(self.get_iovar("cur_etheraddr", &mut mac_addr).await, 6);
78 info!("mac addr: {:02x}", mac_addr);
79
80 let country = countries::WORLD_WIDE_XX;
81 let country_info = CountryInfo {
82 country_abbrev: [country.code[0], country.code[1], 0, 0],
83 country_code: [country.code[0], country.code[1], 0, 0],
84 rev: if country.rev == 0 { -1 } else { country.rev as _ },
85 };
86 self.set_iovar("country", &country_info.to_bytes()).await;
87
88 // set country takes some time, next ioctls fail if we don't wait.
89 Timer::after(Duration::from_millis(100)).await;
90
91 // Set antenna to chip antenna
92 self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await;
93
94 self.set_iovar_u32("bus:txglom", 0).await;
95 Timer::after(Duration::from_millis(100)).await;
96 //self.set_iovar_u32("apsta", 1).await; // this crashes, also we already did it before...??
97 //Timer::after(Duration::from_millis(100)).await;
98 self.set_iovar_u32("ampdu_ba_wsize", 8).await;
99 Timer::after(Duration::from_millis(100)).await;
100 self.set_iovar_u32("ampdu_mpdu", 4).await;
101 Timer::after(Duration::from_millis(100)).await;
102 //self.set_iovar_u32("ampdu_rx_factor", 0).await; // this crashes
103
104 //Timer::after(Duration::from_millis(100)).await;
105
106 // evts
107 let mut evts = EventMask {
108 iface: 0,
109 events: [0xFF; 24],
110 };
111
112 // Disable spammy uninteresting events.
113 evts.unset(Event::RADIO);
114 evts.unset(Event::IF);
115 evts.unset(Event::PROBREQ_MSG);
116 evts.unset(Event::PROBREQ_MSG_RX);
117 evts.unset(Event::PROBRESP_MSG);
118 evts.unset(Event::PROBRESP_MSG);
119 evts.unset(Event::ROAM);
120
121 self.set_iovar("bsscfg:event_msgs", &evts.to_bytes()).await;
122
123 Timer::after(Duration::from_millis(100)).await;
124
125 // set wifi up
126 self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await;
127
128 Timer::after(Duration::from_millis(100)).await;
129
130 self.ioctl_set_u32(110, 0, 1).await; // SET_GMODE = auto
131 self.ioctl_set_u32(142, 0, 0).await; // SET_BAND = any
132
133 Timer::after(Duration::from_millis(100)).await;
134
135 self.state_ch.set_ethernet_address(mac_addr);
136 self.state_ch.set_link_state(LinkState::Up); // TODO do on join/leave
137
138 info!("INIT DONE");
139 }
140
141 pub async fn set_power_management(&mut self, mode: PowerManagementMode) {
142 // power save mode
143 let mode_num = mode.mode();
144 if mode_num == 2 {
145 self.set_iovar_u32("pm2_sleep_ret", mode.sleep_ret_ms() as u32).await;
146 self.set_iovar_u32("bcn_li_bcn", mode.beacon_period() as u32).await;
147 self.set_iovar_u32("bcn_li_dtim", mode.dtim_period() as u32).await;
148 self.set_iovar_u32("assoc_listen", mode.assoc() as u32).await;
149 }
150 self.ioctl_set_u32(86, 0, mode_num).await;
151 }
152
153 pub async fn join_open(&mut self, ssid: &str) {
154 self.set_iovar_u32("ampdu_ba_wsize", 8).await;
155
156 self.ioctl_set_u32(134, 0, 0).await; // wsec = open
157 self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 0).await;
158 self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1
159 self.ioctl_set_u32(22, 0, 0).await; // set_auth = open (0)
160
161 let mut i = SsidInfo {
162 len: ssid.len() as _,
163 ssid: [0; 32],
164 };
165 i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes());
166 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_SSID, 0, &mut i.to_bytes())
167 .await; // set_ssid
168
169 info!("JOINED");
170 }
171
172 pub async fn join_wpa2(&mut self, ssid: &str, passphrase: &str) {
173 self.set_iovar_u32("ampdu_ba_wsize", 8).await;
174
175 self.ioctl_set_u32(134, 0, 4).await; // wsec = wpa2
176 self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 1).await;
177 self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await;
178 self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await;
179
180 Timer::after(Duration::from_millis(100)).await;
181
182 let mut pfi = PassphraseInfo {
183 len: passphrase.len() as _,
184 flags: 1,
185 passphrase: [0; 64],
186 };
187 pfi.passphrase[..passphrase.len()].copy_from_slice(passphrase.as_bytes());
188 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_PASSPHRASE, 0, &mut pfi.to_bytes())
189 .await; // WLC_SET_WSEC_PMK
190
191 self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1
192 self.ioctl_set_u32(22, 0, 0).await; // set_auth = 0 (open)
193 self.ioctl_set_u32(165, 0, 0x80).await; // set_wpa_auth
194
195 let mut i = SsidInfo {
196 len: ssid.len() as _,
197 ssid: [0; 32],
198 };
199 i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes());
200
201 let mut subscriber = self.event_sub.subscriber().unwrap();
202 self.ioctl(IoctlType::Set, 26, 0, &mut i.to_bytes()).await; // set_ssid
203
204 loop {
205 let msg = subscriber.next_message_pure().await;
206 if msg.event_type == Event::AUTH && msg.status != 0 {
207 // retry
208 defmt::warn!("JOIN failed with status={}", msg.status);
209 self.ioctl(IoctlType::Set, 26, 0, &mut i.to_bytes()).await;
210 } else if msg.event_type == Event::JOIN && msg.status == 0 {
211 // successful join
212 break;
213 }
214 }
215
216 info!("JOINED");
217 }
218
219 pub async fn gpio_set(&mut self, gpio_n: u8, gpio_en: bool) {
220 assert!(gpio_n < 3);
221 self.set_iovar_u32x2("gpioout", 1 << gpio_n, if gpio_en { 1 << gpio_n } else { 0 })
222 .await
223 }
224
225 async fn set_iovar_u32x2(&mut self, name: &str, val1: u32, val2: u32) {
226 let mut buf = [0; 8];
227 buf[0..4].copy_from_slice(&val1.to_le_bytes());
228 buf[4..8].copy_from_slice(&val2.to_le_bytes());
229 self.set_iovar(name, &buf).await
230 }
231
232 async fn set_iovar_u32(&mut self, name: &str, val: u32) {
233 self.set_iovar(name, &val.to_le_bytes()).await
234 }
235
236 async fn get_iovar_u32(&mut self, name: &str) -> u32 {
237 let mut buf = [0; 4];
238 let len = self.get_iovar(name, &mut buf).await;
239 assert_eq!(len, 4);
240 u32::from_le_bytes(buf)
241 }
242
243 async fn set_iovar(&mut self, name: &str, val: &[u8]) {
244 info!("set {} = {:02x}", name, val);
245
246 let mut buf = [0; 64];
247 buf[..name.len()].copy_from_slice(name.as_bytes());
248 buf[name.len()] = 0;
249 buf[name.len() + 1..][..val.len()].copy_from_slice(val);
250
251 let total_len = name.len() + 1 + val.len();
252 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..total_len])
253 .await;
254 }
255
256 // TODO this is not really working, it always returns all zeros.
257 async fn get_iovar(&mut self, name: &str, res: &mut [u8]) -> usize {
258 info!("get {}", name);
259
260 let mut buf = [0; 64];
261 buf[..name.len()].copy_from_slice(name.as_bytes());
262 buf[name.len()] = 0;
263
264 let total_len = max(name.len() + 1, res.len());
265 let res_len = self
266 .ioctl(IoctlType::Get, IOCTL_CMD_GET_VAR, 0, &mut buf[..total_len])
267 .await;
268
269 let out_len = min(res.len(), res_len);
270 res[..out_len].copy_from_slice(&buf[..out_len]);
271 out_len
272 }
273
274 async fn ioctl_set_u32(&mut self, cmd: u32, iface: u32, val: u32) {
275 let mut buf = val.to_le_bytes();
276 self.ioctl(IoctlType::Set, cmd, iface, &mut buf).await;
277 }
278
279 async fn ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize {
280 // TODO cancel ioctl on future drop.
281
282 while !matches!(self.ioctl_state.get(), IoctlState::Idle) {
283 yield_now().await;
284 }
285
286 self.ioctl_state.set(IoctlState::Pending { kind, cmd, iface, buf });
287
288 let resp_len = loop {
289 if let IoctlState::Done { resp_len } = self.ioctl_state.get() {
290 break resp_len;
291 }
292 yield_now().await;
293 };
294
295 self.ioctl_state.set(IoctlState::Idle);
296
297 resp_len
298 }
299}