2023-03-02 15:34:08 +01:00
use embassy_futures ::select ::{ select3 , Either3 } ;
2023-03-02 12:10:13 +01:00
use embassy_net_driver_channel as ch ;
use embassy_sync ::pubsub ::PubSubBehavior ;
use embassy_time ::{ block_for , Duration , Timer } ;
use embedded_hal_1 ::digital ::OutputPin ;
use crate ::bus ::Bus ;
pub use crate ::bus ::SpiBusCyw43 ;
use crate ::consts ::* ;
2023-03-30 17:05:29 +02:00
use crate ::events ::{ Event , Events , Status } ;
2023-03-27 03:33:06 +02:00
use crate ::fmt ::Bytes ;
2023-03-02 15:34:08 +01:00
use crate ::ioctl ::{ IoctlState , IoctlType , PendingIoctl } ;
2023-03-02 12:10:13 +01:00
use crate ::nvram ::NVRAM ;
use crate ::structs ::* ;
2023-04-02 20:19:47 +02:00
use crate ::{ events , slice8_mut , Core , CHIP , MTU } ;
2023-03-02 12:10:13 +01:00
#[ cfg(feature = " firmware-logs " ) ]
struct LogState {
addr : u32 ,
last_idx : usize ,
buf : [ u8 ; 256 ] ,
buf_count : usize ,
}
2023-03-27 03:33:06 +02:00
#[ cfg(feature = " firmware-logs " ) ]
2023-03-02 12:10:13 +01:00
impl Default for LogState {
fn default ( ) -> Self {
Self {
addr : Default ::default ( ) ,
last_idx : Default ::default ( ) ,
buf : [ 0 ; 256 ] ,
buf_count : Default ::default ( ) ,
}
}
}
pub struct Runner < ' a , PWR , SPI > {
ch : ch ::Runner < ' a , MTU > ,
bus : Bus < PWR , SPI > ,
2023-03-02 15:34:08 +01:00
ioctl_state : & ' a IoctlState ,
2023-03-02 12:10:13 +01:00
ioctl_id : u16 ,
sdpcm_seq : u8 ,
sdpcm_seq_max : u8 ,
2023-04-02 20:19:47 +02:00
events : & ' a Events ,
2023-03-02 12:10:13 +01:00
#[ cfg(feature = " firmware-logs " ) ]
log : LogState ,
}
impl < ' a , PWR , SPI > Runner < ' a , PWR , SPI >
where
PWR : OutputPin ,
SPI : SpiBusCyw43 ,
{
pub ( crate ) fn new (
ch : ch ::Runner < ' a , MTU > ,
bus : Bus < PWR , SPI > ,
2023-03-02 15:34:08 +01:00
ioctl_state : & ' a IoctlState ,
2023-04-02 20:19:47 +02:00
events : & ' a Events ,
2023-03-02 12:10:13 +01:00
) -> Self {
Self {
ch ,
bus ,
ioctl_state ,
ioctl_id : 0 ,
sdpcm_seq : 0 ,
sdpcm_seq_max : 1 ,
events ,
#[ cfg(feature = " firmware-logs " ) ]
log : LogState ::default ( ) ,
}
}
pub ( crate ) async fn init ( & mut self , firmware : & [ u8 ] ) {
self . bus . init ( ) . await ;
// Init ALP (Active Low Power) clock
self . bus
. write8 ( FUNC_BACKPLANE , REG_BACKPLANE_CHIP_CLOCK_CSR , BACKPLANE_ALP_AVAIL_REQ )
. await ;
2023-05-08 20:27:44 +02:00
debug! ( " waiting for clock... " ) ;
2023-03-02 12:10:13 +01:00
while self . bus . read8 ( FUNC_BACKPLANE , REG_BACKPLANE_CHIP_CLOCK_CSR ) . await & BACKPLANE_ALP_AVAIL = = 0 { }
2023-05-08 20:27:44 +02:00
debug! ( " clock ok " ) ;
2023-03-02 12:10:13 +01:00
let chip_id = self . bus . bp_read16 ( 0x1800_0000 ) . await ;
2023-05-08 20:27:44 +02:00
debug! ( " chip ID: {} " , chip_id ) ;
2023-03-02 12:10:13 +01:00
// Upload firmware.
self . core_disable ( Core ::WLAN ) . await ;
self . core_reset ( Core ::SOCSRAM ) . await ;
self . bus . bp_write32 ( CHIP . socsram_base_address + 0x10 , 3 ) . await ;
self . bus . bp_write32 ( CHIP . socsram_base_address + 0x44 , 0 ) . await ;
let ram_addr = CHIP . atcm_ram_base_address ;
2023-05-08 20:27:44 +02:00
debug! ( " loading fw " ) ;
2023-03-02 12:10:13 +01:00
self . bus . bp_write ( ram_addr , firmware ) . await ;
2023-05-08 20:27:44 +02:00
debug! ( " loading nvram " ) ;
2023-03-02 12:10:13 +01:00
// Round up to 4 bytes.
let nvram_len = ( NVRAM . len ( ) + 3 ) / 4 * 4 ;
self . bus
. bp_write ( ram_addr + CHIP . chip_ram_size - 4 - nvram_len as u32 , NVRAM )
. await ;
let nvram_len_words = nvram_len as u32 / 4 ;
let nvram_len_magic = ( ! nvram_len_words < < 16 ) | nvram_len_words ;
self . bus
. bp_write32 ( ram_addr + CHIP . chip_ram_size - 4 , nvram_len_magic )
. await ;
// Start core!
2023-05-08 20:27:44 +02:00
debug! ( " starting up core... " ) ;
2023-03-02 12:10:13 +01:00
self . core_reset ( Core ::WLAN ) . await ;
assert! ( self . core_is_up ( Core ::WLAN ) . await ) ;
while self . bus . read8 ( FUNC_BACKPLANE , REG_BACKPLANE_CHIP_CLOCK_CSR ) . await & 0x80 = = 0 { }
// "Set up the interrupt mask and enable interrupts"
2023-03-02 19:02:32 +01:00
// self.bus.bp_write32(CHIP.sdiod_core_base_address + 0x24, 0xF0).await;
self . bus
. write16 ( FUNC_BUS , REG_BUS_INTERRUPT_ENABLE , IRQ_F2_PACKET_AVAILABLE )
. await ;
2023-03-02 12:10:13 +01:00
// "Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped."
// Sounds scary...
self . bus
. write8 ( FUNC_BACKPLANE , REG_BACKPLANE_FUNCTION2_WATERMARK , 32 )
. await ;
// wait for wifi startup
2023-05-08 20:27:44 +02:00
debug! ( " waiting for wifi init... " ) ;
2023-03-02 12:10:13 +01:00
while self . bus . read32 ( FUNC_BUS , REG_BUS_STATUS ) . await & STATUS_F2_RX_READY = = 0 { }
// Some random configs related to sleep.
// These aren't needed if we don't want to sleep the bus.
// TODO do we need to sleep the bus to read the irq line, due to
// being on the same pin as MOSI/MISO?
/*
let mut val = self . bus . read8 ( FUNC_BACKPLANE , REG_BACKPLANE_WAKEUP_CTRL ) . await ;
val | = 0x02 ; // WAKE_TILL_HT_AVAIL
self . bus . write8 ( FUNC_BACKPLANE , REG_BACKPLANE_WAKEUP_CTRL , val ) . await ;
self . bus . write8 ( FUNC_BUS , 0xF0 , 0x08 ) . await ; // SDIOD_CCCR_BRCM_CARDCAP.CMD_NODEC = 1
self . bus . write8 ( FUNC_BACKPLANE , REG_BACKPLANE_CHIP_CLOCK_CSR , 0x02 ) . await ; // SBSDIO_FORCE_HT
let mut val = self . bus . read8 ( FUNC_BACKPLANE , REG_BACKPLANE_SLEEP_CSR ) . await ;
val | = 0x01 ; // SBSDIO_SLPCSR_KEEP_SDIO_ON
self . bus . write8 ( FUNC_BACKPLANE , REG_BACKPLANE_SLEEP_CSR , val ) . await ;
* /
// clear pulls
self . bus . write8 ( FUNC_BACKPLANE , REG_BACKPLANE_PULL_UP , 0 ) . await ;
let _ = self . bus . read8 ( FUNC_BACKPLANE , REG_BACKPLANE_PULL_UP ) . await ;
// start HT clock
//self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x10).await;
2023-05-08 20:27:44 +02:00
//debug!("waiting for HT clock...");
2023-03-02 12:10:13 +01:00
//while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {}
2023-05-08 20:27:44 +02:00
//debug!("clock ok");
2023-03-02 12:10:13 +01:00
#[ cfg(feature = " firmware-logs " ) ]
self . log_init ( ) . await ;
2023-05-08 20:27:44 +02:00
debug! ( " wifi init done " ) ;
2023-03-02 12:10:13 +01:00
}
#[ cfg(feature = " firmware-logs " ) ]
async fn log_init ( & mut self ) {
// Initialize shared memory for logging.
let addr = CHIP . atcm_ram_base_address + CHIP . chip_ram_size - 4 - CHIP . socram_srmem_size ;
let shared_addr = self . bus . bp_read32 ( addr ) . await ;
2023-05-08 20:27:44 +02:00
debug! ( " shared_addr {:08x} " , shared_addr ) ;
2023-03-02 12:10:13 +01:00
let mut shared = [ 0 ; SharedMemData ::SIZE ] ;
self . bus . bp_read ( shared_addr , & mut shared ) . await ;
let shared = SharedMemData ::from_bytes ( & shared ) ;
self . log . addr = shared . console_addr + 8 ;
}
#[ cfg(feature = " firmware-logs " ) ]
async fn log_read ( & mut self ) {
// Read log struct
let mut log = [ 0 ; SharedMemLog ::SIZE ] ;
self . bus . bp_read ( self . log . addr , & mut log ) . await ;
let log = SharedMemLog ::from_bytes ( & log ) ;
let idx = log . idx as usize ;
// If pointer hasn't moved, no need to do anything.
if idx = = self . log . last_idx {
return ;
}
// Read entire buf for now. We could read only what we need, but then we
// run into annoying alignment issues in `bp_read`.
let mut buf = [ 0 ; 0x400 ] ;
self . bus . bp_read ( log . buf , & mut buf ) . await ;
while self . log . last_idx ! = idx as usize {
let b = buf [ self . log . last_idx ] ;
if b = = b '\r' | | b = = b '\n' {
if self . log . buf_count ! = 0 {
let s = unsafe { core ::str ::from_utf8_unchecked ( & self . log . buf [ .. self . log . buf_count ] ) } ;
debug! ( " LOGS: {} " , s ) ;
self . log . buf_count = 0 ;
}
} else if self . log . buf_count < self . log . buf . len ( ) {
self . log . buf [ self . log . buf_count ] = b ;
self . log . buf_count + = 1 ;
}
self . log . last_idx + = 1 ;
if self . log . last_idx = = 0x400 {
self . log . last_idx = 0 ;
}
}
}
pub async fn run ( mut self ) -> ! {
let mut buf = [ 0 ; 512 ] ;
loop {
#[ cfg(feature = " firmware-logs " ) ]
self . log_read ( ) . await ;
2023-03-02 15:34:08 +01:00
if self . has_credit ( ) {
let ioctl = self . ioctl_state . wait_pending ( ) ;
let tx = self . ch . tx_buf ( ) ;
2023-03-02 19:02:32 +01:00
let ev = self . bus . wait_for_event ( ) ;
match select3 ( ioctl , tx , ev ) . await {
Either3 ::First ( PendingIoctl {
buf : iobuf ,
kind ,
cmd ,
iface ,
} ) = > {
self . send_ioctl ( kind , cmd , iface , unsafe { & * iobuf } ) . await ;
self . check_status ( & mut buf ) . await ;
2023-03-02 15:34:08 +01:00
}
Either3 ::Second ( packet ) = > {
2023-03-27 03:33:06 +02:00
trace! ( " tx pkt {:02x} " , Bytes ( & packet [ .. packet . len ( ) . min ( 48 ) ] ) ) ;
2023-03-02 12:10:13 +01:00
let mut buf = [ 0 ; 512 ] ;
let buf8 = slice8_mut ( & mut buf ) ;
2023-05-08 22:01:44 +02:00
// There MUST be 2 bytes of padding between the SDPCM and BDC headers.
2023-05-08 21:45:54 +02:00
// And ONLY for data packets!
// No idea why, but the firmware will append two zero bytes to the tx'd packets
// otherwise. If the packet is exactly 1514 bytes (the max MTU), this makes it
// be oversized and get dropped.
// WHD adds it here https://github.com/Infineon/wifi-host-driver/blob/c04fcbb6b0d049304f376cf483fd7b1b570c8cd5/WiFi_Host_Driver/src/include/whd_sdpcm.h#L90
// and adds it to the header size her https://github.com/Infineon/wifi-host-driver/blob/c04fcbb6b0d049304f376cf483fd7b1b570c8cd5/WiFi_Host_Driver/src/whd_sdpcm.c#L597
// ¯\_(ツ)_/¯
const PADDING_SIZE : usize = 2 ;
2023-05-08 22:01:44 +02:00
let total_len = SdpcmHeader ::SIZE + PADDING_SIZE + BdcHeader ::SIZE + packet . len ( ) ;
2023-03-02 12:10:13 +01:00
let seq = self . sdpcm_seq ;
self . sdpcm_seq = self . sdpcm_seq . wrapping_add ( 1 ) ;
let sdpcm_header = SdpcmHeader {
len : total_len as u16 , // TODO does this len need to be rounded up to u32?
len_inv : ! total_len as u16 ,
sequence : seq ,
channel_and_flags : CHANNEL_TYPE_DATA ,
next_length : 0 ,
2023-05-08 21:45:54 +02:00
header_length : ( SdpcmHeader ::SIZE + PADDING_SIZE ) as _ ,
2023-03-02 12:10:13 +01:00
wireless_flow_control : 0 ,
bus_data_credit : 0 ,
reserved : [ 0 , 0 ] ,
} ;
2023-05-08 22:01:44 +02:00
let bdc_header = BdcHeader {
2023-03-02 12:10:13 +01:00
flags : BDC_VERSION < < BDC_VERSION_SHIFT ,
priority : 0 ,
flags2 : 0 ,
data_offset : 0 ,
} ;
trace! ( " tx {:?} " , sdpcm_header ) ;
2023-05-08 22:01:44 +02:00
trace! ( " {:?} " , bdc_header ) ;
2023-03-02 12:10:13 +01:00
buf8 [ 0 .. SdpcmHeader ::SIZE ] . copy_from_slice ( & sdpcm_header . to_bytes ( ) ) ;
2023-05-08 22:01:44 +02:00
buf8 [ SdpcmHeader ::SIZE + PADDING_SIZE .. ] [ .. BdcHeader ::SIZE ]
. copy_from_slice ( & bdc_header . to_bytes ( ) ) ;
buf8 [ SdpcmHeader ::SIZE + PADDING_SIZE + BdcHeader ::SIZE .. ] [ .. packet . len ( ) ]
2023-05-08 21:45:54 +02:00
. copy_from_slice ( packet ) ;
2023-03-02 12:10:13 +01:00
let total_len = ( total_len + 3 ) & ! 3 ; // round up to 4byte
2023-03-27 03:33:06 +02:00
trace! ( " {:02x} " , Bytes ( & buf8 [ .. total_len . min ( 48 ) ] ) ) ;
2023-03-02 12:10:13 +01:00
self . bus . wlan_write ( & buf [ .. ( total_len / 4 ) ] ) . await ;
self . ch . tx_done ( ) ;
2023-03-02 19:02:32 +01:00
self . check_status ( & mut buf ) . await ;
2023-03-02 12:10:13 +01:00
}
2023-03-02 15:34:08 +01:00
Either3 ::Third ( ( ) ) = > {
2023-03-02 19:02:32 +01:00
self . handle_irq ( & mut buf ) . await ;
2023-03-02 15:34:08 +01:00
}
2023-03-02 12:10:13 +01:00
}
2023-03-02 15:34:08 +01:00
} else {
warn! ( " TX stalled " ) ;
2023-03-02 19:02:32 +01:00
self . bus . wait_for_event ( ) . await ;
self . handle_irq ( & mut buf ) . await ;
}
}
}
2023-03-02 12:10:13 +01:00
2023-03-02 19:02:32 +01:00
/// Wait for IRQ on F2 packet available
async fn handle_irq ( & mut self , buf : & mut [ u32 ; 512 ] ) {
// Receive stuff
let irq = self . bus . read16 ( FUNC_BUS , REG_BUS_INTERRUPT ) . await ;
trace! ( " irq{} " , FormatInterrupt ( irq ) ) ;
2023-03-02 12:10:13 +01:00
2023-03-02 19:02:32 +01:00
if irq & IRQ_F2_PACKET_AVAILABLE ! = 0 {
self . check_status ( buf ) . await ;
}
2023-03-30 12:24:37 +02:00
if irq & IRQ_DATA_UNAVAILABLE ! = 0 {
// TODO what should we do here?
warn! ( " IRQ DATA_UNAVAILABLE, clearing... " ) ;
self . bus . write16 ( FUNC_BUS , REG_BUS_INTERRUPT , 1 ) . await ;
}
2023-03-02 19:02:32 +01:00
}
2023-03-02 12:10:13 +01:00
2023-03-02 19:02:32 +01:00
/// Handle F2 events while status register is set
async fn check_status ( & mut self , buf : & mut [ u32 ; 512 ] ) {
loop {
2023-03-27 17:24:45 +02:00
let status = self . bus . status ( ) ;
2023-03-02 19:02:32 +01:00
trace! ( " check status{} " , FormatStatus ( status ) ) ;
if status & STATUS_F2_PKT_AVAILABLE ! = 0 {
let len = ( status & STATUS_F2_PKT_LEN_MASK ) > > STATUS_F2_PKT_LEN_SHIFT ;
self . bus . wlan_read ( buf , len ) . await ;
trace! ( " rx {:02x} " , Bytes ( & slice8_mut ( buf ) [ .. ( len as usize ) . min ( 48 ) ] ) ) ;
2023-03-31 14:18:39 +02:00
self . rx ( & mut slice8_mut ( buf ) [ .. len as usize ] ) ;
2023-03-02 19:02:32 +01:00
} else {
break ;
}
2023-03-02 12:10:13 +01:00
}
}
2023-03-31 14:18:39 +02:00
fn rx ( & mut self , packet : & mut [ u8 ] ) {
let Some ( ( sdpcm_header , payload ) ) = SdpcmHeader ::parse ( packet ) else { return } ;
2023-03-02 12:10:13 +01:00
self . update_credit ( & sdpcm_header ) ;
let channel = sdpcm_header . channel_and_flags & 0x0f ;
match channel {
CHANNEL_TYPE_CONTROL = > {
2023-03-31 14:18:39 +02:00
let Some ( ( cdc_header , response ) ) = CdcHeader ::parse ( payload ) else { return ; } ;
2023-03-02 12:10:13 +01:00
trace! ( " {:?} " , cdc_header ) ;
2023-03-02 15:34:08 +01:00
if cdc_header . id = = self . ioctl_id {
if cdc_header . status ! = 0 {
// TODO: propagate error instead
panic! ( " IOCTL error {} " , cdc_header . status as i32 ) ;
}
2023-03-02 12:10:13 +01:00
2023-03-02 15:34:08 +01:00
self . ioctl_state . ioctl_done ( response ) ;
2023-03-02 12:10:13 +01:00
}
}
CHANNEL_TYPE_EVENT = > {
2023-05-08 22:01:44 +02:00
let Some ( ( _ , bdc_packet ) ) = BdcHeader ::parse ( payload ) else {
warn! ( " BDC event, incomplete header " ) ;
2023-03-02 12:10:13 +01:00
return ;
2023-03-31 14:18:39 +02:00
} ;
2023-03-02 12:10:13 +01:00
2023-05-08 22:01:44 +02:00
let Some ( ( event_packet , evt_data ) ) = EventPacket ::parse ( bdc_packet ) else {
warn! ( " BDC event, incomplete data " ) ;
2023-03-31 14:18:39 +02:00
return ;
} ;
2023-03-02 12:10:13 +01:00
const ETH_P_LINK_CTL : u16 = 0x886c ; // HPNA, wlan link local tunnel, according to linux if_ether.h
if event_packet . eth . ether_type ! = ETH_P_LINK_CTL {
warn! (
" unexpected ethernet type 0x{:04x}, expected Broadcom ether type 0x{:04x} " ,
event_packet . eth . ether_type , ETH_P_LINK_CTL
) ;
return ;
}
const BROADCOM_OUI : & [ u8 ] = & [ 0x00 , 0x10 , 0x18 ] ;
if event_packet . hdr . oui ! = BROADCOM_OUI {
warn! (
" unexpected ethernet OUI {:02x}, expected Broadcom OUI {:02x} " ,
2023-03-27 03:33:06 +02:00
Bytes ( & event_packet . hdr . oui ) ,
Bytes ( BROADCOM_OUI )
2023-03-02 12:10:13 +01:00
) ;
return ;
}
const BCMILCP_SUBTYPE_VENDOR_LONG : u16 = 32769 ;
if event_packet . hdr . subtype ! = BCMILCP_SUBTYPE_VENDOR_LONG {
warn! ( " unexpected subtype {} " , event_packet . hdr . subtype ) ;
return ;
}
const BCMILCP_BCM_SUBTYPE_EVENT : u16 = 1 ;
if event_packet . hdr . user_subtype ! = BCMILCP_BCM_SUBTYPE_EVENT {
warn! ( " unexpected user_subtype {} " , event_packet . hdr . subtype ) ;
return ;
}
let evt_type = events ::Event ::from ( event_packet . msg . event_type as u8 ) ;
2023-03-27 03:33:06 +02:00
debug! (
" === EVENT {:?}: {:?} {:02x} " ,
evt_type ,
event_packet . msg ,
Bytes ( evt_data )
) ;
2023-03-02 12:10:13 +01:00
2023-04-02 20:19:47 +02:00
if self . events . mask . is_enabled ( evt_type ) {
let status = event_packet . msg . status ;
2023-03-30 17:05:29 +02:00
let event_payload = match evt_type {
Event ::ESCAN_RESULT if status = = EStatus ::PARTIAL = > {
let Some ( ( _ , bss_info ) ) = ScanResults ::parse ( evt_data ) else { return } ;
let Some ( bss_info ) = BssInfo ::parse ( bss_info ) else { return } ;
events ::Payload ::BssInfo ( * bss_info )
}
Event ::ESCAN_RESULT = > events ::Payload ::None ,
_ = > events ::Payload ::None ,
} ;
2023-04-02 20:19:47 +02:00
2023-04-25 19:08:47 +02:00
// this intentionally uses the non-blocking publish immediate
// publish() is a deadlock risk in the current design as awaiting here prevents ioctls
// The `Runner` always yields when accessing the device, so consumers always have a chance to receive the event
// (if they are actively awaiting the queue)
2023-04-02 20:19:47 +02:00
self . events . queue . publish_immediate ( events ::Message ::new (
Status {
event_type : evt_type ,
status ,
} ,
event_payload ,
) ) ;
2023-03-02 12:10:13 +01:00
}
}
CHANNEL_TYPE_DATA = > {
2023-05-08 22:01:44 +02:00
let Some ( ( _ , packet ) ) = BdcHeader ::parse ( payload ) else { return } ;
2023-03-31 14:18:39 +02:00
trace! ( " rx pkt {:02x} " , Bytes ( & packet [ .. packet . len ( ) . min ( 48 ) ] ) ) ;
2023-03-02 12:10:13 +01:00
match self . ch . try_rx_buf ( ) {
Some ( buf ) = > {
buf [ .. packet . len ( ) ] . copy_from_slice ( packet ) ;
self . ch . rx_done ( packet . len ( ) )
}
None = > warn! ( " failed to push rxd packet to the channel. " ) ,
}
}
_ = > { }
}
}
fn update_credit ( & mut self , sdpcm_header : & SdpcmHeader ) {
if sdpcm_header . channel_and_flags & 0xf < 3 {
let mut sdpcm_seq_max = sdpcm_header . bus_data_credit ;
if sdpcm_seq_max . wrapping_sub ( self . sdpcm_seq ) > 0x40 {
sdpcm_seq_max = self . sdpcm_seq + 2 ;
}
self . sdpcm_seq_max = sdpcm_seq_max ;
}
}
fn has_credit ( & self ) -> bool {
self . sdpcm_seq ! = self . sdpcm_seq_max & & self . sdpcm_seq_max . wrapping_sub ( self . sdpcm_seq ) & 0x80 = = 0
}
async fn send_ioctl ( & mut self , kind : IoctlType , cmd : u32 , iface : u32 , data : & [ u8 ] ) {
let mut buf = [ 0 ; 512 ] ;
let buf8 = slice8_mut ( & mut buf ) ;
let total_len = SdpcmHeader ::SIZE + CdcHeader ::SIZE + data . len ( ) ;
let sdpcm_seq = self . sdpcm_seq ;
self . sdpcm_seq = self . sdpcm_seq . wrapping_add ( 1 ) ;
self . ioctl_id = self . ioctl_id . wrapping_add ( 1 ) ;
let sdpcm_header = SdpcmHeader {
len : total_len as u16 , // TODO does this len need to be rounded up to u32?
len_inv : ! total_len as u16 ,
sequence : sdpcm_seq ,
channel_and_flags : CHANNEL_TYPE_CONTROL ,
next_length : 0 ,
header_length : SdpcmHeader ::SIZE as _ ,
wireless_flow_control : 0 ,
bus_data_credit : 0 ,
reserved : [ 0 , 0 ] ,
} ;
let cdc_header = CdcHeader {
cmd : cmd ,
len : data . len ( ) as _ ,
flags : kind as u16 | ( iface as u16 ) < < 12 ,
id : self . ioctl_id ,
status : 0 ,
} ;
trace! ( " tx {:?} " , sdpcm_header ) ;
trace! ( " {:?} " , cdc_header ) ;
buf8 [ 0 .. SdpcmHeader ::SIZE ] . copy_from_slice ( & sdpcm_header . to_bytes ( ) ) ;
buf8 [ SdpcmHeader ::SIZE .. ] [ .. CdcHeader ::SIZE ] . copy_from_slice ( & cdc_header . to_bytes ( ) ) ;
buf8 [ SdpcmHeader ::SIZE + CdcHeader ::SIZE .. ] [ .. data . len ( ) ] . copy_from_slice ( data ) ;
let total_len = ( total_len + 3 ) & ! 3 ; // round up to 4byte
2023-03-27 03:33:06 +02:00
trace! ( " {:02x} " , Bytes ( & buf8 [ .. total_len . min ( 48 ) ] ) ) ;
2023-03-02 12:10:13 +01:00
self . bus . wlan_write ( & buf [ .. total_len / 4 ] ) . await ;
}
async fn core_disable ( & mut self , core : Core ) {
let base = core . base_addr ( ) ;
// Dummy read?
let _ = self . bus . bp_read8 ( base + AI_RESETCTRL_OFFSET ) . await ;
// Check it isn't already reset
let r = self . bus . bp_read8 ( base + AI_RESETCTRL_OFFSET ) . await ;
if r & AI_RESETCTRL_BIT_RESET ! = 0 {
return ;
}
self . bus . bp_write8 ( base + AI_IOCTRL_OFFSET , 0 ) . await ;
let _ = self . bus . bp_read8 ( base + AI_IOCTRL_OFFSET ) . await ;
block_for ( Duration ::from_millis ( 1 ) ) ;
self . bus
. bp_write8 ( base + AI_RESETCTRL_OFFSET , AI_RESETCTRL_BIT_RESET )
. await ;
let _ = self . bus . bp_read8 ( base + AI_RESETCTRL_OFFSET ) . await ;
}
async fn core_reset ( & mut self , core : Core ) {
self . core_disable ( core ) . await ;
let base = core . base_addr ( ) ;
self . bus
. bp_write8 ( base + AI_IOCTRL_OFFSET , AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN )
. await ;
let _ = self . bus . bp_read8 ( base + AI_IOCTRL_OFFSET ) . await ;
self . bus . bp_write8 ( base + AI_RESETCTRL_OFFSET , 0 ) . await ;
Timer ::after ( Duration ::from_millis ( 1 ) ) . await ;
self . bus
. bp_write8 ( base + AI_IOCTRL_OFFSET , AI_IOCTRL_BIT_CLOCK_EN )
. await ;
let _ = self . bus . bp_read8 ( base + AI_IOCTRL_OFFSET ) . await ;
Timer ::after ( Duration ::from_millis ( 1 ) ) . await ;
}
async fn core_is_up ( & mut self , core : Core ) -> bool {
let base = core . base_addr ( ) ;
let io = self . bus . bp_read8 ( base + AI_IOCTRL_OFFSET ) . await ;
if io & ( AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN ) ! = AI_IOCTRL_BIT_CLOCK_EN {
debug! ( " core_is_up: returning false due to bad ioctrl {:02x} " , io ) ;
return false ;
}
let r = self . bus . bp_read8 ( base + AI_RESETCTRL_OFFSET ) . await ;
if r & ( AI_RESETCTRL_BIT_RESET ) ! = 0 {
debug! ( " core_is_up: returning false due to bad resetctrl {:02x} " , r ) ;
return false ;
}
true
}
}