Работа с Generic HID Class на платформе Windows PC |
![]() |
Добавил(а) microsin |
В статье описывается реализация USB драйверов PC для Generic HID Class. На самом деле здесь имеется в виду не написание обычного драйвера как такового, а описание способа применения уже готового драйвера USB HID, встроенного в операционную систему Windows, с помощью специальной библиотеки Atmel USB HID DLL (AtUsbHid.dll). Текст статьи - почти дословный перевод даташита Atmel "USB PC Drivers Based on Generic HID Class" (doc7645.pdf). [Возможности библиотеки Atmel USB HID DLL] • Поддерживаются все операционные системы Windows, начиная от Windows 98® SE (все более поздние версии Windows также поддерживаются). Описанная в статье Atmel USB HID DLL (AtUsbHid.dll) является по сути простой оберткой над функциями HID.dll от Microsoft, написанной для облегчения их использования. Поэтому AtUsbHid.dll имеет некоторые ограничения по функционалу, но зато позволяет легко и просто писать программы для компьютера, осуществляющие обмен данными с устройством USB HID, а также отслеживать в программе события подключения и отключения устройства. К сожалению, исходный код AtUsbHid.dll недоступен. Если же Вы гуру в Windows API, то возможно Вам лучше использовать библиотеку HID.dll напрямую - в SDK от Microsoft есть примеры использования HID.dll. См. также обзор библиотек для работы с USB HID [2]. [1. Введение] Этот апноут описывает способ интеграции библиотеки USB HID DLL в Ваше приложение (программу для компьютера, ПО хоста USB). Предоставленные примеры основаны на компиляторах VC++ (имеется в составе Visual Studio), JAVA, однако среда программирования и язык программы имеет мало значения, можно использовать и любые другие компиляторы - VB (Visual Basic), Delphi, LabView, и т. п. Простые примеры кода демонстрируют разные варианты реализации программы. Далее, где в тексте статьи упоминается DLL, то имеется в виду AtUsbHid.dll. [2. Описание функций, встроенных в AtUsbHid.dll] Как указано в стандарте USB HID, приложение для класса Generic HID использует два репорта report IN и report OUT для приема и отправки данных соответственно (полезная нагрузка). Длина этих репортов назначается в коде firmware микроконтроллера (эта длина задана в дескрипторах устройства USB HID), и она автоматически определяется библиотекой AtUsbHid.dll в точном соответствии с настройками проекта firmware для Вашего микроконтроллера. Подробности см. в [1], там подробно описана структура firmware, его настройки, и как эти настройки менять. Имейте в виду, что библиотека DLL, описанная в этой статье, позволяет одновременно вести обмен данными с одним и только одним устройством USB Generic HID. Вы не можете обработать одновременный обмен данными с несколькими устройствами USB HID, используя эту DLL. Это сделано для упрощения использования библиотеки (хендл открытого устройства USB для простоты спрятан в коде библиотеки). Для одновременной работы с несколькими устройствами используйте другие библиотеки [2]. Рис. 2-1. Упрощенная структура приложения, построенного на AtUsbHid.dll. 2.1 findHidDevice Эта функция (возвращает значение типа BOOLEAN, т. е. true или false) позволяет найти в системе Windows подключенное устройство Generic HID по его идентификаторам vendor ID (VID) и product ID (PID). Эта функция также открывает хендл (handle) к этому USB-устройству, если оно подключено. Входные параметры: Выходное возвращаемое значение: Вызов GetLastError (в случае возврата FALSE) может вернуть: 2.2 closeDevice Эта функция прекращает обмен с устройством USB HID и закрывает хендл к нему. 2.3 writeData Функция (BOOLEAN) отправляет данные в устройство (OUT data). Максимальная длина блока данных, поддерживаемая этой функцией, может быть меньше или равна значению, полученному вызовом функции getOutputReportLength (см. секцию 2.9 этой статьи), т. е. не больше максимального размера пакета устройства USB HID. Если длина данных, которые надо передать, превышает это значение, то пользователь библиотеки (программист) должен отправить данные по частям в нескольких отдельных пакетах. То есть нужно вызвать функцию writeData несколько раз, по отдельности для каждого куска данных (каждый кусок не должен превышать максимального размера пакета устройства USB HID). Когда отправляемый размер данных меньше максимального размера пакета, то передается все равно блок данных максимального размера, просто в хвост данных дописываются нулевые данные (байты 0x00). Входной параметр: Выходное возвращаемое значение: 2.4 readData Эта функция (BOOLEAN) читает пакеты данных, отправленные устройством USB HID (пакеты IN data). Чтобы предотвратить потери данных, это функция должна вызваться постоянно (с использованием отдельного потока или таймера). Входной параметр: Выходное возвращаемое значение: 2.5 setFeature Дословно название этой функции можно перевести как "установить фичу", т. е. настроить какую-то возможность. На самом же деле функция setFeature (также возвращает BOOLEAN) позволяет пользователю отправить данные команды для управления устройством USB HID (например, запустить бутлоадер, запустить новую задачу и т. п.). Команды должны расшифровываться внутри firmware устройства USB HID, в соответствии с протоколом, полностью определенным пользователем (программистом). Данные, передаваемые функцией setFeature, передаются через конечную точку 0 (endpoint 0, управляющая конечная точка, она же default endpoint, конечная точка по умолчанию) через запрос SetReport. Подробности, если они Вам нужны, см. в [3]. Имейте в виду, что конечная точка 0 не относится к другим конечным точкам IN и OUT, которые применяются для простого обмена пакетами данных. Длина данных, которые можно передать вызовом функции setFeature, можно определить через вызов функции getFeatureReportLength (см. секцию 2.11 этой статьи). Длина передаваемых данных не должна превышать длины, которую возвратила getFeatureReportLength. Входной параметр: Выходное возвращаемое значение: 2.6 hidRegisterDeviceNotification Внимание: имейте в виду, что эта функция может использоваться только для проекта VC++. Эта функция оповещает ПО хоста USB (приложение для компьютера) о переподключениях устройства USB. Входной параметр: Выходное возвращаемое значение: 2.7 hidUnregisterDeviceNotification Внимание: имейте в виду, что эта функция может использоваться только для проекта VC++. Эта функция закрывает указанный хендл оповещения о переподключениях USB-устройства (device notification handle). Входной параметр: Выходное возвращаемое значение: 2.8 isMyDeviceNotification Внимание: имейте в виду, что эта функция может использоваться только для проекта VC++. Эта функция позволяет проверить, пришло или нет настроенное через hidRegisterDeviceNotification оповещение (подключено или отключено устройство) для используемого устройства USB HID. Входной параметр: Выходное возвращаемое значение: 2.9 getOutputReportLength Эта функция позволяет пользователю библиотеки получить длину OUT report (размер пакета, который отправляется от компьютера PC к устройству USB HID). Эта длина задается в firmware устройства USB HID (описана в дескрипторах). 2.10 getInputReportLength Эта функция позволяет пользователю библиотеки получить длину IN report (размер пакета, который отправляется от устройства USB HID к компьютеру PC). Эта длина задается в firmware устройства USB HID (описана в дескрипторах). 2.11 getFeatureReportLength Эта функция позволяет пользователю библиотеки получить длину Feature report (пакет управления Control data packet, который оправляется от компьютера PC к устройству USB). Эта длина задается в firmware устройства USB (описана в дескрипторах). [3. PC demos - демонстрационные примеры программ ПО хоста USB] 3.1 VC++ demo Демонстрационная программа VC++ показывает, как загрузить AtUsbHid.dll в проект, и как использовать оповещения о переподключениях устройства USB (plug & play notification). 3.1.1 Загрузка DLL в приложении на Visual C++ Файл заголовка AtUsbHid.h предоставляет макросы, которые помогают загрузить и использовать функции, представленные в Atmel USB HID DLL. Когда Вы разрабатываете приложение, использующее DLL, то Вам нужно сделать следующее (это стандартная практика работы с функциями DLL): • Создать хендлер (handler) для DLL и сбросить его: HINSTANCE hLib = NULL; Как только все эти шаги выполнены без ошибок, DLL и её функции загружены в Ваше приложение и готовы к работе. Теперь Вы можете вызвать нужные функции с помощью макроса DYNCALL(DllFunction()). Когда приложение завершает свою работу, то неплохо освободить память, выгрузив DLL с помощью функции API FreeLibrary(hLib). Перед выгрузкой DLL из памяти Вы должны убедиться, что хендл устройства USB предварительно был закрыт (через вызов функции closeDevice). 3.1.2 Использование возможности автоматического подключения/отключения (Automatic Device Connection/Disconnection Feature) DLL предоставляет функции, которые позволяют пользователю детектировать события подключения и отключения устройства. Чтобы добиться этого, проделайте следующие действия: • Зарегистрируйте программно Ваше приложение, чтобы оно могло получать оповещения от операционной системы. Это делается следующим образом: 3.1.3 Чтение данных от устройства USB HID - использование readData Устройство USB HID может постоянно передавать от себя данные (например, клавиатурные нажатия или перемещения курсора мыши). Интересна возможность периодически читать данные с использованием таймера. Это позволит организовать опрос принимаемых данных вызовами функции readData. Чтобы добиться этого, сделайте следующее: • Добавьте функцию ON_WM_TIMER() в список событий приложения (Message Map). 3.1.4 Внешний вид программы (интерфейс пользователя) На рис. 3-1 приведен скриншот предоставленного демонстрационного приложения. Имейте в виду, что PID по умолчанию относится к специфическому demo (демки Atmel, которые имеют интерфейс Generic HID, могут не иметь одинаковые PID). Поэтому проверьте в приложении параметр PID (и на всякий случай и VID), чтобы он соответствовал тому, который используется в Вашем устройстве USB HID. Установленные VID/PID в устройстве USB можно узнать либо через Диспетчер Устройств Windows, либо через просмотр исходного кода firmware Вашего устройства USB (параметры VID и PID указаны в дескрипторах). Рис. 3-1. VC++ based demo Описание компонентов интерфейса GUI программы (рис. 3-1): • Поля ввода Vendor ID, Product ID используются для того, чтобы указать нужные значения VID/PID для подключения к нужному устройству USB HID. 3.1.5 DOS demo (консольное демонстрационное приложение VC++) Это демо предоставляет простой пример консольного приложения. В нем используются фиксированные значения VID/PID, поэтому при их изменении требуется перекомпиляция приложения. Перед запуском консольного приложения должно быть подключено устройство с загруженным Generic HID firmware. Рис. 3-2. DOS Interface (консольное приложение, запускаемое в среде cmd.exe) Внимание: консольное приложение может быть скомпилировано с использованием среды MinGw [4]. Командная строка для компиляции приложения: 3.2 JAVA demo Эта демка показывает, как интегрировать AtUsbHid.dll в проект на языке JAVA. Интерфейс между AtUsbHid.dll и JAVA осуществляется через пакет AtUsbHidJni.jar. 3.2.1 Интегрирование AtUsbHid.dll Чтобы встроить в приложение JAVA использование AtUsbHid.dll, выполните следующие простые шаги: • Добавьте следующий код в секцию импорта (import section) Вашего файла JAVA: Дополнительную информацию можете получить из HTML-документации, предоставленном в пакете DLL [5]. 3.2.2 Внешний вид программы (интерфейс пользователя) Исходный код GUI-интерфейса программы на JAVA находится в папке JNICodeForHIDDLL. На рис. 3.3 показан скриншот пользовательского интерфейса на JAVA. Рис. 3.3. Интерфейс пользователя программы, написанной на JAVA Как можно видеть, программа на JAVA имеет интерфейс полностью аналогичный интерфейсу программы на VC++. Чекбокс Auto-Connect используется, чтобы разрешить приложению автоматически детектировать подключение/отключение устройства. 3.2.3 DOS demo (консольное демонстрационное приложение JAVA) Это демо дает простой пример консольного приложения. Демо использует фиксированные значения VID/PID, и поэтому требуется перекомпиляция после изменения этих параметров в коде программы. Перед запуском консольного приложения должно быть подключено устройство с загруженным Generic HID firmware. Рис. 3-4. DOS Interface (консольное приложение JAVA) [4. Структура пакета AtUsbHid.dll] Когда Вы распакуете архив пакета DLL, то Вы увидите несколько папок, которые имеют следующее назначение: AtUsbHid - эта папка содержит бинарный файл AtUsbHid.dll и файл заголовка AtUsbHid.h. [Словарик] Здесь даны краткие описания некоторых терминов, встречающихся в статье - для упрощения понимания. Подробности и значения других терминов ищите в [3] или в Википедии. endpoint - конечная точка устройства USB. Обычно это аппаратный буфер, через который устройство USB может автоматически отправить (тогда это IN endpoint) или принять (тогда это OUT endpoint) данные. Устройство USB может иметь несколько конечных точек, параметры которых (размер в частности) описаны в дескрипторах устройства USB. Обычно в устройстве USB 3 конечные точки. Минимально возможное количество конечных точек - одна, поскольку в устройстве USB всегда должна быть и имеется конечная точка 0 (она же control endpoint, она же default endpoint). Эта конечная точка control endpoint всегда имеет номер 0 и очень важна, поскольку через нее хост USB получает через дескрипторы информацию об устройстве USB. [Ссылки] 1. AVR328: стандартная (generic) реализация устройства USB HID (USB Generic HID Implementation). |