1use super::macros::reset_and_restore_bufs;
15use super::{bus, constants, sdpcm};
16use crate::wifi;
17use core::cell::Cell;
18use core::iter::{Enumerate, Peekable};
19use core::slice::Chunks;
20use enum_primitive::cast::FromPrimitive;
21use kernel::hil::time::ConvertTicks;
22use kernel::utilities::cells::{MapCell, OptionalCell};
23use kernel::utilities::leasable_buffer::SubSliceMut;
24use kernel::{hil, ErrorCode};
25
26#[derive(Clone, Copy, Debug, Default)]
28enum State {
29 #[default]
30 Idle,
31 NotInit,
32 PoweredDown,
33 PoweredUp,
34 BusInit,
35 Command(Command),
36 Ethernet,
37}
38
39#[derive(Clone, Copy, Debug)]
40enum Command {
41 Init,
42 Join,
43 Leave,
44 Scan,
45 StopScan,
46 Ap,
47 Sta,
48}
49
50#[derive(Clone, Copy)]
52enum Pending {
53 Scan,
54 MacAddr,
55}
56
57pub struct CYW4343x<'a, P: hil::gpio::Pin, A: hil::time::Alarm<'a>, B: bus::CYW4343xBus<'a>> {
59 alarm: &'a A,
62 bus: &'a B,
64 pwr: &'a P,
66 state: Cell<State>,
68 buffer: OptionalCell<SubSliceMut<'static, u8>>,
70 client: OptionalCell<&'a dyn wifi::Client>,
72 eth_client: OptionalCell<&'a dyn hil::ethernet::EthernetAdapterDatapathClient>,
74 sdpcm_seq: Cell<u8>,
76 id: Cell<u16>,
78 receive: Cell<bool>,
80 eth_tx_data: OptionalCell<(usize, &'static mut [u8])>,
82 ioctl_tasks: ioctl::Tasks,
84 clm: MapCell<Peekable<Enumerate<Chunks<'static, u8>>>>,
86 ssid: OptionalCell<wifi::Ssid>,
88 security: OptionalCell<wifi::Passphrase>,
90 channel: OptionalCell<u8>,
92 pending: OptionalCell<Pending>,
94 mac: OptionalCell<[u8; 6]>,
96}
97
98impl<'a, P: hil::gpio::Pin, A: hil::time::Alarm<'a>, B: bus::CYW4343xBus<'a>>
99 CYW4343x<'a, P, A, B>
100{
101 pub fn new(
102 alarm: &'a A,
103 bus: &'a B,
104 pwr: &'a P,
105 clm: &'static [u8],
106 buffer: &'static mut [u8; 1600],
107 ) -> Self {
108 Self {
109 alarm,
110 bus,
111 pwr,
112 state: Cell::new(State::NotInit),
113 client: OptionalCell::empty(),
114 eth_client: OptionalCell::empty(),
115 sdpcm_seq: Cell::new(0),
116 id: Cell::new(0),
117 receive: Cell::new(false),
118 ssid: OptionalCell::empty(),
119 security: OptionalCell::empty(),
120 channel: OptionalCell::empty(),
121 ioctl_tasks: ioctl::Tasks::new(),
122 eth_tx_data: OptionalCell::empty(),
123 pending: OptionalCell::empty(),
124 clm: MapCell::new(clm.chunks(constants::CLM_CHUNK_SIZE).enumerate().peekable()),
125 buffer: OptionalCell::new(SubSliceMut::new(buffer)),
126 mac: OptionalCell::empty(),
127 }
128 }
129
130 fn send_bdc(&self, data: &[u8]) -> Result<(), ErrorCode> {
132 let Some(mut buffer) = self.buffer.take() else {
133 return Err(ErrorCode::NOMEM);
134 };
135
136 let total_len = sdpcm::SdpcmHeader::SIZE
137 + constants::BDC_PADDING_SIZE
138 + sdpcm::BdcHeader::SIZE
139 + data.len();
140
141 let seq = self.sdpcm_seq.get();
142 self.sdpcm_seq.set(seq.wrapping_add(1));
143
144 let sdpcm_header = sdpcm::SdpcmHeader {
145 len: total_len as u16,
146 len_inv: !total_len as u16,
147 seq,
148 flags: sdpcm::ChannelType::Data as _,
149 next_len: 0,
150 data_offset: (sdpcm::SdpcmHeader::SIZE + constants::BDC_PADDING_SIZE) as _,
151 flow_ctrl: 0,
152 data_credit: 0,
153 reserved: 0,
154 }
155 .into_bytes();
156
157 let bdc_header = sdpcm::BdcHeader {
158 flags: constants::BDC_VERSION << constants::BDC_VERSION_SHIFT,
159 priority: 0,
160 flags2: 0,
161 data_offset: 0,
162 }
163 .into_bytes();
164
165 buffer.slice(0..total_len);
166 let slice = buffer.as_mut_slice();
167 slice[0..sdpcm::SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header);
168 slice[sdpcm::SdpcmHeader::SIZE + constants::BDC_PADDING_SIZE..][..sdpcm::BdcHeader::SIZE]
169 .copy_from_slice(&bdc_header);
170 slice[sdpcm::SdpcmHeader::SIZE + constants::BDC_PADDING_SIZE + sdpcm::BdcHeader::SIZE..]
171 [..data.len()]
172 .copy_from_slice(data);
173
174 self.bus.write_bytes(buffer).map_err(|(err, mut buffer)| {
175 reset_and_restore_bufs!(self, buffer);
176 err
177 })
178 }
179
180 fn send_cdc(
181 &self,
182 ioctl: sdpcm::IoctlType,
183 cmd: sdpcm::IoctlCommand,
184 data: &[u8],
185 ) -> Result<(), ErrorCode> {
186 let Some(mut buffer) = self.buffer.take() else {
187 return Err(ErrorCode::NOMEM);
188 };
189
190 let total_len = sdpcm::SdpcmHeader::SIZE + sdpcm::CdcHeader::SIZE + data.len();
191
192 let seq = self.sdpcm_seq.get();
193 self.sdpcm_seq.set(seq.wrapping_add(1));
194 self.id.set(self.id.get().wrapping_add(1));
195
196 let sdpcm_header = sdpcm::SdpcmHeader {
197 len: total_len as u16,
198 len_inv: !total_len as u16,
199 seq,
200 flags: sdpcm::ChannelType::Control as u8,
201 next_len: 0,
202 data_offset: sdpcm::SdpcmHeader::SIZE as _,
203 flow_ctrl: 0,
204 data_credit: 0,
205 reserved: 0,
206 }
207 .into_bytes();
208
209 let cdc_header = sdpcm::CdcHeader {
210 cmd: cmd as u32,
211 len: data.len() as _,
212 flags: ioctl as u32 | (self.id.get() as u32) << 16,
213 status: 0,
214 }
215 .into_bytes();
216
217 buffer.slice(0..total_len);
218 let slice = buffer.as_mut_slice();
219 slice[0..sdpcm::SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header);
220 slice[sdpcm::SdpcmHeader::SIZE..][..sdpcm::CdcHeader::SIZE].copy_from_slice(&cdc_header);
221 slice[sdpcm::SdpcmHeader::SIZE + sdpcm::CdcHeader::SIZE..][..data.len()]
222 .copy_from_slice(data);
223
224 self.bus.write_bytes(buffer).map_err(|(err, mut buffer)| {
225 reset_and_restore_bufs!(self, buffer);
226 err
227 })
228 }
229}
230
231impl<'a, P: hil::gpio::Pin, A: hil::time::Alarm<'a>, B: bus::CYW4343xBus<'a>>
232 CYW4343x<'a, P, A, B>
233{
234 fn init_tasks(&self, tasks: &'static [ioctl::Op]) -> Result<(), ErrorCode> {
236 if !self.ioctl_tasks.is_empty() || self.pending.is_some() {
237 Err(ErrorCode::BUSY)
238 } else {
239 self.ioctl_tasks.init(tasks);
240 let advance = self.do_task(tasks[0])?;
241 if advance {
242 self.ioctl_tasks.advance();
243 }
244 Ok(())
245 }
246 }
247
248 fn do_task(&self, task: ioctl::Op) -> Result<bool, ErrorCode> {
252 let mut advance = true;
253 match task {
254 ioctl::Op::Ioctl(ioctl) => self.ioctl(ioctl),
255 ioctl::Op::LoadCLM => self
256 .clm
257 .map(|chunks| {
258 let Some(curr) = chunks.next() else {
259 return Err(ErrorCode::FAIL);
260 };
261 let next = chunks.peek();
262 let mut flag = constants::CLM_DOWNLOAD_FLAG_HANDLER_VER;
263
264 if next.is_none() {
265 flag |= constants::CLM_DOWNLOAD_FLAG_END;
266 } else {
267 advance = false;
268 }
269
270 if curr.0 == 0 {
271 flag |= constants::CLM_DOWNLOAD_FLAG_BEGIN;
272 }
273 let header = sdpcm::WlDloadData {
274 flag,
275 dload_type: constants::CLM_DOWNLOAD_TYPE,
276 len: curr.1.len() as _,
277 crc: 0,
278 }
279 .into_bytes();
280 const IOVAR_SIZE: usize = sdpcm::Iovar::ClmLoad.len();
281 let mut data =
282 [0; IOVAR_SIZE + sdpcm::WlDloadData::SIZE + constants::CLM_CHUNK_SIZE];
283 data[0..IOVAR_SIZE].copy_from_slice(sdpcm::Iovar::ClmLoad.into());
284 data[IOVAR_SIZE..][..sdpcm::WlDloadData::SIZE].copy_from_slice(&header);
285
286 data[IOVAR_SIZE + sdpcm::WlDloadData::SIZE..][..curr.1.len()]
287 .copy_from_slice(curr.1);
288
289 let total_len = IOVAR_SIZE + sdpcm::WlDloadData::SIZE + curr.1.len();
290 self.send_cdc(
291 sdpcm::IoctlType::Set,
292 sdpcm::IoctlCommand::SetVar,
293 &data[..total_len],
294 )
295 })
296 .unwrap_or(Err(ErrorCode::FAIL)),
297 ioctl::Op::WaitMs(ms) => {
298 self.alarm
299 .set_alarm(self.alarm.now(), self.alarm.ticks_from_ms(ms));
300 Ok(())
301 }
302 ioctl::Op::MacAddr => {
303 self.pending.set(Pending::MacAddr);
304 self.send_cdc(
305 sdpcm::IoctlType::Get,
306 sdpcm::IoctlCommand::GetVar,
307 sdpcm::Iovar::CurEthAddr.into(),
308 )
309 .map(|()| self.pending.set(Pending::MacAddr))
310 }
311 }
312 .map(|()| advance)
313 }
314
315 fn ioctl(&self, ioctl: ioctl::Ioctl) -> Result<(), ErrorCode> {
317 let data = match ioctl.data {
318 ioctl::IoctlData::Empty => &[],
319 ioctl::IoctlData::Word(ref bytes) => &bytes[..],
320 ioctl::IoctlData::DWord(ref bytes) => &bytes[..],
321 ioctl::IoctlData::BssSsid => &self
322 .ssid
323 .take()
324 .map(|wifi::Ssid { len, buf }| {
325 sdpcm::SsidInfoWithIndex {
326 idx: 0,
327 len: len.get() as _,
328 buf,
329 }
330 .into_bytes()
331 })
332 .ok_or(ErrorCode::FAIL)?,
333 ioctl::IoctlData::Ssid => &self
334 .ssid
335 .take()
336 .map(|wifi::Ssid { len, buf }| {
337 sdpcm::SsidInfo {
338 len: len.get() as _,
339 buf,
340 }
341 .into_bytes()
342 })
343 .ok_or(ErrorCode::FAIL)?,
344 ioctl::IoctlData::Wpa1Passphrase => &self
345 .security
346 .take()
347 .map(<[u8; sdpcm::PassphraseInfo::SIZE]>::from)
348 .ok_or(ErrorCode::FAIL)?,
349 ioctl::IoctlData::Wpa3Passphrase => &self
350 .security
351 .take()
352 .map(<[u8; sdpcm::SaePassphraseInfo::SIZE]>::from)
353 .ok_or(ErrorCode::FAIL)?,
354 ioctl::IoctlData::Channel => &self
355 .channel
356 .take()
357 .map(|channel| [channel])
358 .ok_or(ErrorCode::FAIL)?,
359 ioctl::IoctlData::ScanParameters => &ioctl::start_scan::SCAN_PARAMS,
360 ioctl::IoctlData::AbortScanParameters => &ioctl::stop_scan::SCAN_PARAMS,
361 ioctl::IoctlData::CountryInfo => &ioctl::init::COUNTRY_INFO,
362 ioctl::IoctlData::EventMask => &ioctl::init::EVENTS,
363 };
364
365 if let Some(name) = ioctl.name {
366 const MAX_LEN: usize = sdpcm::SaePassphraseInfo::SIZE + sdpcm::MAX_IOVAR_LEN;
367 let len = name.len() + data.len();
368
369 let mut iovar: [u8; MAX_LEN] = [0; MAX_LEN];
370 iovar[..name.len()].copy_from_slice(name.into());
371 iovar[name.len()..][..data.len()].copy_from_slice(data);
372
373 self.send_cdc(sdpcm::IoctlType::Set, ioctl.cmd, &iovar[..len])
374 } else {
375 self.send_cdc(sdpcm::IoctlType::Set, ioctl.cmd, data)
376 }
377 }
378
379 fn parse(&self, buffer: &[u8]) {
381 if buffer.len() < sdpcm::SdpcmHeader::SIZE {
382 return;
383 }
384
385 let mut header = &buffer[..sdpcm::SdpcmHeader::SIZE];
386 let sdpcm_header = sdpcm::SdpcmHeader::from_bytes(header);
387
388 let Some(channel) = sdpcm::ChannelType::from_u8(sdpcm_header.flags & 0xf) else {
389 return;
390 };
391 let mut data = &buffer[sdpcm_header.data_offset as usize..];
392
393 match channel {
394 sdpcm::ChannelType::Control => {
396 if data.len() < sdpcm::CdcHeader::SIZE {
397 return;
398 }
399
400 (header, data) = data.split_at(sdpcm::CdcHeader::SIZE);
401 let cdc_header = sdpcm::CdcHeader::from_bytes(header);
402 if cdc_header.status != 0 {
403 return;
404 }
405
406 if (cdc_header.flags >> 16) as u16 == self.id.get()
407 && cdc_header.cmd == sdpcm::IoctlCommand::GetVar as u32
408 {
409 if let Some(Pending::MacAddr) = self.pending.get() {
410 let mut mac = [0u8; 6];
411 mac[..].copy_from_slice(&data[..6]);
412 self.mac.set(mac);
413 self.pending.clear();
414 }
415 }
416 }
417 sdpcm::ChannelType::Event => {
419 if data.len()
421 < sdpcm::BdcHeader::SIZE
422 + sdpcm::EthernetHeader::SIZE
423 + sdpcm::EventHeader::SIZE
424 + sdpcm::EventMessage::SIZE
425 {
426 return;
427 }
428
429 (header, data) = data.split_at(sdpcm::BdcHeader::SIZE);
430 let bdc_hdr = sdpcm::BdcHeader::from_bytes(header);
431 let offset = 4 * bdc_hdr.data_offset as usize;
432 if offset > data.len() {
433 return;
434 }
435 data = &data[offset..];
436 (header, data) = data.split_at(sdpcm::EthernetHeader::SIZE);
437 let eth_hdr = sdpcm::EthernetHeader::from_bytes(header);
438 (header, data) = data.split_at(sdpcm::EventHeader::SIZE);
439 let event_hdr = sdpcm::EventHeader::from_bytes(header);
440
441 if eth_hdr.ethertype.to_be() != constants::ETHER_TYPE_BRCM
442 || event_hdr.oui != constants::BRCM_OUI
443 || event_hdr.subtype.to_be() != constants::EVT_SUBTYPE
444 {
445 return;
446 }
447
448 (header, data) = data.split_at(sdpcm::EventMessage::SIZE);
449 let evt_msg = sdpcm::EventMessage::from_bytes(header);
450 let Some(evt_type) = sdpcm::Event::from_u8(evt_msg.event_type.to_be() as _) else {
451 return;
452 };
453
454 const ESCAN_PARTIAL: u32 = 8;
455 match evt_type {
456 sdpcm::Event::EscanResult if evt_msg.status.to_be() == ESCAN_PARTIAL => {
457 let Some(Pending::Scan) = self.pending.get() else {
458 return;
459 };
460 if data.len() < sdpcm::ScanResults::SIZE + sdpcm::BssInfo::SIZE {
461 return;
462 }
463 data = &data[sdpcm::ScanResults::SIZE..];
464 let bss_info = sdpcm::BssInfo::from_bytes(&data[..sdpcm::BssInfo::SIZE]);
465 if let Ok(mut ssid) = wifi::Ssid::try_new(bss_info.ssid_len) {
466 ssid.buf = bss_info.ssid;
467 self.client.map(|client| client.scanned_network(ssid));
468 }
469 }
470 sdpcm::Event::EscanResult => {
471 let Some(Pending::Scan) = self.pending.get() else {
472 return;
473 };
474 self.client.map(|client| client.scan_done());
476 self.pending.clear();
477 }
478 sdpcm::Event::SetSsid => {
479 let State::Command(Command::Join) = self.state.get() else {
480 return;
481 };
482 self.client.map(|client| {
483 client.command_done(if evt_msg.status == 0 {
484 Ok(())
485 } else {
486 Err(ErrorCode::FAIL)
487 });
488 self.tasks_done();
489 });
490 }
491 _ => (),
492 }
493 }
494 sdpcm::ChannelType::Data if self.receive.get() => {
496 if data.len() < sdpcm::BdcHeader::SIZE {
497 return;
498 }
499 (_, data) = data.split_at(sdpcm::BdcHeader::SIZE);
500 self.eth_client
501 .map(|client| client.received_frame(data, None));
502 }
503 _ => (),
504 }
505 }
506
507 fn waiting_or_busy(&self) -> bool {
508 if self.pending.is_some() {
509 true
510 } else {
511 match self.bus.state().unwrap() {
512 bus::State::Incoming => true,
513 bus::State::Available(len) => {
514 self.bus
515 .read_bytes(self.buffer.take().unwrap(), len)
516 .unwrap();
517 true
518 }
519 bus::State::Idle => false,
520 }
521 }
522 }
523
524 fn tasks_done(&self) {
525 let _ = self.state.take();
526 self.ioctl_tasks.reset();
527 }
528
529 fn update_task(&self) {
531 let Some(task) = self.ioctl_tasks.get() else {
532 if let State::Command(command) = self.state.get() {
533 if let Command::Join = command {
534 return;
536 } else if let Command::Scan = command {
537 self.pending.set(Pending::Scan);
538 }
539 self.client.map(|client| client.command_done(Ok(())));
540 self.tasks_done();
541 }
542 return;
543 };
544
545 match self.do_task(*task) {
546 Ok(advance) => {
547 if advance {
548 self.ioctl_tasks.advance();
549 }
550 }
551 Err(err) => {
552 if let State::Command(_) = self.state.take() {
553 self.client.map(|client| client.command_done(Err(err)));
554 }
555 self.tasks_done();
556 }
557 }
558 }
559}
560
561impl<'a, P: hil::gpio::Pin, A: hil::time::Alarm<'a>, B: bus::CYW4343xBus<'a>>
562 hil::ethernet::EthernetAdapterDatapath<'a> for CYW4343x<'a, P, A, B>
563{
564 fn set_client(&self, client: &'a dyn hil::ethernet::EthernetAdapterDatapathClient) {
565 self.eth_client.set(client)
566 }
567
568 fn enable_receive(&self) {
569 self.receive.set(true);
570 }
571
572 fn disable_receive(&self) {
573 self.receive.set(false);
574 }
575
576 fn transmit_frame(
577 &self,
578 frame_buffer: &'static mut [u8],
579 len: u16,
580 transmission_identifier: usize,
581 ) -> Result<(), (ErrorCode, &'static mut [u8])> {
582 let State::Idle = self.state.get() else {
583 return Err((ErrorCode::BUSY, frame_buffer));
584 };
585
586 if let Err(err) = self.send_bdc(&frame_buffer[..len as _]) {
587 Err((err, frame_buffer))
588 } else {
589 self.eth_tx_data
590 .set((transmission_identifier, frame_buffer));
591 self.state.set(State::Ethernet);
592 Ok(())
593 }
594 }
595}
596
597impl<'a, P: hil::gpio::Pin, A: hil::time::Alarm<'a>, B: bus::CYW4343xBus<'a>> wifi::Device<'a>
598 for CYW4343x<'a, P, A, B>
599{
600 fn set_client(&self, client: &'a dyn wifi::Client) {
601 self.client.set(client);
602 }
603
604 fn init(&self) -> Result<(), kernel::ErrorCode> {
605 let State::NotInit = self.state.get() else {
606 return Err(ErrorCode::ALREADY);
607 };
608
609 self.pwr.clear();
611 let now = self.alarm.now();
612 self.alarm.set_alarm(now, self.alarm.ticks_from_ms(20));
613 self.state.set(State::PoweredDown);
614
615 Ok(())
616 }
617
618 fn mac(&self) -> Result<[u8; 6], ErrorCode> {
619 self.mac.get().ok_or(ErrorCode::BUSY)
620 }
621
622 fn join(
623 &self,
624 ssid: wifi::Ssid,
625 security: Option<(wifi::Security, wifi::Passphrase)>,
626 ) -> Result<(), kernel::ErrorCode> {
627 if let State::NotInit = self.state.get() {
628 return Err(ErrorCode::FAIL);
629 }
630
631 if let Some((security, passphrase)) = security {
632 match security {
633 wifi::Security::WpaPsk => self.init_tasks(&ioctl::join_wpa::WPA1)?,
634 wifi::Security::Wpa2Psk => self.init_tasks(&ioctl::join_wpa::WPA2)?,
635 wifi::Security::Wpa2PskWpa3Sae => {
636 self.init_tasks(&ioctl::join_wpa::WPA2_WPA3)?;
637 }
638 wifi::Security::Wpa3Sae => self.init_tasks(&ioctl::join_wpa::WPA3)?,
639 }
640 self.security.set(passphrase);
641 } else {
642 self.init_tasks(&ioctl::join_open::OPS)?;
643 }
644 self.ssid.set(ssid);
645 self.state.set(State::Command(Command::Join));
646
647 Ok(())
648 }
649
650 fn leave(&self) -> Result<(), kernel::ErrorCode> {
651 if let State::NotInit = self.state.get() {
652 return Err(ErrorCode::FAIL);
653 }
654
655 self.init_tasks(&[ioctl::leave::OP])?;
656 self.state.set(State::Command(Command::Leave));
657 Ok(())
658 }
659
660 fn scan(&self) -> Result<(), kernel::ErrorCode> {
661 if let State::NotInit = self.state.get() {
662 return Err(ErrorCode::FAIL);
663 }
664
665 self.init_tasks(&[ioctl::start_scan::OP])?;
666 self.state.set(State::Command(Command::Scan));
667 Ok(())
668 }
669
670 fn stop_scan(&self) -> Result<(), kernel::ErrorCode> {
671 if let State::NotInit = self.state.get() {
672 return Err(ErrorCode::FAIL);
673 }
674
675 self.init_tasks(&[ioctl::stop_scan::OP])?;
676 self.state.set(State::Command(Command::StopScan));
677 Ok(())
678 }
679
680 fn access_point(
681 &self,
682 ssid: wifi::Ssid,
683 security: Option<(wifi::Security, wifi::Passphrase)>,
684 channel: u8,
685 ) -> Result<(), kernel::ErrorCode> {
686 let (None | Some((wifi::Security::Wpa2Psk, _))) = security else {
687 return Err(ErrorCode::NOSUPPORT);
688 };
689
690 if let State::NotInit = self.state.get() {
691 return Err(ErrorCode::FAIL);
692 }
693
694 if let Some((_, passphrase)) = security {
695 self.init_tasks(&ioctl::start_ap_wpa::OPS)?;
696 self.security.set(passphrase);
697 } else {
698 self.init_tasks(&ioctl::start_ap::OPS)?;
699 }
700
701 self.ssid.set(ssid);
702 self.channel.set(channel);
703 self.state.set(State::Command(Command::Ap));
704 Ok(())
705 }
706
707 fn station(&self) -> Result<(), kernel::ErrorCode> {
708 if let State::NotInit = self.state.get() {
709 return Err(ErrorCode::FAIL);
710 }
711
712 self.init_tasks(&ioctl::stop_ap::OPS)?;
713 self.state.set(State::Command(Command::Sta));
714 Ok(())
715 }
716}
717
718impl<'a, P: hil::gpio::Pin, A: hil::time::Alarm<'a>, B: bus::CYW4343xBus<'a>> hil::time::AlarmClient
719 for CYW4343x<'a, P, A, B>
720{
721 fn alarm(&self) {
722 match self.state.get() {
723 State::PoweredDown => {
724 self.pwr.set();
725
726 let now = self.alarm.now();
727 self.alarm.set_alarm(now, self.alarm.ticks_from_ms(250));
728 self.state.set(State::PoweredUp);
729 }
730 State::PoweredUp => {
731 if let Err(err) = self.bus.init().map(|()| self.state.set(State::BusInit)) {
733 self.client.map(|client| client.command_done(Err(err)));
734 }
735 }
736 State::Command(_) if !self.waiting_or_busy() => self.update_task(),
737 _ => (),
739 }
740 }
741}
742
743impl<'a, P: hil::gpio::Pin, A: hil::time::Alarm<'a>, B: bus::CYW4343xBus<'a>> bus::CYW4343xBusClient
744 for CYW4343x<'a, P, A, B>
745{
746 fn init_done(&self, rval: Result<(), ErrorCode>) {
747 if let Err(err) = rval.and_then(|()| self.init_tasks(ioctl::init::OPS)) {
748 self.client.map(|client| client.command_done(Err(err)));
749 self.state.set(State::Idle);
750 } else {
751 self.state.set(State::Command(Command::Init));
752 }
753 }
754
755 fn packet_available(&self, len: usize) {
756 if len == 0 && !self.waiting_or_busy() {
757 self.update_task();
758 } else {
759 self.bus
760 .read_bytes(self.buffer.take().unwrap(), len)
761 .unwrap();
762 }
763 }
764
765 fn write_bytes_done(
766 &self,
767 mut buffer: SubSliceMut<'static, u8>,
768 rval: Result<(), kernel::ErrorCode>,
769 ) {
770 reset_and_restore_bufs!(self, buffer);
771
772 match (self.state.get(), rval) {
773 (State::Command(_), Err(err)) => {
774 self.client.map(|client| client.command_done(Err(err)));
775 if let State::Command(Command::Init) = self.state.get() {
776 self.state.set(State::NotInit);
777 } else {
778 self.state.set(State::Idle);
779 }
780 }
781 (State::Command(_), Ok(())) if !self.waiting_or_busy() => {
782 self.update_task();
783 }
784 (State::Ethernet, _) => todo!(),
785 _ => {}
786 }
787 }
788
789 fn read_bytes_done(
790 &self,
791 mut buffer: SubSliceMut<'static, u8>,
792 rval: Result<(), kernel::ErrorCode>,
793 ) {
794 if rval.is_ok() {
795 self.parse(buffer.as_mut_slice());
796 }
797
798 reset_and_restore_bufs!(self, buffer);
799 if let State::Command(_) = self.state.get() {
800 if !self.waiting_or_busy() {
801 self.update_task()
802 }
803 }
804 }
805}
806
807mod ioctl {
811 use crate::cyw4343::sdpcm::{self, IoctlCommand};
812 use core::cell::Cell;
813 use kernel::utilities::cells::OptionalCell;
814
815 #[derive(Default)]
816 pub struct Tasks {
817 list: OptionalCell<&'static [Op]>,
818 idx: Cell<u8>,
819 }
820
821 impl Tasks {
822 pub fn new() -> Self {
823 Self::default()
824 }
825
826 pub fn init(&self, list: &'static [Op]) {
827 self.list.set(list);
828 self.idx.set(0);
829 }
830
831 pub fn reset(&self) {
832 self.list.clear();
833 self.idx.set(0);
834 }
835
836 pub fn get(&self) -> Option<&Op> {
837 self.list
838 .map(|list| list.get(self.idx.get() as usize))
839 .flatten()
840 }
841
842 pub fn advance(&self) {
843 self.idx.set(self.idx.get() + 1)
844 }
845
846 pub fn is_empty(&self) -> bool {
847 self.list.is_none()
848 }
849 }
850
851 #[derive(Debug, Clone, Copy)]
858 pub enum Op {
859 WaitMs(u32),
861 Ioctl(Ioctl),
863 LoadCLM,
865 MacAddr,
867 }
868
869 impl Default for Op {
870 fn default() -> Self {
871 Self::WaitMs(0)
872 }
873 }
874
875 impl Op {
876 pub(super) const fn ioctl(cmd: IoctlCommand, data: IoctlData) -> Self {
877 Self::Ioctl(Ioctl {
878 cmd,
879 data,
880 name: None,
881 })
882 }
883
884 pub(super) const fn iovar(name: sdpcm::Iovar, data: IoctlData) -> Self {
885 Self::Ioctl(Ioctl {
886 cmd: IoctlCommand::SetVar,
887 data,
888 name: Some(name),
889 })
890 }
891
892 pub(super) const fn wait_ms(ms: u32) -> Self {
893 Self::WaitMs(ms)
894 }
895 }
896
897 #[derive(Debug, Clone, Copy)]
899 pub struct Ioctl {
900 pub cmd: IoctlCommand,
901 pub data: IoctlData,
902 pub name: Option<sdpcm::Iovar>,
903 }
904
905 #[derive(Debug, Clone, Copy)]
907 pub enum IoctlData {
908 Word([u8; 4]),
910 DWord([u8; 8]),
911 Empty,
912 Ssid,
914 BssSsid,
915 Wpa1Passphrase,
916 Wpa3Passphrase,
917 Channel,
918 ScanParameters,
920 AbortScanParameters,
921 CountryInfo,
922 EventMask,
923 }
924
925 impl IoctlData {
926 pub const fn from_2xu32(val0: u32, val1: u32) -> Self {
927 let mut bytes = [0u8; 8];
928 let val0_bytes = val0.to_le_bytes();
929 [bytes[0], bytes[1], bytes[2], bytes[3]] =
930 [val0_bytes[0], val0_bytes[1], val0_bytes[2], val0_bytes[3]];
931 let val1_bytes = val1.to_le_bytes();
932 [bytes[4], bytes[5], bytes[6], bytes[7]] =
933 [val1_bytes[0], val1_bytes[1], val1_bytes[2], val1_bytes[3]];
934
935 Self::DWord(bytes)
936 }
937
938 pub const fn from_u32(val: u32) -> Self {
939 Self::Word(val.to_le_bytes())
940 }
941
942 pub const fn empty() -> Self {
943 Self::Empty
944 }
945 }
946
947 pub mod init {
950 use super::sdpcm::{CountryInfo, Event, EventMask, Iovar};
951 use super::{IoctlCommand as Cmd, IoctlData as Data, Op};
952
953 pub const COUNTRY_INFO: [u8; CountryInfo::SIZE] = CountryInfo {
954 country_abbrev: [88, 88, 0, 0],
955 country_code: [88, 88, 0, 0],
956 rev: -1,
957 }
958 .into_bytes();
959
960 pub const EVENTS: [u8; EventMask::SIZE] = EventMask::with_masked_evts(&[
961 Event::Radio,
962 Event::If,
963 Event::ProbreqMsg,
964 Event::ProbreqMsgRx,
965 Event::Roam,
966 Event::ProbreqMsg,
967 ])
968 .into_bytes();
969
970 pub static OPS: &[Op] = &[
971 Op::WaitMs(2000),
972 Op::LoadCLM,
973 Op::iovar(Iovar::BusTxGlom, Data::from_u32(0)),
974 Op::iovar(Iovar::Apsta, Data::from_u32(1)),
975 Op::MacAddr,
976 Op::iovar(Iovar::Country, Data::CountryInfo),
977 Op::WaitMs(100),
978 Op::ioctl(Cmd::SetAntdiv, Data::from_u32(0)),
979 Op::iovar(Iovar::BusTxGlom, Data::from_u32(0)),
980 Op::WaitMs(100),
981 Op::iovar(Iovar::AmpduBaWsize, Data::from_u32(8)),
982 Op::WaitMs(100),
983 Op::iovar(Iovar::AmpduMpdu, Data::from_u32(4)),
984 Op::WaitMs(100),
985 Op::iovar(Iovar::BssCfgEventMsgs, Data::EventMask),
986 Op::WaitMs(100),
987 Op::ioctl(Cmd::Up, Data::Empty),
988 Op::WaitMs(100),
989 Op::ioctl(Cmd::SetGmode, Data::from_u32(1)),
990 Op::ioctl(Cmd::SetBand, Data::from_u32(0)),
991 Op::WaitMs(100),
992 ];
993 }
994
995 pub mod start_ap {
997 use super::sdpcm::Iovar;
998 use super::{IoctlCommand as Cmd, IoctlData as Data, Op};
999
1000 pub static OPS: [Op; 9] = [
1001 Op::ioctl(Cmd::Down, Data::empty()),
1002 Op::iovar(Iovar::Apsta, Data::from_u32(0)),
1003 Op::ioctl(Cmd::Up, Data::empty()),
1004 Op::ioctl(Cmd::SetAp, Data::from_u32(1)),
1005 Op::iovar(Iovar::BssCfgSsid, Data::BssSsid),
1006 Op::ioctl(Cmd::SetChannel, Data::Channel),
1007 Op::iovar(Iovar::BssCfgWsec, Data::from_2xu32(0, 0)),
1008 Op::iovar(Iovar::G2Mrate, Data::from_u32(11000000 / 500000)),
1009 Op::iovar(Iovar::Bss, Data::from_2xu32(0, 1)),
1010 ];
1011 }
1012
1013 pub mod start_ap_wpa {
1015 use super::sdpcm::Iovar;
1016 use super::{IoctlCommand as Cmd, IoctlData as Data, Op};
1017
1018 pub static OPS: [Op; 12] = [
1019 Op::ioctl(Cmd::Down, Data::empty()),
1020 Op::iovar(Iovar::Apsta, Data::from_u32(0)),
1021 Op::ioctl(Cmd::Up, Data::empty()),
1022 Op::ioctl(Cmd::SetAp, Data::from_u32(1)),
1023 Op::iovar(Iovar::BssCfgSsid, Data::BssSsid),
1024 Op::ioctl(Cmd::SetChannel, Data::Channel),
1025 Op::iovar(Iovar::BssCfgWsec, Data::from_2xu32(0, 0x4)),
1026 Op::iovar(Iovar::BssCfgWpaAuth, Data::from_2xu32(0, 0x084)),
1027 Op::wait_ms(100),
1028 Op::ioctl(Cmd::SetWsecPmk, Data::Wpa1Passphrase),
1029 Op::iovar(Iovar::G2Mrate, Data::from_u32(11000000 / 500000)),
1030 Op::iovar(Iovar::Bss, Data::from_2xu32(0, 1)),
1031 ];
1032 }
1033
1034 pub mod stop_ap {
1036 use super::sdpcm::Iovar;
1037 use super::{IoctlCommand as Cmd, IoctlData as Data, Op};
1038
1039 pub static OPS: [Op; 5] = [
1040 Op::iovar(Iovar::Bss, Data::from_2xu32(0, 0)),
1041 Op::ioctl(Cmd::SetAp, Data::from_u32(0)),
1042 Op::ioctl(Cmd::Down, Data::empty()),
1043 Op::iovar(Iovar::Apsta, Data::from_u32(1)),
1044 Op::ioctl(Cmd::Up, Data::empty()),
1045 ];
1046 }
1047
1048 pub mod join_open {
1050 use super::sdpcm::Iovar;
1051 use super::{IoctlCommand as Cmd, IoctlData as Data, Op};
1052
1053 pub static OPS: [Op; 7] = [
1054 Op::iovar(Iovar::AmpduBaWsize, Data::from_u32(8)),
1055 Op::ioctl(Cmd::SetWsec, Data::from_u32(0)),
1056 Op::iovar(Iovar::BssCfgSupWpa, Data::from_2xu32(0, 0)),
1057 Op::ioctl(Cmd::SetInfra, Data::from_u32(1)),
1058 Op::ioctl(Cmd::SetAuth, Data::from_u32(0)),
1059 Op::ioctl(Cmd::SetWpaAuth, Data::from_u32(0)),
1060 Op::ioctl(Cmd::SetSsid, Data::Ssid),
1061 ];
1062 }
1063
1064 pub mod join_wpa {
1066 use super::sdpcm::Iovar;
1067 use super::{IoctlCommand as Cmd, IoctlData as Data, Op};
1068 use crate::cyw4343::constants;
1069
1070 mod wpa1 {
1071 pub(super) const MFP: u32 = 0;
1072 pub(super) const AUTH: u32 = 0;
1073 pub(super) const WPA_AUTH: u32 = 0x4;
1074 }
1075
1076 mod wpa2 {
1077 pub(super) const MFP: u32 = 1;
1078 pub(super) const AUTH: u32 = 0;
1079 pub(super) const WPA_AUTH: u32 = 0x80;
1080 }
1081
1082 mod wpa3 {
1083 pub(super) const MFP: u32 = 2;
1084 pub(super) const AUTH: u32 = 3;
1085 pub(super) const WPA_AUTH: u32 = 0x40000;
1086 }
1087
1088 const WPA1_SET: Op = Op::ioctl(Cmd::SetWsecPmk, Data::Wpa1Passphrase);
1089 const WPA3_SET: Op = Op::iovar(Iovar::SaePassword, Data::Wpa3Passphrase);
1090 const fn ops(wpa_set: Op, mfp: u32, auth: u32, wpa_auth: u32) -> [Op; 12] {
1091 [
1092 Op::iovar(Iovar::AmpduBaWsize, Data::from_u32(8)),
1093 Op::ioctl(Cmd::SetWsec, Data::from_u32(constants::WSEC_AES)),
1094 Op::iovar(Iovar::BssCfgSupWpa, Data::from_2xu32(0, 1)),
1095 Op::iovar(Iovar::BssCfgSupWpa2Eapver, Data::from_2xu32(0, 0xFFFF_FFFF)),
1096 Op::iovar(Iovar::BssCfgSupWpaTmo, Data::from_2xu32(0, 2500)),
1097 Op::wait_ms(110),
1098 wpa_set,
1099 Op::ioctl(Cmd::SetInfra, Data::from_u32(1)),
1100 Op::ioctl(Cmd::SetAuth, Data::from_u32(auth)),
1101 Op::iovar(Iovar::Mfp, Data::from_u32(mfp)),
1102 Op::ioctl(Cmd::SetWpaAuth, Data::from_u32(wpa_auth)),
1103 Op::ioctl(Cmd::SetSsid, Data::Ssid),
1104 ]
1105 }
1106
1107 pub static WPA1: [Op; 12] = ops(WPA1_SET, wpa1::MFP, wpa1::AUTH, wpa1::WPA_AUTH);
1108 pub static WPA2: [Op; 12] = ops(WPA1_SET, wpa2::MFP, wpa2::AUTH, wpa2::WPA_AUTH);
1109 pub static WPA3: [Op; 12] = ops(WPA3_SET, wpa3::MFP, wpa3::AUTH, wpa3::WPA_AUTH);
1110 pub static WPA2_WPA3: [Op; 13] = [
1111 Op::iovar(Iovar::AmpduBaWsize, Data::from_u32(8)),
1112 Op::ioctl(Cmd::SetWsec, Data::from_u32(constants::WSEC_AES)),
1113 Op::iovar(Iovar::BssCfgSupWpa, Data::from_2xu32(0, 1)),
1114 Op::iovar(Iovar::BssCfgSupWpa2Eapver, Data::from_2xu32(0, 0xFFFF_FFFF)),
1115 Op::iovar(Iovar::BssCfgSupWpaTmo, Data::from_2xu32(0, 2500)),
1116 Op::wait_ms(110),
1117 WPA1_SET,
1118 WPA3_SET,
1119 Op::ioctl(Cmd::SetInfra, Data::from_u32(1)),
1120 Op::ioctl(Cmd::SetAuth, Data::from_u32(wpa3::AUTH)),
1121 Op::iovar(Iovar::Mfp, Data::from_u32(wpa2::MFP)),
1122 Op::ioctl(Cmd::SetWpaAuth, Data::from_u32(wpa3::WPA_AUTH)),
1123 Op::ioctl(Cmd::SetSsid, Data::Ssid),
1124 ];
1125 }
1126
1127 pub mod leave {
1129 use super::{IoctlCommand as Cmd, IoctlData as Data, Op};
1130
1131 pub const OP: Op = Op::ioctl(Cmd::Disassoc, Data::empty());
1132 }
1133
1134 pub mod start_scan {
1136 use super::sdpcm::Iovar;
1137 use super::{IoctlData as Data, Op};
1138 use crate::cyw4343::{constants, sdpcm};
1139
1140 pub const SCAN_PARAMS: [u8; sdpcm::ScanParams::SIZE] = sdpcm::ScanParams {
1141 version: 1,
1142 action: constants::WL_SCAN_ACTION_START,
1143 sync_id: 1,
1144 ssid_len: 0,
1145 ssid: [0; 32],
1146 bssid: [0xff; 6],
1147 bss_type: 2,
1148 scan_type: constants::SCANTYPE_PASSIVE,
1149 nprobes: !0,
1150 active_time: !0,
1151 passive_time: !0,
1152 home_time: !0,
1153 channel_num: 0,
1154 channel_list: 0,
1155 }
1156 .into_bytes();
1157
1158 pub const OP: Op = Op::iovar(Iovar::Escan, Data::ScanParameters);
1159 }
1160
1161 pub mod stop_scan {
1163 use super::sdpcm::Iovar;
1164 use super::{IoctlData as Data, Op};
1165 use crate::cyw4343::{constants, sdpcm};
1166
1167 pub const SCAN_PARAMS: [u8; sdpcm::ScanParams::SIZE] = sdpcm::ScanParams {
1168 version: 1,
1169 action: constants::WL_SCAN_ACTION_ABORT,
1170 sync_id: 0,
1171 ssid_len: 0,
1172 ssid: [0; 32],
1173 bssid: [0x00; 6],
1174 bss_type: 0,
1175 scan_type: 0,
1176 nprobes: 0,
1177 active_time: 0,
1178 passive_time: 0,
1179 home_time: 0,
1180 channel_num: 0,
1181 channel_list: 0,
1182 }
1183 .into_bytes();
1184 pub const OP: Op = Op::iovar(Iovar::Escan, Data::AbortScanParameters);
1185 }
1186}