mirror of
https://github.com/ferrous-systems/embedded-trainings-2020.git
synced 2024-10-31 22:28:49 +00:00
usb-3, sb-3-solution.rs, get-descriptor-configuration.rs: handle SET_ADDRESS
This commit is contained in:
parent
bffed51a77
commit
bb7ea8f685
3 changed files with 88 additions and 64 deletions
|
@ -1,13 +1,15 @@
|
|||
//! Some USB 2.0 data types
|
||||
// NOTE this is a solution to exercise `usb-2`
|
||||
// NOTE this is a solution to exercise `usb-3`
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![deny(warnings)]
|
||||
#![no_std]
|
||||
|
||||
#[cfg(TODO)]
|
||||
use core::num::NonZeroU8;
|
||||
|
||||
/// Device address assigned by the host; will be in the range 1..=127
|
||||
pub type Address = NonZeroU8;
|
||||
|
||||
/// Standard USB request
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum Request {
|
||||
|
@ -22,10 +24,9 @@ pub enum Request {
|
|||
|
||||
/// SET_ADDRESS
|
||||
// see section 9.4.6 of the USB specification
|
||||
#[cfg(TODO)]
|
||||
SetAddress {
|
||||
/// New device address, in the range `1..=127`
|
||||
address: Option<NonZeroU8>,
|
||||
address: Option<Address>,
|
||||
},
|
||||
|
||||
/// SET_CONFIGURATION
|
||||
|
@ -50,7 +51,8 @@ impl Request {
|
|||
windex: u16,
|
||||
wlength: u16,
|
||||
) -> Result<Self, ()> {
|
||||
// see table 9-4
|
||||
// see table 9-4 (USB specification)
|
||||
const SET_ADDRESS: u8 = 5;
|
||||
const GET_DESCRIPTOR: u8 = 6;
|
||||
|
||||
if bmrequesttype == 0b10000000 && brequest == GET_DESCRIPTOR {
|
||||
|
@ -75,6 +77,18 @@ impl Request {
|
|||
} else {
|
||||
Err(())
|
||||
}
|
||||
} else if bmrequesttype == 0b00000000 && brequest == SET_ADDRESS {
|
||||
// Set the device address for all future accesses.
|
||||
// (Needed to successfully init when conected to Apple devices)
|
||||
// Section 9.4.6 Set Address of the USB specification explains which values for wvalue,
|
||||
// windex and wlength are valid.
|
||||
if wvalue < 128 && windex == 0 && wlength == 0 {
|
||||
Ok(Request::SetAddress {
|
||||
address: NonZeroU8::new(wvalue as u8),
|
||||
})
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
|
@ -97,7 +111,6 @@ pub enum Descriptor {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[cfg(TODO)]
|
||||
use core::num::NonZeroU8;
|
||||
|
||||
use crate::{Descriptor, Request};
|
||||
|
@ -122,23 +135,6 @@ mod tests {
|
|||
// ^^^^
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_descriptor_configuration() {
|
||||
// OK: GET_DESCRIPTOR Configuration 0 [length=9]
|
||||
assert_eq!(
|
||||
Request::parse(0b1000_0000, 0x06, 0x02_00, 0, 9),
|
||||
Ok(Request::GetDescriptor {
|
||||
descriptor: Descriptor::Configuration { index: 0 },
|
||||
length: 9
|
||||
})
|
||||
);
|
||||
|
||||
// has language ID but shouldn't
|
||||
assert!(Request::parse(0b1000_0000, 0x06, 0x02_00, 1033, 9).is_err());
|
||||
// ^^^^
|
||||
}
|
||||
|
||||
#[cfg(TODO)]
|
||||
#[test]
|
||||
fn set_address() {
|
||||
// OK: SET_ADDRESS 16
|
||||
|
@ -168,6 +164,22 @@ mod tests {
|
|||
// ^
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_descriptor_configuration() {
|
||||
// OK: GET_DESCRIPTOR Configuration 0 [length=9]
|
||||
assert_eq!(
|
||||
Request::parse(0b1000_0000, 0x06, 0x02_00, 0, 9),
|
||||
Ok(Request::GetDescriptor {
|
||||
descriptor: Descriptor::Configuration { index: 0 },
|
||||
length: 9
|
||||
})
|
||||
);
|
||||
|
||||
// has language ID but shouldn't
|
||||
assert!(Request::parse(0b1000_0000, 0x06, 0x02_00, 1033, 9).is_err());
|
||||
// ^^^^
|
||||
}
|
||||
|
||||
#[cfg(TODO)]
|
||||
#[test]
|
||||
fn set_configuration() {
|
||||
|
|
|
@ -64,35 +64,41 @@ fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) {
|
|||
wvalue
|
||||
);
|
||||
|
||||
if let Ok(Request::GetDescriptor { descriptor, length }) =
|
||||
Request::parse(bmrequesttype, brequest, wvalue, windex, wlength)
|
||||
{
|
||||
match descriptor {
|
||||
Descriptor::Device => {
|
||||
log::info!("GET_DESCRIPTOR Device [length={}]", length);
|
||||
let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength)
|
||||
.expect("Error parsing request");
|
||||
match request {
|
||||
Request::GetDescriptor { descriptor, length }
|
||||
if descriptor == Descriptor::Device =>
|
||||
{
|
||||
log::info!("GET_DESCRIPTOR Device [length={}]", length);
|
||||
|
||||
let desc = usb2::device::Descriptor {
|
||||
bDeviceClass: 0,
|
||||
bDeviceProtocol: 0,
|
||||
bDeviceSubClass: 0,
|
||||
bMaxPacketSize0: usb2::device::bMaxPacketSize0::B64,
|
||||
bNumConfigurations: core::num::NonZeroU8::new(1).unwrap(),
|
||||
bcdDevice: 0x01_00, // 1.00
|
||||
iManufacturer: None,
|
||||
iProduct: None,
|
||||
iSerialNumber: None,
|
||||
idProduct: consts::PID,
|
||||
idVendor: consts::VID,
|
||||
};
|
||||
let desc_bytes = desc.bytes();
|
||||
let resp =
|
||||
&desc_bytes[..core::cmp::min(desc_bytes.len(), usize::from(length))];
|
||||
ep0in.start(&resp, usbd);
|
||||
}
|
||||
let desc = usb2::device::Descriptor {
|
||||
bDeviceClass: 0,
|
||||
bDeviceProtocol: 0,
|
||||
bDeviceSubClass: 0,
|
||||
bMaxPacketSize0: usb2::device::bMaxPacketSize0::B64,
|
||||
bNumConfigurations: core::num::NonZeroU8::new(1).unwrap(),
|
||||
bcdDevice: 0x01_00, // 1.00
|
||||
iManufacturer: None,
|
||||
iProduct: None,
|
||||
iSerialNumber: None,
|
||||
idProduct: consts::PID,
|
||||
idVendor: consts::VID,
|
||||
};
|
||||
let desc_bytes = desc.bytes();
|
||||
let resp =
|
||||
&desc_bytes[..core::cmp::min(desc_bytes.len(), usize::from(length))];
|
||||
ep0in.start(&resp, usbd);
|
||||
}
|
||||
Request::SetAddress { .. } => {
|
||||
// On Mac OS you'll get this request before the GET_DESCRIPTOR request so we
|
||||
// need to catch it here. We'll properly handle this request later
|
||||
// but for now it's OK to do nothing.
|
||||
},
|
||||
_ => {
|
||||
log::error!("unknown request (goal achieved if GET_DESCRIPTOR Device was handled)");
|
||||
dk::exit()
|
||||
}
|
||||
} else {
|
||||
log::error!("unknown request (goal achieved if GET_DESCRIPTOR Device was handled)");
|
||||
dk::exit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,22 +64,28 @@ fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) {
|
|||
wvalue
|
||||
);
|
||||
|
||||
if let Ok(Request::GetDescriptor { descriptor, length }) =
|
||||
Request::parse(bmrequesttype, brequest, wvalue, windex, wlength)
|
||||
{
|
||||
match descriptor {
|
||||
Descriptor::Device => {
|
||||
log::info!("GET_DESCRIPTOR Device [length={}]", length);
|
||||
let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength)
|
||||
.expect("Error parsing request");
|
||||
match request {
|
||||
Request::GetDescriptor { descriptor, length }
|
||||
if descriptor == Descriptor::Device =>
|
||||
{
|
||||
log::info!("GET_DESCRIPTOR Device [length={}]", length);
|
||||
|
||||
// FIXME send back a valid device descriptor, truncated to `length` bytes
|
||||
// let desc = usb2::device::Descriptor { .. };
|
||||
let resp = [];
|
||||
ep0in.start(&resp, usbd);
|
||||
}
|
||||
// TODO send back a valid device descriptor, truncated to `length` bytes
|
||||
// let desc = usb2::device::Descriptor { .. };
|
||||
let resp = [];
|
||||
ep0in.start(&resp, usbd);
|
||||
}
|
||||
Request::SetAddress { .. } => {
|
||||
// On Mac OS you'll get this request before the GET_DESCRIPTOR request so we
|
||||
// need to catch it here. We'll properly handle this request later
|
||||
// but for now it's OK to do nothing.
|
||||
},
|
||||
_ => {
|
||||
log::error!("unknown request (goal achieved if GET_DESCRIPTOR Device was handled)");
|
||||
dk::exit()
|
||||
}
|
||||
} else {
|
||||
log::error!("unknown request (goal achieved if GET_DESCRIPTOR Device was handled)");
|
||||
dk::exit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue