Форум программистов, компьютерный форум, киберфорум
Железо в Linux
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.71/7: Рейтинг темы: голосов - 7, средняя оценка - 4.71
Windows must die
666 / 866 / 103
Регистрация: 23.11.2021
Сообщений: 5,119
Записей в блоге: 18

А как, собственно, различить USB CDC устройства?

30.03.2023, 13:46. Показов 1977. Ответов 12

Студворк — интернет-сервис помощи студентам
Собственно, имею кучу железяк на разных STM32. Все они подключаются к компьютеру по USB. Для того, чтобы железяки работали без проблем и "из коробки" (а еще, чтобы имена в /dev/ были не уродскими ttyACMx, а ttyUSBx, кроме того, в мастдайках вроде бубунты, где запущена всякая лишняя дрянь, modemmanager может блокировать такое устройство после подключения, считая его модемом), я сделал на них эмуляцию "старых" PL2303 (это еще хорошо тем, что вендовозы к своим игровым приставкам мои железяки вряд ли смогут подключить, т.к. новые "драйвера" не поддерживают старых чипов).
Итак, проблема: при подключении к одному компьютеру более одной железяки непонятно, какому демону какой из /dev/ttyUSBx обслуживать. Может, есть какие-то текстовые поля в USB-дескрипторах, которые не повлияют на опознавание устройства, но помогут udev различить их и создать симлинки (скажем, /dev/CANx, /dev/lensx, /dev/motorsx и т.п.)? Приходится демону перебирать все устройства, отправлять запрос на выдачу справки и парсить первую строчку (где содержится название железки, ссылка на репу на гитхабе, дата и номер сборки).
В принципе, если на эмуляторе PL2303 сделать такое не выйдет, а на обычном CDC - получится, то я готов смириться с некоторыми неудобствами ради удобств в распознавании.
Возможно, @COKPOWEHEU сможет мне помочь (кажется, именно он когда-то на каком-то форуме об этом обмолвился). Блин, как тут юзера кастовать?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
30.03.2023, 13:46
Ответы с готовыми решениями:

Как отключить посылку AT команд при подключение CDC USB устройства (COM порта)?
При подключение к компьютеру моего CDC USB устройства на базе микроконтроллера (USB COM порт), Ubuntu начинает посылать AT команды и в...

STM32F103 CubeMX USB composite CDC + CDC (2xCDC)
Добрый день! Задача сделать на STM32F103 два виртуальных СОМ-порта. Сгенерировал проект через CubeMX, вставил в код эхо, все...

Обмен данными с несколькими USB CDC устройствами, подключёнными через USB HUB с внешним питанием
Добрый день уважаемые форумчане, форумчанки, форумчата и форумчатки. Столкнулся с такой проблемой, есть несколько одинаковых устройств,...

12
 Аватар для COKPOWEHEU
4084 / 2682 / 432
Регистрация: 09.09.2017
Сообщений: 11,933
31.03.2023, 12:55
Лучший ответ Сообщение было отмечено Eddy_Em как решение

Решение

Ну, я через udev делал. Строковое описание интерфейса вполне доступно и не влияет на выбор драйвера. В принципе, кратко это решение я уже когда-то описывал.
Code
1
2
SUBSYSTEM=="tty", ATTRS{manufacturer}=="COKPOWEHEU" ENV{CONNECTED_vusb}="yes"
ENV{CONNECTED_vusb}=="yes", SUBSYSTEM=="tty", ATTRS{interface}=="?*", PROGRAM="/bin/bash -c \"ls /dev | grep tty_$attr{interface}_ | wc -l \"", SYMLINK+="tty_$attr{interface}_%c"
На всякий случай: решал я не абстрактную задачу, а вполне конкретную: есть составное устройство из CDC для прошивки, CDC для отладки, CDC для ведения логов предыдущих двух. Плюс HID и Audio, но они ни с чем не конфликтуют. А вот разным CDC надо было дать осмысленные имена (точнее, симлинки), чтобы использовать в скриптах, makefile'ах и прочем. Привязку к Manufacturer string я делал чтобы этот рулез не пытался именовать чужие устройства. Имя переменной CONNECTED_vusb выбрано неудачно, лучше его заменить на что-то более осмысленное.
Цитата Сообщение от Eddy_Em Посмотреть сообщение
В принципе, если на эмуляторе PL2303 сделать такое не выйдет
С тем, чтобы прописать interface string проблемы вряд ли будут.
1
Windows must die
666 / 866 / 103
Регистрация: 23.11.2021
Сообщений: 5,119
Записей в блоге: 18
31.03.2023, 13:55  [ТС]
Спасибо!
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
interface string
А какой у этого дескриптора wValue?

У меня тоже есть идея на основе F072 сделать устройство "семь в одном": один CDC использовать для настройки и доступа к GPIO, а остальные - CAN, RS232, RS485, I2C и SPI.

Добавлено через 21 минуту
Правильно ли я понял, что если я в дескрипторе интерфейса выставлю iInterface, скажем, в 5, то отдать эту строку я должен по запросу с vWalue == 0x305? Ну и аналогично для других интерфейсов свой номер можно выставить?

Добавлено через 11 минут
Похоже, что да: то, что я воспринимал как одно число - вроде
C
1
2
3
4
5
6
7
#define DEVICE_DESCRIPTOR               0x100
#define CONFIGURATION_DESCRIPTOR        0x200
#define STRING_LANG_DESCRIPTOR          0x300
#define STRING_MAN_DESCRIPTOR           0x301
#define STRING_PROD_DESCRIPTOR          0x302
#define STRING_SN_DESCRIPTOR            0x303
#define DEVICE_QUALIFIER_DESCRIPTOR     0x600
на самом деле ведь состоит из двух байт, где старший - поле Descriptor Type, а младший - Descriptor Index.
Теперь-то понятно. Спасибо еще раз! Как будет время, попробую "на кошках".
0
Windows must die
666 / 866 / 103
Регистрация: 23.11.2021
Сообщений: 5,119
Записей в блоге: 18
10.04.2023, 21:42  [ТС]
COKPOWEHEU, странно. Пишу вот так:
C
1
2
3
4
5
6
7
8
9
10
11
...         /*Interface Descriptor */
        0x09, /* bLength: Interface Descriptor size */
        0x04, /* bDescriptorType: Interface */
        0x00, /* bInterfaceNumber: Number of Interface */
        0x00, /* bAlternateSetting: Alternate setting */
        0x03, /* bNumEndpoints: 3 endpoints used */
        0xff, /* bInterfaceClass */
        0x00, /* bInterfaceSubClass */
        0x00, /* bInterfaceProtocol */
        iINTERFACE_DESCR, /* iInterface: */
...
Объявляю дескрипторы:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#define LANG_US (uint16_t*)0x0409
 
typedef struct{
    uint8_t  bLength;
    uint8_t  bDescriptorType;
    uint16_t *bString;
} string_descriptor_t;
 
#define _USB_STRING_(name, str) string_descriptor_t name = {sizeof(name), STRING_DESCRIPTOR, str}
 
...
_USB_STRING_(LD, LANG_US);
_USB_STRING_(SD, u"0.0.1");
_USB_STRING_(MD, u"Prolific Technology Inc.");
_USB_STRING_(PD, u"USB-Serial Controller");
_USB_STRING_(ID, u"nitrogen_flooding");
static string_descriptor_t const *StringDescriptor[iDESCR_AMOUNT] = {
    [iLANGUAGE_DESCR] = &LD,
    [iMANUFACTURER_DESCR] = &MD,
    [iPRODUCT_DESCR] = &PD,
    [iSERIAL_DESCR] = &SD,
    [iINTERFACE_DESCR] = &ID
};
Покуда не выделял iInterface, оно отображало правильно iManufacturer, iProduct и iSerial. Как только добавил этот дескриптор - нет, не работает.

А на iInterface lsusb выдает:
Code
1
 iInterface              4 (error)
ЧЯДНТ?

Добавлено через 21 минуту
Ага, проблема отпала: я сам себя обманул, пытаясь сделать оптимально и красиво - ведь всю эту структуру нужно за один присест посылать, т.е. финт с указателем на строку не проходит. Сделал так:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#define LANG_US (uint16_t)0x0409
#define _USB_STRING_(name, str)                  \
static const struct name \
{                          \
        uint8_t  bLength;                       \
        uint8_t  bDescriptorType;               \
        uint16_t bString[(sizeof(str) - 2) / 2]; \
    \
} \
name = {sizeof(name), 0x03, str}
 
#define _USB_LANG_ID_(name, lng_id)     \
    \
static const struct name \
{         \
        uint8_t  bLength;         \
        uint8_t  bDescriptorType; \
        uint16_t bString;         \
    \
} \
name = {0x04, 0x03, lng_id}
 
...
 
_USB_LANG_ID_(LD, LANG_US);
_USB_STRING_(SD, u"0.0.1");
_USB_STRING_(MD, u"Prolific Technology Inc.");
_USB_STRING_(PD, u"USB-Serial Controller");
_USB_STRING_(ID, u"nitrogen_flooding");
static void const *StringDescriptor[iDESCR_AMOUNT] = {
    [iLANGUAGE_DESCR] = &LD,
    [iMANUFACTURER_DESCR] = &MD,
    [iPRODUCT_DESCR] = &PD,
    [iSERIAL_DESCR] = &SD,
    [iINTERFACE_DESCR] = &ID
};
И точно так же оно работает в свиче:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static inline void get_descriptor(){
    uint8_t descrtype = setup_packet->wValue >> 8,
            descridx = setup_packet->wValue & 0xff;
    switch(descrtype){
        case DEVICE_DESCRIPTOR:
            wr0(USB_DeviceDescriptor, sizeof(USB_DeviceDescriptor));
        break;
        case CONFIGURATION_DESCRIPTOR:
            wr0(USB_ConfigDescriptor, sizeof(USB_ConfigDescriptor));
        break;
        case STRING_DESCRIPTOR:
            if(descridx < iDESCR_AMOUNT) wr0((const uint8_t *)StringDescriptor[descridx], *((uint8_t*)StringDescriptor[descridx]));
            else EP_WriteIRQ(0, (uint8_t*)0, 0);
        break;
        case DEVICE_QUALIFIER_DESCRIPTOR:
            wr0(USB_DeviceQualifierDescriptor, USB_DeviceQualifierDescriptor[0]);
        break;
        default:
        break;
    }
}
Ну и lsusb показывает мне:
Code
1
      iInterface              4 nitrogen_flooding
Т.е. можно будет спокойно так и продолжать выдавать устройства за PL2303, но различать их по iInterface, как, собственно, ты и рекомендовал.

Спасибо!

Добавлено через 16 минут
Вот черт! Несмотря на наличие атрибута iInterface, в udev это поле не попадает!
Копаю дальше, что за проблемы.

Добавлено через 10 минут
Ах, черт подери! Устройство, у которого есть атрибуты idVendor/idProduct и устройство с атрибутом interface - разные! Т.е. не выйдет по VID/PID их так разделять ☹
Буду думать дальше.

Добавлено через 30 минут
Здесь нашел решение: на время прогона "родительского" устройства нужно сохранить VID/PID в переменную, а потом проверить:
Code
1
2
ACTION=="add", DRIVERS=="usb", ENV{USB_IDS}="%s{idVendor}:%s{idProduct}"
ACTION=="add", ENV{USB_IDS}=="067b:2303", ATTRS{interface}=="?*", SYMLINK+="$attr{interface}_%n"
Другой вариант — просто воспользоваться тем, что можно различить железяку по полу DRIVERS:
Code
1
DRIVERS=="pl2303", ACTION=="add", ATTRS{interface}=="?*", SYMLINK+="$attr{interface}_%n"
0
 Аватар для COKPOWEHEU
4084 / 2682 / 432
Регистрация: 09.09.2017
Сообщений: 11,933
10.04.2023, 21:50
Лучший ответ Сообщение было отмечено Eddy_Em как решение

Решение

Цитата Сообщение от Eddy_Em Посмотреть сообщение
Ах, черт подери! Устройство, у которого есть атрибуты idVendor/idProduct и устройство с атрибутом interface - разные! Т.е. не выйдет по VID/PID их так разделять ☹
Выйдет. Я ведь именно для этого ввожу переменную ENV{CONNECTED_vusb}="yes". Так и вам не нужно сохранять VID:PID, достаточно флага, что VID:PID совпадают с заданным.
1
Windows must die
666 / 866 / 103
Регистрация: 23.11.2021
Сообщений: 5,119
Записей в блоге: 18
10.04.2023, 22:49  [ТС]
COKPOWEHEU, ага, малость разобрался. Еще раз спасибо.
Написал об этом в ЖЖ.
0
 Аватар для COKPOWEHEU
4084 / 2682 / 432
Регистрация: 09.09.2017
Сообщений: 11,933
11.04.2023, 09:51
Цитата Сообщение от Eddy_Em Посмотреть сообщение
SYMLINK+="$attr{interface}_%n
С %n поосторожнее, у меня с ним какие-то проблемы были. То ли вообще все устройства пыталось посчитать, то ли наоборот не считало нужное. Я не от хорошей жизни туда скрипт вкорячил PROGRAM="/bin/bash -c "ls /dev | grep tty_$attr{interface}_ | wc -l "". Хотя, наверное, его можно было бы сделать и попроще... ну да ладно, не каждый час в usb что-то вставляют.
0
Windows must die
666 / 866 / 103
Регистрация: 23.11.2021
Сообщений: 5,119
Записей в блоге: 18
11.04.2023, 11:18  [ТС]
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
С %n поосторожнее, у меня с ним какие-то проблемы были.
Проверю еще на парочке одинаковых устройств. Но раньше проблем не видел (использую его и для флешек, чтобы создавать /media/fs-%n при подключении флешки и заносить соответствующую запись в fstab).
0
 Аватар для COKPOWEHEU
4084 / 2682 / 432
Регистрация: 09.09.2017
Сообщений: 11,933
11.04.2023, 13:42
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
С %n поосторожнее
Возможно, %n относится к устройству, а не к интерфейсу. То есть если в одном устройстве реализовано три CDC, то %n для них будет неправильно работать. Надо будет дома проверить.
0
Windows must die
666 / 866 / 103
Регистрация: 23.11.2021
Сообщений: 5,119
Записей в блоге: 18
11.04.2023, 14:37  [ТС]
[inline]man udev[/iniline] пишет, что "%n" — номер, выданный устройству ядром. Тут уж действительно непонятно, как в составном устройстве будут именоваться части. Если "%n" для всех них будет иметь одно и то же значение — хорошо, иначе (если каждый интерфейс, подпадающий под данный модуль ядра, будет нумероваться последовательно) придется и правда вот так выворачиваться…
0
 Аватар для COKPOWEHEU
4084 / 2682 / 432
Регистрация: 09.09.2017
Сообщений: 11,933
12.04.2023, 10:17
Проверил на ft4232, оказалось, что мой вариант работает хуже, чем %n. Но из-за чего-то же я от него отказался. Надо бы проверить на нескольких одинаковых устройствах или что-то в этом роде, но мне это сейчас неудобно.
0
Windows must die
666 / 866 / 103
Регистрация: 23.11.2021
Сообщений: 5,119
Записей в блоге: 18
12.04.2023, 10:59  [ТС]
Ну вот мне пока некогда, но как будет время, проверю на составном устройстве.
Обычные-то эмуляторы PL2303 у меня отлично нумеруются по очередности подключения, проверял вчера на преобразователях CAN-USB (заодно им тоже пофиксил прошивку, чтобы выдавали системе строковый дескриптор интерфейса).
Вообще, подозреваю, что ядро не проверяет ни iManufacturer, ни iProduct — можно было бы и туда что-нибудь записать…
0
 Аватар для COKPOWEHEU
4084 / 2682 / 432
Регистрация: 09.09.2017
Сообщений: 11,933
12.04.2023, 11:37
Цитата Сообщение от Eddy_Em Посмотреть сообщение
Вообще, подозреваю, что ядро не проверяет ни iManufacturer, ни iProduct — можно было бы и туда что-нибудь записать…
Насколько мне известно, не проверяет. Но может и не отображать. В lsusb оно берет строки из собственной базы данных, и только если его явно попросить через -v, таки запросит. Причем, кажется, только от рута.
Другое дело, много ли смысла туда что-то писать. Хотя я так делал для HID. Оставил VID:PID от vusb, а по manufacturer/product моя софтина его отличала от любых других vusb. Но то CustomHID, где без специфичной управляющей программы не обойтись, плюс само устройство достаточно простое.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
12.04.2023, 11:37
Помогаю со студенческими работами здесь

USB Audio + USB CDC на одной STM32F4
Итак, есть ЦАП с входом I2S, есть FMприёмник с выходом I2S, есть STM32F405 с двумя I2S. Задача сделать USB аудиокарту/FMприёмник в одном...

Два и более CDC устройства на AT90USB82 на одном компе
Привет всем. Сделал USB-HID устройства на AT90USB82 (аппаратная поддержка USB). Все заработало, и все отлично. Но мне нужно чтобы компьютер...

Переводить команды USB WIFI Адаптера через компьютер по USB-USB для устройства
name: как передавать сигнал от требующего установку драйверов USB WIFI Адаптера через компьютер по USB-USB папа-папа кабелю для устройства...

STM32F4Discovery USB CDC
Всем добрый день. Вопрос такой. Есть плата STM32F4Dyscovery, начал осваивать USB, с теорией интерфейса ознакомился.В Ref Man на данный МК...

USB CDC for CC1111
Существует ли в природе полноценный субж, а не то недоделанное создание, которое предлагается в архиве USB firmware omd examples .zip ?


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

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Новые блоги и статьи
My Business CRM
MaGz GoLd 16.04.2026
Всем привет, недавно возникла потребность создать CRM, для личных нужд. Собственно программа предоставляет из себя базу данных клиентов, в которой можно фиксировать звонки, стадии сделки, а также. . .
Знаешь почему 90% людей редко бывают счастливыми?
kumehtar 14.04.2026
Потому что они ждут. Ждут выходных, ждут отпуска, ждут удачного момента. . . а удачный момент так и не приходит.
Фиксация колонок в отчете СКД
Maks 14.04.2026
Фиксация колонок в СКД отчета типа Таблица. Задача: зафиксировать три левых колонки в отчете. Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка) / / . . .
Настройки VS Code
Loafer 13.04.2026
{ "cmake. configureOnOpen": false, "diffEditor. ignoreTrimWhitespace": true, "editor. guides. bracketPairs": "active", "extensions. ignoreRecommendations": true, . . .
Оптимизация кода на разграничение прав доступа к элементам формы
Maks 13.04.2026
Алгоритм из решения ниже реализован на нетиповом документе, разработанного в конфигурации КА2. Задачи, как таковой, поставлено не было, проделанное ниже исключительно моя инициатива. Было так:. . .
Контроль заполнения и очистка дат в зависимости от значения перечислений
Maks 12.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: реализовать контроль корректности заполнения дат назначения. . .
Архитектура слоя интернета для сервера-слоя.
Hrethgir 11.04.2026
В продолжение https:/ / www. cyberforum. ru/ blogs/ 223907/ 10860. html Знаешь что я подумал? Раз мы все источники пишем в голове ветки, то ничего не мешает добавить в голову такой источник, который сам. . .
Подстановка значения реквизита справочника в табличную часть документа
Maks 10.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача №1: при указании работ (справочник РаботыПоРемонтуСпецтехники),. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru