Как записать данные на устройство USB HID в Android только с одной конечной точкой ввода - PullRequest
0 голосов
/ 06 сентября 2018

У меня есть USB HID-устройство, с которым я хотел бы связаться. Я успешно делаю это в Windows с помощью библиотеки HidSharp (ссылка: https://github.com/treehopper-electronics/HIDSharp). Мое приложение для Windows разработано с использованием .NET Framework 4.5, C # и Visual Studio.

Теперь я хочу общаться с этим же USB HID устройством с планшета Android, а не с рабочего стола Windows. Я сталкиваюсь с некоторыми проблемами при этом. Когда устройство подключено к планшету, оно сообщает об одном интерфейсе с одной конечной точкой «чтения». Вот что мне сообщили:

Interface #0 
Class: Human Interaction Device (0x3)
Endpoint: #0
Address        : 0x81 (10000001)
Number         : 1
Direction      : Inbound (0x80)
Type           : Intrrupt (0x3)
Poll Interval  : 1
Max Packet Size: 64
Attributes     : 000000011

Как видите, он сообщает только об одной конечной точке, которая является входящей конечной точкой. Мне нужно иметь возможность выводить простые команды на это устройство, что я смог успешно сделать на Windows с помощью HidSharp.

HidSharp абстрагировал все в один «потоковый» объект, из которого вы могли бы читать и писать. При использовании API-интерфейсов Android не существует ни одного «потокового» объекта, а скорее существует 3 различных способа чтения / записи: массовая передача, передача управления и USB-запрос. Я пытался отправить данные, используя все 3, но, похоже, безуспешно.

Есть предложения, что делать? Есть ли причина, по которой я мог бы отправлять данные на это устройство в Windows, но, похоже, не могу сделать это с Android? Есть ли способ использовать одну конечную точку как для чтения, так и для записи? Есть ли что-то, чего я просто упускаю и не понимаю?

Я использую Xamarin в качестве среды разработки (C #, Visual Studio 2017). Поскольку код всегда полезен, вот как я подключаюсь к устройству:

int VendorID = 0x04d8;
int ProductID = 0x2742;
UsbManager USB_Manager = null;
UsbDevice USB_Device = null;
UsbDeviceConnection DeviceConnection = null;
UsbInterface DeviceInterface = null;
UsbEndpoint OutputEndpoint = null;
UsbEndpoint InputEndpoint = null;

//Grab the Android USB manager and get a list of connected devices
var USB_Manager = MyMainActivity.ApplicationContext.GetSystemService(Android.Content.Context.UsbService) as Android.Hardware.Usb.UsbManager;
var attached_devices = USB_Manager.DeviceList;

//Find the device in the list of connected devices
foreach (var d in attached_devices.Keys)
{
    if (attached_devices[d].VendorId == VendorID && attached_devices[d].ProductId == ProductID)
    {
        USB_Device = attached_devices[d];
        break;
    }
}

//Assuming we found the correct device, let's set everything up
if (USB_Device != null)
{
    for (int j = 0; j < USB_Device.InterfaceCount; j++)
    {
        DeviceInterface = USB_Device.GetInterface(j);
        for (int i = 0; i < DeviceInterface.EndpointCount; i++)
        {
            var temp_ep = DeviceInterface.GetEndpoint(i);
            if (temp_ep.Type == Android.Hardware.Usb.UsbAddressing.XferInterrupt)
            {
                if (temp_ep.Direction == Android.Hardware.Usb.UsbAddressing.In)
                {
                    InputEndpoint = temp_ep;
                }

                if (temp_ep.Direction == Android.Hardware.Usb.UsbAddressing.Out)
                {
                    OutputEndpoint = temp_ep;
                }
            }
        }
    }

    //Request permission to communicate with this USB device
    UsbReceiver receiver = new UsbReceiver();
    PendingIntent pending_intent = PendingIntent.GetBroadcast(Game.Activity, 0, new Android.Content.Intent(UsbReceiver.ACTION_USB_PERMISSION), 0);
    IntentFilter intent_filter = new IntentFilter(UsbReceiver.ACTION_USB_PERMISSION);
    Game.Activity.RegisterReceiver(receiver, intent_filter);
    USB_Manager.RequestPermission(USB_Device, pending_intent);
    bool has_permission = USB_Manager.HasPermission(USB_Device);
    var device_connection = USB_Manager.OpenDevice(USB_Device);
    device_connection.ClaimInterface(DeviceInterface, true);
    DeviceConnection = device_connection;
}

Далее, вот как я пытаюсь прочитать с устройства:

//3 methods of attempting to read from the device

//Method 1:
byte[] inpt = new byte[64];
var request = new UsbRequest();
request.Initialize(DeviceConnection, InputEndpoint);
var byte_buffer = ByteBuffer.Allocate(64);
request.Queue(byte_buffer, 64);
DeviceConnection.RequestWait();
byte_buffer.Rewind();
for(int i = 0; i < 64; i++)
{
    inpt[i] = (byte) byte_buffer.Get();
}

//Method 2:
byte[] inpt = new byte[64];
DeviceConnection.BulkTransfer(InputEndpoint, inpt, inpt.Length, 1000);

//Method 3:
byte[] inpt = new byte[64];
DeviceConnection.ControlTransfer(UsbAddressing.In, 0, 0, 0, inpt, 64, 1000);

И, наконец, вот как я пытаюсь записать данные на это устройство:

//Method 1:
byte[] output_msg; //This variable is assigned elsewhere in the code
DeviceConnection.BulkTransfer(OutputEndpoint, output_msg, output_msg.Length, 30);

//Method 2:
byte[] output_msg; //This variable is assigned elsewhere in the code
DeviceConnection.ControlTransfer(UsbAddressing.Out, 0, 0, 0, output_msg, output_msg.Length, 1000);

//Method 3:
byte[] output_msg; //This variable is assigned elsewhere in the code
var write_request = new UsbRequest();
write_request.Initialize(DeviceConnection, OutputEndpoint);
var byte_buffer_write = ByteBuffer.Wrap(output_msg);
request.Queue(byte_buffer_write, output_msg.Length);
DeviceConnection.RequestWait();

«OutputEndpoint» обычно равен нулю, потому что нет конечной точки вывода, поэтому я часто заменяю «OutputEndpoint» на «InputEndpoint», но безуспешно.

Любая помощь будет принята с благодарностью! Спасибо !!!

1 Ответ

0 голосов
/ 27 ноября 2018

Вы имеете дело с HID-устройствами, что означает, что вы должны делать переводы прерываний.

В Android вы должны использовать UsbRequest для выполнения передачи прерываний (как это делает асинхронный неблокирующий ввод-вывод).

Конечные точки являются однонаправленными и могут использоваться как для входящих, так и для исходящих (но не одновременно)

Если конечная точка является входящей, то отправьте Urb, используя UsbRequest и очередь, как вы пытались ранее, но используя пустой буфер с ожидаемым bufferLength.

RequestWait вернет объект UsbRequest обратно после завершения.

Если usbRequest.getEndPoint (). GetDirection () является входящим, то ваша буферная переменная будет обновлена ​​с помощью буфера чтения с устройства. Если usbRequest.getEndpoint (). GetDirection () является исходящим, то вы должны передать свой буфер для записи данных на устройство

...