Getting it Configured
At this stage the device will be in the Address stage. It has been identified and enumerated by the host but cannot yet be used by host applications. The device must first move to the Configured state before the host can start, for example, HID communication or send non-standard requests over the control endpoint.
Windows and macOS will enumerate the device but not automatically configure it after enumeration. Here's what you should do to force the host to configure the device.
Linux and Mac OS
Nothing extra needs to be done if you're working on a Linux or Mac OS host. The host will automatically send a SET_CONFIGURATION request so proceed to the SET_CONFIGURATION section to see how to handle the request.
Windows
After getting the device enumerated and into the idle state, open the Zadig tool (covered in the setup instructions; see the top README) and use it to associate the nRF52840 USB device to the WinUSB driver. The nRF52840 will appear as a "unknown device" with a VID and PID that matches the ones defined in the common crate
Now modify the print-descs program to "open" the device -- this operation is commented out in the source code. With this modification print-descs will cause Windows to send a SET_CONFIGURATION request to configure the device. You'll need to run print-descs to test out the correct handling of the SET_CONFIGURATION request.
SET_CONFIGURATION
The SET_CONFIGURATION request is sent by the host to configure the device. Its configuration according to section 9.4.7. of the USB specification is:
bmrequesttypeis 0b00000000brequestis 9 (i.e. the SET_CONFIGURATION Request Code, see table 9-4 in the USB spec)wValuecontains the requested configuration valuewIndexandwLengthare 0, there is nowData
✅ To handle a SET_CONFIGURATION, do the following:
-
If the device is in the
Defaultstate, you should stall the endpoint because the operation is not permitted in that state. -
If the device is in the
Addressstate, then- if
wValueis 0 (Nonein theusbAPI) then stay in theAddressstate - if
wValueis non-zero and valid (was previously reported in a configuration descriptor) then move to theConfiguredstate - if
wValueis not valid then stall the endpoint
- if
-
If the device is in the
Configuredstate, then read the requested configuration value fromwValue- if
wValueis 0 (Nonein theusbAPI) then return to theAddressstate - if
wValueis non-zero and valid (was previously reported in a configuration descriptor) then move to theConfiguredstate with the new configuration value - if
wValueis not valid then stall the endpoint
- if
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.
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:
INFO:usb_5 -- USB: UsbReset @ 397.15576ms
INFO:usb_5 -- USB reset condition detected
INFO:usb_5 -- USB: UsbEp0Setup @ 470.00122ms
INFO:usb_5 -- EP0: GetDescriptor { descriptor: Device, length: 64 }
INFO:dk::usbd -- EP0IN: start 18B transfer
INFO:usb_5 -- USB: UsbEp0DataDone @ 470.306395ms
INFO:usb_5 -- EP0IN: transfer complete
INFO:dk::usbd -- EP0IN: transfer done
INFO:usb_5 -- USB: UsbReset @ 520.721433ms
INFO:usb_5 -- USB reset condition detected
INFO:usb_5 -- USB: UsbEp0Setup @ 593.292235ms
INFO:usb_5 -- EP0: SetAddress { address: Some(21) }
INFO:usb_5 -- USB: UsbEp0Setup @ 609.954832ms
INFO:usb_5 -- EP0: GetDescriptor { descriptor: Device, length: 18 }
INFO:dk::usbd -- EP0IN: start 18B transfer
INFO:usb_5 -- USB: UsbEp0DataDone @ 610.260008ms
INFO:usb_5 -- EP0IN: transfer complete
INFO:dk::usbd -- EP0IN: transfer done
INFO:usb_5 -- USB: UsbEp0Setup @ 610.443113ms
INFO:usb_5 -- EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 }
WARN:usb_5 -- EP0IN: stalled
INFO:usb_5 -- USB: UsbEp0Setup @ 610.809325ms
INFO:usb_5 -- EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 }
WARN:usb_5 -- EP0IN: stalled
INFO:usb_5 -- USB: UsbEp0Setup @ 611.175535ms
INFO:usb_5 -- EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 }
WARN:usb_5 -- EP0IN: stalled
INFO:usb_5 -- USB: UsbEp0Setup @ 611.511228ms
INFO:usb_5 -- EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 9 }
INFO:dk::usbd -- EP0IN: start 9B transfer
INFO:usb_5 -- USB: UsbEp0DataDone @ 611.846922ms
INFO:usb_5 -- EP0IN: transfer complete
INFO:dk::usbd -- EP0IN: transfer done
INFO:usb_5 -- USB: UsbEp0Setup @ 612.030027ms
INFO:usb_5 -- EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 18 }
INFO:dk::usbd -- EP0IN: start 18B transfer
INFO:usb_5 -- USB: UsbEp0DataDone @ 612.365721ms
INFO:usb_5 -- EP0IN: transfer complete
INFO:dk::usbd -- EP0IN: transfer done
INFO:usb_5 -- USB: UsbEp0Setup @ 612.640378ms
INFO:usb_5 -- EP0: SetConfiguration { value: Some(42) }
INFO:usb_5 -- entering the configured state
These logs are from a Linux host. You can find traces for other OSes in these files (they are in the advanced folder):
linux-configured.txt(same logs as the ones shown above)win-configured.txt, this file only contains the logs produced by runningprint-descsmacos-configured.txt
You can find a solution to this part of the exercise in src/bin/usb-5-solution.rs.