diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..3ead519 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,40 @@ +name: CI + +on: [push, pull_request] + +jobs: + format: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: rustup toolchain install stable --no-self-update --profile minimal + - run: cargo fmt --verbose --check + + clippy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: rustup toolchain install stable --no-self-update --profile minimal --component clippy + # Small chip => fast to build => fast answers + - run: cargo clippy --tests --features=imxrt-ral/imxrt1011 -- -D warnings + + tests: + runs-on: ubuntu-latest + strategy: + matrix: + # Should be enough coverage, but feel free to add more. + chip: [imxrt1011, imxrt1062, imxrt1176_cm7] + steps: + - uses: actions/checkout@v4 + - run: rustup toolchain install stable --no-self-update --profile minimal + - run: cargo test --features=imxrt-ral/${{ matrix.chip }} + + target: + runs-on: ubuntu-latest + strategy: + matrix: + chip: [imxrt1011, imxrt1062, imxrt1176_cm7] + steps: + - uses: actions/checkout@v4 + - run: rustup toolchain install stable --no-self-update --profile minimal --target thumbv7em-none-eabihf + - run: cargo build --target=thumbv7em-none-eabihf --features=imxrt-ral/${{ matrix.chip }} diff --git a/.gitignore b/.gitignore index ea8c4bf..96ef6c0 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml index 14e0c67..8fd1295 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] +cotton-usb-host = { version = "0.2.1", default-features = false } +defmt = "1.0" +futures-core = { version = "0.3.31", default-features = false } +imxrt-ral = "0.6" diff --git a/README.md b/README.md index 4c52385..2712a65 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,45 @@ a Teensy 4.1, on the USB2 port. [`cotton-usb-host`]: https://github.com/pdh11/cotton/tree/main/cotton-usb-host +Development +----------- + +This repository contains the driver. The driver can build when targeting your +development system or an i.MX RT microcontroller. + +When you make a change, you can check that it builds like this: + +``` +cargo build --features=imxrt-ral/imxrt1062 +``` + +That built the library for your development system, not the MCU! This means you +can run unit and documentation tests on your development system. + +``` +cargo test --features=imxrt-ral/imxrt1062 +``` + +To generate code for the MCU, append a target specifier. Hopefully, the code is +portable, so this shouldn't always be necessary. + +``` +cargo build --features=imxrt-ral/imxrt1062 --target=thumbv7em-none-eabihf +``` + +Hardware testing +---------------- + +This repository does not contain hardware examples. Those are in the [imxrt-hal] +repository. See the imxrt-hal documentation to learn how to run examples on your +board. + +[imxrt-hal]: https://github.com/imxrt-rs/imxrt-hal + +To test your changes, clone the imxrt-hal repository. In `imxrt-hal/Cargo.toml`, +find the `[patch.crates-io.imxrt-usbh]` directive, and point the patch to your +copy of this driver. Now, the changes you make _here_, in this driver, will be +incorporated into the hardware example you're running from imxrt-hal. License ------- diff --git a/src/lib.rs b/src/lib.rs index b93cf3f..3e112c1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,14 +1,127 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right +#![cfg_attr(target_os = "none", no_std)] + +pub use cotton_usb_host::{async_pool, bitset, host_controller, topology, usb_bus, wire}; +use imxrt_ral as ral; + +#[expect(dead_code)] +pub struct HostController { + // Not sure if we need more or fewer instances! + // We'll figure that out later. + usb: ral::usb::Instance, + phy: ral::usbphy::Instance, + nc: ral::usbnc::Instance, +} + +impl HostController { + pub fn new( + usb: ral::usb::Instance, + phy: ral::usbphy::Instance, + nc: ral::usbnc::Instance, + ) -> Self { + Self { usb, phy, nc } + } +} + +pub struct InterruptPipe {} +pub struct DeviceDetect {} + +impl futures_core::Stream for InterruptPipe { + type Item = host_controller::InterruptPacket; + + fn poll_next( + self: core::pin::Pin<&mut Self>, + _: &mut core::task::Context<'_>, + ) -> core::task::Poll> { + defmt::todo!() + } +} + +impl futures_core::Stream for DeviceDetect { + type Item = host_controller::DeviceStatus; + + fn poll_next( + self: core::pin::Pin<&mut Self>, + _: &mut core::task::Context<'_>, + ) -> core::task::Poll> { + defmt::todo!() + } +} + +#[expect(unused_variables, reason = "Autofill filled it in")] +impl host_controller::HostController for HostController { + type InterruptPipe = InterruptPipe; + type DeviceDetect = DeviceDetect; + + fn device_detect(&self) -> Self::DeviceDetect { + defmt::todo!() + } + + fn reset_root_port(&self, rst: bool) { + defmt::todo!() + } + + async fn control_transfer( + &self, + address: u8, + transfer_extras: usb_bus::TransferExtras, + packet_size: u8, + setup: wire::SetupPacket, + data_phase: usb_bus::DataPhase<'_>, + ) -> Result { + defmt::todo!() + } + + async fn bulk_in_transfer( + &self, + address: u8, + endpoint: u8, + packet_size: u16, + data: &mut [u8], + transfer_type: usb_bus::TransferType, + data_toggle: &core::cell::Cell, + ) -> Result { + defmt::todo!() + } + + async fn bulk_out_transfer( + &self, + address: u8, + endpoint: u8, + packet_size: u16, + data: &[u8], + transfer_type: usb_bus::TransferType, + data_toggle: &core::cell::Cell, + ) -> Result { + defmt::todo!() + } + + async fn alloc_interrupt_pipe( + &self, + address: u8, + transfer_extras: usb_bus::TransferExtras, + endpoint: u8, + max_packet_size: u16, + interval_ms: u8, + ) -> Self::InterruptPipe { + defmt::todo!() + } + + fn try_alloc_interrupt_pipe( + &self, + address: u8, + transfer_extras: usb_bus::TransferExtras, + endpoint: u8, + max_packet_size: u16, + interval_ms: u8, + ) -> Result { + defmt::todo!() + } } #[cfg(test)] mod tests { - use super::*; - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); + fn you_can_test_the_units() { + assert_eq!(1 + 1, 2); } }