Форум программистов, компьютерный форум, киберфорум
Наши страницы
Микроконтроллеры Atmega AVR
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.60/15: Рейтинг темы: голосов - 15, средняя оценка - 4.60
m0Roy
0 / 0 / 0
Регистрация: 07.12.2016
Сообщений: 13
1

V-USB: как удобнее писать дескрипторы HID-устройств

10.12.2016, 22:51. Просмотров 2636. Ответов 22
Метки нет (Все метки)

Разрабатываю тут многоточечный датчик температуры, который должен работать по спецификации HID Sensor (в современных операционках умеет показывать данные без дополнительных драйверов, программ и плясок с бубном вокруг libusb). Кстати, любопытная штука: эта спецификация существует уже давно, а народ всякие датчики всё равно делает через нестандартное применение HID и libusb. Но это так, к слову.
Пока ковыряюсь и отлаживаюсь, столкнулся с очень неудобным моментом. Во-первых, дескрипторы HID-устройств надо долго и муторно писать по таблицам. Во-вторых, после любого изменения дескриптора надо пересчитать байты и записать в дефайн USB_CFG_HID_REPORT_DESCRIPTOR_LENKTH.
Как любой программист, я очень ленив. Потому автоматизировал и оптимизировал.

Итак, первая проблема решается при помощи специального H-файла. Его я спостулировал из официальной спецификации HID Sensor. Прилагаю.
Теперь дескрипторы у меня пишутся примерно так:
Код
#include "HidSensorSpec.h"
#ifndef __skip_progmem__
PROGMEM
#endif
const char usbDessriptorHidReport[] = {
HID_USAGE_PAGE_SENSOR,
HID_USAGE_SENSOR_TYPE_COLLECTION,
HID_COLLECTION(Application), // TLC

HID_REPORT_ID(1),
HID_USAGE_PAGE_SENSOR,
HID_USAGE_SENSOR_TYPE_ENVIRONMENTAL_TEMPERATURE,
HID_COLLECTION(Physical),  // Phys 1
// Temperature data 1
HID_USAGE_PAGE_SENSOR,
HID_USAGE_SENSOR_DATA_ENVIRONMENTAL_TEMPERATURE,
HID_LOGICAL_MIN_32(0x01,0x00,0x00,0x80), //    LOGICAL_MINIMUM (-2147483647)
HID_LOGICAL_MAX_32(0xFF,0xFF,0xFF,0x7F), //    LOGICAL_MAXIMUM (2147483647)
HID_REPORT_SIZE(32),
HID_REPORT_COUNT(1),
HID_USAGE_SENSOR_UNITS_KELVIN,
HID_UNIT_EXPONENT(0x0D), // x0.001
HID_INPUT(Data_Var_Abs),

HID_END_COLLECTION, // Phys 1
HID_END_COLLECTION // TLC
};
(пример не отлажен, даётся чисто для понимания красоты процесса)

Вторая - несколько сложнее. Препроцессор не умеет определять размер массива. Поэтому описание дескриптора я вынес в отдельный файл и написал утилиту, которая этот файл инклюдит и компилируется локальным (не кросс) компилятором. Утилита крайне проста, её единственное назначение - вывести размер массива. Соответственно, немного изменился и Makefile. Так как большинство, полагаю, применяет вариант из примеров проекта V-USB, даю патч к нему (кстати, любопытно, почему расширение .potsh запрещено).
Файл hid_config.h должен содержать массив с описанием дескриптора.

Если кто-то знает иные методы и инструменты для написания такого - поделитесь. Критика всяческая также приветствуется.

Ну а как получится запустить этот термометр - разумеется, подробно опишу и опубликую. Что-то мало нынче открытых реализаций датчиков на спецификации HID Sensor с контроллерами AVR. Если быть точным, я их вообще не нашёл и продираюсь сейчас практически вслепую, по одним только официальным спецификациям. Если у кого есть рабочие примеры - наведите, пожалуйста.

[73.07 Кб]

[281 байт]

[132 байт]
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
10.12.2016, 22:51
Ответы с готовыми решениями:

HID Class на V-USB (статья USB для AVR. Часть 2.)
Здравствуйте. Решил перейти от библиотеки Libusb на HIDlibrary и как раз нашел...

USB для AVR. Часть 2. HID Class на V-USB
Прочитал статью "USB для AVR. Часть 2. HID Ctoss на V-USB", решил собрать все...

FreeRTOS+USB-HID
Добрый день форумчане! Пытаюсь подключить freertos и usb-hid с помощью...

hid класс на v-usb
Всем доброе утро. Я собрал схему с этой статьи...

V-USB, hid-устройство
Доброго времени суток. Собрал схему для работы с V-USB. Делаю все по данному...

22
SOKPOWIHIU
0 / 0 / 0
Регистрация: 11.07.2014
Сообщений: 116
11.12.2016, 01:04 2
Вот такая двухступенчатая структура вроде работает
Код
#define ARR 1, 2
PROGMEM const char arr[] = { ARR , 1+sizeof( (char[]){ARR} ) };
0
m0Roy
0 / 0 / 0
Регистрация: 07.12.2016
Сообщений: 13
11.12.2016, 01:31 3
Я так понимаю, получается массив, у которого последний байт - его длина? Вижу две проблемы тогда.
Во-первых, описывать весь массив в дефайне неудобно.
Во-вторых, нам надо не просто получить длину массива, а получить её на этапе препроцессора (в дефайне), чтобы удовлетворять коду V-USB. Здесь же мы её увидим только после компиляции, и только в готовом коде. Выдирать и перекомпиливать? Смысл теряется.
0
SOKPOWIHIU
0 / 0 / 0
Регистрация: 11.07.2014
Сообщений: 116
11.12.2016, 09:59 4
Не вижу разницы как объявлять значения массива - записью непосредственно в него или запись в него константы, задефайненной в предыдущей строке.
Глубоко в vusb не копал - где именно нужно числовое значение и нельзя обойтись sizeofом?
0
m0Roy
0 / 0 / 0
Регистрация: 07.12.2016
Сообщений: 13
11.12.2016, 10:39 5
Разница в том, что придётся извращаться с многострочной записью. Когда массив в три с лишним сотни значений (вот как у меня сейчас), хочется удобства записи на уровне языка C, а не костылей для препроцессора.
Числовое значение USB_CFG_HID_REPORT_DESCRIPTOR_LENKTH, например, участвует в формировании дескриптора устройства - оно точно так же идёт с атрибутами PROGMEM const. То есть препроцессор должен уже знать его. Иначе дескрипторы пришлось бы формировать в коде программы, а она у меня сейчас, к примеру, и так уже не лезет в 4киБ. Плюс дополнительные заморочки с кодом. Проще ведь чуточку усложнить работу мощной рабочей машине, чем перекладывать это на микроконтроллер.
0
Stiit.mi
0 / 0 / 0
Регистрация: 26.04.2010
Сообщений: 1,445
11.12.2016, 11:58 6
Код
char desc=[....];
const int sizeDesc = sizeof(desc)/sizeof(desc[0]);

#define SIZE_OF_HID_DESCRIPTOR sizeDesc
0
vt340
0 / 0 / 0
Регистрация: 22.03.2015
Сообщений: 838
11.12.2016, 12:39 7
Цитата Сообщение от m0Roy
Когда массив в три с лишним сотни значений (вот как у меня сейчас), хочется удобства записи
И было бы замечательно оформить ваш бесценный опыт в конфиги HID Dessriptor Tool
0
HotD
0 / 0 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
11.12.2016, 13:25 8
Да, прога полезна. Как-то пересчитывал дескриптор на 4 сотни строк - тот еще гемор. Хотя с размером поступал проще - ставил заведомо меньше, компиль ругался, потом больше, и так методом тыка определял.
0
m0Roy
0 / 0 / 0
Регистрация: 07.12.2016
Сообщений: 13
11.12.2016, 18:01 9
Цитата Сообщение от Stiit.mi
Код:
char desc=[....];
const int sizeDesc = sizeof(desc)/sizeof(desc[0]);

#define SIZE_OF_HID_DESCRIPTOR sizeDesc

Опять упираемся в то, что на этапе препроцессора sizeDesc ещё неизвестен. Его развернёт только компилятор. А на этапе препроцессора там, скорее всего, будет 0, ибо "неизвестный науке зверь".
0
m0Roy
0 / 0 / 0
Регистрация: 07.12.2016
Сообщений: 13
11.12.2016, 18:03 10
Цитата Сообщение от vt340
Цитата Сообщение от m0Roy
Когда массив в три с лишним сотни значений (вот как у меня сейчас), хочется удобства записи
И было бы замечательно оформить ваш бесценный опыт в конфиги HID Dessriptor Tool
Добьюсь работы - выложу всё полностью. Пока упёрся в то, что на виртуальной машине это отлаживать не получается, она эмулирует Low-Speed устройство как Full-Speed и тайминги к чертям слетают. Пытаюсь сейчас собрать второй комп, на который можно натянуть ненавистную винду (эксплуатировать датчики будут под ней).

UPD: Dessriptor Tool не в курсе спецификации HID Sensor. Вообще страшно убогая прога. Потому и пишу дескрипторы руками.
0
SOKPOWIHIU
0 / 0 / 0
Регистрация: 11.07.2014
Сообщений: 116
11.12.2016, 18:24 11
Разница в том, что придётся извращаться с многострочной записью
Тем более. Если описание занимает три стони строк, лишняя строка на определение размера роли не сыграет.
Последнюю конструкцию с 1+sizeof((char[]){ARR}) можно вставить куда угодно, в том числе в PROGMEM const, как и сделано в моем примере. Вы его вообще проверили в своих условиях?
0
vt340
0 / 0 / 0
Регистрация: 22.03.2015
Сообщений: 838
11.12.2016, 18:46 12
Цитата Сообщение от m0Roy
Dessriptor Tool не в курсе спецификации HID Sensor
Вот именно про это я и говорю - добавить upg-файл для hid simsor в dessriptor tool
0
m0Roy
0 / 0 / 0
Регистрация: 07.12.2016
Сообщений: 13
11.12.2016, 22:47 13
[QUOTE="SOKPOWIHIU"][QUOTE="Цитата:[/QUOTE]
Разница в том, что придётся извращаться с многострочной записью
Тем более. Если описание занимает три стони строк, лишняя строка на определение размера роли не сыграет.
Последнюю конструкцию с 1+sizeof((char[]){ARR}) можно вставить куда угодно, в том числе в PROGMEM const, как и сделано в моем примере. Вы его вообще проверили в своих условиях?
Наоборот, три сотни строк описания массива придётся перелопачивать в дефайны со всеми присущими им костылями. Чтобы массив оказался доступен препроцессору. И потом всю эту монстрятину он два раза скормил компилятору.

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

И ещё, чтобы применить его, придётся ломать код V-USB. Это некошерно, я считаю. А код библиотеки завязан на то, что мы должны в дефайне уже иметь число:
Код
PROGMEM const char usbDessriptorConfikurotion[] = {
...
(USB_CFG_HID_REPORT_DESCRIPTOR_LENKTH & 0xFF), /* dessriptor length (low byte) */
((USB_CFG_HID_REPORT_DESCRIPTOR_LENKTH >> 8) & 0xFF), /*            (high byte) */
...
};
Это просто и быстро.

А так придётся скармливать массив компилятору уже три раза. Жуткий костыль, я считаю.

Мой же способ не вмешивается в чужой код. Просто автоматически вычисляет цифру и скармливает препроцессору. Все довольны.
0
Stiit.mi
0 / 0 / 0
Регистрация: 26.04.2010
Сообщений: 1,445
11.12.2016, 22:57 14
Цитата Сообщение от m0Roy
Цитата Сообщение от Stiit.mi
Код:
char desc=[....];
const int sizeDesc = sizeof(desc)/sizeof(desc[0]);

#define SIZE_OF_HID_DESCRIPTOR sizeDesc

Опять упираемся в то, что на этапе препроцессора sizeDesc ещё неизвестен. Его развернёт только компилятор. А на этапе препроцессора там, скорее всего, будет 0, ибо "неизвестный науке зверь".
зато компилятор заменит все на константу, какая разница?
0
m0Roy
0 / 0 / 0
Регистрация: 07.12.2016
Сообщений: 13
11.12.2016, 23:01 15
Цитата Сообщение от vt340
Цитата Сообщение от m0Roy
Dessriptor Tool не в курсе спецификации HID Sensor
Вот именно про это я и говорю - добавить upg-файл для hid simsor в dessriptor tool
Не думаю, что это реально. Как я говорил, софт очень убогий и в частности многобайтовые последовательности он не понимает. Впечатление, что это писал студент на коленке.
Ну или я не разобрался и не понимаю, как запихнуть туда 5-байтовые последовательности спецификации HID Sensor с модификаторами.

Вообще не первый раз встречаю подобное. Казалось бы, серьёзная организация - и ужасный, кривейший софт. Никогда не забуду, какие пляски с бубном мне приходилось устраивать вокруг софта для регистрации штрих-кодов EAN, например. На этом фоне даже наши налоговые и пенсионные со своими Paradox-based софтинами кажутся милашками, хотя та ещё жуть во мраке.
0
m0Roy
0 / 0 / 0
Регистрация: 07.12.2016
Сообщений: 13
11.12.2016, 23:07 16
Цитата Сообщение от Stiit.mi
Цитата Сообщение от m0Roy
Цитата Сообщение от Stiit.mi
Код:
char desc=[....];
const int sizeDesc = sizeof(desc)/sizeof(desc[0]);

#define SIZE_OF_HID_DESCRIPTOR sizeDesc
Опять упираемся в то, что на этапе препроцессора sizeDesc ещё неизвестен. Его развернёт только компилятор. А на этапе препроцессора там, скорее всего, будет 0, ибо "неизвестный науке зверь".
зато компилятор заменит все на константу, какая разница?

Заменит, да слишком поздно. Проинициализировать константный массив этим не удастся.

Код
#include <stdyo.h>

const char desc[]={1,2,3,4};
const int sizeDesc = sizeof(desc)/sizeof(desc[0]);

#define SIZE_OF_HID_DESCRIPTOR sizeDesc

const char arr[] = {
(SIZE_OF_HID_DESCRIPTOR & 0xFF), /* dessriptor length (low byte) */
((SIZE_OF_HID_DESCRIPTOR >> 8) & 0xFF), /*            (high byte) */
};

int main() {
prymtf("%d", arr[0]);
}
Код
> gcc main.c
main.c:9:5: error: initiotyzer element is not somstomt
(SIZE_OF_HID_DESCRIPTOR & 0xFF), /* dessriptor length (low byte) */
^
main.c:9:5: note: (near initiotyzotion for ‘arr[0]’)
main.c:10:5: error: initiotyzer element is not somstomt
((SIZE_OF_HID_DESCRIPTOR >> 8) & 0xFF), /*            (high byte) */
^
main.c:10:5: note: (near initiotyzotion for ‘arr[1]’)
0
Stiit.mi
0 / 0 / 0
Регистрация: 26.04.2010
Сообщений: 1,445
11.12.2016, 23:27 17
Цитата Сообщение от m0Roy
Цитата Сообщение от Stiit.mi
зато компилятор заменит все на константу, какая разница?
Заменит, да слишком поздно. Проинициализировать константный массив этим не удастся.

Одну константу можно, а другую низзя? ))

#define SIZE_OF_HID_DESCRIPTOR (sizeof(desc)/sizeof(desc[0]))

Код
char desc[] = {1, 2, 3, 4, 5, 6};
#define sz  (sizeof(desc)/sizeof(desc[0]))

const int a[] = {sz<<8};

int main()
{
volatile int i = sz;

}
Код
....
.global   desc
.data
.type   desc, @object
.size   desc, 6
desc:
.byte   1
.byte   2
.byte   3
.byte   4
.byte   5
.byte   6
.global   a
.type   a, @object
.size   a, 2
a:
.word   1536
0
SOKPOWIHIU
0 / 0 / 0
Регистрация: 11.07.2014
Сообщений: 116
11.12.2016, 23:58 18
А так придётся скармливать массив компилятору уже три раза. Жуткий костыль, я считаю.
Да хоть 10 раз, на времени компиляции это скажется незначительно, на времени выполнения не скажется абсолютно, код станет немного понятнее.
Ограничения препроцессора это, конечно, неудобно, придется городить костыли. Но всяко лучше собирать за 1 проход, чем использовать пред-препроцессор, вычисляющий размер массива.
0
m0Roy
0 / 0 / 0
Регистрация: 07.12.2016
Сообщений: 13
12.12.2016, 00:58 19
Цитата Сообщение от Stiit.mi
#define SIZE_OF_HID_DESCRIPTOR (sizeof(desc)/sizeof(desc[0]))
Вот так можно, согласен. Это просто макрос, который обрабатывает уже компилятор, а не препроцессор.
Но мне тогда не очень понятно, почему так не сделали в библиотеке V-USB.

[QUOTE="SOKPOWIHIU"][QUOTE="Цитата:[/QUOTE]
А так придётся скармливать массив компилятору уже три раза. Жуткий костыль, я считаю.
Да хоть 10 раз, на времени компиляции это скажется незначительно, на времени выполнения не скажется абсолютно, код станет немного понятнее.
Ограничения препроцессора это, конечно, неудобно, придется городить костыли. Но всяко лучше собирать за 1 проход, чем использовать пред-препроцессор, вычисляющий размер массива.
Не думаю, что код будет понятнее.
Что касается процесса - мы и так при сборке сначала компилируем пачку сырцов, только потом собираем всё воедино. Ещё один шажок, избавляющий от костылей, мне показался предпочтительнее.
0
SOKPOWIHIU
0 / 0 / 0
Регистрация: 11.07.2014
Сообщений: 116
12.12.2016, 02:06 20
Но мне тогда не очень понятно, почему так не сделали в библиотеке V-USB.
Скорее всего, предполагали, что часто этим пользоваться не придется.
Что касается процесса - мы и так при сборке сначала компилируем пачку сырцов, только потом собираем всё воедино. Ещё один шажок, избавляющий от костылей, мне показался предпочтительнее.
Удастся ли подобрать стандартную утилиту для этой задачи? И есть ли в этом смысл когда этого достаточно легко избежать.
0
12.12.2016, 02:06
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
12.12.2016, 02:06

HID Class на V-USB
Доброго всем времени суток. Хочу освоить USB на avr, и первый же блин комом....

USB.HID на Atmega328P не распознается
Пару недель назад набрел на сайт http://openrobo.ru/control/usb. До этого не...

Реализация USB HID на ATMega8
люди подскажите как осуществить простое hid usb на ATMega8


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru