mirror of
https://github.com/ferrous-systems/embedded-trainings-2020.git
synced 2024-10-31 22:28:49 +00:00
re organise info
This commit is contained in:
parent
86f1fefcc2
commit
e7a872b120
1 changed files with 36 additions and 22 deletions
|
@ -7,24 +7,32 @@ In `usb-2.rs`, you will find a short description of each register above the vari
|
||||||
|
|
||||||
[nrf product spec]: https://infocenter.nordicsemi.com/pdf/nRF52840_PS_v1.1.pdf
|
[nrf product spec]: https://infocenter.nordicsemi.com/pdf/nRF52840_PS_v1.1.pdf
|
||||||
|
|
||||||
|
## Writing a parser for the data of this SETUP stage.
|
||||||
|
|
||||||
|
❗️ Keep the cable connected to the J3 port for the rest of the workshop
|
||||||
|
|
||||||
|
✅ Parse GET_DESCRIPTOR requests for DEVICE descriptors.
|
||||||
|
|
||||||
|
Modify `Request::parse()` in `advanced/common/usb/src/lib.rs` to recognize a GET_DESCRIPTOR request of type DEVICE so that the `get_descriptor_device` test passes. Note that the parser already handles SET_ADDRESS requests.
|
||||||
|
|
||||||
|
**Getting Started:**
|
||||||
|
|
||||||
|
**1. Writing code that can be tested**
|
||||||
|
|
||||||
When you need to write some `no_std` code that does not involve device-specific I/O you should consider writing it as a separate crate. This way, you can test it on your development machine (e.g. `x86_64`) using the standard `cargo test` functionality.
|
When you need to write some `no_std` code that does not involve device-specific I/O you should consider writing it as a separate crate. This way, you can test it on your development machine (e.g. `x86_64`) using the standard `cargo test` functionality.
|
||||||
|
|
||||||
So that's what we'll do here. In `advanced/common/usb/lib.rs` you'll find starter code for writing a `no_std` SETUP data parser. The starter code contains some unit tests; you can run them with `cargo test` (from within the `usb` folder) or you can use Rust Analyzer's "Test" button in VS code.
|
So that's what we'll do here. In `advanced/common/usb/lib.rs` you'll find starter code for writing a `no_std` SETUP data parser. The starter code contains some unit tests; you can run them with `cargo test` (from within the `usb` folder) or you can use Rust Analyzer's "Test" button in VS code.
|
||||||
|
|
||||||
The definition of `Descriptor::Configuration` as well as the associated test has been "commented out" using an `#[cfg(TODO)]` attribute because it is not handled by the firmware yet. Delete the `#[cfg(TODO)]` so that the unit tests can access it. This pattern is used for enum members and test functions throughout this workshop, so keep it in mind should you see it again.
|
The definition of `Descriptor::Configuration` as well as the associated test has been "commented out" using an `#[cfg(TODO)]` attribute because it is not handled by the firmware yet. Delete the `#[cfg(TODO)]` so that the unit tests can access it. This pattern is used for enum members and test functions throughout this workshop, so keep it in mind should you see it again.
|
||||||
|
|
||||||
✅ Parse the data of this SETUP stage.
|
**2. Description of GET_DESCRIPTOR request**
|
||||||
|
|
||||||
❗️ Keep the cable connected to the J3 port for the rest of the workshop
|
|
||||||
|
|
||||||
Start with the GET_DESCRIPTOR request, which is described in detail in section 9.4.3 of the [USB specification][usb_spec]. All the constants we'll be using are also described in Tables 9-3, 9-4 and 9-5 of the same document.
|
|
||||||
|
|
||||||
[usb_spec]: https://www.usb.org/document-library/usb-20-specification
|
|
||||||
|
|
||||||
We can recognize a GET_DESCRIPTOR request by the following properties:
|
We can recognize a GET_DESCRIPTOR request by the following properties:
|
||||||
- `bmRequestType` is **0b10000000**
|
- `bmRequestType` is **0b10000000**
|
||||||
- `bRequest` is **6** (i.e. the GET_DESCRIPTOR Request Code, defined in table 9-4 in the USB spec)
|
- `bRequest` is **6** (i.e. the GET_DESCRIPTOR Request Code, defined in table 9-4 in the USB spec)
|
||||||
|
|
||||||
|
|
||||||
|
**3. Description of DEVICE descriptor requests**
|
||||||
In this task, we only want to parse DEVICE descriptor requests. They have the following properties:
|
In this task, we only want to parse DEVICE descriptor requests. They have the following properties:
|
||||||
|
|
||||||
- the descriptor type is **1** (i.e. DEVICE, defined in table 9-5 of the USB spec)
|
- the descriptor type is **1** (i.e. DEVICE, defined in table 9-5 of the USB spec)
|
||||||
|
@ -32,29 +40,33 @@ In this task, we only want to parse DEVICE descriptor requests. They have the fo
|
||||||
- the wIndex is **0** for our purposes
|
- the wIndex is **0** for our purposes
|
||||||
- ❗️you need to fetch the descriptor type from the high byte of `wValue`, and the descriptor index from the the low byte of `wValue`
|
- ❗️you need to fetch the descriptor type from the high byte of `wValue`, and the descriptor index from the the low byte of `wValue`
|
||||||
|
|
||||||
|
Check section 9.4.3 of the [USB specification][usb_spec] for a very detailed description of the requests. All the constants we'll be using are also described in Tables 9-3, 9-4 and 9-5 of the same document.
|
||||||
|
|
||||||
|
**4. Remember that you can define binary literals by prefixing them with `0b`.**
|
||||||
|
|
||||||
|
**5. You can use bit shifts (`>>`) and casts (`as u8`) to get the high/low bytes of `wValue`.**
|
||||||
|
|
||||||
|
**6. Return `Err` if properties aren't met.**
|
||||||
|
|
||||||
|
|
||||||
You will also find this information in the `// TODO implement ...` comment in the `Request::parse()` function of `lib.rs` file.
|
You will also find this information in the `// TODO implement ...` comment in the `Request::parse()` function of `lib.rs` file.
|
||||||
> NOTE: If you'd like to learn more, take a look at Section 9.4.3 Get Descriptor of the USB specification.
|
> NOTE: If you'd like to learn more, take a look at Section 9.4.3 Get Descriptor of the USB specification.
|
||||||
|
|
||||||
To complete the task, proceed like this:
|
|
||||||
|
|
||||||
1. **Parse GET_DESCRIPTOR requests for DEVICE descriptors:**
|
|
||||||
Modify `Request::parse()` in `advanced/common/usb/src/lib.rs` to recognize a GET_DESCRIPTOR request of type DEVICE so that the `get_descriptor_device` test passes. Note that the parser already handles SET_ADDRESS requests.
|
|
||||||
|
|
||||||
- remember the GET_DESCRIPTOR fields described at the start of this section
|
|
||||||
- remember that you can define binary literals by prefixing them with `0b`
|
|
||||||
- you can use bit shifts (`>>`) and casts (`as u8`) to get the high/low bytes of `wValue`
|
|
||||||
|
|
||||||
See `advanced/common/usb/solution-get-descriptor-device.rs` for a solution.
|
See `advanced/common/usb/solution-get-descriptor-device.rs` for a solution.
|
||||||
|
|
||||||
2. **Read incoming request information and pass it to the parser:**
|
✅ Read incoming request information and pass it to the parser:
|
||||||
modify `usb-2.rs` to read `USBD` registers and parse the SETUP data when an EPSETUP event is received.
|
|
||||||
|
modify `usb-2.rs` to read `USBD` registers and parse the SETUP data when an EP0SETUP event is received.
|
||||||
|
|
||||||
|
**Getting Started:**
|
||||||
|
|
||||||
- for a mapping of register names to the `USBD` API, check the entry for `nrf52840_hal::target::usbd` in the documentation you've created using `cargo doc`
|
- for a mapping of register names to the `USBD` API, check the entry for `nrf52840_hal::target::usbd` in the documentation you've created using `cargo doc`
|
||||||
- remember that we've learned how to read registers in `events.rs`
|
- let bmrequesttype = usbd.bmrequesttype.read().bits() as u8;
|
||||||
|
- remember that we've learned how to read registers in `events.rs`.
|
||||||
- you will need to put together the higher and lower bits of `wlength`, `windex` and `wvalue` to get the whole field
|
- you will need to put together the higher and lower bits of `wlength`, `windex` and `wvalue` to get the whole field
|
||||||
- > Note: If you're using a Mac, you need to catch `SetAddress` requests returned by the parser as these are sent before the first GetDescriptor request. You can handle them by doing nothing.
|
- > Note: If you're using a Mac, you need to catch `SetAddress` requests returned by the parser as these are sent before the first GetDescriptor request. You can handle them by doing nothing.
|
||||||
|
|
||||||
3. when you have successfully received a GET_DESCRIPTOR request for a Device descriptor you are done. You should see an output like this:
|
1. when you have successfully received a GET_DESCRIPTOR request for a Device descriptor you are done. You should see an output like this:
|
||||||
|
|
||||||
``` console
|
``` console
|
||||||
INFO:usb_2 -- USB: UsbReset @ 438.842772ms
|
INFO:usb_2 -- USB: UsbReset @ 438.842772ms
|
||||||
|
@ -67,5 +79,7 @@ INFO:usb_2 -- Goal reached; move to the next section
|
||||||
|
|
||||||
`wlength` / `length` can vary depending on the OS, USB port (USB 2.0 vs USB 3.0) or the presence of a USB hub so you may see a different value.
|
`wlength` / `length` can vary depending on the OS, USB port (USB 2.0 vs USB 3.0) or the presence of a USB hub so you may see a different value.
|
||||||
|
|
||||||
You can find a solution to step 1. in `advanced/common/usb/solution-get-descriptor-device.rs`.
|
|
||||||
You can find a solution to step 2. in `advanced/firmware/src/bin/usb-2-solution.rs`.
|
You can find a solution to this step in `advanced/firmware/src/bin/usb-2-solution.rs`.
|
||||||
|
|
||||||
|
[usb_spec]: https://www.usb.org/document-library/usb-20-specification
|
||||||
|
|
Loading…
Reference in a new issue