-
-
Notifications
You must be signed in to change notification settings - Fork 2
05. USB Address
The next packet to tackle is the address. This will require some state management, as the address can only be applied after the reception confirmation was sent.
The next step required of the device is to set the address of the device. For this the host sends the matching control request and expects a status message from the device, which is simply a transfer with length 0 (ZeroLengthPacket, ZLP).
The address is a bit different than other requests, as the device is only allowed to change the address once the status packet has been transmitted.
First we add the necessary types and variables to remember our last Setup to which the current control transaction belongs.
typedef struct {
USB_SETUP_PACKET Setup;
} USB_CONTROL_STATE;
static USB_CONTROL_STATE ControlState;
Next, in the USB_HandleSetup
we copy the new setup packet into the ControlState. If we receive a Setup packet, we have to abandon all prior communication and start with that packet.
static void USB_HandleSetup(USB_SETUP_PACKET *setup) {
USB_CopyMemory(setup, &ControlState.Setup, sizeof(USB_SETUP_PACKET));
...
}
The recipient of a control communication needs to send a zero-length status packet to confirm reception. As the recipient of the device descriptor request was the host, we did not care about the state - if it failed, the host would have to try again.
Now we need to send a confirmation though, as we are the ones receiving the data. This is done by sending a packet of length 0. We don't need to save anything, as this was already done before.
case 0x05: // Set Address
BTable[0].COUNT_TX = 0;
USB_SetEP(&USB->EP0R, USB_EP_TX_VALID, USB_EP_TX_VALID);
break;
To confirm reception, send TX_VALID
, to tell the host you need more time, send TX_NAK
. If you encountered an error processing the request, send TX_STALL
.
The address should only be set once the status packet is sent and the control request is completed. To do this we need to listen to the TX-complete handler and check our last active setup packet.
if (USB->EP0R & USB_EP_CTR_TX) {
// We just sent a control message
if(ControlState.Setup.Request == 0x05) {
USB->DADDR = USB_DADDR_EF | ControlState.Setup.Value;
}
USB_SetEP(&USB->EP0R, 0x00, USB_EP_CTR_TX);
}
Windows should take a while to enumerate the device. Breaking the code afterwards, USB_DADDR
should contain a number greater 0 in the first seven bits.
The device manager should change the entry to Unknown USB Device (Invalid Configuration Descriptor)
.