UsbLibrary — C# USB HID Library

Понадобилась мне как-то для своих поделок, а позже и по работе пригодилась, библиотека для работы с USB HID устройствами. После непродолжительных поисков в далеком 2010 году был найден проект USB HID Component for C#.

Но она явно была не доделана, имелись некоторые проблемы и не хватало поддержки Feature Report’ов. Также она не была предназначена или, скорее, не было примера, как эту библиотеку использовать на WPF, т.к. изначальный пример в статье дан для Windows Forms. Попробуем доработать… :)

Общее описание и существующие проблемы

Когда изучил эту библиотеку, она понравилась продуманностью и хорошими комментариями, на момент необходимости подобной библиотеки мне не хватало только реализации обмена с устройством посредством Feature Report’ов. Также была пара небольших косяков, к примеру, если подписаться на основное событие подключения указанного устройства (OnSpecifiedDeviceArrived), могли вызываться другие дополнительные события с null ссылкой без проверки (OnDataRecieved или OnDataSend), а также если не было подписки на OnDeviceArrived, то устройства вообще не проверяются! (не вызывается функция CheckDevicePresent(); ) Из дополнений для оригинальной библиотеки:

  • реализована возможность искать и подключаться устройству не только по паре PID\VID, но еще и дополнительно с проверкой Product String;
  • обновление на лету Product String с автопереподключением;
  • проверка возможности подключения к указанному устройству без поддержания связи (т.е. библиотека пробует подключиться к устройству с заданными параметрами, если успешно найдено и не занято — возвращает true и отключается от него, тем самым освобождая доступ для других приложений);
  • чтение не только длины всех поддерживаемых устройством Report’ов, но и строк Manufacturer и Product.

Но остался не решенный, как и в оригинальной библиотеке, так и в мною измененной, такой баг — категорически не работает поиск устройств, если собрать программу под x64 или All Platforms. Для корректной работы библиотеки необходимо, чтобы она была скомпилирована под x86, тогда прекрасно работает и на x86, и на x64 системах (проверялась временем на Windows 7, 8, 8.1, 10).

b9-1

Пример использования библиотеки

Пример взаимодействия библиотеки я сделал как для Windows Forms, так и для WPF, по структуре кода и взаимодействию с библиотекой они практически идентичны, отличается только часть, отвечающая за парсинг событий ОС от USB шины.

b9-2

Визуально же код оформлен в обоих проектах одинаково и показано минимально необходимое количество кода для работы с библиотекой:

Внешний вид также максимально похож, хотя это и не имеет особого значения:

Минимальный код для обоих проектов, чтобы открыть USB устройство и записать\прочитать что-либо:

UsbHidPort usb = new UsbHidPort();

usb.ProductId = 0x2301;
usb.VendorId = 0xC251;
usb.Open(true);

if(usb.Ready())
{
// тут исполняемый код
}

Но этот кусок кода будет работать, только если устройство уже подключено к ПК. Если оно не было подключено до запуска программы или его переподключили\отключили — программа ничего об этом не узнает и в первом случае просто не сможет работать с устройством, во втором же даже будет считать, что она всё еще подключена к нему! Для этого и необходимо парсить события ОС по части USB шины, чтобы оперативно реагировать на подключение\отключение любых USB устройств.

Для Windows Forms парсинг событий ОС выглядит крайне просто и переписывает оригинальные функции окна приложения. Просто вставляем в Main Windows этот код и ничего более делать не надо:

protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
usb.RegisterHandle(Handle);
}

protected override void WndProc(ref Message m)
{
usb.ParseMessages(ref m);
base.WndProc(ref m);
}

Для WPF чуть сложнее, тут нельзя просто так переопределить подобные функции, к примеру, WndProc тут просто-напросто нет (это Windows Forms функция), для реализации этого в WPF необходимо добавить в References ссылку на System.Windows.Forms:

b9-6

Добавить при загрузке приложения нашу функцию-обработчик событий:

private void Window_Loaded(object sender, RoutedEventArgs e)
{
HwndSource src = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
src.AddHook(new HwndSourceHook(WndProc));
// ....
// ваш код
}

А так выглядят переделанные функции парсинга событий ОС для WPF:

#region Обработка системных событий
 private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
 {
 Message m = new Message();
 m.HWnd = hwnd;
 m.Msg = msg;
 m.WParam = wParam;
 m.LParam = lParam;

 usb.ParseMessages(ref m);
 return IntPtr.Zero;
 }

 protected override void OnSourceInitialized(EventArgs e)
 {
 base.OnSourceInitialized(e);

 var handle = new WindowInteropHelper(this).Handle;

 usb.RegisterHandle(handle);
 }
 #endregion

Пример отправки Report’а

В качестве примера взаимодействия программы на ПК и устройства  разберем функцию команды условного протокола:

// определяем константой, сколько у нас байт в Report'е
// можно прочитать это и из устройства, но проверять его наличие до этого по usb.Ready()
// или же по возвращаемому значению - если = 0, то отменяем отправку
const byte USB_ReportLength = 127 + 1; // +1 - Report ID

// условная функция для применения настроек, которая описана уже в приложении, не библиотеке
public static bool ApplySettings()
{
// создаем массивы для отправки и приёма
byte[] ReportData = new byte[USB_ReportLength];
byte[] ReportAnswer = new byte[USB_ReportLength];
// флаг успешной отправки
bool Succsess = true;

// Условная команда в устройстве
// используется только первые 2 байта (не считая Report ID)
ReportData[0] = 0x82;
ReportData[1] = 0x90;

// устройство подключено?
if (usb.Ready())
{
// Report ID = 0, массив для отправки = ReportData, принимаемый массив = ReportAnswer
Succsess = usb.WriteFeatureReport(0x00, ReportData, ref ReportAnswer);

// далее можно обработать принятый массив (report)
// в принятом report'e 0й байт = Report ID
// после него уже идет по порядку сам ответный Report
if(ReportAnswer[1] != 0x82) Succsess = false;
}
else
{
Succsess = false;
}

return Succsess;
}

Итог и ссылки

Библиотека проверялась с различными программными реализациями USB HID устройств на разных архитектурах МК и проблем стабильности работы замечено не было. Проверенные библиотеки для МК:

Cсылка для скачивания библиотеки и двух простейших примеров — UsbLibrary-Example (по лицензии WTFPL ;) )

Реклама

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s