Всем доброго дня! Сегодня мы будем писать свою собственную программу для хоста, которая будет осуществлять прием и передачу данных от устройства, для которого мы уже реализовали класс USB Custom HID. А произошло это в двух предыдущих статьях, посвященных работе с USB HID - раз и два. В качестве среды разработки я буду использовать мой любимый Qt Creator, а для работы с USB предлагаю использовать специально для этого созданную библиотеку Libusb. Собственно, начать думаю стоит с ее установки.
1. Скачиваем архив с библиотекой с официального сайта Libusb.
2. Теперь необходимо скопировать ряд файлов, которые можно найти в распакованном архиве в папке bin. Файл libusb0.dll копируем в папку C:\Windows\System32, а файл libusb0.sys - в C:\Windows\System32\drivers. На этом операции с файловой системой заканчиваются и мы переходим к шагу 3.
3. На каждое устройство, которое планируется использовать необходимо установить так называемый фильтр. Делается это следующим образом. Все в той же папке bin находим файл install-filter-win.exe и запускаем. В появившемся окне выбираем Install a device filter и нажимаем Next. Сразу же открывается новое окно, в котором мы видим список подключенных устройств. Нам необходимо найти наш девайс и выбрать именно его:
Жмем на Install и все - фильтр успешно установлен 👍
4. Создаем где-нибудь директорию для хранения файлов библиотеки - я к примеру создал папку прямо на диске C:/ и назвал ее вполне тривиально - libusb. В эту папку из скачанного архива переносим папки include и lib.
С установкой библиотеки на этом заканчиваем и переходим к созданию нового проекта в Qt Creator. Библиотеки-то готовы к использованию, но их необходимо подключить непосредственно к нашему проекту, для этого в файле .pro добавляем строки следующего содержания:
LIBS += C:/libusb/lib/gcc/libusb.a INCLUDEPATH += C:/libusb/include/ DEPENDPATH += C:/libusb/include/ PRE_TARGETDEPS += C:/libusb/lib/gcc/libusb.a
А в файле MainWindow.h добавляем:
#include "C:/libusb/include/lusb0_usb.h"
Сразу же определим переменную:
usb_dev_handle *USB_Device = NULL;
Для работы с USB-устройством нам по сути требуется научиться делать три вещи - обеспечивать подключение/открытие устройства с нужными значениями PID/VID, принимать данные и передавать данные. Вот именно в такой последовательности и будем разбираться. Начинаем с того, что определяем все подключенные к шине устройства:
usb_init(); usb_find_busses(); usb_find_devices();
Перебираем все устройства в поисках того, которое нам нужно. А нужен нам девайс со значениями PID / VID - 0x0483 / 0x5750:
struct usb_bus *usbBus; struct usb_device *usbDevice; for (usbBus = usb_get_busses(); usbBus; usbBus = usbBus->next) { for (usbDevice = usbBus->devices; usbDevice; usbDevice = usbDevice->next) { if ((usbDevice->descriptor.idVendor == 0x0483) && (usbDevice->descriptor.idProduct == 0x5750)) { USB_Device = usb_open(usbDevice); } } }
Открыв устройство выполняем настройку:
usb_set_configuration(dev, 1); usb_claim_interface(dev, 0);
Для примера делаем все максимально просто, в реальном проекте как минимум стоит проверить, какой код возвращают все эти функции, для того, чтобы детектировать возможные ошибки при подключении устройства. В качестве теста при приеме и передаче данных мы как раз-таки произведем анализ на ошибки и выведем их код.
А тем временем переходим к приему данных, делается это очень просто:
int ret=0; char usbData[64]; ret = usb_bulk_read(USB_Device, 0x81, usbData, 4, 2000); if (ret < 0) { qDebug() << "No received data!" << ret; } else { qDebug() << "Received data" << usbData; }
Все сводится к вызову одной функции, и ее аргументы:
- объект USB_Device
- 0x81 - это адрес конечной точки нашего устройства (помните, мы определяли все это при создании дескрипторов)
- usbData - массив для сохранения принятых данных
- количество принимаемых байт
- таймаут
С приемом и инициализацией разобрались, на очереди передача данных. Выглядит все это следующим образом:
usbData[0] = 'S'; usbData[1] = 'n'; usbData[2] = 'd'; usbData[3] = '\0'; ret = usb_bulk_write(USB_Device, 0x01, usbData, 4, 500); if (ret < 0) { qDebug() << "No sended data!" << ret; } else { qDebug() << "Sended data" << usbData; }
Здесь все практически так же, как и в случае приема данных, только не упускаем из виду, что адрес конечной точки стал другим. Что абсолютно логично, ведь для приема и передачи у нас используются разные endpoint'ы.
Теперь можно без проблем написать свое маленькое приложение, которое будет, к примеру, по нажатию кнопки выполнять отправку данных. А наша статья на этом подходит к концу, даже больше того, подходит к концу "трехстатейный" мини-курс посвященный работе с USB HID ) Надеюсь информация окажется полезной и интересной, следите за обновлениями и новыми статьями, ждем вас на сайте MicroTechnics снова!