async ioctls working.
This commit is contained in:
parent
e560415fde
commit
069a57fcf8
@ -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);
|
Loading…
Reference in New Issue
Block a user