aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Cully <bjc@kublai.com>2019-08-04 14:19:25 -0400
committerBrian Cully <bjc@kublai.com>2019-08-04 14:19:25 -0400
commite405c474f5e0e94288191223de7ae0f31ae0b15f (patch)
tree4ca89a92f0c868eb8feae272513c1e924b834adc
parentabd478d9425dd2d4acd5b58202b1a95b73ff217b (diff)
downloadsamd21-demo-e405c474f5e0e94288191223de7ae0f31ae0b15f.tar.gz
samd21-demo-e405c474f5e0e94288191223de7ae0f31ae0b15f.zip
Migrate everything over to separate libraries.
* `usb-host` is the crate containing the HAL traits. * `bootkbd` is a crate for a bare-bones boot protocol keyboard driver. * `samd21-host` is a crate with an implementation of `usb-host` for a SAMD21 platform, with an example for the trinket-m0 which uses the `bootkbd` driver to print keyboard reports.
-rw-r--r--app/logitech-kb-start.pcapngbin8616 -> 0 bytes
-rw-r--r--app/src/dotstar.rs42
-rw-r--r--bootkbd/Cargo.toml1
-rwxr-xr-x[-rw-r--r--]bootkbd/src/lib.rs40
-rw-r--r--samd21-host/.cargo/config (renamed from app/.cargo/config)0
-rw-r--r--samd21-host/Cargo.lock (renamed from app/Cargo.lock)113
-rw-r--r--samd21-host/Cargo.toml (renamed from app/Cargo.toml)23
-rw-r--r--samd21-host/Makefile (renamed from app/Makefile)12
-rw-r--r--samd21-host/examples/simple/logger.rs (renamed from app/src/logger.rs)0
-rw-r--r--samd21-host/examples/simple/macros.rs (renamed from app/src/macros.rs)0
-rwxr-xr-xsamd21-host/examples/simple/main.rs (renamed from app/src/main.rs)51
-rw-r--r--samd21-host/examples/simple/rtc.rs (renamed from app/src/rtc.rs)0
-rwxr-xr-xsamd21-host/find-serial-port (renamed from app/find-serial-port)0
-rwxr-xr-xsamd21-host/simple.binbin0 -> 123568 bytes
-rw-r--r--samd21-host/simple.uf2bin0 -> 247296 bytes
-rwxr-xr-xsamd21-host/src/lib.rs (renamed from usbh/src/lib.rs)309
-rw-r--r--samd21-host/src/pipe.rs (renamed from usbh/src/pipe.rs)157
-rw-r--r--samd21-host/src/pipe/addr.rs (renamed from usbh/src/pipe/addr.rs)10
-rw-r--r--samd21-host/src/pipe/ctrl_pipe.rs (renamed from usbh/src/pipe/ctrl_pipe.rs)18
-rw-r--r--samd21-host/src/pipe/ext_reg.rs (renamed from usbh/src/pipe/ext_reg.rs)0
-rw-r--r--samd21-host/src/pipe/pck_size.rs (renamed from usbh/src/pipe/pck_size.rs)0
-rw-r--r--samd21-host/src/pipe/status_bk.rs (renamed from usbh/src/pipe/status_bk.rs)0
-rw-r--r--samd21-host/src/pipe/status_pipe.rs (renamed from usbh/src/pipe/status_pipe.rs)0
-rwxr-xr-x[-rw-r--r--]usb-host/src/lib.rs38
-rw-r--r--usbh/Cargo.lock269
-rw-r--r--usbh/Cargo.toml16
-rw-r--r--usbh/src/device.rs392
-rw-r--r--usbh/src/usbproto.rs438
28 files changed, 444 insertions, 1485 deletions
diff --git a/app/logitech-kb-start.pcapng b/app/logitech-kb-start.pcapng
deleted file mode 100644
index ab22fd0..0000000
--- a/app/logitech-kb-start.pcapng
+++ /dev/null
Binary files differ
diff --git a/app/src/dotstar.rs b/app/src/dotstar.rs
deleted file mode 100644
index 8e930d0..0000000
--- a/app/src/dotstar.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-use trinket_m0::{
- clock::GenericClockController,
- gpio::{self, Floating, Input},
- prelude::*,
- sercom::{self, PadPin, SPIMaster1},
- PM, SERCOM1,
-};
-
-use apa102_spi::Apa102;
-
-pub fn new(
- sercom: SERCOM1,
- miso: gpio::Pa31<Input<Floating>>,
- mosi: gpio::Pa0<Input<Floating>>,
- sck: gpio::Pa1<Input<Floating>>,
- port: &mut gpio::Port,
- pm: &mut PM,
- clocks: &mut GenericClockController,
-) -> Apa102<
- SPIMaster1<
- sercom::Sercom1Pad3<gpio::Pa31<gpio::PfD>>,
- sercom::Sercom1Pad0<gpio::Pa0<gpio::PfD>>,
- sercom::Sercom1Pad1<gpio::Pa1<gpio::PfD>>,
- >,
-> {
- let gclk = clocks.gclk0();
- let miso = miso.into_pad(port);
- let mosi = mosi.into_pad(port);
- let sck = sck.into_pad(port);
- let spi = SPIMaster1::new(
- &clocks
- .sercom1_core(&gclk)
- .expect("setting up sercom1 clock"),
- 3.mhz(),
- apa102_spi::MODE,
- sercom,
- pm,
- (miso, mosi, sck),
- );
-
- Apa102::new(spi)
-}
diff --git a/bootkbd/Cargo.toml b/bootkbd/Cargo.toml
index 7b1b02d..5ae7bd4 100644
--- a/bootkbd/Cargo.toml
+++ b/bootkbd/Cargo.toml
@@ -8,4 +8,3 @@ license = "GPL-3.0-or-later"
[dependencies]
usb-host = { path = "../usb-host" }
log = "~0.4"
-
diff --git a/bootkbd/src/lib.rs b/bootkbd/src/lib.rs
index c143512..dde9e71 100644..100755
--- a/bootkbd/src/lib.rs
+++ b/bootkbd/src/lib.rs
@@ -1,8 +1,10 @@
+#![no_std]
+
use log::{debug, error, info};
use usb_host::{
- ConfigurationDescriptor, DescriptorType, DeviceDescriptor, Direction, Driver, Endpoint,
- Error as USBError, RequestCode, RequestDirection, RequestKind, RequestRecipient, RequestType,
- TransferType, USBHost, WValue,
+ ConfigurationDescriptor, DescriptorType, DeviceDescriptor, Direction, Driver, DriverError,
+ Endpoint, RequestCode, RequestDirection, RequestKind, RequestRecipient, RequestType,
+ TransferError, TransferType, USBHost, WValue,
};
use core::mem::{self, MaybeUninit};
@@ -21,6 +23,11 @@ const MAX_ENDPOINTS: usize = 2;
pub struct BootKeyboard {
devices: [Option<Device>; MAX_DEVICES],
}
+impl core::fmt::Debug for BootKeyboard {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "BootKeyboard")
+ }
+}
impl BootKeyboard {
pub fn new() -> Self {
@@ -35,14 +42,14 @@ impl Driver for BootKeyboard {
true
}
- fn add_device(&mut self, _device: DeviceDescriptor, address: u8) -> Result<(), USBError> {
+ fn add_device(&mut self, _device: DeviceDescriptor, address: u8) -> Result<(), DriverError> {
for i in 0..self.devices.len() {
if self.devices[i].is_none() {
self.devices[i] = Some(Device::new(address));
return Ok(());
}
}
- Err(USBError::Permanent("out of devices"))
+ Err(DriverError::Permanent(address, "out of devices"))
}
fn remove_device(&mut self, address: u8) {
@@ -56,20 +63,15 @@ impl Driver for BootKeyboard {
}
}
- fn tick_device(
- &mut self,
- address: u8,
- millis: usize,
- host: &mut dyn USBHost,
- ) -> Result<(), USBError> {
- for i in 0..self.devices.len() {
- if let Some(ref mut dev) = self.devices[i] {
- if dev.addr == address {
- return dev.fsm(millis, host);
+ fn tick(&mut self, millis: usize, host: &mut dyn USBHost) -> Result<(), DriverError> {
+ for d in &mut self.devices[..] {
+ if let Some(ref mut dev) = d {
+ if let Err(TransferError::Permanent(e)) = dev.fsm(millis, host) {
+ return Err(DriverError::Permanent(dev.addr, e));
}
}
}
- Err(USBError::Permanent("no device at address"))
+ Ok(())
}
}
@@ -110,7 +112,7 @@ impl Device {
}
}
- fn fsm(&mut self, millis: usize, host: &mut dyn USBHost) -> Result<(), USBError> {
+ fn fsm(&mut self, millis: usize, host: &mut dyn USBHost) -> Result<(), TransferError> {
// TODO: either we need another `control_transfer` that
// doesn't take data, or this `none` value needs to be put in
// the usb-host layer. None of these options are good.
@@ -252,8 +254,8 @@ impl Device {
let mut buf: [u8; 8] = [0; 8];
if let Some(ref mut ep) = self.endpoints[0] {
match host.in_transfer(ep, &mut buf) {
- Err(USBError::Permanent(msg)) => error!("reading report: {}", msg),
- Err(USBError::Retry(_)) => return Ok(()),
+ Err(TransferError::Permanent(msg)) => error!("reading report: {}", msg),
+ Err(TransferError::Retry(_)) => return Ok(()),
Ok(len) => info!("report: {} - {:?}", len, buf),
}
}
diff --git a/app/.cargo/config b/samd21-host/.cargo/config
index b6cdff0..b6cdff0 100644
--- a/app/.cargo/config
+++ b/samd21-host/.cargo/config
diff --git a/app/Cargo.lock b/samd21-host/Cargo.lock
index 599825f..7c24483 100644
--- a/app/Cargo.lock
+++ b/samd21-host/Cargo.lock
@@ -14,15 +14,6 @@ dependencies = [
]
[[package]]
-name = "apa102-spi"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "smart-leds-trait 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
name = "as-slice"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -51,7 +42,7 @@ version = "0.4.0"
dependencies = [
"bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cortex-m 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "cortex-m-rt 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cortex-m-rt 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -69,6 +60,14 @@ version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "bootkbd"
+version = "0.1.0"
+dependencies = [
+ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "usb-host 0.1.0",
+]
+
+[[package]]
name = "cfg-if"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -103,7 +102,7 @@ dependencies = [
[[package]]
name = "cortex-m-rt"
-version = "0.6.8"
+version = "0.6.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cortex-m-rt-macros 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -116,9 +115,9 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -140,7 +139,7 @@ dependencies = [
[[package]]
name = "log"
-version = "0.4.7"
+version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -152,17 +151,12 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "panic-halt"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
name = "paste"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "proc-macro-hack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro-hack 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -170,20 +164,20 @@ name = "paste-impl"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro-hack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro-hack 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro-hack"
-version = "0.5.7"
+version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -196,7 +190,7 @@ dependencies = [
[[package]]
name = "quote"
-version = "0.6.12"
+version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -233,11 +227,6 @@ name = "rb"
version = "0.1.0"
[[package]]
-name = "rgb"
-version = "0.8.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -246,22 +235,20 @@ dependencies = [
]
[[package]]
-name = "samd21-demo"
+name = "samd21-host"
version = "0.1.0"
dependencies = [
- "apa102-spi 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "atsamd-hal 0.5.0",
+ "bootkbd 0.1.0",
"clint 0.2.0",
"cortex-m 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cortex-m-rt 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cortex-m-rt 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "panic-halt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rb 0.1.0",
- "smart-leds 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "smart-leds-trait 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"trinket_m0 0.3.0",
- "usbh 0.1.0",
+ "usb-host 0.1.0",
]
[[package]]
@@ -278,33 +265,17 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "smart-leds"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "smart-leds-trait 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "smart-leds-trait"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "rgb 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
name = "stable_deref_trait"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syn"
-version = "0.15.38"
+version = "0.15.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -314,7 +285,7 @@ version = "0.3.0"
dependencies = [
"atsamd-hal 0.5.0",
"cortex-m 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "cortex-m-rt 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cortex-m-rt 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -330,15 +301,8 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "usbh"
+name = "usb-host"
version = "0.1.0"
-dependencies = [
- "atsamd-hal 0.5.0",
- "embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "rb 0.1.0",
- "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
[[package]]
name = "vcell"
@@ -361,37 +325,32 @@ dependencies = [
[metadata]
"checksum aligned 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d39da9b88ae1a81c03c9c082b8db83f1d0e93914126041962af61034ab44c4a5"
"checksum aligned 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a316c7ea8e1e9ece54862c992def5a7ac14de9f5832b69d71760680efeeefa"
-"checksum apa102-spi 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "244c305e53cabeadfce23409fe24bfcedaa20166aa3f16f6c4ab256302158fd5"
"checksum as-slice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "293dac66b274fab06f95e7efb05ec439a6b70136081ea522d270bc351ae5bb27"
"checksum bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a3caf393d93b2d453e80638d0674597020cef3382ada454faacd43d1a55a735a"
"checksum bitfield 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
"checksum cortex-m 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0b159a1e8306949579de3698c841dba58058197b65c60807194e4fa1e7a554"
"checksum cortex-m 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f3c18719fdc57db65668bfc977db9a0fa1a41d718c5d9cd4f652c9d4b0e0956a"
-"checksum cortex-m-rt 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7e1ccc9052352415ec4e3f762f4541098d012016f9354a1a5b2dede39b67f426"
+"checksum cortex-m-rt 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "17805910e3ecf029bdbfcc42b7384d9e3d9e5626153fa810002c1ef9839338ac"
"checksum cortex-m-rt-macros 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d7ae692573e0acccb1579fef1abf5a5bf1d2f3f0149a22b16870ec9309aee25f"
"checksum embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee4908a155094da7723c2d60d617b820061e3b4efcc3d9e293d206a5a76c170b"
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
-"checksum log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c275b6ad54070ac2d665eef9197db647b32239c9d244bfb6f041a766d00da5b3"
+"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b1411551beb3c11dedfb0a90a0fa256b47d28b9ec2cdff34c25a2fa59e45dbdc"
-"checksum panic-halt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812"
"checksum paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4a4a1c555c6505821f9d58b8779d0f630a6b7e4e1be24ba718610acf01fa79"
"checksum paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "26e796e623b8b257215f27e6c80a5478856cae305f5b59810ff9acdaa34570e6"
-"checksum proc-macro-hack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0c1dd4172a1e1f96f709341418f49b11ea6c2d95d53dca08c0f74cbd332d9cf3"
+"checksum proc-macro-hack 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "982a35d1194084ba319d65c4a68d24ca28f5fdb5b8bc20899e4eef8641ea5178"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
-"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
+"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f"
"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
-"checksum rgb 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)" = "4f089652ca87f5a82a62935ec6172a534066c7b97be003cc8f702ee9a7a59c92"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-"checksum smart-leds 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab0a30e934e60850bfc020d4c2727cc8a3635371f6af2cb3f55f36f0134ed080"
-"checksum smart-leds-trait 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fef18e60d41a6fde19e640cd7590c03fb27aa23146bf60e4da85028d7410cee7"
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
-"checksum syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)" = "37ea458a750f59ab679b47fef9b6722c586c5742f4cfe18a120bbc807e5e01fd"
+"checksum syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)" = "eadc09306ca51a40555dd6fc2b415538e9e18bc9f870e47b1a524a79fe2dcf5e"
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45c297f0afb6928cd08ab1ff9d95e99392595ea25ae1b5ecf822ff8764e57a0d"
diff --git a/app/Cargo.toml b/samd21-host/Cargo.toml
index 1bf5ab8..446bf1d 100644
--- a/app/Cargo.toml
+++ b/samd21-host/Cargo.toml
@@ -1,27 +1,24 @@
[package]
-name = "samd21-demo"
+name = "samd21-host"
version = "0.1.0"
authors = ["Brian Cully <bjc@kublai.com>"]
edition = "2018"
-readme = "../README.md"
license = "GPL-3.0-or-later"
[dependencies]
+usb-host = { path = "../usb-host" }
rb = { path = "../rb" }
-usbh = { path = "../usbh" }
+log = "~0.4"
+embedded-hal = "~0.2"
+atsamd-hal = { path = "../../atsamd/hal" }
-trinket_m0 = { path = "../../atsamd/boards/trinket_m0" }
+[dev-dependencies]
+bootkbd = { path = "../bootkbd" }
clint = { path = "../../clint" }
-
-panic-halt = "~0.2"
-smart-leds = "~0.2"
-smart-leds-trait = "~0.2"
-apa102-spi = "~0.2" # DotStar driver.
-nb = "~0.1"
cortex-m = "~0.6"
cortex-m-rt = "~0.6"
-embedded-hal = "~0.2"
-log = { version = "~0.4", features = ["max_level_trace", "release_max_level_warn"] }
+nb = "~0.1"
+trinket_m0 = { path = "../../atsamd/boards/trinket_m0" }
[features]
-default = ["cortex-m/const-fn"]
+default = ["atsamd-hal/samd21e18a"]
diff --git a/app/Makefile b/samd21-host/Makefile
index a5ef39f..87fbc8d 100644
--- a/app/Makefile
+++ b/samd21-host/Makefile
@@ -1,4 +1,4 @@
-APP = samd21-demo
+APP = simple
USBVID = 239a
USBPID = '001e|801e'
@@ -7,7 +7,7 @@ BOSSAC = bossac
SERIAL = $(shell ./find-serial-port $(USBVID) $(USBPID) || echo 'cant-find-serial-port')
OFFSET = 0x2000
-.PHONY: all clean cargo-build
+.PHONY: all clean cargo-build target/thumbv6m-none-eabi/debug/examples/$(APP)
all: $(APP).uf2
@@ -17,12 +17,12 @@ clean:
cargo clean
cargo-build:
- cargo build
+ cargo build --example $(APP)
-target/thumbv6m-none-eabi/debug/$(APP): cargo-build
+target/thumbv6m-none-eabi/debug/examples/$(APP): cargo-build
-$(APP).bin: target/thumbv6m-none-eabi/debug/$(APP)
- cargo objcopy --bin $(APP) -- -O binary $(APP).bin
+$(APP).bin: target/thumbv6m-none-eabi/debug/examples/$(APP)
+ cargo objcopy --example $(APP) -- -O binary $(APP).bin
# Requires https://github.com/sajattack/uf2conv-rs.git
%.uf2: %.bin
diff --git a/app/src/logger.rs b/samd21-host/examples/simple/logger.rs
index 9f9452e..9f9452e 100644
--- a/app/src/logger.rs
+++ b/samd21-host/examples/simple/logger.rs
diff --git a/app/src/macros.rs b/samd21-host/examples/simple/macros.rs
index 46d2d07..46d2d07 100644
--- a/app/src/macros.rs
+++ b/samd21-host/examples/simple/macros.rs
diff --git a/app/src/main.rs b/samd21-host/examples/simple/main.rs
index 1f8805b..c262905 100755
--- a/app/src/main.rs
+++ b/samd21-host/examples/simple/main.rs
@@ -4,21 +4,17 @@
#![feature(const_transmute)]
#![allow(dead_code)]
-mod dotstar;
mod logger;
mod macros;
mod rtc;
-//#[allow(unused)]
-//use panic_halt;
-
+use bootkbd::BootKeyboard;
use clint::HandlerArray;
use cortex_m::asm::wfi;
use cortex_m_rt::{entry, exception, ExceptionFrame};
use embedded_hal::digital::v2::OutputPin;
use log::{debug, info, LevelFilter};
-use smart_leds::colors;
-use smart_leds_trait::SmartLedsWrite;
+use samd21_host::SAMDHost;
use trinket_m0::{
self as hal,
clock::GenericClockController,
@@ -28,7 +24,7 @@ use trinket_m0::{
time::*,
CorePeripherals, Peripherals,
};
-use usbh::USBHost;
+use usb_host::Driver;
static HANDLERS: HandlerArray = HandlerArray::new();
@@ -79,26 +75,11 @@ fn main() -> ! {
unsafe { log::set_logger_racy(logger_ref).expect("couldn't set logger") };
log::set_max_level(LevelFilter::Info);
- info!("setting up dotstar");
-
- let mut dotstar = dotstar::new(
- peripherals.SERCOM1,
- pins.swdio,
- pins.dotstar_di,
- pins.dotstar_ci,
- &mut pins.port,
- &mut peripherals.PM,
- &mut clocks,
- );
-
- let black = [colors::BLACK];
- let blue = [colors::DARK_MAGENTA];
-
info!("setting up timer");
let mut rtc_handler = rtc::setup(peripherals.RTC, &mut clocks);
info!("setting up usb host");
- let (mut usb_host, mut usb_handler) = USBHost::new(
+ let (mut usb_host, mut usb_handler) = SAMDHost::new(
peripherals.USB,
pins.usb_sof,
pins.usb_dm,
@@ -110,6 +91,9 @@ fn main() -> ! {
&rtc::millis,
);
+ let mut bootkbd = BootKeyboard::new();
+ let mut drivers: [&mut dyn Driver; 1] = [&mut bootkbd];
+
info!("setting up handlers");
HANDLERS.with_overrides(|hs| {
hs.register(0, &mut rtc_handler);
@@ -121,27 +105,8 @@ fn main() -> ! {
info!("Boot up complete.");
- let mut last_tick = 0;
loop {
- cortex_m::interrupt::free(|_cs| {
- dotstar
- .write(black.iter().cloned())
- .expect("turning off dotstar");
- });
-
- let tick = rtc::millis();
- if tick >= last_tick + 1_024 {
- last_tick = tick;
- // trace!("{}: tick\r\n", rtc::millis());
- }
-
- usb_host.task();
-
- cortex_m::interrupt::free(|_cs| {
- dotstar
- .write(blue.iter().cloned())
- .expect("turning on dotstar");
- });
+ usb_host.task(&mut drivers[..]);
wfi();
}
});
diff --git a/app/src/rtc.rs b/samd21-host/examples/simple/rtc.rs
index 79e450a..79e450a 100644
--- a/app/src/rtc.rs
+++ b/samd21-host/examples/simple/rtc.rs
diff --git a/app/find-serial-port b/samd21-host/find-serial-port
index 62e2c0c..62e2c0c 100755
--- a/app/find-serial-port
+++ b/samd21-host/find-serial-port
diff --git a/samd21-host/simple.bin b/samd21-host/simple.bin
new file mode 100755
index 0000000..26b330f
--- /dev/null
+++ b/samd21-host/simple.bin
Binary files differ
diff --git a/samd21-host/simple.uf2 b/samd21-host/simple.uf2
new file mode 100644
index 0000000..817dcb3
--- /dev/null
+++ b/samd21-host/simple.uf2
Binary files differ
diff --git a/usbh/src/lib.rs b/samd21-host/src/lib.rs
index 1ed414c..98ebcff 100755
--- a/usbh/src/lib.rs
+++ b/samd21-host/src/lib.rs
@@ -1,14 +1,13 @@
#![no_std]
-#![allow(dead_code)]
-
-mod device;
mod pipe;
-mod usbproto;
-use device::{Device, DeviceTable};
-use pipe::{PipeErr, PipeTable, NO_DATA_STAGE};
-use rb::{Reader, RingBuffer, Writer};
-use usbproto::*;
+use pipe::{PipeErr, PipeTable};
+
+use usb_host::{
+ DescriptorType, DeviceDescriptor, Direction, Driver, DriverError, Endpoint, RequestCode,
+ RequestDirection, RequestKind, RequestRecipient, RequestType, TransferError, TransferType,
+ USBHost, WValue,
+};
use atsamd_hal::{
calibration::{usb_transn_cal, usb_transp_cal, usb_trim_cal},
@@ -18,6 +17,7 @@ use atsamd_hal::{
};
use embedded_hal::digital::v2::OutputPin;
use log::{debug, error, trace, warn};
+use rb::{Reader, RingBuffer, Writer};
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Event {
@@ -29,6 +29,17 @@ type Events = RingBuffer<Event>;
type EventReader = Reader<'static, Event>;
type EventWriter = Writer<'static, Event>;
+const NAK_LIMIT: usize = 15;
+
+// Must be at least 100ms. cf §9.1.2 of USB 2.0.
+const SETTLE_DELAY: usize = 205; // Delay in sec/1024
+
+// Ring buffer for sharing events from interrupt context.
+static mut EVENTS: Events = Events::new(Event::Error);
+// FIXME: this is just for testing. The enum needs to be
+// thread-safe if this is the way we're going.
+static mut LATEST_EVENT: Event = Event::Detached;
+
#[derive(Clone, Copy, Debug, PartialEq)]
enum DetachedState {
Initialize,
@@ -57,19 +68,53 @@ enum TaskState {
Steady(SteadyState),
}
-// Must be at least 100ms. cf §9.1.2 of USB 2.0.
-const SETTLE_DELAY: usize = 205; // Delay in sec/1024
-const NAK_LIMIT: usize = 15;
+use core::mem::{self, MaybeUninit};
+use core::ptr;
-static mut EVENTS: Events = Events::new(Event::Error);
-// FIXME: this is just for testing. The enum needs to be
-// thread-safe if this is the way we're going.
-static mut LATEST_EVENT: Event = Event::Detached;
+const MAX_DEVICES: usize = 4;
+struct DeviceTable {
+ tbl: [Option<Device>; MAX_DEVICES],
+}
+impl DeviceTable {
+ fn new() -> Self {
+ let tbl = {
+ let mut devs: [MaybeUninit<Option<Device>>; MAX_DEVICES] =
+ unsafe { MaybeUninit::uninit().assume_init() };
+ for d in &mut devs[..] {
+ unsafe { ptr::write(d.as_mut_ptr(), None) }
+ }
+ unsafe { mem::transmute(devs) }
+ };
-pub struct USBHost<F>
-where
- F: Fn() -> usize + 'static,
-{
+ Self { tbl: tbl }
+ }
+
+ /// Allocate a device with the next available address.
+ // TODO: get rid of the millis argument somehow, but the device
+ // does need a way of tracking time for Settle reasons.
+ fn next(&mut self) -> Option<&mut Device> {
+ for i in 1..self.tbl.len() {
+ if self.tbl[i].is_none() {
+ let d = Device { addr: i as u8 };
+ self.tbl[i] = Some(d);
+ return self.tbl[i].as_mut();
+ }
+ }
+ None
+ }
+
+ /// Remove the device at address `addr`.
+ fn remove(&mut self, addr: u8) -> Option<Device> {
+ let v = core::mem::replace(&mut self.tbl[addr as usize], None);
+ v
+ }
+}
+
+struct Device {
+ addr: u8,
+}
+
+pub struct SAMDHost<'a, F> {
usb: USB,
events: EventReader,
@@ -80,7 +125,6 @@ where
pipe_table: PipeTable,
devices: DeviceTable,
- addr0: Device,
// need sof 1kHz pad?
_sof_pad: gpio::Pa23<gpio::PfG>,
@@ -89,12 +133,12 @@ where
host_enable_pin: Option<gpio::Pa28<Output<OpenDrain>>>,
// To get current milliseconds.
- millis: &'static F,
+ millis: &'a F,
}
-impl<F> USBHost<F>
+impl<'a, F> SAMDHost<'a, F>
where
- F: Fn() -> usize + 'static,
+ F: Fn() -> usize,
{
pub fn new(
usb: USB,
@@ -105,7 +149,7 @@ where
port: &mut gpio::Port,
clocks: &mut GenericClockController,
pm: &mut PM,
- millis: &'static F,
+ millis: &'a F,
) -> (Self, impl FnMut()) {
let (eventr, mut eventw) = unsafe { EVENTS.split() };
@@ -117,8 +161,7 @@ where
pipe_table: PipeTable::new(),
- devices: DeviceTable::new(millis),
- addr0: Device::new(0, 8, millis),
+ devices: DeviceTable::new(),
_sof_pad: sof_pin.into_function_g(port),
_dm_pad: dm_pin.into_function_g(port),
@@ -197,7 +240,7 @@ where
debug!("...done");
}
- pub fn task(&mut self) {
+ pub fn task(&mut self, drivers: &mut [&mut dyn Driver]) {
static mut LAST_EVENT: Event = Event::Error;
unsafe {
if LAST_EVENT != LATEST_EVENT {
@@ -267,21 +310,18 @@ where
// };
}
- self.fsm();
+ self.fsm(drivers);
unsafe {
LAST_EVENT = LATEST_EVENT;
}
}
-
- fn poll_devices(&mut self) {}
-
- fn fsm(&mut self) {
+ fn fsm(&mut self, drivers: &mut [&mut dyn Driver]) {
// respond to events from interrupt.
match self.task_state {
TaskState::Detached(s) => self.detached_fsm(s),
TaskState::Attached(s) => self.attached_fsm(s),
- TaskState::Steady(s) => self.steady_fsm(s),
+ TaskState::Steady(s) => self.steady_fsm(s, drivers),
};
}
@@ -337,10 +377,10 @@ where
}
}
- fn steady_fsm(&mut self, s: SteadyState) {
+ fn steady_fsm(&mut self, s: SteadyState, drivers: &mut [&mut dyn Driver]) {
match s {
SteadyState::Configuring => {
- self.task_state = match self.configure_dev() {
+ self.task_state = match self.configure_dev(drivers) {
Ok(_) => TaskState::Steady(SteadyState::Running),
Err(e) => {
warn!("Enumeration error: {:?}", e);
@@ -350,51 +390,117 @@ where
}
SteadyState::Running => {
- self.devices.run(&mut self.pipe_table, self.usb.host_mut());
+ for d in &mut drivers[..] {
+ if let Err(e) = d.tick((self.millis)(), self) {
+ warn!("running driver {:?}: {:?}", d, e);
+ if let DriverError::Permanent(a, _) = e {
+ self.devices.remove(a);
+ }
+ }
+ }
}
SteadyState::Error => {}
}
}
- fn configure_dev(&mut self) -> Result<(), PipeErr> {
- let mut pipe = self
- .pipe_table
- .pipe_for(self.usb.host_mut(), &self.addr0.ep0);
- let mut vol_descr = ::vcell::VolatileCell::<DeviceDescriptor>::new(Default::default());
- pipe.control_transfer(
- &mut self.addr0.ep0,
- RequestType::get_descr(),
+ fn configure_dev(&mut self, drivers: &mut [&mut dyn Driver]) -> Result<(), TransferError> {
+ let none: Option<&mut [u8]> = None;
+ let mut a0ep0 = Addr0EP0 {
+ in_toggle: true,
+ out_toggle: true,
+ };
+ let mut dev_desc: DeviceDescriptor =
+ unsafe { MaybeUninit::<DeviceDescriptor>::uninit().assume_init() };
+ self.control_transfer(
+ &mut a0ep0,
+ RequestType::from((
+ RequestDirection::DeviceToHost,
+ RequestKind::Standard,
+ RequestRecipient::Device,
+ )),
RequestCode::GetDescriptor,
WValue::from((0, DescriptorType::Device as u8)),
0,
- Some(&mut vol_descr),
- self.millis,
+ Some(unsafe { to_slice_mut(&mut dev_desc) }),
+ )?;
+
+ trace!(" -- dev_desc: {:?}", dev_desc);
+
+ // TODO: new error for being out of devices.
+ let addr = self
+ .devices
+ .next()
+ .ok_or(TransferError::Permanent("out of devices"))?
+ .addr;
+ debug!("Setting address to {}.", addr);
+ self.control_transfer(
+ &mut a0ep0,
+ RequestType::from((
+ RequestDirection::HostToDevice,
+ RequestKind::Standard,
+ RequestRecipient::Device,
+ )),
+ RequestCode::SetAddress,
+ WValue::from((addr, 0)),
+ 0,
+ none,
)?;
- let desc = vol_descr.get();
- trace!(" -- devDesc: {:?}", desc);
-
- match self.devices.next(desc.b_max_packet_size, self.millis) {
- // TODO: new error for being out of devices.
- None => Err(PipeErr::Other("out of devices")),
- Some(device) => {
- debug!("Setting address to {}.", device.addr);
- pipe.control_transfer(
- &mut self.addr0.ep0,
- RequestType::set(),
- RequestCode::SetAddress,
- WValue::from((device.addr, 0)),
- 0,
- NO_DATA_STAGE,
- self.millis,
- )?;
-
- // Now that the device is addressed, `Device` can handle the
- // rest of the setup in its FSM.
- Ok(())
+ // Now that the device is addressed, see if any drivers want
+ // it.
+ for d in &mut drivers[..] {
+ if d.want_device(&dev_desc) {
+ let res = d.add_device(dev_desc, addr);
+ match res {
+ Ok(_) => return Ok(()),
+ Err(_) => return Err(TransferError::Permanent("out of addresses")),
+ }
}
}
+ Ok(())
+ }
+}
+
+struct Addr0EP0 {
+ in_toggle: bool,
+ out_toggle: bool,
+}
+impl Endpoint for Addr0EP0 {
+ fn address(&self) -> u8 {
+ 0
+ }
+
+ fn endpoint_num(&self) -> u8 {
+ 0
+ }
+
+ fn transfer_type(&self) -> TransferType {
+ TransferType::Control
+ }
+
+ fn direction(&self) -> Direction {
+ Direction::In
+ }
+
+ fn max_packet_size(&self) -> u16 {
+ 8
+ }
+
+ fn in_toggle(&self) -> bool {
+ self.in_toggle
+ }
+
+ fn set_in_toggle(&mut self, toggle: bool) {
+ self.in_toggle = toggle;
+ }
+
+ fn out_toggle(&self) -> bool {
+ self.out_toggle
+ }
+
+ fn set_out_toggle(&mut self, toggle: bool) {
+ self.out_toggle = toggle;
}
}
@@ -464,11 +570,76 @@ pub fn handler(usbp: usize, events: &mut EventWriter) {
trace!(" +ddisc");
usb.host().intflag.write(|w| w.ddisc().set_bit());
usb.host().intenclr.write(|w| w.ddisc().set_bit());
- // // Stop reset signal, in case of disconnection during reset
- // uhd_stop_reset(); // nothing on samd21
usb.host().intflag.write(|w| w.dconn().set_bit());
usb.host().intenset.write(|w| w.dconn().set_bit());
usb.host().intflag.write(|w| w.ddisc().set_bit());
unshift_event(Event::Detached);
}
}
+
+impl From<PipeErr> for TransferError {
+ fn from(v: PipeErr) -> Self {
+ match v {
+ PipeErr::TransferFail => Self::Retry("transfer failed"),
+ PipeErr::Flow => Self::Retry("data flow"),
+ PipeErr::DataToggle => Self::Retry("toggle sequence"),
+ PipeErr::ShortPacket => Self::Permanent("short packet"),
+ PipeErr::InvalidPipe => Self::Permanent("invalid pipe"),
+ PipeErr::InvalidToken => Self::Permanent("invalid token"),
+ PipeErr::Stall => Self::Permanent("stall"),
+ PipeErr::PipeErr => Self::Permanent("pipe error"),
+ PipeErr::HWTimeout => Self::Permanent("hardware timeout"),
+ PipeErr::SWTimeout => Self::Permanent("software timeout"),
+ PipeErr::Other(s) => Self::Permanent(s),
+ }
+ }
+}
+
+impl<F> USBHost for SAMDHost<'_, F>
+where
+ F: Fn() -> usize,
+{
+ fn control_transfer(
+ &mut self,
+ ep: &mut dyn Endpoint,
+ bm_request_type: RequestType,
+ b_request: RequestCode,
+ w_value: WValue,
+ w_index: u16,
+ buf: Option<&mut [u8]>,
+ ) -> Result<usize, TransferError> {
+ let mut pipe = self.pipe_table.pipe_for(self.usb.host_mut(), ep);
+ let len = pipe.control_transfer(
+ ep,
+ bm_request_type,
+ b_request,
+ w_value,
+ w_index,
+ buf,
+ self.millis,
+ )?;
+ Ok(len)
+ }
+
+ fn in_transfer(
+ &mut self,
+ ep: &mut dyn Endpoint,
+ buf: &mut [u8],
+ ) -> Result<usize, TransferError> {
+ let mut pipe = self.pipe_table.pipe_for(self.usb.host_mut(), ep);
+ let len = pipe.in_transfer(ep, buf, NAK_LIMIT, self.millis)?;
+ Ok(len)
+ }
+
+ fn out_transfer(&mut self, ep: &mut dyn Endpoint, buf: &[u8]) -> Result<usize, TransferError> {
+ let mut pipe = self.pipe_table.pipe_for(self.usb.host_mut(), ep);
+ let len = pipe.out_transfer(ep, buf, NAK_LIMIT, self.millis)?;
+ Ok(len)
+ }
+}
+
+unsafe fn to_slice_mut<T>(v: &mut T) -> &mut [u8] {
+ let ptr = v as *mut T as *mut u8;
+ let len = mem::size_of::<T>();
+ core::slice::from_raw_parts_mut(ptr, len)
+}
diff --git a/usbh/src/pipe.rs b/samd21-host/src/pipe.rs
index 80ebe11..0da0e7f 100644
--- a/usbh/src/pipe.rs
+++ b/samd21-host/src/pipe.rs
@@ -1,8 +1,14 @@
+#[allow(unused)]
pub mod addr;
+#[allow(unused)]
pub mod ctrl_pipe;
+#[allow(unused)]
pub mod ext_reg;
+#[allow(unused)]
pub mod pck_size;
+#[allow(unused)]
pub mod status_bk;
+#[allow(unused)]
pub mod status_pipe;
use addr::Addr;
@@ -12,16 +18,16 @@ use pck_size::PckSize;
use status_bk::StatusBk;
use status_pipe::StatusPipe;
-use super::device::{Endpoint, TransferType};
-
-use super::usbproto::*;
+use usb_host::{
+ Endpoint, RequestCode, RequestDirection, RequestType, SetupPacket, TransferType, WValue,
+};
use atsamd_hal::target_device::usb::{
self,
host::{BINTERVAL, PCFG, PINTFLAG, PSTATUS, PSTATUSCLR, PSTATUSSET},
};
use core::convert::TryInto;
-use log::{trace, warn};
+use log::trace;
// Maximum time to wait for a control request with data to finish. cf
// §9.2.6.1 of USB 2.0.
@@ -33,9 +39,6 @@ const MAX_PIPES: usize = 8;
// How many times to retry a transaction that has transient errors.
const NAK_LIMIT: usize = 15;
-// For use in control requests that do not require a data stage.
-pub(crate) const NO_DATA_STAGE: Option<&mut ()> = None;
-
#[derive(Copy, Clone, Debug, PartialEq)]
pub(crate) enum PipeErr {
ShortPacket,
@@ -78,31 +81,31 @@ impl PipeTable {
pub(crate) fn pipe_for<'a, 'b>(
&'a mut self,
host: &'b mut usb::HOST,
- endpoint: &Endpoint,
+ endpoint: &dyn Endpoint,
) -> Pipe<'a, 'b> {
// Just use two pipes for now. 0 is always for control
// endpoints, 1 for everything else.
//
// TODO: cache in-use pipes and return them without init if
// possible.
- let i = if endpoint.num == 0 { 0 } else { 1 };
+ let i = if endpoint.endpoint_num() == 0 { 0 } else { 1 };
let pregs = PipeRegs::from(host, i);
let pdesc = &mut self.tbl[i];
pregs.cfg.write(|w| {
- let ptype = PType::from(endpoint.transfer_type) as u8;
+ let ptype = PType::from(endpoint.transfer_type()) as u8;
unsafe { w.ptype().bits(ptype) }
});
trace!(
"setting paddr of pipe {} to {}:{}",
i,
- endpoint.addr,
- endpoint.num
+ endpoint.address(),
+ endpoint.endpoint_num()
);
pdesc.bank0.ctrl_pipe.write(|w| {
- w.pdaddr().set_addr(endpoint.addr);
- w.pepnum().set_epnum(endpoint.num)
+ w.pdaddr().set_addr(endpoint.address());
+ w.pepnum().set_epnum(endpoint.endpoint_num())
});
Pipe {
num: i,
@@ -120,30 +123,26 @@ pub(crate) struct Pipe<'a, 'b> {
pub(crate) desc: &'a mut PipeDesc,
}
impl Pipe<'_, '_> {
- pub(crate) fn control_transfer<T>(
+ pub(crate) fn control_transfer(
&mut self,
- ep: &mut Endpoint,
+ ep: &mut dyn Endpoint,
bm_request_type: RequestType,
b_request: RequestCode,
w_value: WValue,
w_index: u16,
- buf: Option<&mut T>,
+ buf: Option<&mut [u8]>,
millis: &dyn Fn() -> usize,
- ) -> Result<(), PipeErr> {
- let len = match buf {
- None => 0,
- _ => core::mem::size_of::<T>(),
- };
-
+ ) -> Result<usize, PipeErr> {
/*
* Setup stage.
*/
+ let buflen = buf.as_ref().map_or(0, |b| b.len() as u16);
let mut setup_packet = SetupPacket {
bm_request_type: bm_request_type,
b_request: b_request,
w_value: w_value,
w_index: w_index,
- w_length: len as u16,
+ w_length: buflen,
};
self.send(
ep,
@@ -156,16 +155,17 @@ impl Pipe<'_, '_> {
/*
* Data stage.
*/
+ let mut transfer_len = 0;
if let Some(b) = buf {
// TODO: data stage, has up to 5,000ms (in 500ms
// per-packet chunks) to complete. cf §9.2.6.4 of USB 2.0.
match bm_request_type.direction()? {
RequestDirection::DeviceToHost => {
- self.in_transfer(ep, b, NAK_LIMIT, millis)?;
+ transfer_len = self.in_transfer(ep, b, NAK_LIMIT, millis)?;
}
RequestDirection::HostToDevice => {
- self.out_transfer(ep, b, NAK_LIMIT, millis)?;
+ transfer_len = self.out_transfer(ep, b, NAK_LIMIT, millis)?;
}
}
}
@@ -188,12 +188,12 @@ impl Pipe<'_, '_> {
trace!("dispatching status stage");
self.dispatch_retries(ep, token, NAK_LIMIT, millis)?;
- Ok(())
+ Ok(transfer_len)
}
fn send(
&mut self,
- ep: &mut Endpoint,
+ ep: &mut dyn Endpoint,
token: PToken,
buf: &DataBuf,
nak_limit: usize,
@@ -214,21 +214,19 @@ impl Pipe<'_, '_> {
self.dispatch_retries(ep, token, nak_limit, millis)
}
- pub(crate) fn in_transfer<T>(
+ pub(crate) fn in_transfer(
&mut self,
- ep: &mut Endpoint,
- buf: &mut T,
+ ep: &mut dyn Endpoint,
+ buf: &mut [u8],
nak_limit: usize,
millis: &dyn Fn() -> usize,
) -> Result<usize, PipeErr> {
// TODO: pull this from pipe descriptor for this addr/ep.
let packet_size = 8;
- let db: DataBuf = buf.into();
-
- trace!("p{}: Should IN for {}b.", self.num, db.len);
+ trace!("p{}: Should IN for {}b.", self.num, buf.len());
self.desc.bank0.pcksize.write(|w| {
- unsafe { w.byte_count().bits(db.len as u16) };
+ unsafe { w.byte_count().bits(buf.len() as u16) };
unsafe { w.multi_packet_size().bits(0) }
});
@@ -240,12 +238,12 @@ impl Pipe<'_, '_> {
// variable length data is desired by the driver. cf §5.3.2 of
// USB 2.0.
let mut bytes_received = 0;
- while bytes_received < db.len {
+ while bytes_received < buf.len() {
// Move the buffer pointer forward as we get data.
- self.desc
- .bank0
- .addr
- .write(|w| unsafe { w.addr().bits(db.ptr as u32 + bytes_received as u32) });
+ self.desc.bank0.addr.write(|w| unsafe {
+ w.addr()
+ .bits(buf.as_mut_ptr() as u32 + bytes_received as u32)
+ });
self.regs.statusclr.write(|w| w.bk0rdy().set_bit());
trace!("--- !!! regs-pre-dispatch !!! ---");
self.log_regs();
@@ -253,17 +251,17 @@ impl Pipe<'_, '_> {
self.dispatch_retries(ep, PToken::In, nak_limit, millis)?;
let recvd = self.desc.bank0.pcksize.read().byte_count().bits() as usize;
bytes_received += recvd;
- trace!("!! read {} of {}", bytes_received, db.len);
+ trace!("!! read {} of {}", bytes_received, buf.len());
if recvd < packet_size {
break;
}
// Don't allow writing past the buffer.
- assert!(bytes_received <= db.len);
+ assert!(bytes_received <= buf.len());
}
self.regs.statusset.write(|w| w.pfreeze().set_bit());
- if bytes_received < db.len {
+ if bytes_received < buf.len() {
self.log_regs();
// TODO: honestly, this is probably a panic condition,
// since whatever's in DataBuf.ptr is totally
@@ -277,38 +275,36 @@ impl Pipe<'_, '_> {
}
}
- pub(crate) fn out_transfer<T>(
+ pub(crate) fn out_transfer(
&mut self,
- ep: &mut Endpoint,
- buf: &mut T,
+ ep: &mut dyn Endpoint,
+ buf: &[u8],
nak_limit: usize,
millis: &dyn Fn() -> usize,
) -> Result<usize, PipeErr> {
- let db: DataBuf = buf.into();
-
- trace!("p{}: Should OUT for {}b.", self.num, db.len);
+ trace!("p{}: Should OUT for {}b.", self.num, buf.len());
self.desc.bank0.pcksize.write(|w| {
- unsafe { w.byte_count().bits(db.len as u16) };
+ unsafe { w.byte_count().bits(buf.len() as u16) };
unsafe { w.multi_packet_size().bits(0) }
});
let mut bytes_sent = 0;
- while bytes_sent < db.len {
+ while bytes_sent < buf.len() {
self.desc
.bank0
.addr
- .write(|w| unsafe { w.addr().bits(db.ptr as u32 + bytes_sent as u32) });
+ .write(|w| unsafe { w.addr().bits(buf.as_ptr() as u32 + bytes_sent as u32) });
self.dispatch_retries(ep, PToken::Out, nak_limit, millis)?;
let sent = self.desc.bank0.pcksize.read().byte_count().bits() as usize;
bytes_sent += sent;
- trace!("!! wrote {} of {}", bytes_sent, db.len);
+ trace!("!! wrote {} of {}", bytes_sent, buf.len());
}
Ok(bytes_sent)
}
- pub(crate) fn dtgl(&mut self, ep: &mut Endpoint, token: PToken) {
+ fn dtgl(&mut self, ep: &mut dyn Endpoint, token: PToken) {
// TODO: this makes no sense to me, and docs are unclear. If
// the status bit is set, set it again? if it's clear then
// clear it? This is what I get for having to work from
@@ -317,28 +313,40 @@ impl Pipe<'_, '_> {
"~~~ tok: {:?}, dtgl: {}, i: {}, o: {}",
token,
self.regs.status.read().dtgl().bit(),
- ep.in_toggle,
- ep.out_toggle,
+ ep.in_toggle(),
+ ep.out_toggle(),
);
- if self.regs.status.read().dtgl().bit_is_set() {
+
+ let toggle = match token {
+ PToken::In => {
+ let t = !ep.in_toggle();
+ ep.set_in_toggle(t);
+ t
+ }
+
+ PToken::Out => {
+ let t = !ep.out_toggle();
+ ep.set_out_toggle(t);
+ t
+ }
+
+ _ => !self.regs.status.read().dtgl().bit_is_set(),
+ };
+
+ if toggle {
self.dtgl_set();
} else {
self.dtgl_clear();
}
- if token == PToken::In {
- ep.in_toggle = self.regs.status.read().dtgl().bit_is_set()
- } else {
- ep.out_toggle = self.regs.status.read().dtgl().bit_is_set()
- }
}
- pub(crate) fn dtgl_set(&mut self) {
+ fn dtgl_set(&mut self) {
self.regs.statusset.write(|w| w.dtgl().set_bit());
}
- pub(crate) fn dtgl_clear(&mut self) {
+ fn dtgl_clear(&mut self) {
self.regs.statusclr.write(|w| unsafe {
- // No function for this. FIXME: need to patch the SVD for
+ // FIXME: need to patch the SVD for
// PSTATUSCLR.DTGL at bit0. No? This is in the SVD, but
// not the rust output.
w.bits(1)
@@ -350,7 +358,7 @@ impl Pipe<'_, '_> {
// non-blocking.
fn dispatch_retries(
&mut self,
- ep: &mut Endpoint,
+ ep: &mut dyn Endpoint,
token: PToken,
retries: usize,
millis: &dyn Fn() -> usize,
@@ -365,9 +373,9 @@ impl Pipe<'_, '_> {
match res {
Ok(true) => {
if token == PToken::In {
- ep.in_toggle = self.regs.status.read().dtgl().bit_is_set();
+ ep.set_in_toggle(self.regs.status.read().dtgl().bit_is_set());
} else if token == PToken::Out {
- ep.out_toggle = self.regs.status.read().dtgl().bit_is_set();
+ ep.set_out_toggle(self.regs.status.read().dtgl().bit_is_set());
}
return Ok(());
}
@@ -382,7 +390,7 @@ impl Pipe<'_, '_> {
// a NAK, which in this context means there's
// no data. cf §32.8.7.5 of SAM D21 data
// sheet.
- PipeErr::Flow if ep.transfer_type == TransferType::Interrupt => break,
+ PipeErr::Flow if ep.transfer_type() == TransferType::Interrupt => break,
PipeErr::Stall => break,
_ => {
@@ -401,7 +409,7 @@ impl Pipe<'_, '_> {
Err(last_err)
}
- fn dispatch_packet(&mut self, ep: &mut Endpoint, token: PToken) {
+ fn dispatch_packet(&mut self, ep: &mut dyn Endpoint, token: PToken) {
self.regs
.cfg
.modify(|_, w| unsafe { w.ptoken().bits(token as u8) });
@@ -417,12 +425,12 @@ impl Pipe<'_, '_> {
// sequence at end of setup transaction. cf §8.6.1 of
// USB 2.0.
self.dtgl_clear();
- ep.in_toggle = true;
- ep.out_toggle = true;
+ ep.set_in_toggle(true);
+ ep.set_out_toggle(true);
}
PToken::In => {
self.regs.statusclr.write(|w| w.bk0rdy().set_bit());
- if ep.in_toggle {
+ if ep.in_toggle() {
self.dtgl_set();
} else {
self.dtgl_clear();
@@ -431,7 +439,7 @@ impl Pipe<'_, '_> {
PToken::Out => {
self.regs.intflag.write(|w| w.trcpt0().set_bit());
self.regs.statusset.write(|w| w.bk0rdy().set_bit());
- if ep.out_toggle {
+ if ep.out_toggle() {
self.dtgl_set();
} else {
self.dtgl_clear();
@@ -552,6 +560,7 @@ pub(crate) enum PToken {
}
// TODO: merge into SVD for pipe cfg register.
+#[allow(unused)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub(crate) enum PType {
Disabled = 0x0,
diff --git a/usbh/src/pipe/addr.rs b/samd21-host/src/pipe/addr.rs
index aa26048..b3548cf 100644
--- a/usbh/src/pipe/addr.rs
+++ b/samd21-host/src/pipe/addr.rs
@@ -6,13 +6,13 @@
/// Property: NA
#[derive(Clone, Copy, Debug)]
#[repr(C, packed)]
-pub(crate) struct Addr(u32);
+pub struct Addr(u32);
-pub(crate) struct R {
+pub struct R {
bits: u32,
}
-pub(crate) struct W {
+pub struct W {
bits: u32,
}
@@ -63,7 +63,7 @@ impl R {
/// These bits define the data pointer address as an absolute double
/// word address in RAM. The two least significant bits must be zero
/// to ensure the descriptor is 32-bit aligned.
-pub(crate) struct AddrR(u32);
+pub struct AddrR(u32);
impl AddrR {
pub fn bits(&self) -> u32 {
self.0
@@ -82,7 +82,7 @@ impl W {
}
}
-pub(crate) struct AddrW<'a> {
+pub struct AddrW<'a> {
w: &'a mut W,
}
impl<'a> AddrW<'a> {
diff --git a/usbh/src/pipe/ctrl_pipe.rs b/samd21-host/src/pipe/ctrl_pipe.rs
index 179b615..9301d51 100644
--- a/usbh/src/pipe/ctrl_pipe.rs
+++ b/samd21-host/src/pipe/ctrl_pipe.rs
@@ -5,13 +5,13 @@
/// Property: PAC Write-Protection, Write-Synchronized, Read-Synchronized
#[derive(Clone, Copy, Debug)]
#[repr(C, packed)]
-pub(crate) struct CtrlPipe(u16);
+pub struct CtrlPipe(u16);
-pub(crate) struct R {
+pub struct R {
bits: u16,
}
-pub(crate) struct W {
+pub struct W {
bits: u16,
}
@@ -77,7 +77,7 @@ impl R {
///
/// These bits define the maximum number of error for this Pipe before
/// freezing the pipe automatically.
-pub(crate) struct PErMaxR(u8);
+pub struct PErMaxR(u8);
impl PErMaxR {
pub fn max(&self) -> u8 {
self.0
@@ -87,7 +87,7 @@ impl PErMaxR {
/// Pipe EndPoint Number
///
/// These bits define the number of endpoint for this Pipe.
-pub(crate) struct PEpNumR(u8);
+pub struct PEpNumR(u8);
impl PEpNumR {
pub fn epnum(&self) -> u8 {
self.0
@@ -97,7 +97,7 @@ impl PEpNumR {
/// Pipe Device Address
///
/// These bits define the Device Address for this pipe.
-pub(crate) struct PDAddrR(u8);
+pub struct PDAddrR(u8);
impl PDAddrR {
pub fn addr(&self) -> u8 {
self.0
@@ -125,7 +125,7 @@ impl W {
}
}
-pub(crate) struct PErMaxW<'a> {
+pub struct PErMaxW<'a> {
w: &'a mut W,
}
impl<'a> PErMaxW<'a> {
@@ -142,7 +142,7 @@ impl<'a> PErMaxW<'a> {
}
}
-pub(crate) struct PEpNumW<'a> {
+pub struct PEpNumW<'a> {
w: &'a mut W,
}
impl<'a> PEpNumW<'a> {
@@ -159,7 +159,7 @@ impl<'a> PEpNumW<'a> {
}
}
-pub(crate) struct PDAddrW<'a> {
+pub struct PDAddrW<'a> {
w: &'a mut W,
}
impl<'a> PDAddrW<'a> {
diff --git a/usbh/src/pipe/ext_reg.rs b/samd21-host/src/pipe/ext_reg.rs
index 9778f1b..9778f1b 100644
--- a/usbh/src/pipe/ext_reg.rs
+++ b/samd21-host/src/pipe/ext_reg.rs
diff --git a/usbh/src/pipe/pck_size.rs b/samd21-host/src/pipe/pck_size.rs
index acc499f..acc499f 100644
--- a/usbh/src/pipe/pck_size.rs
+++ b/samd21-host/src/pipe/pck_size.rs
diff --git a/usbh/src/pipe/status_bk.rs b/samd21-host/src/pipe/status_bk.rs
index 489fc62..489fc62 100644
--- a/usbh/src/pipe/status_bk.rs
+++ b/samd21-host/src/pipe/status_bk.rs
diff --git a/usbh/src/pipe/status_pipe.rs b/samd21-host/src/pipe/status_pipe.rs
index be135c5..be135c5 100644
--- a/usbh/src/pipe/status_pipe.rs
+++ b/samd21-host/src/pipe/status_pipe.rs
diff --git a/usb-host/src/lib.rs b/usb-host/src/lib.rs
index 831a67c..551824a 100644..100755
--- a/usb-host/src/lib.rs
+++ b/usb-host/src/lib.rs
@@ -1,10 +1,13 @@
+#![no_std]
+
mod descriptor;
mod setup;
pub use descriptor::*;
pub use setup::*;
-pub enum Error {
+#[derive(Debug)]
+pub enum TransferError {
Retry(&'static str),
Permanent(&'static str),
}
@@ -18,11 +21,15 @@ pub trait USBHost {
w_value: WValue,
w_index: u16,
buf: Option<&mut [u8]>,
- ) -> Result<usize, Error>;
+ ) -> Result<usize, TransferError>;
- fn in_transfer(&mut self, ep: &mut dyn Endpoint, buf: &mut [u8]) -> Result<usize, Error>;
+ fn in_transfer(
+ &mut self,
+ ep: &mut dyn Endpoint,
+ buf: &mut [u8],
+ ) -> Result<usize, TransferError>;
- fn out_transfer(&mut self, ep: &mut dyn Endpoint, buf: &[u8]) -> Result<usize, Error>;
+ fn out_transfer(&mut self, ep: &mut dyn Endpoint, buf: &[u8]) -> Result<usize, TransferError>;
}
// cf §9.6.6 of USB 2.0
@@ -40,6 +47,7 @@ pub enum Direction {
Out,
In,
}
+
pub trait Endpoint {
fn address(&self) -> u8;
@@ -60,17 +68,23 @@ pub trait Endpoint {
fn set_out_toggle(&mut self, toggle: bool);
}
-pub trait Driver {
+#[derive(Copy, Clone, Debug)]
+pub enum DriverError {
+ Retry(u8, &'static str),
+ Permanent(u8, &'static str),
+}
+pub trait Driver: core::fmt::Debug {
fn want_device(&self, device: &DeviceDescriptor) -> bool;
- fn add_device(&mut self, device: DeviceDescriptor, address: u8) -> Result<(), Error>;
+ fn add_device(&mut self, device: DeviceDescriptor, address: u8) -> Result<(), DriverError>;
fn remove_device(&mut self, address: u8);
- fn tick_device(
- &mut self,
- address: u8,
- millis: usize,
- usbhost: &mut dyn USBHost,
- ) -> Result<(), Error>;
+ fn tick(&mut self, millis: usize, usbhost: &mut dyn USBHost) -> Result<(), DriverError>;
}
+
+// TODO: There needs to be a per-interface/function driver trait, as
+// well, since that's how most drivers will actually work.
+//
+// As a result, the host driver has to at least get the full
+// configuration.
diff --git a/usbh/Cargo.lock b/usbh/Cargo.lock
deleted file mode 100644
index 5b973da..0000000
--- a/usbh/Cargo.lock
+++ /dev/null
@@ -1,269 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-[[package]]
-name = "aligned"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "aligned"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "as-slice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "as-slice"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "atsamd-hal"
-version = "0.5.0"
-dependencies = [
- "atsamd21e18a 0.4.0",
- "bitfield 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "cortex-m 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "atsamd21e18a"
-version = "0.4.0"
-dependencies = [
- "bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "cortex-m 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "bare-metal"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "bitfield"
-version = "0.13.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "cfg-if"
-version = "0.1.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "cortex-m"
-version = "0.5.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "aligned 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "cortex-m 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "cortex-m"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "aligned 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "embedded-hal"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "generic-array"
-version = "0.12.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "log"
-version = "0.4.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "nb"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "paste"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "proc-macro-hack 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "paste-impl"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro-hack 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "proc-macro-hack"
-version = "0.5.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "proc-macro2"
-version = "0.4.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "quote"
-version = "0.6.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "rb"
-version = "0.1.0"
-
-[[package]]
-name = "rustc_version"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "semver"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "semver-parser"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "stable_deref_trait"
-version = "1.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "syn"
-version = "0.15.42"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "typenum"
-version = "1.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "unicode-xid"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "usbh"
-version = "0.1.0"
-dependencies = [
- "atsamd-hal 0.5.0",
- "embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "rb 0.1.0",
- "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "vcell"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "void"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "volatile-register"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[metadata]
-"checksum aligned 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d39da9b88ae1a81c03c9c082b8db83f1d0e93914126041962af61034ab44c4a5"
-"checksum aligned 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a316c7ea8e1e9ece54862c992def5a7ac14de9f5832b69d71760680efeeefa"
-"checksum as-slice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "293dac66b274fab06f95e7efb05ec439a6b70136081ea522d270bc351ae5bb27"
-"checksum bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a3caf393d93b2d453e80638d0674597020cef3382ada454faacd43d1a55a735a"
-"checksum bitfield 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
-"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
-"checksum cortex-m 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0b159a1e8306949579de3698c841dba58058197b65c60807194e4fa1e7a554"
-"checksum cortex-m 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f3c18719fdc57db65668bfc977db9a0fa1a41d718c5d9cd4f652c9d4b0e0956a"
-"checksum embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee4908a155094da7723c2d60d617b820061e3b4efcc3d9e293d206a5a76c170b"
-"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
-"checksum log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c275b6ad54070ac2d665eef9197db647b32239c9d244bfb6f041a766d00da5b3"
-"checksum nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b1411551beb3c11dedfb0a90a0fa256b47d28b9ec2cdff34c25a2fa59e45dbdc"
-"checksum paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4a4a1c555c6505821f9d58b8779d0f630a6b7e4e1be24ba718610acf01fa79"
-"checksum paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "26e796e623b8b257215f27e6c80a5478856cae305f5b59810ff9acdaa34570e6"
-"checksum proc-macro-hack 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "982a35d1194084ba319d65c4a68d24ca28f5fdb5b8bc20899e4eef8641ea5178"
-"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
-"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
-"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
-"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
-"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
-"checksum syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)" = "eadc09306ca51a40555dd6fc2b415538e9e18bc9f870e47b1a524a79fe2dcf5e"
-"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
-"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
-"checksum vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45c297f0afb6928cd08ab1ff9d95e99392595ea25ae1b5ecf822ff8764e57a0d"
-"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
-"checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286"
diff --git a/usbh/Cargo.toml b/usbh/Cargo.toml
deleted file mode 100644
index ecbd6c5..0000000
--- a/usbh/Cargo.toml
+++ /dev/null
@@ -1,16 +0,0 @@
-[package]
-name = "usbh"
-version = "0.1.0"
-authors = ["Brian Cully <bjc@kublai.com>"]
-edition = "2018"
-license = "GPL-3.0-or-later"
-
-[dependencies]
-rb = { path = "../rb" }
-atsamd-hal = { path = "../../atsamd/hal" }
-embedded-hal = "~0.2"
-log = "~0.4"
-vcell = "~0.1"
-
-[features]
-default = ["atsamd-hal/samd21e18a"]
diff --git a/usbh/src/device.rs b/usbh/src/device.rs
deleted file mode 100644
index fd5c1a1..0000000
--- a/usbh/src/device.rs
+++ /dev/null
@@ -1,392 +0,0 @@
-use super::pipe::{PipeErr, PipeTable, NO_DATA_STAGE};
-use super::usbproto::*;
-
-use core::convert::TryInto;
-use log::{debug, error, info, trace};
-
-// TODO: impl Drop for Device/Endpoint cleanup if any ends up being
-// required.
-
-// FIXME: once again, this doesn't belong here. The issue is that
-// we're using `pipe_for`, which requires it.
-use atsamd_hal::target_device::usb;
-
-const MAX_DEVICES: usize = 16;
-
-// TODO:
-// This may be wrong. It may be 15 additional input + 15 additional
-// output! cf §5.3.1.2 of USB 2.0.
-const MAX_ENDPOINTS: usize = 16;
-
-// How long to wait before talking to the device again after setting
-// its address. cf §9.2.6.3 of USB 2.0
-const SETTLE_DELAY: usize = 2;
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub(crate) enum Error {
- PipeErr(PipeErr),
-}
-impl From<PipeErr> for Error {
- fn from(e: PipeErr) -> Self {
- Self::PipeErr(e)
- }
-}
-
-enum FSM {
- AddressSet,
- WaitForSettle(usize),
- GetConfigDescriptor,
- SetConfig,
- GetReport(usize),
- Steady,
-}
-
-pub(crate) struct DeviceTable {
- devices: [Option<Device>; MAX_DEVICES],
-}
-// TODO: Untie device address from table index. Right now it's wasting
-// a table slot because addr 0 isn't used here. And rather than just
-// putting in an offset, which can be forgotten, it's better to let
-// something else handle address assignment.
-impl DeviceTable {
- pub(crate) fn new<F>(millis: &'static F) -> Self
- where
- F: Fn() -> usize + 'static,
- {
- let mut devices: [Option<Device>; MAX_DEVICES] = {
- let mut devs: [core::mem::MaybeUninit<Option<Device>>; MAX_DEVICES] =
- unsafe { core::mem::MaybeUninit::uninit().assume_init() };
- for d in &mut devs[..] {
- unsafe { core::ptr::write(d.as_mut_ptr(), None) }
- }
- unsafe { core::mem::transmute(devs) }
- };
- devices[0] = Some(Device::new(0, 8, millis));
- Self { devices: devices }
- }
-
- /// Return the device at address `addr`.
- pub(crate) fn device_for(&mut self, addr: u8) -> Option<&mut Device> {
- if let Some(ref mut d) = self.devices[addr as usize] {
- Some(d)
- } else {
- None
- }
- }
-
- /// Allocate a device with the next available address.
- // TODO: get rid of the millis argument somehow, but the device
- // does need a way of tracking time for Settle reasons.
- pub(crate) fn next(
- &mut self,
- max_packet_size: u8,
- millis: &'static dyn Fn() -> usize,
- ) -> Option<&mut Device> {
- for i in 1..self.devices.len() {
- if self.devices[i].is_none() {
- let a = i.try_into().unwrap();
- let d = Device::new(a, max_packet_size, millis);
- self.devices[i] = Some(d);
- return self.device_for(a);
- }
- }
- None
- }
-
- /// Remove the device at address `addr`.
- pub(crate) fn remove(&mut self, addr: u8) -> Option<Device> {
- let v = core::mem::replace(&mut self.devices[addr as usize], None);
- v
- }
-
- pub(crate) fn run(&mut self, pipe_table: &mut PipeTable, host: &mut usb::HOST) {
- for i in 1..self.devices.len() {
- // TODO: Woof, this is ugly, but I'm not sure of a better
- // way to avoid mutably borrowing self twice.
- let mut remove_addr: Option<u8> = None;
- if let Some(ref mut d) = self.devices[i] {
- if let Err(e) = d.fsm(pipe_table, host) {
- error!("Removing device {}: {:?}", d.addr, e);
- remove_addr = Some(d.addr);
- } else {
- remove_addr = None;
- }
- }
-
- if let Some(addr) = remove_addr {
- self.remove(addr);
- }
- }
- }
-}
-
-pub struct Device {
- pub addr: u8,
- pub max_packet_size: u8,
- pub endpoints: [Option<Endpoint>; MAX_ENDPOINTS],
- pub ep0: Endpoint,
-
- state: FSM,
- millis: &'static dyn Fn() -> usize,
-}
-impl Device {
- // TODO: get max packet size from device descriptor.
- pub fn new(addr: u8, max_packet_size: u8, millis: &'static dyn Fn() -> usize) -> Self {
- // Set up endpoints array with 0 as default control endpoint.
- let endpoints: [Option<Endpoint>; MAX_ENDPOINTS] = {
- let mut eps: [core::mem::MaybeUninit<Option<Endpoint>>; MAX_ENDPOINTS] =
- unsafe { core::mem::MaybeUninit::uninit().assume_init() };
- for ep in &mut eps[..] {
- unsafe { core::ptr::write(ep.as_mut_ptr(), None) }
- }
- unsafe { core::mem::transmute(eps) }
- };
-
- Self {
- addr: addr,
- max_packet_size: max_packet_size,
- endpoints: endpoints,
- ep0: Endpoint::new(
- addr,
- 0,
- TransferType::Control,
- TransferDirection::In,
- max_packet_size,
- ),
-
- state: FSM::AddressSet,
-
- // TODO: This doesn't belong here. Ideally the current
- // time is passed in to the FSM routine.
- millis: millis,
- }
- }
-}
-
-impl Device {
- pub(crate) fn fsm(
- &mut self,
- pipe_table: &mut PipeTable,
- host: &mut usb::HOST,
- ) -> Result<(), Error> {
- match self.state {
- FSM::AddressSet => self.state = FSM::WaitForSettle((self.millis)() + SETTLE_DELAY),
-
- FSM::WaitForSettle(until) => {
- if (self.millis)() >= until {
- // Dunno why we get the device descriptor a second time.
- let mut pipe = pipe_table.pipe_for(host, &self.ep0);
-
- let mut vol_descr =
- ::vcell::VolatileCell::<DeviceDescriptor>::new(Default::default());
- pipe.control_transfer(
- &mut self.ep0,
- RequestType::get_descr(),
- RequestCode::GetDescriptor,
- WValue::from((0, DescriptorType::Device as u8)),
- 0,
- Some(&mut vol_descr),
- self.millis,
- )?;
-
- let desc = vol_descr.get();
- trace!(" -- devDesc: {:?}", desc);
-
- self.state = FSM::GetConfigDescriptor
- }
- }
-
- FSM::GetConfigDescriptor => {
- // Get config descriptor with minimal data, to see how much we need to allocate for the full descriptor.
- let mut pipe = pipe_table.pipe_for(host, &self.ep0);
-
- let mut vol_descr =
- ::vcell::VolatileCell::<ConfigurationDescriptor>::new(Default::default());
- pipe.control_transfer(
- &mut self.ep0,
- RequestType::get_descr(),
- RequestCode::GetDescriptor,
- WValue::from((0, DescriptorType::Configuration as u8)),
- 0,
- Some(&mut vol_descr),
- self.millis,
- )?;
- let desc = vol_descr.get();
- debug!("config: {:?}", desc);
-
- // TODO: do real allocation later.
- assert!(desc.w_total_length < 64);
- let buf: [u8; 64] = [0; 64];
- let mut tmp = &buf[..desc.w_total_length as usize];
- pipe.control_transfer(
- &mut self.ep0,
- RequestType::get_descr(),
- RequestCode::GetDescriptor,
- WValue::from((0, DescriptorType::Configuration as u8)),
- 0,
- Some(&mut tmp),
- self.millis,
- )?;
-
- self.state = FSM::SetConfig
- }
-
- FSM::SetConfig => {
- let mut pipe = pipe_table.pipe_for(host, &self.ep0);
-
- debug!("+++ setting configuration");
- let conf: u8 = 1;
- pipe.control_transfer(
- &mut self.ep0,
- RequestType::set(),
- RequestCode::SetConfiguration,
- WValue::from((conf, 0)),
- 0,
- NO_DATA_STAGE,
- self.millis,
- )?;
- debug!(" -- configuration set");
-
- debug!("+++ setting idle");
- pipe.control_transfer(
- &mut self.ep0,
- RequestType::from((
- RequestDirection::HostToDevice,
- RequestKind::Class,
- RequestRecipient::Interface,
- )),
- RequestCode::GetInterface, // This is also idle, but can't have two enums with the same value.
- WValue::from((0, 0)),
- 0,
- NO_DATA_STAGE,
- self.millis,
- )?;
- debug!(" -- idle set");
-
- debug!("+++ setting report");
- let mut report: u8 = 0;
- pipe.control_transfer(
- &mut self.ep0,
- RequestType::from((
- RequestDirection::HostToDevice,
- RequestKind::Class,
- RequestRecipient::Interface,
- )),
- RequestCode::SetConfiguration,
- WValue::from((0, 2)),
- 0,
- Some(&mut report),
- self.millis,
- )?;
- debug!(" -- report set");
-
- // Stub in some endpoints until we can parse the
- // configuration descriptor.
- self.endpoints[1] = Some(Endpoint::new(
- self.addr,
- 1,
- TransferType::Interrupt,
- TransferDirection::In,
- 8,
- ));
- self.endpoints[2] = Some(Endpoint::new(
- self.addr,
- 2,
- TransferType::Interrupt,
- TransferDirection::In,
- 8,
- ));
- self.state = FSM::GetReport(2)
- }
-
- FSM::GetReport(0) => self.state = FSM::Steady,
-
- FSM::GetReport(count) => {
- debug!("+++ getting report {}", count);
-
- // For now, just do an IN transfer to see if we can
- // get some keyboard reports without further setup.
-
- // EP 1 is boot proto keyboard.
- self.read_report(pipe_table, host, 1);
-
- // EP 2 is consumer control keys.
- self.read_report(pipe_table, host, 2);
-
- self.state = FSM::GetReport(count)
- }
-
- FSM::Steady => {}
- }
- Ok(())
- }
-
- fn read_report(&mut self, pipe_table: &mut PipeTable, host: &mut usb::HOST, id: u8) {
- if let Some(ref mut ep) = self.endpoints[id as usize] {
- let mut pipe = pipe_table.pipe_for(host, ep);
- let mut buf: [u8; 8] = [0; 8];
- match pipe.in_transfer(ep, &mut buf, 15, self.millis) {
- Ok(bytes_received) => info!("report {}: {} - {:?}", id, bytes_received, buf),
-
- Err(PipeErr::Flow) => return,
-
- Err(e) => trace!("error {}: {:?}", id, e),
- }
- } else {
- error!("endpoint {} doesn't exist!", id)
- }
- }
-}
-
-// TransferType (INTERRUPT)
-// Direction (IN)
-pub struct Endpoint {
- // This just points back to the address because we need to know it
- // for all endpoint operations, but we don't want to pass the
- // address struct (which contains all endpoints) around.
- pub addr: u8,
- pub num: u8,
- pub transfer_type: TransferType,
- pub direction: TransferDirection,
- pub in_toggle: bool,
- pub out_toggle: bool,
- pub max_packet_size: u8,
-}
-
-// cf §9.6.6 of USB 2.0
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub enum TransferDirection {
- Out,
- In,
-}
-
-// ibid
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub enum TransferType {
- Control = 0,
- Isochronous = 1,
- Bulk = 2,
- Interrupt = 3,
-}
-
-impl Endpoint {
- // TODO: direction is ignored on control endpoints. Try to remove
- // it from the API in those cases as well.
- pub fn new(
- addr: u8,
- num: u8,
- transfer_type: TransferType,
- direction: TransferDirection,
- max_packet_size: u8,
- ) -> Self {
- Self {
- addr: addr,
- num: num,
- transfer_type: transfer_type,
- direction: direction,
- in_toggle: false,
- out_toggle: false,
- max_packet_size: max_packet_size,
- }
- }
-}
diff --git a/usbh/src/usbproto.rs b/usbh/src/usbproto.rs
deleted file mode 100644
index 33bc28c..0000000
--- a/usbh/src/usbproto.rs
+++ /dev/null
@@ -1,438 +0,0 @@
-/// USB Protocol level types and functions.
-///
-/// Everything in here is defined by the USB specification, and
-/// hardware independent.
-use core::convert::TryFrom;
-use core::convert::TryInto;
-
-// TODO: Put protocol section references in for types and
-// documentation.
-
-#[derive(Copy, Clone, Debug, Default, PartialEq)]
-#[repr(C, packed)]
-pub struct DeviceDescriptor {
- pub b_length: u8,
- pub b_descriptor_type: DescriptorType,
- pub bcd_usb: u16,
- pub b_device_class: u8,
- pub b_device_sub_class: u8,
- pub b_device_protocol: u8,
- pub b_max_packet_size: u8,
- pub id_vendor: u16,
- pub id_product: u16,
- pub bcd_device: u16,
- pub i_manufacturer: u8,
- pub i_product: u8,
- pub i_serial_number: u8,
- pub b_num_configurations: u8,
-}
-
-#[derive(Copy, Clone, Debug, Default, PartialEq)]
-#[repr(C, packed)]
-pub struct ConfigurationDescriptor {
- pub b_length: u8,
- pub b_descriptor_type: DescriptorType,
- pub w_total_length: u16,
- pub b_num_interfaces: u8,
- pub b_configuration_value: u8,
- pub i_configuration: u8,
- pub bm_attributes: u8,
- pub b_max_power: u8,
-}
-
-#[derive(Copy, Clone, Debug, Default, PartialEq)]
-#[repr(C, packed)]
-pub struct InterfaceDescriptor {
- pub b_length: u8,
- pub b_descriptor_type: DescriptorType,
- pub b_interface_number: u8,
- pub b_alternate_setting: u8,
- pub b_num_endpoints: u8,
- pub b_interface_class: u8,
- pub b_interface_sub_class: u8,
- pub b_interface_protocol: u8,
- pub i_interface: u8,
-}
-
-#[derive(Copy, Clone, Debug, Default, PartialEq)]
-#[repr(C, packed)]
-pub struct EndpointDescriptor {
- pub b_length: u8,
- pub b_descriptor_type: DescriptorType,
- pub b_endpoint_address: u8,
- pub bm_attributes: u8,
- pub w_max_packet_size: u16,
- pub b_interval: u8,
-}
-
-#[derive(Copy, Clone, Debug, Default, PartialEq)]
-#[repr(C, packed)]
-pub struct SetupPacket {
- pub bm_request_type: RequestType,
- pub b_request: RequestCode,
- pub w_value: WValue,
- pub w_index: u16,
- pub w_length: u16,
-}
-
-#[derive(Clone, Copy, Debug, Default, PartialEq)]
-#[repr(C)]
-pub struct RequestType(u8);
-impl RequestType {
- // Get descriptor request type.
- pub fn get_descr() -> Self {
- Self::from((
- RequestDirection::DeviceToHost,
- RequestKind::Standard,
- RequestRecipient::Device,
- ))
- }
-
- // Set request type for all but 'set feature' and 'set interface'.
- pub fn set() -> Self {
- Self::from((
- RequestDirection::HostToDevice,
- RequestKind::Standard,
- RequestRecipient::Device,
- ))
- }
-
- // Get interface request type.
- pub fn cl_get_intf() -> Self {
- Self::from((
- RequestDirection::DeviceToHost,
- RequestKind::Class,
- RequestRecipient::Interface,
- ))
- }
-
- pub fn recipient(&self) -> Result<RequestRecipient, &'static str> {
- const POS: u8 = 0;
- const MASK: u8 = 0x1f;
- (self.0 & (MASK << POS)).try_into()
- }
-
- pub fn set_recipient(&mut self, v: RequestRecipient) {
- const POS: u8 = 0;
- const MASK: u8 = 0x1f;
- self.0 &= !(MASK << POS);
- self.0 |= v as u8 & MASK;
- }
-
- pub fn kind(&self) -> Result<RequestKind, &'static str> {
- const POS: u8 = 5;
- const MASK: u8 = 0x3;
- (self.0 & (MASK << POS)).try_into()
- }
-
- pub fn set_kind(&mut self, v: RequestKind) {
- const POS: u8 = 5;
- const MASK: u8 = 0x3;
- self.0 &= !(MASK << POS);
- self.0 |= v as u8 & MASK;
- }
-
- pub fn direction(&self) -> Result<RequestDirection, &'static str> {
- const POS: u8 = 7;
- const MASK: u8 = 0x1;
- (self.0 & (MASK << POS)).try_into()
- }
-
- pub fn set_direction(&mut self, v: RequestDirection) {
- const POS: u8 = 7;
- const MASK: u8 = 0x1;
- self.0 &= !(MASK << POS);
- self.0 |= v as u8 & MASK;
- }
-}
-impl From<(RequestDirection, RequestKind, RequestRecipient)> for RequestType {
- fn from(v: (RequestDirection, RequestKind, RequestRecipient)) -> Self {
- Self(v.0 as u8 | v.1 as u8 | v.2 as u8)
- }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub enum RequestDirection {
- HostToDevice = 0x00,
- DeviceToHost = 0x80,
-}
-impl TryFrom<u8> for RequestDirection {
- type Error = &'static str;
-
- fn try_from(v: u8) -> Result<Self, Self::Error> {
- match v {
- 0x00 => Ok(Self::HostToDevice),
- 0x80 => Ok(Self::DeviceToHost),
- _ => Err("direction can only be 0x00 or 0x80"),
- }
- }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub enum RequestKind {
- Standard = 0x00,
- Class = 0x20,
- Vendor = 0x40,
-}
-impl TryFrom<u8> for RequestKind {
- type Error = &'static str;
-
- fn try_from(v: u8) -> Result<Self, Self::Error> {
- match v {
- 0x00 => Ok(Self::Standard),
- 0x20 => Ok(Self::Class),
- 0x40 => Ok(Self::Vendor),
- _ => Err("type can only be 0x00, 0x20, or 0x40"),
- }
- }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub enum RequestRecipient {
- Device = 0x00,
- Interface = 0x01,
- Endpoint = 0x02,
- Other = 0x03,
-}
-impl TryFrom<u8> for RequestRecipient {
- type Error = &'static str;
-
- fn try_from(v: u8) -> Result<Self, Self::Error> {
- match v {
- 0x00 => Ok(Self::Device),
- 0x01 => Ok(Self::Interface),
- 0x02 => Ok(Self::Endpoint),
- 0x03 => Ok(Self::Other),
- _ => Err("recipient can only be between 0 and 3"),
- }
- }
-}
-
-#[derive(Clone, Copy, Debug, Default, PartialEq)]
-#[repr(C)]
-pub struct WValue(u16);
-impl WValue {
- pub fn w_value_lo(&self) -> u8 {
- const POS: u8 = 0;
- const MASK: u16 = 0xff;
- ((self.0 >> POS) & MASK) as u8
- }
-
- pub fn set_w_value_lo(&mut self, v: u8) {
- const POS: u8 = 0;
- const MASK: u8 = 0xff;
- self.0 &= !((MASK as u16) << POS);
- self.0 |= ((v & MASK) as u16) << POS;
- }
-
- pub fn w_value_hi(&self) -> u8 {
- const POS: u8 = 8;
- const MASK: u16 = 0xff;
- ((self.0 >> POS) & MASK) as u8
- }
-
- pub fn set_w_value_hi(&mut self, v: u8) {
- const POS: u8 = 8;
- const MASK: u8 = 0xff;
- self.0 &= !((MASK as u16) << POS);
- self.0 |= ((v & MASK) as u16) << POS;
- }
-}
-impl From<(u8, u8)> for WValue {
- fn from(v: (u8, u8)) -> Self {
- let mut rc = Self(0);
- rc.set_w_value_lo(v.0);
- rc.set_w_value_hi(v.1);
- rc
- }
-}
-
-#[derive(Clone, Copy, Debug, PartialEq)]
-pub enum RequestCode {
- GetStatus = 0,
- ClearFeature = 1,
- SetFeature = 3,
- SetAddress = 5,
- GetDescriptor = 6,
- SetDescriptor = 7,
- GetConfiguration = 8,
- SetConfiguration = 9,
- GetInterface = 10,
- SetInterface = 11,
- SynchFrame = 12,
-}
-impl TryFrom<u8> for RequestCode {
- type Error = &'static str;
-
- fn try_from(v: u8) -> Result<Self, Self::Error> {
- match v {
- 0 => Ok(Self::GetStatus),
- 1 => Ok(Self::ClearFeature),
- 3 => Ok(Self::SetFeature),
- 5 => Ok(Self::SetAddress),
- 6 => Ok(Self::GetDescriptor),
- 7 => Ok(Self::SetDescriptor),
- 8 => Ok(Self::GetConfiguration),
- 9 => Ok(Self::SetConfiguration),
- 10 => Ok(Self::GetInterface),
- 11 => Ok(Self::SetInterface),
- 12 => Ok(Self::SynchFrame),
- _ => Err("invalid request value"),
- }
- }
-}
-impl Default for RequestCode {
- fn default() -> Self {
- Self::GetStatus
- }
-}
-
-#[derive(Clone, Copy, Debug, PartialEq)]
-pub enum USBFeature {
- EndpointHalt = 0,
- DeviceRemoteWakeup = 1,
- TestMode = 2,
-}
-
-#[derive(Clone, Copy, Debug, PartialEq)]
-pub enum DescriptorType {
- Device = 1,
- Configuration = 2,
- String = 3,
- Interface = 4,
- Endpoint = 5,
- DeviceQualifier = 6,
- OtherSpeed = 7,
- InterfacePower = 8,
-}
-impl Default for DescriptorType {
- fn default() -> Self {
- Self::Device
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
-
- #[test]
- fn dev_desc_serialize() {
- let desc = DeviceDescriptor {
- b_length: 18,
- b_descriptor_type: DescriptorType::Device,
- bcd_usb: 0x0110,
- b_device_class: 0x02,
- b_device_sub_class: 0x03,
- b_device_protocol: 0x04,
- b_max_packet_size: 64,
- id_vendor: 0xdead,
- id_product: 0xbeef,
- bcd_device: 0x5432,
- i_manufacturer: 0xa0,
- i_product: 0xa1,
- i_serial_number: 0xa2,
- b_num_configurations: 1,
- };
- let want = [
- 0x12, 0x01, 0x10, 0x01, 0x02, 0x03, 0x04, 64, 0xad, 0xde, 0xef, 0xbe, 0x32, 0x54, 0xa0,
- 0xa1, 0xa2, 1,
- ];
-
- serde_test(&desc, &want);
- }
-
- #[test]
- fn config_desc_serialize() {
- let desc = ConfigurationDescriptor {
- b_length: 18,
- b_descriptor_type: DescriptorType::Configuration,
- w_total_length: 0x20,
- b_num_interfaces: 5,
- b_configuration_value: 10,
- i_configuration: 1,
- bm_attributes: 0x40,
- b_max_power: 0xfa,
- };
- let want = [0x12, 0x02, 0x20, 0x00, 0x05, 0x0a, 0x01, 0x40, 0xfa];
-
- serde_test(&desc, &want);
- }
-
- #[test]
- fn interface_desc_serialize() {
- let desc = InterfaceDescriptor {
- b_length: 18,
- b_descriptor_type: DescriptorType::Interface,
- b_interface_number: 2,
- b_alternate_setting: 0xaa,
- b_num_endpoints: 5,
- b_interface_class: 0x11,
- b_interface_sub_class: 0x22,
- b_interface_protocol: 0x33,
- i_interface: 10,
- };
- let want = [0x12, 0x04, 0x02, 0xaa, 0x05, 0x11, 0x22, 0x33, 0x0a];
-
- serde_test(&desc, &want);
- }
-
- #[test]
- fn endpoint_desc_serialize() {
- let desc = EndpointDescriptor {
- b_length: 18,
- b_descriptor_type: DescriptorType::Endpoint,
- b_endpoint_address: 1,
- bm_attributes: 0x22,
- w_max_packet_size: 0xdead,
- b_interval: 0x33,
- };
- let want = [0x12, 0x05, 0x01, 0x22, 0xad, 0xde, 0x33];
-
- serde_test(&desc, &want);
- }
-
- #[test]
- fn setup_packet_serialize() {
- let setup_packet = SetupPacket {
- bm_request_type: RequestType::get_descr(),
- b_request: RequestCode::GetDescriptor,
- w_value: WValue::from((0x00, 0x01)),
- w_index: 0xbeef,
- w_length: 18,
- };
- let want = [0x80, 0x06, 0x00, 0x01, 0xef, 0xbe, 0x012, 0x00];
-
- serde_test(&setup_packet, &want);
- }
-
- fn serde_test<T>(native: &T, raw: &[u8])
- where
- T: Default + PartialEq + core::fmt::Debug,
- {
- ser_test(native, raw);
- de_test(raw, native);
- }
-
- fn ser_test<T>(native: &T, raw: &[u8]) {
- let ptr = native as *const T as *const u8;
- let len = core::mem::size_of::<T>();
- assert_eq!(len, raw.len());
- let got_raw = unsafe { core::slice::from_raw_parts(ptr, len) };
- assert_eq!(got_raw, raw);
- }
-
- fn de_test<T>(raw: &[u8], native: &T)
- where
- T: Default + PartialEq + core::fmt::Debug,
- {
- let mut got_native: T = Default::default();
- let ptr = &mut got_native as *mut T as *mut u8;
- let len = core::mem::size_of::<T>();
- assert_eq!(raw.len(), len);
- let dbslice = unsafe { core::slice::from_raw_parts_mut(ptr, len) };
- for i in 0..len {
- dbslice[i] = raw[i];
- }
- assert_eq!(got_native, *native);
- }
-}