async ioctls working.
This commit is contained in:
		| @@ -6,11 +6,12 @@ use core::slice; | ||||
|  | ||||
| use defmt::{assert, assert_eq, panic, *}; | ||||
| use embassy::executor::Spawner; | ||||
| use embassy::util::Forever; | ||||
| use embassy_rp::gpio::{Flex, Level, Output, Pin}; | ||||
| use embassy_rp::peripherals::{PIN_23, PIN_24, PIN_25, PIN_29}; | ||||
| use embassy_rp::Peripherals; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
|  | ||||
| macro_rules! forever { | ||||
|     ($val:expr) => {{ | ||||
|         type T = impl Sized; | ||||
| @@ -19,21 +20,29 @@ macro_rules! forever { | ||||
|     }}; | ||||
| } | ||||
|  | ||||
| #[embassy::task] | ||||
| async fn wifi_task(runner: cyw43::Runner<'static, PIN_23, PIN_25, PIN_29, PIN_24>) -> ! { | ||||
|     runner.run().await | ||||
| } | ||||
|  | ||||
| #[embassy::main] | ||||
| async fn main(_spawner: Spawner, p: Peripherals) { | ||||
| async fn main(spawner: Spawner, p: Peripherals) { | ||||
|     info!("Hello World!"); | ||||
|  | ||||
|     let (pwr, cs, clk, dio) = (p.PIN_23, p.PIN_25, p.PIN_29, p.PIN_24); | ||||
|     //let (pwr, cs, clk, dio) = (p.PIN_23, p.PIN_0, p.PIN_1, p.PIN_2); | ||||
|  | ||||
|     let mut driver = cyw43::Driver::new( | ||||
|     let state = forever!(cyw43::State::new()); | ||||
|     let (mut control, runner) = cyw43::new( | ||||
|         state, | ||||
|         Output::new(pwr, Level::Low), | ||||
|         Output::new(cs, Level::High), | ||||
|         Output::new(clk, Level::Low), | ||||
|         Flex::new(dio), | ||||
|     ); | ||||
|     ) | ||||
|     .await; | ||||
|  | ||||
|     driver.init().await; | ||||
|     spawner.spawn(wifi_task(runner)).unwrap(); | ||||
|  | ||||
|     loop {} | ||||
|     control.init().await; | ||||
| } | ||||
|   | ||||
							
								
								
									
										8
									
								
								rust-toolchain.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								rust-toolchain.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| # Before upgrading check that everything is available on all tier1 targets here: | ||||
| # https://rust-lang.github.io/rustup-components-history | ||||
| [toolchain] | ||||
| channel = "nightly-2022-07-09" | ||||
| components = [ "rust-src", "rustfmt" ] | ||||
| targets = [ | ||||
|     "thumbv6m-none-eabi", | ||||
| ] | ||||
							
								
								
									
										200
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										200
									
								
								src/lib.rs
									
									
									
									
									
								
							| @@ -1,16 +1,20 @@ | ||||
| #![no_std] | ||||
| #![no_main] | ||||
| #![feature(type_alias_impl_trait, concat_bytes)] | ||||
|  | ||||
| #![feature(type_alias_impl_trait, concat_bytes, const_slice_from_raw_parts)] | ||||
| // This mod MUST go first, so that the others see its macros. | ||||
| pub(crate) mod fmt; | ||||
|  | ||||
| mod structs; | ||||
|  | ||||
| use core::cell::Cell; | ||||
| use core::slice; | ||||
|  | ||||
| use embassy::time::{block_for, Duration, Timer}; | ||||
| use embassy::util::yield_now; | ||||
| use embassy_rp::gpio::{Flex, Output, Pin}; | ||||
|  | ||||
| use self::structs::*; | ||||
|  | ||||
| fn swap16(x: u32) -> u32 { | ||||
|     (x & 0xFF00FF00) >> 8 | (x & 0x00FF00FF) << 8 | ||||
| } | ||||
| @@ -169,68 +173,73 @@ const CHIP: Chip = Chip { | ||||
| }; | ||||
|  | ||||
| #[derive(Clone, Copy)] | ||||
| #[repr(C)] | ||||
| struct SdpcmHeader { | ||||
|     len: u16, | ||||
|     len_inv: u16, | ||||
|     /// Rx/Tx sequence number | ||||
|     sequence: u8, | ||||
|     ///  4 MSB Channel number, 4 LSB arbitrary flag | ||||
|     channel_and_flags: u8, | ||||
|     /// Length of next data frame, reserved for Tx | ||||
|     next_length: u8, | ||||
|     /// Data offset | ||||
|     header_length: u8, | ||||
|     /// Flow control bits, reserved for Tx | ||||
|     wireless_flow_control: u8, | ||||
|     /// Maximum Sequence number allowed by firmware for Tx | ||||
|     bus_data_credit: u8, | ||||
|     /// Reserved | ||||
|     reserved: [u8; 2], | ||||
| enum IoctlState { | ||||
|     Idle, | ||||
|  | ||||
|     Pending { | ||||
|         kind: u32, | ||||
|         cmd: u32, | ||||
|         iface: u32, | ||||
|         buf: *const [u8], | ||||
|     }, | ||||
|     Sent, | ||||
|     Done, | ||||
| } | ||||
|  | ||||
| #[derive(Clone, Copy)] | ||||
| #[repr(C)] | ||||
| struct CdcHeader { | ||||
|     cmd: u32, | ||||
|     out_len: u16, | ||||
|     in_len: u16, | ||||
|     flags: u16, | ||||
|     id: u16, | ||||
|     status: u32, | ||||
| pub struct State { | ||||
|     ioctl_id: Cell<u16>, | ||||
|     ioctl_state: Cell<IoctlState>, | ||||
| } | ||||
|  | ||||
| #[derive(Clone, Copy)] | ||||
| #[repr(C)] | ||||
| struct BdcHeader { | ||||
|     flags: u8, | ||||
|     /// 802.1d Priority (low 3 bits) | ||||
|     priority: u8, | ||||
|     flags2: u8, | ||||
|     /// Offset from end of BDC header to packet data, in 4-uint8_t words. Leaves room for optional headers. | ||||
|     data_offset: u8, | ||||
| } | ||||
|  | ||||
| macro_rules! impl_bytes { | ||||
|     ($t:ident) => { | ||||
|         impl $t { | ||||
|             const SIZE: usize = core::mem::size_of::<Self>(); | ||||
|  | ||||
|             pub fn to_bytes(&self) -> [u8; Self::SIZE] { | ||||
|                 unsafe { core::mem::transmute(*self) } | ||||
|             } | ||||
|  | ||||
|             pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> Self { | ||||
|                 unsafe { core::mem::transmute(*bytes) } | ||||
|             } | ||||
| impl State { | ||||
|     pub fn new() -> Self { | ||||
|         Self { | ||||
|             ioctl_id: Cell::new(0), | ||||
|             ioctl_state: Cell::new(IoctlState::Idle), | ||||
|         } | ||||
|     }; | ||||
|     } | ||||
| } | ||||
| impl_bytes!(SdpcmHeader); | ||||
| impl_bytes!(CdcHeader); | ||||
| impl_bytes!(BdcHeader); | ||||
|  | ||||
| pub struct Driver<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> { | ||||
| pub struct Control<'a> { | ||||
|     state: &'a State, | ||||
| } | ||||
|  | ||||
| impl<'a> Control<'a> { | ||||
|     pub async fn init(&mut self) { | ||||
|         let clm = unsafe { slice::from_raw_parts(0x10140000 as *const u8, 4752) }; | ||||
|  | ||||
|         let mut buf = [0; 8 + 12 + 1024]; | ||||
|         buf[0..8].copy_from_slice(b"clmload\x00"); | ||||
|         buf[8..20].copy_from_slice(b"\x02\x10\x02\x00\x00\x04\x00\x00\x00\x00\x00\x00"); | ||||
|         buf[20..].copy_from_slice(&clm[..1024]); | ||||
|         self.ioctl(2, 263, 0, &buf).await; | ||||
|         info!("IOCTL done"); | ||||
|     } | ||||
|  | ||||
|     async fn ioctl(&mut self, kind: u32, cmd: u32, iface: u32, buf: &[u8]) { | ||||
|         // TODO cancel ioctl on future drop. | ||||
|  | ||||
|         while !matches!(self.state.ioctl_state.get(), IoctlState::Idle) { | ||||
|             yield_now().await; | ||||
|         } | ||||
|  | ||||
|         self.state.ioctl_id.set(self.state.ioctl_id.get().wrapping_add(1)); | ||||
|  | ||||
|         self.state | ||||
|             .ioctl_state | ||||
|             .set(IoctlState::Pending { kind, cmd, iface, buf }); | ||||
|  | ||||
|         while !matches!(self.state.ioctl_state.get(), IoctlState::Done) { | ||||
|             yield_now().await; | ||||
|         } | ||||
|  | ||||
|         self.state.ioctl_state.set(IoctlState::Idle); | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub struct Runner<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> { | ||||
|     state: &'a State, | ||||
|  | ||||
|     pwr: Output<'a, PWR>, | ||||
|  | ||||
|     /// SPI chip-select. | ||||
| @@ -249,18 +258,29 @@ pub struct Driver<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> { | ||||
|     backplane_window: u32, | ||||
| } | ||||
|  | ||||
| impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | ||||
|     pub fn new(pwr: Output<'a, PWR>, cs: Output<'a, CS>, clk: Output<'a, CLK>, dio: Flex<'a, DIO>) -> Self { | ||||
|         Self { | ||||
|             pwr, | ||||
|             cs, | ||||
|             clk, | ||||
|             dio, | ||||
|             backplane_window: 0xAAAA_AAAA, | ||||
|         } | ||||
|     } | ||||
| pub async fn new<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin>( | ||||
|     state: &'a State, | ||||
|     pwr: Output<'a, PWR>, | ||||
|     cs: Output<'a, CS>, | ||||
|     clk: Output<'a, CLK>, | ||||
|     dio: Flex<'a, DIO>, | ||||
| ) -> (Control<'a>, Runner<'a, PWR, CS, CLK, DIO>) { | ||||
|     let mut runner = Runner { | ||||
|         state, | ||||
|         pwr, | ||||
|         cs, | ||||
|         clk, | ||||
|         dio, | ||||
|         backplane_window: 0xAAAA_AAAA, | ||||
|     }; | ||||
|  | ||||
|     pub async fn init(&mut self) { | ||||
|     runner.init().await; | ||||
|  | ||||
|     (Control { state }, runner) | ||||
| } | ||||
|  | ||||
| impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Runner<'a, PWR, CS, CLK, DIO> { | ||||
|     async fn init(&mut self) { | ||||
|         // Set strap to select gSPI mode. | ||||
|         self.dio.set_as_output(); | ||||
|         self.dio.set_low(); | ||||
| @@ -306,6 +326,8 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | ||||
|         self.bp_write32(CHIP.socsram_base_address + 0x10, 3); | ||||
|         self.bp_write32(CHIP.socsram_base_address + 0x44, 0); | ||||
|  | ||||
|         let ram_addr = CHIP.atcm_ram_base_address; | ||||
|  | ||||
|         // I'm flashing the firmwares independently at hardcoded addresses, instead of baking them | ||||
|         // into the program with `include_bytes!` or similar, so that flashing the program stays fast. | ||||
|         // | ||||
| @@ -314,9 +336,6 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | ||||
|         // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 | ||||
|         // probe-rs-cli download 43439A0.clm_blob --format bin --chip RP2040 --base-address 0x10140000 | ||||
|         let fw = unsafe { slice::from_raw_parts(0x10100000 as *const u8, 224190) }; | ||||
|         let clm = unsafe { slice::from_raw_parts(0x10140000 as *const u8, 4752) }; | ||||
|  | ||||
|         let ram_addr = CHIP.atcm_ram_base_address; | ||||
|  | ||||
|         info!("loading fw"); | ||||
|         self.bp_write(ram_addr, fw); | ||||
| @@ -374,17 +393,20 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | ||||
|         let _ = self.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP); | ||||
|          */ | ||||
|  | ||||
|         let mut buf = [0; 8 + 12 + 1024]; | ||||
|         buf[0..8].copy_from_slice(b"clmload\x00"); | ||||
|         buf[8..20].copy_from_slice(b"\x02\x10\x02\x00\x00\x04\x00\x00\x00\x00\x00\x00"); | ||||
|         buf[20..].copy_from_slice(&clm[..1024]); | ||||
|         self.send_ioctl(2, 263, 0, &buf); | ||||
|  | ||||
|         info!("init done "); | ||||
|     } | ||||
|  | ||||
|     pub async fn run(mut self) -> ! { | ||||
|         let mut old_irq = 0; | ||||
|         let mut buf = [0; 2048]; | ||||
|         loop { | ||||
|             // Send stuff | ||||
|             if let IoctlState::Pending { kind, cmd, iface, buf } = self.state.ioctl_state.get() { | ||||
|                 self.send_ioctl(kind, cmd, iface, unsafe { &*buf }, self.state.ioctl_id.get()); | ||||
|                 self.state.ioctl_state.set(IoctlState::Sent); | ||||
|             } | ||||
|  | ||||
|             // Receive stuff | ||||
|             let irq = self.read16(FUNC_BUS, REG_BUS_INTERRUPT); | ||||
|             if irq != old_irq { | ||||
|                 info!("irq: {:04x}", irq); | ||||
| @@ -419,6 +441,7 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // TODO use IRQs | ||||
|             yield_now().await; | ||||
|         } | ||||
|     } | ||||
| @@ -453,14 +476,16 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | ||||
|                 let cdc_header = | ||||
|                     CdcHeader::from_bytes(packet[SdpcmHeader::SIZE..][..CdcHeader::SIZE].try_into().unwrap()); | ||||
|  | ||||
|                 // TODO check cdc_header.id matches | ||||
|                 // TODO check status | ||||
|                 if cdc_header.id == self.state.ioctl_id.get() { | ||||
|                     assert_eq!(cdc_header.status, 0); // todo propagate error | ||||
|                     self.state.ioctl_state.set(IoctlState::Done); | ||||
|                 } | ||||
|             } | ||||
|             _ => {} | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn send_ioctl(&mut self, kind: u32, cmd: u32, iface: u32, data: &[u8]) { | ||||
|     fn send_ioctl(&mut self, kind: u32, cmd: u32, iface: u32, data: &[u8], id: u16) { | ||||
|         let mut buf = [0; 2048]; | ||||
|  | ||||
|         let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len(); | ||||
| @@ -469,7 +494,7 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | ||||
|             len: total_len as u16, | ||||
|             len_inv: !total_len as u16, | ||||
|             sequence: 0x02,       // todo | ||||
|             channel_and_flags: 0, // control channle | ||||
|             channel_and_flags: 0, // control channel | ||||
|             next_length: 0, | ||||
|             header_length: SdpcmHeader::SIZE as _, | ||||
|             wireless_flow_control: 0, | ||||
| @@ -482,7 +507,7 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | ||||
|             out_len: data.len() as _, | ||||
|             in_len: 0, | ||||
|             flags: kind as u16 | (iface as u16) << 12, | ||||
|             id: 1, // todo | ||||
|             id, | ||||
|             status: 0, | ||||
|         }; | ||||
|  | ||||
| @@ -780,16 +805,13 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | ||||
|                     w |= 0x01; | ||||
|                 } | ||||
|                 self.clk.set_high(); | ||||
|                 delay(); | ||||
|  | ||||
|                 // falling edge | ||||
|                 self.clk.set_low(); | ||||
|                 delay(); | ||||
|             } | ||||
|             *word = w | ||||
|         } | ||||
|         self.clk.set_low(); | ||||
|         delay(); | ||||
|     } | ||||
|  | ||||
|     fn spi_write(&mut self, words: &[u8]) { | ||||
| @@ -804,25 +826,19 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | ||||
|                 } else { | ||||
|                     self.dio.set_high(); | ||||
|                 } | ||||
|                 delay(); | ||||
|  | ||||
|                 // rising edge | ||||
|                 self.clk.set_high(); | ||||
|                 delay(); | ||||
|  | ||||
|                 word = word << 1; | ||||
|             } | ||||
|         } | ||||
|         self.clk.set_low(); | ||||
|         delay(); | ||||
|  | ||||
|         self.dio.set_as_input(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn delay() { | ||||
|     //cortex_m::asm::delay(5); | ||||
| } | ||||
|  | ||||
| macro_rules! nvram { | ||||
|     ($($s:literal,)*) => { | ||||
|         concat_bytes!($($s, b"\x00",)* b"\x00\x00") | ||||
|   | ||||
							
								
								
									
										71
									
								
								src/structs.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/structs.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| #[derive(Clone, Copy)] | ||||
| #[repr(C)] | ||||
| pub struct SdpcmHeader { | ||||
|     pub len: u16, | ||||
|     pub len_inv: u16, | ||||
|     /// Rx/Tx sequence number | ||||
|     pub sequence: u8, | ||||
|     ///  4 MSB Channel number, 4 LSB arbitrary flag | ||||
|     pub channel_and_flags: u8, | ||||
|     /// Length of next data frame, reserved for Tx | ||||
|     pub next_length: u8, | ||||
|     /// Data offset | ||||
|     pub header_length: u8, | ||||
|     /// Flow control bits, reserved for Tx | ||||
|     pub wireless_flow_control: u8, | ||||
|     /// Maximum Sequence number allowed by firmware for Tx | ||||
|     pub bus_data_credit: u8, | ||||
|     /// Reserved | ||||
|     pub reserved: [u8; 2], | ||||
| } | ||||
|  | ||||
| #[derive(Clone, Copy)] | ||||
| #[repr(C)] | ||||
| pub struct CdcHeader { | ||||
|     pub cmd: u32, | ||||
|     pub out_len: u16, | ||||
|     pub in_len: u16, | ||||
|     pub flags: u16, | ||||
|     pub id: u16, | ||||
|     pub status: u32, | ||||
| } | ||||
|  | ||||
| #[derive(Clone, Copy)] | ||||
| #[repr(C)] | ||||
| pub struct BdcHeader { | ||||
|     pub flags: u8, | ||||
|     /// 802.1d Priority (low 3 bits) | ||||
|     pub priority: u8, | ||||
|     pub flags2: u8, | ||||
|     /// Offset from end of BDC header to packet data, in 4-uint8_t words. Leaves room for optional headers. | ||||
|     pub data_offset: u8, | ||||
| } | ||||
|  | ||||
| #[derive(Clone, Copy)] | ||||
| #[repr(C)] | ||||
| pub struct DownloadHeader { | ||||
|     pub flag: u16, | ||||
|     pub dload_type: u16, | ||||
|     pub len: u32, | ||||
|     pub crc: u32, | ||||
| } | ||||
|  | ||||
| macro_rules! impl_bytes { | ||||
|     ($t:ident) => { | ||||
|         impl $t { | ||||
|             pub const SIZE: usize = core::mem::size_of::<Self>(); | ||||
|  | ||||
|             pub fn to_bytes(&self) -> [u8; Self::SIZE] { | ||||
|                 unsafe { core::mem::transmute(*self) } | ||||
|             } | ||||
|  | ||||
|             pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> Self { | ||||
|                 unsafe { core::mem::transmute(*bytes) } | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
| } | ||||
| impl_bytes!(SdpcmHeader); | ||||
| impl_bytes!(CdcHeader); | ||||
| impl_bytes!(BdcHeader); | ||||
| impl_bytes!(DownloadHeader); | ||||
		Reference in New Issue
	
	Block a user