IR + USB HID = очередной пульт для компа (часть 4)


Краткое содержание предыдущих серий:
Захват и декодирование IR протокола
Теория USB HID
Код для STM32

В этой части я расскажу про программы-полезняшки. Куда уж без них.


HID descriptor tool

На сайте USB.org кроме текстов стандартов есть утилитка, позволяющая более-менее удобно составлять HID report descriptor.
Качаем ее по ссылке.

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


Потом можно все выгрузить в формат .h и вставить прямо в код.
Редактирование примитивное — вставить пункт, удалить пункт. Нет возможности даже поменять пункты местами. Но все равно, хоть какое-то подспорье. Не надо запоминать коды и биты. Иногда подглючивает с отступами. Лечится сохранением и открытием заново.

Одним из немаловажных преимуществ есть возможность проверить дескриптор на корректность. Отлавливаются всякие ошибки типа незакрытых коллекций или неуказанных обязательных пунктов.

Правила составления репорт дескрипторов достаточно просты:
  • должна быть COLLECTION (Application) с соответствующим USAGE перед ней
  • должен быть хотя бы один главный элемент INPUT или OUTPUT
  • для главных элементов должны быть обязательно указаны LOGICAL_MINIMUM, LOGICAL_MAXIMUM, REPORT_SIZE, REPORT_COUNT. Если что-то не указано, берется из предыдущего главного элемента.
  • У главного элемента может быть одно или несколько USAGES, они через главный элемент не перескакивают
  • USAGE_PAGE действует до следующего USAGE_PAGE и задает старший байт по умолчанию для последующих USAGES
  • USAGE можно указать полным кодом, вместе с USAGE_PAGE
Есть еще финт ушами с REPORT_ID, но мы его пока отложим.

Монитор USB порта

Нашел небольшую бесплатную утилитку USB монитора, позволяет проконтролировать вывод нашего устройства. Архив прицеплю, так как внятного сайта производителя не нашел.


Помогает быстро промониторить коды нажатых кнопок пульта.

Если заметили, то я втихаря перешел на трехбайтные коды, поскольку в комментариях к первому посту выяснилось, что есть еще расширенный NEC протокол, согласно которому адрес пульта — два байта. И эти коды мы передаем в неиспользуемых полях репорта.

Программа общения с HID-устройством

Попробуем быстро написать программу для PC, которая будет принимать данные от нашего HID-устройства. Написать попробуем на питоне, чтобы жизнь малиной не казалась.

Итак, качаем питон, PyQT4, библиотеку pywinusb, устанавливаем все согласно мануалу.

открываем QT4 Designer, быстренько накидываем такое диалоговое окошко:

Две кнопки, поле ввода и две надписи.

Сохраняем файл IRcmd1.ui
запускаем команду:
c:\Python33\Lib\site-packages\PyQt4\pyuic4.bat IRcmd1.ui -o IRcmd1.py


Эта команда сгенерирует файл IRcmd1.py с текстом на питоне, в котором описано наше окошко.

После этого создадим файл main.py

import os,sys

# подключаем библиотеку PyQt4
from PyQt4 import QtCore,QtGui

# подключаем наш скомпилированный диалог
from IRcmd1 import Ui_Dialog

# подключаем библиотеку pywinusb
import pywinusb.hid as hid

# Создаем класс для нашего главного окна
class Main(QtGui.QMainWindow):
        # конструктор класса
	def __init__(self):
		QtGui.QMainWindow.__init__(self)
		
                # ссылка на наше HID-устройство
		self.hid_device = 0
		
		# Запустим наш подключенный диалог
		self.ui=Ui_Dialog()
		self.ui.setupUi(self)

                # присоединим события нажатия кнопок к обработчикам
		self.ui.pbConnect.clicked.connect(self.IRconnect)
		self.ui.pbDisconnect.clicked.connect(self.IRdisconnect)
		
        # деструктор - надо закрыть наше HID-устройство
	def __del__(self):
		if (self.hid_device != 0):
			self.hid_device.close()
		
        # действие при нажатии кнопки connect
	def IRconnect(self):
		self.hid_device = 0
                # пробегаемся по всем устройствам
		for device in hid.find_all_hid_devices():
                        # если находим наш VID, то считаем что это наше устройство
			if (device.vendor_id == 0x0483):
				self.hid_device = device
				break
                # если в прошлом цикле нашли устройство
		if (self.hid_device != 0):
                        # то откроем его 
			self.hid_device.open()
                        #если открылось
			if (self.hid_device.is_opened()):
                                # то подключаем обработчик приема сырых данных IRread
				self.hid_device.set_raw_data_handler(self.IRread)
                                # и меняем надпись на зеленую "connected"
				self.ui.lStatus.setText('<font color="green">connected</font>')

	def IRdisconnect(self):
                # Закрываем устройство
		if (self.hid_device != 0):
			self.hid_device.close()
                # И меняем надпись
		self.ui.lStatus.setText('<font color="red">disconnected</font>')
		
	def IRread(self, data):
                # Выводим принятые байты в терминал
		print(data[2], data[3], data[4])
                # если там не нулевой адрес
		if(data[3]!=0 or data[4]!=0):
                        # то выводим его в поле leButtonCode в шестнадцатеричном виде
			self.ui.leButtonCode.setText("{:02X} {:02X}{:02X}".format(data[2], data[3], data[4]))
			

def main():
        # создаем и запускаем приложение
	app = QtGui.QApplication(sys.argv)
	window=Main()
	window.show()
	sys.exit(app.exec_())
	

if __name__ == "__main__":
	main()


Все, запускаем:
c:\Python33\python.exe main.py




Пока что эта программка только отображает на экран, что пришло от пульта. В дальнейшем мы ее разовьем до конфигуратора нашего устройства, с возможностью задавать действия для каждой кнопки пульта.

Ну и питоновские файлы прилагаю.
  • +8
  • 26 ноября 2012, 23:17
  • steel_ne
  • 2
Файлы в топике: Usb Monitor Setup.zip, IR_python.zip

Комментарии (15)

RSS свернуть / развернуть
лучше бы на нормальном с++ показал работу с хид
0
плюсы не модно
0
плюсы понятно
0
да вас на баш цитировать можно =)
+1
а что, баш уже поддерживает событийные потоки? консоль рулит )
0
а чем оправдан питон тут? это же мулька для веба что-то вроде явы
0
Как раз в вебе он АФАЙК не особо популярен. Зато популярен для программирования на комп (причем не каждый с первого взгляда отличит прогу на питоне от проги на С++ — такой же exe, только на самом деле там чисто лоадер с вшитым кодом для питона), написания простеньких утилиток (прямо в виде скрипта на питоне) и в качестве встраиваемого скриптового движка.
0
дык это еще можно было лет 12 назад делать на перле
и для пхп что-то такое было
пхп+гтк
0
Если ты про ехе-лоадеры — то да, ничего особенного в этом нет. Но тем не менее они делают менее заметным тот факт, что программа написана на скриптовом языке.
Но в целом питон вполне популярен для десктопных приложений — он мощный и имеет хорошую базу библиотек. И вполне оправдан для таких утилиток — на питоне их куда проще и быстрее накатать, чем на том же С++.
0
И вполне оправдан для таких утилиток — на питоне их куда проще и быстрее накатать, чем на том же С++.

Ну кто больше к чему привык.
0
При такой разнице, как между питоном и С++ — надо быть гуру в С++ и ни разу не видеть питон, чтобы на плюсах проще накатать было…
0
по секрету. qBasic вполне поддерживал подобную «компиляцию»
0
Вполне с тобой согласен. А то каким то полиглотством начинает попахивать. А то так и жизни не хватит все языки выучить. Ценится тот кто знает один но в совершенстве, а не тот кто каждого по чуть.
0
вопрос автору по коду. я не шарю в питоне, но если в IRread придет пакет sizeof(data)<4 то сегфаулта не будет?
0
Будет ошибка Runtime error Index out of bounds. Согласен, надо проверять длину полученного массива.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.