From 1b01180e448ed8a4a15c3befdb0506649a5192f5 Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Wed, 15 Jul 2020 18:53:31 +0200 Subject: [PATCH 1/3] more didactic changes --- embedded-workshop-book/src/data-stage.md | 6 +++++- embedded-workshop-book/src/dma.md | 10 +++++++++- embedded-workshop-book/src/idle-state.md | 2 +- .../src/supporting-standard-requests.md | 6 ++++-- embedded-workshop-book/src/unknown-requests.md | 3 +-- embedded-workshop-book/src/updating-device-state.md | 2 +- 6 files changed, 21 insertions(+), 8 deletions(-) diff --git a/embedded-workshop-book/src/data-stage.md b/embedded-workshop-book/src/data-stage.md index 322ee24..38b67db 100644 --- a/embedded-workshop-book/src/data-stage.md +++ b/embedded-workshop-book/src/data-stage.md @@ -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. diff --git a/embedded-workshop-book/src/dma.md b/embedded-workshop-book/src/dma.md index 2efe4cf..fdeca13 100644 --- a/embedded-workshop-book/src/dma.md +++ b/embedded-workshop-book/src/dma.md @@ -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: diff --git a/embedded-workshop-book/src/idle-state.md b/embedded-workshop-book/src/idle-state.md index b4ba40c..963b9fe 100644 --- a/embedded-workshop-book/src/idle-state.md +++ b/embedded-workshop-book/src/idle-state.md @@ -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 diff --git a/embedded-workshop-book/src/supporting-standard-requests.md b/embedded-workshop-book/src/supporting-standard-requests.md index f3cc5bb..86380d8 100644 --- a/embedded-workshop-book/src/supporting-standard-requests.md +++ b/embedded-workshop-book/src/supporting-standard-requests.md @@ -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: diff --git a/embedded-workshop-book/src/unknown-requests.md b/embedded-workshop-book/src/unknown-requests.md index fbdecb8..a6d48d3 100644 --- a/embedded-workshop-book/src/unknown-requests.md +++ b/embedded-workshop-book/src/unknown-requests.md @@ -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`. \ No newline at end of file +✅ Use the `dk::usbd::ep0stall()` helper function to stall endpoint 0 in `usb-4.rs`. \ No newline at end of file diff --git a/embedded-workshop-book/src/updating-device-state.md b/embedded-workshop-book/src/updating-device-state.md index 29b69cb..a221bcc 100644 --- a/embedded-workshop-book/src/updating-device-state.md +++ b/embedded-workshop-book/src/updating-device-state.md @@ -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. From d71095251d8edb1f9d27be00efae8a43adffb9de Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Thu, 16 Jul 2020 12:41:02 +0200 Subject: [PATCH 2/3] add access denied error to troubleshooting --- embedded-workshop-book/src/SUMMARY.md | 1 + .../src/troubleshoot-usb-error-access-denied.md | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 embedded-workshop-book/src/troubleshoot-usb-error-access-denied.md diff --git a/embedded-workshop-book/src/SUMMARY.md b/embedded-workshop-book/src/SUMMARY.md index 31911bc..281be28 100644 --- a/embedded-workshop-book/src/SUMMARY.md +++ b/embedded-workshop-book/src/SUMMARY.md @@ -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) diff --git a/embedded-workshop-book/src/troubleshoot-usb-error-access-denied.md b/embedded-workshop-book/src/troubleshoot-usb-error-access-denied.md new file mode 100644 index 0000000..cbfb949 --- /dev/null +++ b/embedded-workshop-book/src/troubleshoot-usb-error-access-denied.md @@ -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. \ No newline at end of file From 0ea86f204e252bfceff6c442c30cc17a13ef0ba8 Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Thu, 16 Jul 2020 12:56:20 +0200 Subject: [PATCH 3/3] last batch of didactic changes --- .../src/advanced-next-steps.md | 25 ++++++++++++------- .../src/getting-device-configured.md | 7 ++++-- .../src/inspecting-descriptors.md | 8 ++++-- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/embedded-workshop-book/src/advanced-next-steps.md b/embedded-workshop-book/src/advanced-next-steps.md index 4dccdd5..f5a4fa4 100644 --- a/embedded-workshop-book/src/advanced-next-steps.md +++ b/embedded-workshop-book/src/advanced-next-steps.md @@ -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 diff --git a/embedded-workshop-book/src/getting-device-configured.md b/embedded-workshop-book/src/getting-device-configured.md index f93ac56..3de1585 100644 --- a/embedded-workshop-book/src/getting-device-configured.md +++ b/embedded-workshop-book/src/getting-device-configured.md @@ -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 diff --git a/embedded-workshop-book/src/inspecting-descriptors.md b/embedded-workshop-book/src/inspecting-descriptors.md index b894e2b..a26c839 100644 --- a/embedded-workshop-book/src/inspecting-descriptors.md +++ b/embedded-workshop-book/src/inspecting-descriptors.md @@ -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,