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 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",
|
||||
]
|
182
src/lib.rs
182
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,
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(C)]
|
||||
struct CdcHeader {
|
||||
Pending {
|
||||
kind: u32,
|
||||
cmd: u32,
|
||||
out_len: u16,
|
||||
in_len: u16,
|
||||
flags: u16,
|
||||
id: u16,
|
||||
status: u32,
|
||||
iface: u32,
|
||||
buf: *const [u8],
|
||||
},
|
||||
Sent,
|
||||
Done,
|
||||
}
|
||||
|
||||
#[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,
|
||||
pub struct State {
|
||||
ioctl_id: Cell<u16>,
|
||||
ioctl_state: Cell<IoctlState>,
|
||||
}
|
||||
|
||||
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) }
|
||||
impl State {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
ioctl_id: Cell::new(0),
|
||||
ioctl_state: Cell::new(IoctlState::Idle),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> Self {
|
||||
unsafe { core::mem::transmute(*bytes) }
|
||||
pub struct Control<'a> {
|
||||
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>,
|
||||
|
||||
/// 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 {
|
||||
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,
|
||||
}
|
||||
};
|
||||
|
||||
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.
|
||||
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);
|
Loading…
Reference in New Issue
Block a user