aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-03-27 10:43:53 +0000
committerGitHub <[email protected]>2023-03-27 10:43:53 +0000
commitcde6f0f8628b50008df8cdeb52e80c186f63863a (patch)
treef4d0304ac729d9e4234f26b49b43f7e093c7f300 /src
parentfd3de78b43e1c3607c68a2e12987a28bf60888e2 (diff)
parentc7646eb699e194a7c692b95b49adc76d6d3295ea (diff)
Merge pull request #50 from kbleeke/async-ioctls
Rework Ioctls to an async state machine
Diffstat (limited to 'src')
-rw-r--r--src/control.rs30
-rw-r--r--src/ioctl.rs111
-rw-r--r--src/lib.rs32
-rw-r--r--src/runner.rs108
4 files changed, 185 insertions, 96 deletions
diff --git a/src/control.rs b/src/control.rs
index 79677b554..0dbf6d44f 100644
--- a/src/control.rs
+++ b/src/control.rs
@@ -1,8 +1,6 @@
1use core::cell::Cell;
2use core::cmp::{max, min}; 1use core::cmp::{max, min};
3 2
4use ch::driver::LinkState; 3use ch::driver::LinkState;
5use embassy_futures::yield_now;
6use embassy_net_driver_channel as ch; 4use embassy_net_driver_channel as ch;
7use embassy_time::{Duration, Timer}; 5use embassy_time::{Duration, Timer};
8 6
@@ -10,21 +8,18 @@ pub use crate::bus::SpiBusCyw43;
10use crate::consts::*; 8use crate::consts::*;
11use crate::events::{Event, EventQueue}; 9use crate::events::{Event, EventQueue};
12use crate::fmt::Bytes; 10use crate::fmt::Bytes;
11use crate::ioctl::{IoctlState, IoctlType};
13use crate::structs::*; 12use crate::structs::*;
14use crate::{countries, IoctlState, IoctlType, PowerManagementMode}; 13use crate::{countries, PowerManagementMode};
15 14
16pub struct Control<'a> { 15pub struct Control<'a> {
17 state_ch: ch::StateRunner<'a>, 16 state_ch: ch::StateRunner<'a>,
18 event_sub: &'a EventQueue, 17 event_sub: &'a EventQueue,
19 ioctl_state: &'a Cell<IoctlState>, 18 ioctl_state: &'a IoctlState,
20} 19}
21 20
22impl<'a> Control<'a> { 21impl<'a> Control<'a> {
23 pub(crate) fn new( 22 pub(crate) fn new(state_ch: ch::StateRunner<'a>, event_sub: &'a EventQueue, ioctl_state: &'a IoctlState) -> Self {
24 state_ch: ch::StateRunner<'a>,
25 event_sub: &'a EventQueue,
26 ioctl_state: &'a Cell<IoctlState>,
27 ) -> Self {
28 Self { 23 Self {
29 state_ch, 24 state_ch,
30 event_sub, 25 event_sub,
@@ -285,21 +280,8 @@ impl<'a> Control<'a> {
285 async fn ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize { 280 async fn ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize {
286 // TODO cancel ioctl on future drop. 281 // TODO cancel ioctl on future drop.
287 282
288 while !matches!(self.ioctl_state.get(), IoctlState::Idle) { 283 self.ioctl_state.do_ioctl(kind, cmd, iface, buf).await;
289 yield_now().await; 284 let resp_len = self.ioctl_state.wait_complete().await;
290 }
291
292 self.ioctl_state.set(IoctlState::Pending { kind, cmd, iface, buf });
293
294 let resp_len = loop {
295 if let IoctlState::Done { resp_len } = self.ioctl_state.get() {
296 break resp_len;
297 }
298 yield_now().await;
299 };
300
301 self.ioctl_state.set(IoctlState::Idle);
302
303 resp_len 285 resp_len
304 } 286 }
305} 287}
diff --git a/src/ioctl.rs b/src/ioctl.rs
new file mode 100644
index 000000000..6a7465593
--- /dev/null
+++ b/src/ioctl.rs
@@ -0,0 +1,111 @@
1use core::cell::{Cell, RefCell};
2use core::future::poll_fn;
3use core::task::{Poll, Waker};
4
5use embassy_sync::waitqueue::WakerRegistration;
6
7#[derive(Clone, Copy)]
8pub enum IoctlType {
9 Get = 0,
10 Set = 2,
11}
12
13#[derive(Clone, Copy)]
14pub struct PendingIoctl {
15 pub buf: *mut [u8],
16 pub kind: IoctlType,
17 pub cmd: u32,
18 pub iface: u32,
19}
20
21#[derive(Clone, Copy)]
22enum IoctlStateInner {
23 Pending(PendingIoctl),
24 Sent { buf: *mut [u8] },
25 Done { resp_len: usize },
26}
27
28#[derive(Default)]
29struct Wakers {
30 control: WakerRegistration,
31 runner: WakerRegistration,
32}
33
34pub struct IoctlState {
35 state: Cell<IoctlStateInner>,
36 wakers: RefCell<Wakers>,
37}
38
39impl IoctlState {
40 pub fn new() -> Self {
41 Self {
42 state: Cell::new(IoctlStateInner::Done { resp_len: 0 }),
43 wakers: Default::default(),
44 }
45 }
46
47 fn wake_control(&self) {
48 self.wakers.borrow_mut().control.wake();
49 }
50
51 fn register_control(&self, waker: &Waker) {
52 self.wakers.borrow_mut().control.register(waker);
53 }
54
55 fn wake_runner(&self) {
56 self.wakers.borrow_mut().runner.wake();
57 }
58
59 fn register_runner(&self, waker: &Waker) {
60 self.wakers.borrow_mut().runner.register(waker);
61 }
62
63 pub async fn wait_complete(&self) -> usize {
64 poll_fn(|cx| {
65 if let IoctlStateInner::Done { resp_len } = self.state.get() {
66 Poll::Ready(resp_len)
67 } else {
68 self.register_control(cx.waker());
69 Poll::Pending
70 }
71 })
72 .await
73 }
74
75 pub async fn wait_pending(&self) -> PendingIoctl {
76 let pending = poll_fn(|cx| {
77 if let IoctlStateInner::Pending(pending) = self.state.get() {
78 warn!("found pending ioctl");
79 Poll::Ready(pending)
80 } else {
81 self.register_runner(cx.waker());
82 Poll::Pending
83 }
84 })
85 .await;
86
87 self.state.set(IoctlStateInner::Sent { buf: pending.buf });
88 pending
89 }
90
91 pub async fn do_ioctl(&self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize {
92 warn!("doing ioctl");
93 self.state
94 .set(IoctlStateInner::Pending(PendingIoctl { buf, kind, cmd, iface }));
95 self.wake_runner();
96 self.wait_complete().await
97 }
98
99 pub fn ioctl_done(&self, response: &[u8]) {
100 if let IoctlStateInner::Sent { buf } = self.state.get() {
101 warn!("ioctl complete");
102 // TODO fix this
103 (unsafe { &mut *buf }[..response.len()]).copy_from_slice(response);
104
105 self.state.set(IoctlStateInner::Done {
106 resp_len: response.len(),
107 });
108 self.wake_control();
109 }
110 }
111}
diff --git a/src/lib.rs b/src/lib.rs
index af8f74a6d..069ca40f4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -11,17 +11,17 @@ mod bus;
11mod consts; 11mod consts;
12mod countries; 12mod countries;
13mod events; 13mod events;
14mod ioctl;
14mod structs; 15mod structs;
15 16
16mod control; 17mod control;
17mod nvram; 18mod nvram;
18mod runner; 19mod runner;
19 20
20use core::cell::Cell;
21
22use embassy_net_driver_channel as ch; 21use embassy_net_driver_channel as ch;
23use embedded_hal_1::digital::OutputPin; 22use embedded_hal_1::digital::OutputPin;
24use events::EventQueue; 23use events::EventQueue;
24use ioctl::IoctlState;
25 25
26use crate::bus::Bus; 26use crate::bus::Bus;
27pub use crate::bus::SpiBusCyw43; 27pub use crate::bus::SpiBusCyw43;
@@ -30,12 +30,6 @@ pub use crate::runner::Runner;
30 30
31const MTU: usize = 1514; 31const MTU: usize = 1514;
32 32
33#[derive(Clone, Copy)]
34pub enum IoctlType {
35 Get = 0,
36 Set = 2,
37}
38
39#[allow(unused)] 33#[allow(unused)]
40#[derive(Clone, Copy, PartialEq, Eq)] 34#[derive(Clone, Copy, PartialEq, Eq)]
41enum Core { 35enum Core {
@@ -106,26 +100,8 @@ const CHIP: Chip = Chip {
106 chanspec_ctl_sb_mask: 0x0700, 100 chanspec_ctl_sb_mask: 0x0700,
107}; 101};
108 102
109#[derive(Clone, Copy)]
110enum IoctlState {
111 Idle,
112
113 Pending {
114 kind: IoctlType,
115 cmd: u32,
116 iface: u32,
117 buf: *mut [u8],
118 },
119 Sent {
120 buf: *mut [u8],
121 },
122 Done {
123 resp_len: usize,
124 },
125}
126
127pub struct State { 103pub struct State {
128 ioctl_state: Cell<IoctlState>, 104 ioctl_state: IoctlState,
129 ch: ch::State<MTU, 4, 4>, 105 ch: ch::State<MTU, 4, 4>,
130 events: EventQueue, 106 events: EventQueue,
131} 107}
@@ -133,7 +109,7 @@ pub struct State {
133impl State { 109impl State {
134 pub fn new() -> Self { 110 pub fn new() -> Self {
135 Self { 111 Self {
136 ioctl_state: Cell::new(IoctlState::Idle), 112 ioctl_state: IoctlState::new(),
137 ch: ch::State::new(), 113 ch: ch::State::new(),
138 events: EventQueue::new(), 114 events: EventQueue::new(),
139 } 115 }
diff --git a/src/runner.rs b/src/runner.rs
index 9945af3fc..4abccf48b 100644
--- a/src/runner.rs
+++ b/src/runner.rs
@@ -1,6 +1,6 @@
1use core::cell::Cell;
2use core::slice; 1use core::slice;
3 2
3use embassy_futures::select::{select3, Either3};
4use embassy_futures::yield_now; 4use embassy_futures::yield_now;
5use embassy_net_driver_channel as ch; 5use embassy_net_driver_channel as ch;
6use embassy_sync::pubsub::PubSubBehavior; 6use embassy_sync::pubsub::PubSubBehavior;
@@ -12,9 +12,10 @@ pub use crate::bus::SpiBusCyw43;
12use crate::consts::*; 12use crate::consts::*;
13use crate::events::{EventQueue, EventStatus}; 13use crate::events::{EventQueue, EventStatus};
14use crate::fmt::Bytes; 14use crate::fmt::Bytes;
15use crate::ioctl::{IoctlState, IoctlType, PendingIoctl};
15use crate::nvram::NVRAM; 16use crate::nvram::NVRAM;
16use crate::structs::*; 17use crate::structs::*;
17use crate::{events, Core, IoctlState, IoctlType, CHIP, MTU}; 18use crate::{events, Core, CHIP, MTU};
18 19
19#[cfg(feature = "firmware-logs")] 20#[cfg(feature = "firmware-logs")]
20struct LogState { 21struct LogState {
@@ -40,7 +41,7 @@ pub struct Runner<'a, PWR, SPI> {
40 ch: ch::Runner<'a, MTU>, 41 ch: ch::Runner<'a, MTU>,
41 bus: Bus<PWR, SPI>, 42 bus: Bus<PWR, SPI>,
42 43
43 ioctl_state: &'a Cell<IoctlState>, 44 ioctl_state: &'a IoctlState,
44 ioctl_id: u16, 45 ioctl_id: u16,
45 sdpcm_seq: u8, 46 sdpcm_seq: u8,
46 sdpcm_seq_max: u8, 47 sdpcm_seq_max: u8,
@@ -59,7 +60,7 @@ where
59 pub(crate) fn new( 60 pub(crate) fn new(
60 ch: ch::Runner<'a, MTU>, 61 ch: ch::Runner<'a, MTU>,
61 bus: Bus<PWR, SPI>, 62 bus: Bus<PWR, SPI>,
62 ioctl_state: &'a Cell<IoctlState>, 63 ioctl_state: &'a IoctlState,
63 events: &'a EventQueue, 64 events: &'a EventQueue,
64 ) -> Self { 65 ) -> Self {
65 Self { 66 Self {
@@ -226,19 +227,22 @@ where
226 #[cfg(feature = "firmware-logs")] 227 #[cfg(feature = "firmware-logs")]
227 self.log_read().await; 228 self.log_read().await;
228 229
229 // Send stuff 230 let ev = || async {
230 // TODO flow control not yet complete 231 // TODO use IRQs
231 if !self.has_credit() { 232 yield_now().await;
232 warn!("TX stalled"); 233 };
233 } else { 234
234 if let IoctlState::Pending { kind, cmd, iface, buf } = self.ioctl_state.get() { 235 if self.has_credit() {
235 self.send_ioctl(kind, cmd, iface, unsafe { &*buf }).await; 236 let ioctl = self.ioctl_state.wait_pending();
236 self.ioctl_state.set(IoctlState::Sent { buf }); 237 let tx = self.ch.tx_buf();
237 } 238
238 if !self.has_credit() { 239 match select3(ioctl, tx, ev()).await {
239 warn!("TX stalled"); 240 Either3::First(PendingIoctl { buf, kind, cmd, iface }) => {
240 } else { 241 warn!("ioctl");
241 if let Some(packet) = self.ch.try_tx_buf() { 242 self.send_ioctl(kind, cmd, iface, unsafe { &*buf }).await;
243 }
244 Either3::Second(packet) => {
245 warn!("packet");
242 trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)])); 246 trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)]));
243 247
244 let mut buf = [0; 512]; 248 let mut buf = [0; 512];
@@ -281,28 +285,46 @@ where
281 self.bus.wlan_write(&buf[..(total_len / 4)]).await; 285 self.bus.wlan_write(&buf[..(total_len / 4)]).await;
282 self.ch.tx_done(); 286 self.ch.tx_done();
283 } 287 }
288 Either3::Third(()) => {
289 // Receive stuff
290 let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await;
291
292 if irq & IRQ_F2_PACKET_AVAILABLE != 0 {
293 let mut status = 0xFFFF_FFFF;
294 while status == 0xFFFF_FFFF {
295 status = self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await;
296 }
297
298 if status & STATUS_F2_PKT_AVAILABLE != 0 {
299 let len = (status & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT;
300 self.bus.wlan_read(&mut buf, len).await;
301 trace!("rx {:02x}", Bytes(&slice8_mut(&mut buf)[..(len as usize).min(48)]));
302 self.rx(&slice8_mut(&mut buf)[..len as usize]);
303 }
304 }
305 }
284 } 306 }
285 } 307 } else {
308 warn!("TX stalled");
309 ev().await;
286 310
287 // Receive stuff 311 // Receive stuff
288 let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await; 312 let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await;
289 313
290 if irq & IRQ_F2_PACKET_AVAILABLE != 0 { 314 if irq & IRQ_F2_PACKET_AVAILABLE != 0 {
291 let mut status = 0xFFFF_FFFF; 315 let mut status = 0xFFFF_FFFF;
292 while status == 0xFFFF_FFFF { 316 while status == 0xFFFF_FFFF {
293 status = self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await; 317 status = self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await;
294 } 318 }
295 319
296 if status & STATUS_F2_PKT_AVAILABLE != 0 { 320 if status & STATUS_F2_PKT_AVAILABLE != 0 {
297 let len = (status & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT; 321 let len = (status & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT;
298 self.bus.wlan_read(&mut buf, len).await; 322 self.bus.wlan_read(&mut buf, len).await;
299 trace!("rx {:02x}", Bytes(&slice8_mut(&mut buf)[..(len as usize).min(48)])); 323 trace!("rx {:02x}", Bytes(&slice8_mut(&mut buf)[..(len as usize).min(48)]));
300 self.rx(&slice8_mut(&mut buf)[..len as usize]); 324 self.rx(&slice8_mut(&mut buf)[..len as usize]);
325 }
301 } 326 }
302 } 327 }
303
304 // TODO use IRQs
305 yield_now().await;
306 } 328 }
307 } 329 }
308 330
@@ -340,19 +362,17 @@ where
340 let cdc_header = CdcHeader::from_bytes(payload[..CdcHeader::SIZE].try_into().unwrap()); 362 let cdc_header = CdcHeader::from_bytes(payload[..CdcHeader::SIZE].try_into().unwrap());
341 trace!(" {:?}", cdc_header); 363 trace!(" {:?}", cdc_header);
342 364
343 if let IoctlState::Sent { buf } = self.ioctl_state.get() { 365 if cdc_header.id == self.ioctl_id {
344 if cdc_header.id == self.ioctl_id { 366 if cdc_header.status != 0 {
345 if cdc_header.status != 0 { 367 // TODO: propagate error instead
346 // TODO: propagate error instead 368 panic!("IOCTL error {}", cdc_header.status as i32);
347 panic!("IOCTL error {}", cdc_header.status as i32); 369 }
348 }
349 370
350 let resp_len = cdc_header.len as usize; 371 let resp_len = cdc_header.len as usize;
351 info!("IOCTL Response: {:02x}", Bytes(&payload[CdcHeader::SIZE..][..resp_len])); 372 let response = &payload[CdcHeader::SIZE..][..resp_len];
373 info!("IOCTL Response: {:02x}", Bytes(response));
352 374
353 (unsafe { &mut *buf }[..resp_len]).copy_from_slice(&payload[CdcHeader::SIZE..][..resp_len]); 375 self.ioctl_state.ioctl_done(response);
354 self.ioctl_state.set(IoctlState::Done { resp_len });
355 }
356 } 376 }
357 } 377 }
358 CHANNEL_TYPE_EVENT => { 378 CHANNEL_TYPE_EVENT => {