async ioctls working.
This commit is contained in:
		| @@ -6,11 +6,12 @@ use core::slice; | |||||||
|  |  | ||||||
| use defmt::{assert, assert_eq, panic, *}; | use defmt::{assert, assert_eq, panic, *}; | ||||||
| use embassy::executor::Spawner; | use embassy::executor::Spawner; | ||||||
|  | use embassy::util::Forever; | ||||||
| use embassy_rp::gpio::{Flex, Level, Output, Pin}; | 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 embassy_rp::Peripherals; | ||||||
| use {defmt_rtt as _, panic_probe as _}; | use {defmt_rtt as _, panic_probe as _}; | ||||||
|  |  | ||||||
|  |  | ||||||
| macro_rules! forever { | macro_rules! forever { | ||||||
|     ($val:expr) => {{ |     ($val:expr) => {{ | ||||||
|         type T = impl Sized; |         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] | #[embassy::main] | ||||||
| async fn main(_spawner: Spawner, p: Peripherals) { | async fn main(spawner: Spawner, p: Peripherals) { | ||||||
|     info!("Hello World!"); |     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_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 (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(pwr, Level::Low), | ||||||
|         Output::new(cs, Level::High), |         Output::new(cs, Level::High), | ||||||
|         Output::new(clk, Level::Low), |         Output::new(clk, Level::Low), | ||||||
|         Flex::new(dio), |         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", | ||||||
|  | ] | ||||||
							
								
								
									
										182
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										182
									
								
								src/lib.rs
									
									
									
									
									
								
							| @@ -1,16 +1,20 @@ | |||||||
| #![no_std] | #![no_std] | ||||||
| #![no_main] | #![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. | // This mod MUST go first, so that the others see its macros. | ||||||
| pub(crate) mod fmt; | pub(crate) mod fmt; | ||||||
|  |  | ||||||
|  | mod structs; | ||||||
|  |  | ||||||
|  | use core::cell::Cell; | ||||||
| use core::slice; | use core::slice; | ||||||
|  |  | ||||||
| use embassy::time::{block_for, Duration, Timer}; | use embassy::time::{block_for, Duration, Timer}; | ||||||
| use embassy::util::yield_now; | use embassy::util::yield_now; | ||||||
| use embassy_rp::gpio::{Flex, Output, Pin}; | use embassy_rp::gpio::{Flex, Output, Pin}; | ||||||
|  |  | ||||||
|  | use self::structs::*; | ||||||
|  |  | ||||||
| fn swap16(x: u32) -> u32 { | fn swap16(x: u32) -> u32 { | ||||||
|     (x & 0xFF00FF00) >> 8 | (x & 0x00FF00FF) << 8 |     (x & 0xFF00FF00) >> 8 | (x & 0x00FF00FF) << 8 | ||||||
| } | } | ||||||
| @@ -169,68 +173,73 @@ const CHIP: Chip = Chip { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| #[derive(Clone, Copy)] | #[derive(Clone, Copy)] | ||||||
| #[repr(C)] | enum IoctlState { | ||||||
| struct SdpcmHeader { |     Idle, | ||||||
|     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], |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[derive(Clone, Copy)] |     Pending { | ||||||
| #[repr(C)] |         kind: u32, | ||||||
| struct CdcHeader { |  | ||||||
|         cmd: u32, |         cmd: u32, | ||||||
|     out_len: u16, |         iface: u32, | ||||||
|     in_len: u16, |         buf: *const [u8], | ||||||
|     flags: u16, |     }, | ||||||
|     id: u16, |     Sent, | ||||||
|     status: u32, |     Done, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Clone, Copy)] | pub struct State { | ||||||
| #[repr(C)] |     ioctl_id: Cell<u16>, | ||||||
| struct BdcHeader { |     ioctl_state: Cell<IoctlState>, | ||||||
|     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 { | impl State { | ||||||
|     ($t:ident) => { |     pub fn new() -> Self { | ||||||
|         impl $t { |         Self { | ||||||
|             const SIZE: usize = core::mem::size_of::<Self>(); |             ioctl_id: Cell::new(0), | ||||||
|  |             ioctl_state: Cell::new(IoctlState::Idle), | ||||||
|             pub fn to_bytes(&self) -> [u8; Self::SIZE] { |         } | ||||||
|                 unsafe { core::mem::transmute(*self) } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|             pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> Self { | pub struct Control<'a> { | ||||||
|                 unsafe { core::mem::transmute(*bytes) } |     state: &'a State, | ||||||
| } | } | ||||||
|         } |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
| impl_bytes!(SdpcmHeader); |  | ||||||
| impl_bytes!(CdcHeader); |  | ||||||
| impl_bytes!(BdcHeader); |  | ||||||
|  |  | ||||||
| pub struct Driver<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> { | 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>, |     pwr: Output<'a, PWR>, | ||||||
|  |  | ||||||
|     /// SPI chip-select. |     /// SPI chip-select. | ||||||
| @@ -249,18 +258,29 @@ pub struct Driver<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> { | |||||||
|     backplane_window: u32, |     backplane_window: u32, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | pub async fn new<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin>( | ||||||
|     pub fn new(pwr: Output<'a, PWR>, cs: Output<'a, CS>, clk: Output<'a, CLK>, dio: Flex<'a, DIO>) -> Self { |     state: &'a State, | ||||||
|         Self { |     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, |         pwr, | ||||||
|         cs, |         cs, | ||||||
|         clk, |         clk, | ||||||
|         dio, |         dio, | ||||||
|         backplane_window: 0xAAAA_AAAA, |         backplane_window: 0xAAAA_AAAA, | ||||||
|         } |     }; | ||||||
|  |  | ||||||
|  |     runner.init().await; | ||||||
|  |  | ||||||
|  |     (Control { state }, runner) | ||||||
| } | } | ||||||
|  |  | ||||||
|     pub async fn init(&mut self) { | 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. |         // Set strap to select gSPI mode. | ||||||
|         self.dio.set_as_output(); |         self.dio.set_as_output(); | ||||||
|         self.dio.set_low(); |         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 + 0x10, 3); | ||||||
|         self.bp_write32(CHIP.socsram_base_address + 0x44, 0); |         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 |         // 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. |         // 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.bin --format bin --chip RP2040 --base-address 0x10100000 | ||||||
|         // probe-rs-cli download 43439A0.clm_blob --format bin --chip RP2040 --base-address 0x10140000 |         // 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 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"); |         info!("loading fw"); | ||||||
|         self.bp_write(ram_addr, 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 _ = 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 "); |         info!("init done "); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub async fn run(mut self) -> ! { | ||||||
|         let mut old_irq = 0; |         let mut old_irq = 0; | ||||||
|         let mut buf = [0; 2048]; |         let mut buf = [0; 2048]; | ||||||
|         loop { |         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); |             let irq = self.read16(FUNC_BUS, REG_BUS_INTERRUPT); | ||||||
|             if irq != old_irq { |             if irq != old_irq { | ||||||
|                 info!("irq: {:04x}", 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; |             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 = |                 let cdc_header = | ||||||
|                     CdcHeader::from_bytes(packet[SdpcmHeader::SIZE..][..CdcHeader::SIZE].try_into().unwrap()); |                     CdcHeader::from_bytes(packet[SdpcmHeader::SIZE..][..CdcHeader::SIZE].try_into().unwrap()); | ||||||
|  |  | ||||||
|                 // TODO check cdc_header.id matches |                 if cdc_header.id == self.state.ioctl_id.get() { | ||||||
|                 // TODO check status |                     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 mut buf = [0; 2048]; | ||||||
|  |  | ||||||
|         let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len(); |         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: total_len as u16, | ||||||
|             len_inv: !total_len as u16, |             len_inv: !total_len as u16, | ||||||
|             sequence: 0x02,       // todo |             sequence: 0x02,       // todo | ||||||
|             channel_and_flags: 0, // control channle |             channel_and_flags: 0, // control channel | ||||||
|             next_length: 0, |             next_length: 0, | ||||||
|             header_length: SdpcmHeader::SIZE as _, |             header_length: SdpcmHeader::SIZE as _, | ||||||
|             wireless_flow_control: 0, |             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 _, |             out_len: data.len() as _, | ||||||
|             in_len: 0, |             in_len: 0, | ||||||
|             flags: kind as u16 | (iface as u16) << 12, |             flags: kind as u16 | (iface as u16) << 12, | ||||||
|             id: 1, // todo |             id, | ||||||
|             status: 0, |             status: 0, | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
| @@ -780,16 +805,13 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | |||||||
|                     w |= 0x01; |                     w |= 0x01; | ||||||
|                 } |                 } | ||||||
|                 self.clk.set_high(); |                 self.clk.set_high(); | ||||||
|                 delay(); |  | ||||||
|  |  | ||||||
|                 // falling edge |                 // falling edge | ||||||
|                 self.clk.set_low(); |                 self.clk.set_low(); | ||||||
|                 delay(); |  | ||||||
|             } |             } | ||||||
|             *word = w |             *word = w | ||||||
|         } |         } | ||||||
|         self.clk.set_low(); |         self.clk.set_low(); | ||||||
|         delay(); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn spi_write(&mut self, words: &[u8]) { |     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 { |                 } else { | ||||||
|                     self.dio.set_high(); |                     self.dio.set_high(); | ||||||
|                 } |                 } | ||||||
|                 delay(); |  | ||||||
|  |  | ||||||
|                 // rising edge |                 // rising edge | ||||||
|                 self.clk.set_high(); |                 self.clk.set_high(); | ||||||
|                 delay(); |  | ||||||
|  |  | ||||||
|                 word = word << 1; |                 word = word << 1; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         self.clk.set_low(); |         self.clk.set_low(); | ||||||
|         delay(); |  | ||||||
|         self.dio.set_as_input(); |         self.dio.set_as_input(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| fn delay() { |  | ||||||
|     //cortex_m::asm::delay(5); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| macro_rules! nvram { | macro_rules! nvram { | ||||||
|     ($($s:literal,)*) => { |     ($($s:literal,)*) => { | ||||||
|         concat_bytes!($($s, b"\x00",)* b"\x00\x00") |         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