реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Определить номер COM-порта, USB-COM, знаем VID и PID
toweroff
сообщение Aug 1 2016, 13:26
Сообщение #1


Гуру
******

Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514



Ситуация:
есть USB-COM устройство. Определить его можно (прочитав VID и PID всех подключенных к компьютеру USB устройств)
Также я могу определить все COM-порты компьютера
но что-то никак не соображу, как скрестить это дело

В общем нужно получить следующее - при подключении устройства (или при старте программы, когда устройство уже подключено) определить, что подключено именно оно, определить, какой номер порта выделен устройству, открыть порт и работать с ним.
При извлечении устройства освободить порт и ждать нового подключения
Go to the top of the page
 
+Quote Post
x893
сообщение Aug 1 2016, 14:08
Сообщение #2


Профессионал
*****

Группа: Свой
Сообщений: 1 333
Регистрация: 27-10-08
Из: Планета Земля
Пользователь №: 41 226



Это зависит от операционной системы, но в любоой из двух можно узнать всю информацию об устройстве (она хранится в системе) и перебором найти нужный VID/PID.
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Aug 1 2016, 14:31
Сообщение #3


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(toweroff @ Aug 1 2016, 16:26) *
В общем нужно получить следующее - при подключении устройства (или при старте программы, когда устройство уже подключено) определить, что подключено именно оно, определить, какой номер порта выделен устройству, открыть порт и работать с ним.
При извлечении устройства освободить порт и ждать нового подключения


Вот полный текст функции определения порта по VID и PID.
На вход даем VID, PID и пустой список строк.
На выходе получаем заполненный список с перечнем доступных портов и результат в виде индекса искомого порта в списке.

CODE
unit USB_COM_enumeration;

interface

uses Windows, Classes, SysUtils, JvSetupApi;

function EnumerateUsbCom(VID, PID: Integer; Ports: TStrings): Integer;

const
PortsGUID: TGUID = '{4D36E978-E325-11CE-BFC1-08002BE10318}'; // ports

implementation

function EnumerateUsbCom(VID, PID: Integer; Ports: TStrings): Integer;
var
GUID: TGUID;
PnPHandle: HDevInfo; // handle на базу данных драйверов, раздел ports
i, j: DWORD;
DeviceInfoData: SP_DEVINFO_DATA;
Err: Integer;
RequiredLength: DWORD;
DevicePath: string;
RegType: DWORD;
Name: string;
s: string;
DevPID: Word;
DevVID: Word;
RegKey: HKey;
begin
Ports.Clear;
Result := 0;
GUID := PortsGUID;

// получаем handle на базу данных портов присутствующих в системе
// win7 compat: с флагом DIGCF_DEVICEINTERFACE в некоторых компах с семеркой
// перечисляются только нативные ком-порты
PnPHandle := SetupDiGetClassDevs(@GUID, nil, 0, DIGCF_PRESENT { or DIGCF_DEVICEINTERFACE } );

if PnPHandle = Pointer(INVALID_HANDLE_VALUE) then // не можем открыть базу
raise Exception.Create(SysErrorMessage(GetLastError));
try
i := 0; // первый порт
DeviceInfoData.cbSize := SizeOf(DeviceInfoData);
while SetupDiEnumDeviceInfo(PnPHandle, i, DeviceInfoData) do
// получаем последовательно порты, пока они есть.
begin
DevicePath := '';
Name := '';
// получаем размер строчки HardwareID
SetupDiGetDeviceRegistryProperty(PnPHandle, DeviceInfoData, SPDRP_HARDWAREID, RegType, nil, 0, RequiredLength);
Err := GetLastError;
if Err = ERROR_INSUFFICIENT_BUFFER then
// только эта ошибка должна возникнуть - все другое - что-то не так
begin
if Length(Name) < RequiredLength div SizeOf(Char) then
// если буфер маленький, то
SetLength(Name, RequiredLength div SizeOf(Char));
// устанавливаем размер буфера

if not SetupDiGetDeviceRegistryProperty(PnPHandle, DeviceInfoData, SPDRP_HARDWAREID, RegType, @Name[1], RequiredLength, RequiredLength) then
// получаем HardwareID
begin
inc(i); // если ошибка, то смотрим следущий порт
Continue;
end;
end
else
raise Exception.Create(SysErrorMessage(Err));

Name := UpperCase(Name);
// чтобы сравнивать строки, переводим все в заглавные буквы
if Copy(Name, 1, 3) = 'USB' then
// если первые три символа HardwareID = 'USB' - то это у нас виртуальный порт
begin
j := pos('VID_', Name) + 4; // ищем где у нас VID
s := '';
while Name[j] <> '&' do // получаем VID
begin
s := s + Name[j];
inc(j);
end;
DevVID := StrToInt('$' + s);
// OutputDebugString(PChar('vid = ' + IntToHex(DevVID, 4)));
j := pos('PID_', Name) + 4; // ищем PID
s := '';
while (Name[j] <> '&') and (Name[j] <> #0) do // получаем PID
begin
s := s + Name[j];
inc(j);
end;
DevPID := StrToInt('$' + s);
// OutputDebugString(PChar('pid = ' + IntToHex(DevPID, 4)));
if (DevVID = VID) and (DevPID = PID) then // если VID и PID - наши, то
begin
SetLength(DevicePath, 10);
// 10 символов на название ком-порта - хватит (максимальный COM999999 [последний символ = #0])
RegKey := SetupDiOpenDevRegKey(PnPHandle, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
// получаем Handle на раздел реестра экземпляра устройства
if RegKey = INVALID_HANDLE_VALUE then
begin
inc(i); // если ошибка - следущий порт
Continue;
end;
try
RequiredLength := 10 * SizeOf(Char);
if RegQueryValueEx(RegKey, 'PortName', nil, @RegType, @DevicePath[1], @RequiredLength) <> ERROR_SUCCESS then
// в PortName записано название порта (например - СОМ5)
begin
inc(i);
Continue;
end;
DevicePath := Copy(DevicePath, 1, RequiredLength div SizeOf(Char) - 1);
// в RequiredLength - размер полученной строки, минус 1 - последний ноль нам не нужен
Ports.Add(DevicePath); // добавлеяем имя порта
inc(Result);
// результат функции - количество портов для данного VID&PID
finally
RegCloseKey(RegKey); // Handle надо закрыть, даже в случае ошибки
end;
end;
end;
inc(i); // следущий порт
end;
finally
SetupDiDestroyDeviceInfoList(PnPHandle); // освобождаем занятую память.
end;
end;


end.
Go to the top of the page
 
+Quote Post
toweroff
сообщение Aug 1 2016, 16:02
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514



Цитата(AlexandrY @ Aug 1 2016, 17:31) *
Вот полный текст функции определения порта по VID и PID.

Спасибо!
буду его под CPP перелопачивать
Go to the top of the page
 
+Quote Post
arhiv6
сообщение Aug 1 2016, 18:06
Сообщение #5


Знающий
****

Группа: Свой
Сообщений: 633
Регистрация: 21-05-10
Из: Томск
Пользователь №: 57 423



Если пишите на C++ можете попробовать библиотеку Qt. Там в составе есть класс QSerialPortInfo - он позволяет получить список доступных в системе портов + кое-какую информацию о них (vid, pid, description): http://doc.qt.io/qt-5/qserialportinfo.html


--------------------
Go to the top of the page
 
+Quote Post
toweroff
сообщение Aug 2 2016, 11:13
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514



Цитата(AlexandrY @ Aug 1 2016, 17:31) *
Вот полный текст функции

у меня не срабатывает вот это место:
Код
        while (SetupDiEnumDeviceInfo(PnPHandle, i, &DeviceInfoData))

нет ни одного вхождения в цикл, хотя порт в системе точно есть

предваряет это все такая последовательность действий:
Код
const TGUID PortsGUID = {0x4D36E978, 0xE325, 0x11CE, {0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18}}; // ports
TGUID GUID;

    GUID = PortsGUID;
    PnPHandle = ::SetupDiGetClassDevs(&GUID, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE );

UPD
GetLastError() == ERROR_NO_MORE_ITEMS
Go to the top of the page
 
+Quote Post
toweroff
сообщение Aug 2 2016, 13:24
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514



убрал DIGCF_DEVICEINTERFACE, оставил только
Код
PnPHandle = ::SetupDiGetClassDevs(&GUID, NULL, NULL, DIGCF_PRESENT)

и заработало
Go to the top of the page
 
+Quote Post
AVR
сообщение Oct 29 2016, 18:16
Сообщение #8


фанат Linux'а
*****

Группа: Свой
Сообщений: 1 353
Регистрация: 23-10-05
Из: SPB.RU
Пользователь №: 10 008



Цитата(arhiv6 @ Aug 1 2016, 21:06) *
Если пишите на C++ можете попробовать библиотеку Qt. Там в составе есть класс QSerialPortInfo - он позволяет получить список доступных в системе портов + кое-какую информацию о них (vid, pid, description): http://doc.qt.io/qt-5/qserialportinfo.html
Это vendorIdentifier/productIdentifier? Не знал что такое есть...
А description что пишет? Интересует, можно ли использовать чужой VID/PID но засовывать свой description?


--------------------
Go to the top of the page
 
+Quote Post
rudy_b
сообщение Oct 31 2016, 05:08
Сообщение #9


Знающий
****

Группа: Свой
Сообщений: 888
Регистрация: 25-09-08
Из: Питер
Пользователь №: 40 458



Самые интересные танцы начинаются когда к компу подключено несколько одинаковых устройств USB.
Go to the top of the page
 
+Quote Post
toweroff
сообщение Oct 31 2016, 07:30
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514



Цитата(rudy_b @ Oct 31 2016, 08:08) *
Самые интересные танцы начинаются когда к компу подключено несколько одинаковых устройств USB.

попробовал открыть - не получилось - берем следующий в списке
а вот когда встает задача "схватить" некий конкретный девайс - вот тут да... только в какой-то последовательности подключать одинаковые устройства и ждать события подключения
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 28th July 2025 - 10:37
Рейтинг@Mail.ru


Страница сгенерированна за 0.0155 секунд с 7
ELECTRONIX ©2004-2016