aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-04-27 18:23:36 +0000
committerGitHub <[email protected]>2023-04-27 18:23:36 +0000
commitc19de2984751ba6fa2972ee66cfa2a6310d5f0c1 (patch)
tree9ba8fa01994be9ef43af404cb4399854e8c6de22 /src
parentf4bfda345d3d18232926a87b10333a2e624f4d04 (diff)
parent9e96655757180d7fe32ebff1ed93a35a4c3cff28 (diff)
Merge pull request #63 from kbleeke/generalize-events
rework event handling to allow sending data to `Control`
Diffstat (limited to 'src')
-rw-r--r--src/bus.rs8
-rw-r--r--src/consts.rs44
-rw-r--r--src/control.rs21
-rw-r--r--src/events.rs111
-rw-r--r--src/ioctl.rs6
-rw-r--r--src/lib.rs13
-rw-r--r--src/runner.rs37
7 files changed, 198 insertions, 42 deletions
diff --git a/src/bus.rs b/src/bus.rs
index add346b2f..e26f11120 100644
--- a/src/bus.rs
+++ b/src/bus.rs
@@ -1,11 +1,10 @@
1use core::slice;
2
3use embassy_futures::yield_now; 1use embassy_futures::yield_now;
4use embassy_time::{Duration, Timer}; 2use embassy_time::{Duration, Timer};
5use embedded_hal_1::digital::OutputPin; 3use embedded_hal_1::digital::OutputPin;
6use futures::FutureExt; 4use futures::FutureExt;
7 5
8use crate::consts::*; 6use crate::consts::*;
7use crate::slice8_mut;
9 8
10/// Custom Spi Trait that _only_ supports the bus operation of the cyw43 9/// Custom Spi Trait that _only_ supports the bus operation of the cyw43
11/// Implementors are expected to hold the CS pin low during an operation. 10/// Implementors are expected to hold the CS pin low during an operation.
@@ -327,8 +326,3 @@ fn swap16(x: u32) -> u32 {
327fn cmd_word(write: bool, incr: bool, func: u32, addr: u32, len: u32) -> u32 { 326fn cmd_word(write: bool, incr: bool, func: u32, addr: u32, len: u32) -> u32 {
328 (write as u32) << 31 | (incr as u32) << 30 | (func & 0b11) << 28 | (addr & 0x1FFFF) << 11 | (len & 0x7FF) 327 (write as u32) << 31 | (incr as u32) << 30 | (func & 0b11) << 28 | (addr & 0x1FFFF) << 11 | (len & 0x7FF)
329} 328}
330
331fn slice8_mut(x: &mut [u32]) -> &mut [u8] {
332 let len = x.len() * 4;
333 unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) }
334}
diff --git a/src/consts.rs b/src/consts.rs
index fee2d01ab..18502bd1a 100644
--- a/src/consts.rs
+++ b/src/consts.rs
@@ -109,6 +109,50 @@ pub(crate) const READ: bool = false;
109pub(crate) const INC_ADDR: bool = true; 109pub(crate) const INC_ADDR: bool = true;
110pub(crate) const FIXED_ADDR: bool = false; 110pub(crate) const FIXED_ADDR: bool = false;
111 111
112#[allow(non_camel_case_types)]
113#[derive(Copy, Clone)]
114#[repr(u8)]
115pub enum EStatus {
116 /// operation was successful
117 SUCCESS = 0,
118 /// operation failed
119 FAIL = 1,
120 /// operation timed out
121 TIMEOUT = 2,
122 /// failed due to no matching network found
123 NO_NETWORKS = 3,
124 /// operation was aborted
125 ABORT = 4,
126 /// protocol failure: packet not ack'd
127 NO_ACK = 5,
128 /// AUTH or ASSOC packet was unsolicited
129 UNSOLICITED = 6,
130 /// attempt to assoc to an auto auth configuration
131 ATTEMPT = 7,
132 /// scan results are incomplete
133 PARTIAL = 8,
134 /// scan aborted by another scan
135 NEWSCAN = 9,
136 /// scan aborted due to assoc in progress
137 NEWASSOC = 10,
138 /// 802.11h quiet period started
139 _11HQUIET = 11,
140 /// user disabled scanning (WLC_SET_SCANSUPPRESS)
141 SUPPRESS = 12,
142 /// no allowable channels to scan
143 NOCHANS = 13,
144 /// scan aborted due to CCX fast roam
145 CCXFASTRM = 14,
146 /// abort channel select
147 CS_ABORT = 15,
148}
149
150impl PartialEq<EStatus> for u32 {
151 fn eq(&self, other: &EStatus) -> bool {
152 *self == *other as Self
153 }
154}
155
112#[allow(dead_code)] 156#[allow(dead_code)]
113pub(crate) struct FormatStatus(pub u32); 157pub(crate) struct FormatStatus(pub u32);
114 158
diff --git a/src/control.rs b/src/control.rs
index 30d5d0924..0c06009b9 100644
--- a/src/control.rs
+++ b/src/control.rs
@@ -6,7 +6,7 @@ use embassy_time::{Duration, Timer};
6 6
7pub use crate::bus::SpiBusCyw43; 7pub use crate::bus::SpiBusCyw43;
8use crate::consts::*; 8use crate::consts::*;
9use crate::events::{Event, EventQueue}; 9use crate::events::{Event, Events};
10use crate::fmt::Bytes; 10use crate::fmt::Bytes;
11use crate::ioctl::{IoctlState, IoctlType}; 11use crate::ioctl::{IoctlState, IoctlType};
12use crate::structs::*; 12use crate::structs::*;
@@ -14,15 +14,15 @@ use crate::{countries, PowerManagementMode};
14 14
15pub struct Control<'a> { 15pub struct Control<'a> {
16 state_ch: ch::StateRunner<'a>, 16 state_ch: ch::StateRunner<'a>,
17 event_sub: &'a EventQueue, 17 events: &'a Events,
18 ioctl_state: &'a IoctlState, 18 ioctl_state: &'a IoctlState,
19} 19}
20 20
21impl<'a> Control<'a> { 21impl<'a> Control<'a> {
22 pub(crate) fn new(state_ch: ch::StateRunner<'a>, event_sub: &'a EventQueue, ioctl_state: &'a IoctlState) -> Self { 22 pub(crate) fn new(state_ch: ch::StateRunner<'a>, event_sub: &'a Events, ioctl_state: &'a IoctlState) -> Self {
23 Self { 23 Self {
24 state_ch, 24 state_ch,
25 event_sub, 25 events: event_sub,
26 ioctl_state, 26 ioctl_state,
27 } 27 }
28 } 28 }
@@ -195,24 +195,27 @@ impl<'a> Control<'a> {
195 } 195 }
196 196
197 async fn wait_for_join(&mut self, i: SsidInfo) { 197 async fn wait_for_join(&mut self, i: SsidInfo) {
198 let mut subscriber = self.event_sub.subscriber().unwrap(); 198 self.events.mask.enable(&[Event::JOIN, Event::AUTH]);
199 let mut subscriber = self.events.queue.subscriber().unwrap();
200 // the actual join operation starts here
201 // we make sure to enable events before so we don't miss any
199 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_SSID, 0, &mut i.to_bytes()) 202 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_SSID, 0, &mut i.to_bytes())
200 .await; 203 .await;
201 // set_ssid 204 // set_ssid
202 205
203 loop { 206 loop {
204 let msg = subscriber.next_message_pure().await; 207 let msg = subscriber.next_message_pure().await;
205 if msg.event_type == Event::AUTH && msg.status != 0 { 208 if msg.header.event_type == Event::AUTH && msg.header.status != EStatus::SUCCESS {
206 // retry 209 // retry
207 warn!("JOIN failed with status={}", msg.status); 210 warn!("JOIN failed with status={}", msg.header.status);
208 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_SSID, 0, &mut i.to_bytes()) 211 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_SSID, 0, &mut i.to_bytes())
209 .await; 212 .await;
210 } else if msg.event_type == Event::JOIN && msg.status == 0 { 213 } else if msg.header.event_type == Event::JOIN && msg.header.status == EStatus::SUCCESS {
211 // successful join 214 // successful join
212 break; 215 break;
213 } 216 }
214 } 217 }
215 218 self.events.mask.disable_all();
216 self.state_ch.set_link_state(LinkState::Up); 219 self.state_ch.set_link_state(LinkState::Up);
217 info!("JOINED"); 220 info!("JOINED");
218 } 221 }
diff --git a/src/events.rs b/src/events.rs
index 87f6c01a3..d6f114ed9 100644
--- a/src/events.rs
+++ b/src/events.rs
@@ -1,7 +1,7 @@
1#![allow(unused)] 1#![allow(unused)]
2#![allow(non_camel_case_types)] 2#![allow(non_camel_case_types)]
3 3
4use core::num; 4use core::cell::RefCell;
5 5
6use embassy_sync::blocking_mutex::raw::NoopRawMutex; 6use embassy_sync::blocking_mutex::raw::NoopRawMutex;
7use embassy_sync::pubsub::{PubSubChannel, Publisher, Subscriber}; 7use embassy_sync::pubsub::{PubSubChannel, Publisher, Subscriber};
@@ -284,13 +284,114 @@ pub enum Event {
284 LAST = 190, 284 LAST = 190,
285} 285}
286 286
287pub type EventQueue = PubSubChannel<NoopRawMutex, EventStatus, 2, 1, 1>; 287// TODO this PubSub can probably be replaced with shared memory to make it a bit more efficient.
288pub type EventPublisher<'a> = Publisher<'a, NoopRawMutex, EventStatus, 2, 1, 1>; 288pub type EventQueue = PubSubChannel<NoopRawMutex, Message, 2, 1, 1>;
289pub type EventSubscriber<'a> = Subscriber<'a, NoopRawMutex, EventStatus, 2, 1, 1>; 289pub type EventPublisher<'a> = Publisher<'a, NoopRawMutex, Message, 2, 1, 1>;
290pub type EventSubscriber<'a> = Subscriber<'a, NoopRawMutex, Message, 2, 1, 1>;
291
292pub struct Events {
293 pub queue: EventQueue,
294 pub mask: SharedEventMask,
295}
296
297impl Events {
298 pub fn new() -> Self {
299 Self {
300 queue: EventQueue::new(),
301 mask: SharedEventMask::default(),
302 }
303 }
304}
290 305
291#[derive(Clone, Copy)] 306#[derive(Clone, Copy)]
292#[cfg_attr(feature = "defmt", derive(defmt::Format))] 307#[cfg_attr(feature = "defmt", derive(defmt::Format))]
293pub struct EventStatus { 308pub struct Status {
294 pub event_type: Event, 309 pub event_type: Event,
295 pub status: u32, 310 pub status: u32,
296} 311}
312
313#[derive(Clone, Copy)]
314pub enum Payload {
315 None,
316}
317
318#[derive(Clone, Copy)]
319
320pub struct Message {
321 pub header: Status,
322 pub payload: Payload,
323}
324
325impl Message {
326 pub fn new(status: Status, payload: Payload) -> Self {
327 Self {
328 header: status,
329 payload,
330 }
331 }
332}
333
334#[derive(Default)]
335struct EventMask {
336 mask: [u32; Self::WORD_COUNT],
337}
338
339impl EventMask {
340 const WORD_COUNT: usize = ((Event::LAST as u32 + (u32::BITS - 1)) / u32::BITS) as usize;
341
342 fn enable(&mut self, event: Event) {
343 let n = event as u32;
344 let word = n / u32::BITS;
345 let bit = n % u32::BITS;
346
347 self.mask[word as usize] |= (1 << bit);
348 }
349
350 fn disable(&mut self, event: Event) {
351 let n = event as u32;
352 let word = n / u32::BITS;
353 let bit = n % u32::BITS;
354
355 self.mask[word as usize] &= !(1 << bit);
356 }
357
358 fn is_enabled(&self, event: Event) -> bool {
359 let n = event as u32;
360 let word = n / u32::BITS;
361 let bit = n % u32::BITS;
362
363 self.mask[word as usize] & (1 << bit) > 0
364 }
365}
366
367#[derive(Default)]
368
369pub struct SharedEventMask {
370 mask: RefCell<EventMask>,
371}
372
373impl SharedEventMask {
374 pub fn enable(&self, events: &[Event]) {
375 let mut mask = self.mask.borrow_mut();
376 for event in events {
377 mask.enable(*event);
378 }
379 }
380
381 pub fn disable(&self, events: &[Event]) {
382 let mut mask = self.mask.borrow_mut();
383 for event in events {
384 mask.disable(*event);
385 }
386 }
387
388 pub fn disable_all(&self) {
389 let mut mask = self.mask.borrow_mut();
390 mask.mask = Default::default();
391 }
392
393 pub fn is_enabled(&self, event: Event) -> bool {
394 let mask = self.mask.borrow();
395 mask.is_enabled(event)
396 }
397}
diff --git a/src/ioctl.rs b/src/ioctl.rs
index 0fee1ad19..66c6a10e5 100644
--- a/src/ioctl.rs
+++ b/src/ioctl.rs
@@ -4,6 +4,8 @@ use core::task::{Poll, Waker};
4 4
5use embassy_sync::waitqueue::WakerRegistration; 5use embassy_sync::waitqueue::WakerRegistration;
6 6
7use crate::fmt::Bytes;
8
7#[derive(Clone, Copy)] 9#[derive(Clone, Copy)]
8pub enum IoctlType { 10pub enum IoctlType {
9 Get = 0, 11 Get = 0,
@@ -108,6 +110,8 @@ impl IoctlState {
108 110
109 pub fn ioctl_done(&self, response: &[u8]) { 111 pub fn ioctl_done(&self, response: &[u8]) {
110 if let IoctlStateInner::Sent { buf } = self.state.get() { 112 if let IoctlStateInner::Sent { buf } = self.state.get() {
113 info!("IOCTL Response: {:02x}", Bytes(response));
114
111 // TODO fix this 115 // TODO fix this
112 (unsafe { &mut *buf }[..response.len()]).copy_from_slice(response); 116 (unsafe { &mut *buf }[..response.len()]).copy_from_slice(response);
113 117
@@ -115,6 +119,8 @@ impl IoctlState {
115 resp_len: response.len(), 119 resp_len: response.len(),
116 }); 120 });
117 self.wake_control(); 121 self.wake_control();
122 } else {
123 warn!("IOCTL Response but no pending Ioctl");
118 } 124 }
119 } 125 }
120} 126}
diff --git a/src/lib.rs b/src/lib.rs
index 069ca40f4..f9244bddb 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -18,9 +18,11 @@ mod control;
18mod nvram; 18mod nvram;
19mod runner; 19mod runner;
20 20
21use core::slice;
22
21use embassy_net_driver_channel as ch; 23use embassy_net_driver_channel as ch;
22use embedded_hal_1::digital::OutputPin; 24use embedded_hal_1::digital::OutputPin;
23use events::EventQueue; 25use events::Events;
24use ioctl::IoctlState; 26use ioctl::IoctlState;
25 27
26use crate::bus::Bus; 28use crate::bus::Bus;
@@ -103,7 +105,7 @@ const CHIP: Chip = Chip {
103pub struct State { 105pub struct State {
104 ioctl_state: IoctlState, 106 ioctl_state: IoctlState,
105 ch: ch::State<MTU, 4, 4>, 107 ch: ch::State<MTU, 4, 4>,
106 events: EventQueue, 108 events: Events,
107} 109}
108 110
109impl State { 111impl State {
@@ -111,7 +113,7 @@ impl State {
111 Self { 113 Self {
112 ioctl_state: IoctlState::new(), 114 ioctl_state: IoctlState::new(),
113 ch: ch::State::new(), 115 ch: ch::State::new(),
114 events: EventQueue::new(), 116 events: Events::new(),
115 } 117 }
116 } 118 }
117} 119}
@@ -225,3 +227,8 @@ where
225 runner, 227 runner,
226 ) 228 )
227} 229}
230
231fn slice8_mut(x: &mut [u32]) -> &mut [u8] {
232 let len = x.len() * 4;
233 unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) }
234}
diff --git a/src/runner.rs b/src/runner.rs
index f0f6fceeb..806ddfc49 100644
--- a/src/runner.rs
+++ b/src/runner.rs
@@ -1,5 +1,3 @@
1use core::slice;
2
3use embassy_futures::select::{select3, Either3}; 1use embassy_futures::select::{select3, Either3};
4use embassy_net_driver_channel as ch; 2use embassy_net_driver_channel as ch;
5use embassy_sync::pubsub::PubSubBehavior; 3use embassy_sync::pubsub::PubSubBehavior;
@@ -9,12 +7,12 @@ use embedded_hal_1::digital::OutputPin;
9use crate::bus::Bus; 7use crate::bus::Bus;
10pub use crate::bus::SpiBusCyw43; 8pub use crate::bus::SpiBusCyw43;
11use crate::consts::*; 9use crate::consts::*;
12use crate::events::{EventQueue, EventStatus}; 10use crate::events::{Events, Status};
13use crate::fmt::Bytes; 11use crate::fmt::Bytes;
14use crate::ioctl::{IoctlState, IoctlType, PendingIoctl}; 12use crate::ioctl::{IoctlState, IoctlType, PendingIoctl};
15use crate::nvram::NVRAM; 13use crate::nvram::NVRAM;
16use crate::structs::*; 14use crate::structs::*;
17use crate::{events, Core, CHIP, MTU}; 15use crate::{events, slice8_mut, Core, CHIP, MTU};
18 16
19#[cfg(feature = "firmware-logs")] 17#[cfg(feature = "firmware-logs")]
20struct LogState { 18struct LogState {
@@ -45,7 +43,7 @@ pub struct Runner<'a, PWR, SPI> {
45 sdpcm_seq: u8, 43 sdpcm_seq: u8,
46 sdpcm_seq_max: u8, 44 sdpcm_seq_max: u8,
47 45
48 events: &'a EventQueue, 46 events: &'a Events,
49 47
50 #[cfg(feature = "firmware-logs")] 48 #[cfg(feature = "firmware-logs")]
51 log: LogState, 49 log: LogState,
@@ -60,7 +58,7 @@ where
60 ch: ch::Runner<'a, MTU>, 58 ch: ch::Runner<'a, MTU>,
61 bus: Bus<PWR, SPI>, 59 bus: Bus<PWR, SPI>,
62 ioctl_state: &'a IoctlState, 60 ioctl_state: &'a IoctlState,
63 events: &'a EventQueue, 61 events: &'a Events,
64 ) -> Self { 62 ) -> Self {
65 Self { 63 Self {
66 ch, 64 ch,
@@ -353,8 +351,6 @@ where
353 panic!("IOCTL error {}", cdc_header.status as i32); 351 panic!("IOCTL error {}", cdc_header.status as i32);
354 } 352 }
355 353
356 info!("IOCTL Response: {:02x}", Bytes(response));
357
358 self.ioctl_state.ioctl_done(response); 354 self.ioctl_state.ioctl_done(response);
359 } 355 }
360 } 356 }
@@ -406,11 +402,21 @@ where
406 Bytes(evt_data) 402 Bytes(evt_data)
407 ); 403 );
408 404
409 if evt_type == events::Event::AUTH || evt_type == events::Event::JOIN { 405 if self.events.mask.is_enabled(evt_type) {
410 self.events.publish_immediate(EventStatus { 406 let status = event_packet.msg.status;
411 status: event_packet.msg.status, 407 let event_payload = events::Payload::None;
412 event_type: evt_type, 408
413 }); 409 // this intentionally uses the non-blocking publish immediate
410 // publish() is a deadlock risk in the current design as awaiting here prevents ioctls
411 // The `Runner` always yields when accessing the device, so consumers always have a chance to receive the event
412 // (if they are actively awaiting the queue)
413 self.events.queue.publish_immediate(events::Message::new(
414 Status {
415 event_type: evt_type,
416 status,
417 },
418 event_payload,
419 ));
414 } 420 }
415 } 421 }
416 CHANNEL_TYPE_DATA => { 422 CHANNEL_TYPE_DATA => {
@@ -548,8 +554,3 @@ where
548 true 554 true
549 } 555 }
550} 556}
551
552fn slice8_mut(x: &mut [u32]) -> &mut [u8] {
553 let len = x.len() * 4;
554 unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) }
555}