Como enviar uma transferência de controle USB (aplicativo UWP)
Este artigo demonstra:
- Como formatar um pacote de configuração USB
- Como iniciar uma transferência de controle USB a partir do seu aplicativo
APIs importantes
Um aplicativo que se comunica com um dispositivo USB geralmente envia várias solicitações de transferências de controle. Essas solicitações obtêm informações sobre o dispositivo e enviam comandos de controle que são definidos pelo fornecedor de hardware. Neste tópico, você aprenderá sobre transferências de controle, além de como formatá-las e enviá-las pelo aplicativo UWP.
Uma transferência de controle pode ler ou gravar informações de configuração ou executar funções específicas do dispositivo que o fornecedor de hardware define. Se a transferência executar uma operação de gravação, será uma transferência OUT; uma operação de leitura, é uma transferência IN. Independentemente da direção, um software, como seu aplicativo UWP, no sistema host sempre cria e inicia uma solicitação de transferência de controle. Às vezes, seu aplicativo pode iniciar transferências de controle que leem ou gravam dados. Nesse caso, talvez seja necessário enviar um buffer adicional.
Para acomodar todos os tipos de transferências de controle, o Windows.Devices.Usb disponibiliza estes métodos:
- SendControlOutTransferAsync (UsbSetupPacket)
- SendControlInTransferAsync (UsbSetupPacket)
- SendControlOutTransferAsync (UsbSetupPacket, IBuffer)
- SendControlInTransferAsync (UsbSetupPacket, IBuffer)
As transferências de controle USB também são usadas para obter dados do descritor ou enviar comandos padrão. No entanto, recomendamos que você envie esses tipos de solicitações chamando métodos específicos fornecidos por Windows.Devices.Usb, em vez de criar uma transferência de controle manualmente. Por exemplo, para selecionar uma configuração alternativa, chame SelectSettingAsync em vez de chamar SendControlOutTransferAsync (UsbSetupPacket).
Não é permitido fazer transferências de controle para determinados tipos de solicitações padrão. No entanto, se o dispositivo pertencer a uma classe de dispositivo compatível com Windows.Devices.Usb, você poderá enviar algumas solicitações conforme definido pela especificação de classe de dispositivo.
Antes de começar
- Você deve ter aberto o dispositivo e obtido o objeto UsbDevice. Leia Como se conectar a um dispositivo USB (aplicativo UWP).
- Obtenha informações sobre comandos de controle definidos pelo fornecedor. Esses comandos costumam ser definidos na especificação de hardware.
- Você pode ver o código completo mostrado neste tópico no exemplo CustomUsbDeviceAccess, Scenario2_ControlTransfer.cpp e Scenario2_ControlTransfer.h.
Etapa 1: Preencher o pacote de configuração
Neste tópico, enviaremos uma transferência de controle para um dispositivo que faz luzes piscarem em vários padrões. Para preencher o pacote de instalação, você deve saber que os comandos de controle são definidos pelo fornecedor do hardware:
- bmRequestType (D7): OUT
- bmRequestType (D4): Dispositivo
- bmRequestType (D6…D5): Fornecedor
- bRequest: 0x03
- wValue: 0-7 (qualquer número nesse intervalo, inclusivos)
- wIndex: 0
- wLength: 0
Para a transferência de controle, preencha um pacote de configuração que contenha todas as informações sobre a transferência; se a solicitação lê ou grava dados, o tipo de solicitação, e assim por diante. O formato do pacote de configuração é definido na especificação oficial do USB. Os valores dos campos de pacote de configuração são fornecidos pela especificação de hardware do dispositivo.
Crie um objeto UsbSetupPacket.
Preencha o objeto UsbSetupPacket definindo várias propriedades. Esta tabela mostra os campos de pacote de configuração definidos por USB e as propriedades que correspondem a esses campos:
Campos na Seção 9.3 Propriedade Descrição bmRequestType (D7) UsbControlRequestType.Direction Direção da solicitação. Se a solicitação é do host para o dispositivo (transferências de saída) ou do dispositivo para o host (transferências de entrada) bmRequestType (D4) UsbControlRequestType.Recipient Destinatário da solicitação. Todas as transferências de controle têm como destino o ponto de extremidade padrão. No entanto, o destinatário pode ser dispositivo, interface, ponto de extremidade ou outro. Para obter mais informações sobre dispositivo USB, interface, hierarquia de ponto de extremidade, consulte Layout do dispositivo. bmRequestType (D6…D5) UsbControlRequestType.ControlTransferType Categoria da solicitação. Padrão, classe ou fornecedor. bRequest UsbSetupPacket.Request Tipo de solicitação. Se a solicitação for padrão, como GET_DESCRIPTOR, ela será definida pela especificação USB. Caso contrário, poderá ser definida pelo fornecedor. wValue UsbSetupPacket.Value Depende do tipo de solicitação. wIndex UsbSetupPacket.Index Depende do tipo de solicitação. wLength UsbSetupPacket.Length Comprimento do pacote de dados enviado ou recebido nesta solicitação.
![OBSERVAÇÃO] Para determinadas transferências de controle, pode ser necessário fornecer bmRequestType como um byte bruto. Nesse caso, você pode definir o byte na propriedade UsbControlRequestType.AsByte.
Etapa 2: Iniciar uma operação assíncrona para enviar a transferência de controle
Para enviar transferências de controle, você deve ter um objeto UsbDevice. Sua transferência de controle pode ou não exigir pacotes de dados que seguem o pacote de configuração.
Para iniciar uma transferência de controle, chame uma substituição de SendControlInTransferAsync ou SendControlOutTransferAsync. Se a transferência usar pacotes de dados, chame SendControlOutTransferAsync (UsbSetupPacket, IBuffer), SendControlInTransferAsync (UsbSetupPacket, IBuffer). Esses métodos usam um parâmetro adicional que contém os dados para gravar ou recebe dados do dispositivo. Use o fluxograma para determinar qual substituição chamar.
A chamada inicia uma operação assíncrona. Quando a operação é concluída, a chamada retorna o objeto IAsyncOperation que contém os resultados da operação. Para uma transferência OUT (de saída), o objeto retorna o número de bytes enviados em uma transferência. Para uma transferência IN (de entrada), o objeto contém o buffer com os dados que foram lidos do dispositivo.
Exemplo de código de transferência de controle USB
Este código de exemplo mostra como enviar uma transferência de controle que altera o padrão de luzes piscando no dispositivo SuperMUTT. O pacote de configuração para a transferência contém um comando definido pelo fornecedor. O exemplo está em Scenario2_ControlTransfer.cpp.
async Task SetSuperMuttLedBlinkPatternAsync(Byte pattern)
{
UsbSetupPacket initSetupPacket = new UsbSetupPacket
{
RequestType = new UsbControlRequestType
{
Direction = UsbTransferDirection.Out,
Recipient = UsbControlRecipient.Device,
ControlTransferType = UsbControlTransferType.Vendor
},
Request = SuperMutt.VendorCommand.SetLedBlinkPattern,
Value = pattern,
Length = 0
};
UInt32 bytesTransferred = await EventHandlerForDevice.Current.Device.SendControlOutTransferAsync(initSetupPacket);
MainPage.Current.NotifyUser("The Led blink pattern is set to " + pattern.ToString(), NotifyType.StatusMessage);
}
Este código de exemplo mostra como enviar uma transferência de controle que altera o padrão de luzes piscando no dispositivo SuperMUTT. O pacote de configuração para a transferência contém um comando definido pelo fornecedor. O exemplo está em Scenario2_ControlTransfer.cpp.
async Task<IBuffer> SendVendorControlTransferInToDeviceRecipientAsync(Byte vendorCommand, UInt32 dataPacketLength)
{
// Data will be written to this buffer when we receive it
var buffer = new Windows.Storage.Streams.Buffer(dataPacketLength);
UsbSetupPacket initSetupPacket = new UsbSetupPacket
{
RequestType = new UsbControlRequestType
{
Direction = UsbTransferDirection.In,
Recipient = UsbControlRecipient.Device,
ControlTransferType = UsbControlTransferType.Vendor,
},
Request = vendorCommand,
Length = dataPacketLength
};
return await EventHandlerForDevice.Current.Device.SendControlInTransferAsync(initSetupPacket, buffer);
}