Merge pull request #64 from ferrous-systems/edit-book

last batch of didactic changes
This commit is contained in:
Jorge Aparicio 2020-07-16 11:15:53 +00:00 committed by GitHub
commit c906acceb8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 52 additions and 21 deletions

View file

@ -60,3 +60,4 @@
- [`cargo-build` fails to link](./troubleshoot-cargo-build.md)
- [`dongle-flash` is not working](./troubleshoot-dongle-flash.md)
- [Dongle USB functionality is not working](./troubleshoot-usb-dongle.md)
- [USB error: Access denied](./troubleshoot-usb-error-access-denied.md)

View file

@ -2,17 +2,24 @@
## String descriptors
If you'd like to continue working on your workshop project, we recommend adding String Descriptors support to the USB firmware.
If you'd like to continue working on your workshop project, we recommend adding String Descriptors support to the USB firmware. To do this, follow these steps:
- First, you'll want to read through section 9.6.7 of the USB spec, which covers string descriptors.
- Next, we suggest you change your *configuration* descriptor to use string descriptors. You'll want to change the `iConfiguration` field to a non-zero value. Note that this change will likely break enumeration.
- Now, re-run the program to see what new control requests you get from the host.
- You'll need to update the `usb` parser to handle the new requests.
- Then you can extend the logic of `ep0setup` to handle these new requests.
- Eventually, you'll need to send a string descriptor to the host. Note here that Rust string literals are UTF-8 encoded but the USB protocol uses UTF-**16** strings. You'll need to convert between these formats.
- After you have `iConfiguration` working you can start adding strings to other descriptors like the device descriptor e.g. its `iProduct` field.
✅ Read through section 9.6.7 of the USB spec, which covers string descriptors.
To verify that string descriptors are working in a cross-platform way you can extend the `print-descs` program to also print the device's string descriptors. See the [`read_string_descriptor`] method but note that this must be called on a "device handle", which is what the commented out `open` operation does.
✅ Change your *configuration* descriptor to use string descriptors. You'll want to change the `iConfiguration` field to a non-zero value. Note that this change will likely break enumeration.
✅ Re-run the program to see what new control requests you get from the host.
✅ Update the `usb` parser to handle the new requests.
✅ Extend the logic of `ep0setup` to handle these new requests.
Eventually, you'll need to send a string descriptor to the host. Note here that Rust string literals are UTF-8 encoded but the USB protocol uses UTF-**16** strings. You'll need to convert between these formats.
✅ If this works, add strings to other descriptors like the device descriptor e.g. its `iProduct` field.
✅ To verify that string descriptors are working in a cross-platform way, extend the `print-descs` program to also print the device's string descriptors. See the [`read_string_descriptor`] method but note that this must be called on a "device handle", which is what the commented out `open` operation does.
[`read_string_descriptor`]: https://docs.rs/rusb/0.6.2/rusb/struct.DeviceHandle.html#method.read_string_descriptor

View file

@ -1,6 +1,10 @@
# USB-3: DATA Stage
The next step is to respond to the GET_DESCRIPTOR request with a device descriptor. To do this we'll use the `dk::usb::Ep0In` abstraction -- we'll look into what the abstraction does in a future section; for now we'll just use it.
The next step is to respond to the GET_DESCRIPTOR request with a device descriptor.
✅ Open the file `src/bin/usb-3.rs`. Implement the response to the GET_DESCRIPTOR request. Use the following guide for assistance.
To do this we'll use the `dk::usb::Ep0In` abstraction -- we'll look into what the abstraction does in a future section; for now we'll just use it.
An instance of this abstraction is available in the `board` value (`#[init]` function). The first step is to make this `Ep0In` instance available to the `on_event` function.

View file

@ -1,6 +1,14 @@
# DMA
Let's zoom into the `Ep0In` abstraction used in `usb4.rs` next. You can use VSCode's "Go to Definition" to see the implementation of the `Ep0In.start()` method. What this method does is start a DMA transfer to send `bytes` to the host. The data (`bytes`) is first copied into an internal buffer and then the DMA is configured to move the data from that internal buffer to the USBD peripheral.
[What do endpoints have to do with dma]
[What is the task in this section?]
Let's zoom into the `Ep0In` abstraction used in `usb-4.rs` next.
✅ Open the file. Use VSCode's "Go to Definition" to see the implementation of the `Ep0In.start()` method.
What this method does is start a DMA transfer to send `bytes` to the host. The data (`bytes`) is first copied into an internal buffer and then the DMA is configured to move the data from that internal buffer to the USBD peripheral.
The signature of the `start()` method does *not* ensure that:

View file

@ -23,7 +23,7 @@ The SET_CONFIGURATION request is sent by the host to configure the device. Its c
- `wValue` contains the requested configuration value
- `wIndex` and `wLength` are 0, there is no `wData`
To handle a SET_CONFIGURATION, do the following:
To handle a SET_CONFIGURATION, do the following:
- If the device is in the `Default` state, you should stall the endpoint because the operation is not permitted in that state.
@ -38,12 +38,15 @@ To handle a SET_CONFIGURATION, do the following:
- if `wValue` is not valid then stall the endpoint
In all the cases where you did not stall the endpoint (by returning `Err`) you'll need to acknowledge the request by starting a STATUS stage.
This is done by writing 1 to the TASKS_EP0STATUS register.
✅ This is done by writing 1 to the TASKS_EP0STATUS register.
NOTE: On Windows, you may get a `GET_STATUS` request *before* the `SET_CONFIGURATION` request and although you *should* respond to it, stalling the `GET_STATUS` request seems sufficient to get the device to the `Configured` state.
## Expected output
✅ Run the progam and check the log output.
Once you are correctly handling the `SET_CONFIGURATION` request you should get logs like these:
``` console

View file

@ -55,7 +55,7 @@ You can find traces for other OSes in these files (they are in the `advanced` fo
- `macos-enumeration.txt`
- `win-enumeration.txt`
At this point you can double check that the enumeration works by running the [`usb-list` tool](./listing-usb-devices.md) while `usb-4.rs` is running.
✅ Double check that the enumeration works by running the [`usb-list` tool](./listing-usb-devices.md) while `usb-4.rs` is running.
``` console
Bus 001 Device 013: ID 1366:1015 <- J-Link on the nRF52840 Development Kit

View file

@ -1,9 +1,13 @@
# Inspecting the Descriptors
There's a tool in the `advanced/host/` folder called `print-descs`. You can run this tool to print all the descriptors reported by your application.
There's a tool in the `advanced/host/` folder called `print-descs`, it prints all the descriptors reported by your application.
✅ Run this tool.
Your output should look like this:
``` console
$ print-descs
$ cargo run
DeviceDescriptor {
bLength: 18,
bDescriptorType: 1,

View file

@ -1,13 +1,15 @@
# USB-4: Supporting more Standard Requests
After responding to the `GET_DESCRIPTOR Device` request the host will start sending different requests. The parser in `common/usb` will need to be updated to handle these requests:
After responding to the `GET_DESCRIPTOR Device` request the host will start sending different requests.
✅ Update the parser in `common/usb` so that it can handle the following requests:
1. `GET_DESCRIPTOR Configuration`, see the section on [Handling GET_DESCRIPTOR Configuration Requests](./get-descriptor-config.md#handling-get_descriptor-configuration-requests)
2. `SET_CONFIGURATION`, see the section on [SET_CONFIGURATION](./getting-device-configured.md#set_configuration) of this course material
The starter `common/usb` code contains unit tests for these other requests as well as extra `Request` variants for these requests. All of them have been commented out using a `#[cfg(TODO)]` attribute which you can remove once you need any new variant or new unit test.
For each green test, you can extend `usb-4.rs` to handle the new requests your parser is now able to recognize. **Make sure to read the next sections as you're working**, since they contain explanations about the concepts used and needed to complete this task.
For each green test, extend `usb-4.rs` to handle the new requests your parser is now able to recognize. **Make sure to read the next sections as you're working**, since they contain explanations about the concepts used and needed to complete this task.
If you need a reference, you can find solutions to parsing `GET_DESCRIPTOR Configuration` and `SET_CONFIGURATION` requests in the following files:

View file

@ -0,0 +1,3 @@
## USB error while taking control over USB device: Access denied (insufficient permissions)
If you get this Error when trying to run a different process, check if the old process is still running. If this is the case, end it. Try again.

View file

@ -5,5 +5,4 @@ You may come across host requests other than the ones listed in previous section
For this situation, the USB specification defines a device-side procedure for "stalling an endpoint", which amounts to the device telling the host that it doesn't support some request.
> This procedure should be used to deal with invalid requests, requests whose SETUP stage doesn't match any USB 2.0 standard request, and requests not supported by the device for instance the SET_DESCRIPTOR request is not mandatory.
You can use the `dk::usbd::ep0stall()` helper function to stall endpoint 0.
Your task is to do this in the right place in `usb-4.rs`.
✅ Use the `dk::usbd::ep0stall()` helper function to stall endpoint 0 in `usb-4.rs`.

View file

@ -4,7 +4,7 @@ At some point during the initialization you'll receive a `SET_ADDRESS` request t
The device state should be tracked using a resource so that it's preserved across multiple executions of the `USBD` event handler. The `usb2` crate has a `State` enum with the 3 possible USB states: `Default`, `Address` and `Configured`. You can use that enum or roll your own.
Start tracking and updating the device state to move your request handling forward:
Start tracking and updating the device state to move your request handling forward:
1. **Update the handling of the `USBRESET` event:** Instead of ignoring it, we now want it to change the state of the USB device. See section 9.1 USB Device States of the USB specification for details on what to do.