-
Здравствуйте. Изучаю PIC контроллеры для подключения своих устройств к ПК через USB интерфейс. Для начала зашил простенькую программу. Контроллер ждет передачи данных с ПК, получив байт информации, отвечает Hellow wold и горит секунду светодиодом. Система работает. В MikroC есть HID-терминал. Пытаюсь реализовать свой такой терминал, для дальнейшей разработки пользовательского ПО. В наборе JVC есть компоненты для работы с HID, а также инклуда hid.dll. Вот код:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
lvHidList: TListView;
lvHidParams: TListView;
edWrite: TEdit;
btnWrite: TButton;
btnRead: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
procedure lvHidListClick(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure btnWriteClick(Sender: TObject);
private
public
end;
var
Form1: TForm1;
implementation
uses
SetupAPI, HID;
var
HidHandle : THandle;
ToWrite : Integer;
procedure TForm1.Button1Click(Sender: TObject);
var
HidGuid : TGUID;
PnPHandle : HDevInfo;
DevIndex : DWORD;
Success : LongBool;
DevData : TSPDevInfoData;
DeviceInterfaceData : TSPDeviceInterfaceData;
BytesReturned : DWORD;
FunctionClassDeviceData : PSPDeviceInterfaceDetailData;
HidString : TListItem;
begin
lvHidList.Items.Clear;
lvHidParams.Items.Clear;
HidD_GetHidGuid(HidGuid);
PnPHandle:=SetupDiGetClassDevs(@HidGuid, nil, 0, DIGCF_PRESENT or DIGCF_DEVICEINTERFACE);
if PnPHandle=Pointer(INVALID_HANDLE_VALUE) then begin
ShowMessage('Error');
Exit;
end;
try
DevIndex:=0;
repeat
DeviceInterfaceData.cbSize:=SizeOf(TSPDeviceInterfaceData);
Success:=SetupDiEnumDeviceInterfaces(PnPHandle, nil, HidGuid, DevIndex, DeviceInterfaceData);
if Success then begin
DevData.cbSize:=SizeOf(DevData);
BytesReturned:=0;
SetupDiGetDeviceInterfaceDetail(PnPHandle, @DeviceInterfaceData, nil, 0, BytesReturned, @DevData);
if (BytesReturned<>0)and(GetLastError = ERROR_INSUFFICIENT_BUFFER) then begin
FunctionClassDeviceData:=AllocMem(BytesReturned);
FunctionClassDeviceData.cbSize:=5;
end;
if SetupDiGetDeviceInterfaceDetail(PnPHandle, @DeviceInterfaceData, FunctionClassDeviceData,
BytesReturned, BytesReturned, @DevData) then
begin
HidString:=lvHidList.Items.Add;
HidString.Caption:=StrPas(PChar(@FunctionClassDeviceData.DevicePath));
end;
FreeMem(FunctionClassDeviceData);
end;
Inc(DevIndex);
until not Success;
finally
SetupDiDestroyDeviceInfoList(PnPHandle);
end;
end;
procedure TForm1.lvHidListClick(Sender: TObject);
var
HidAttr : THIDDAttributes;
buf : array [0..254] of WideChar;
lvItem : TListItem;
begin
if HidHandle<>0 then
begin
CloseHandle(HidHandle);
HidHandle:=0;
end;
if lvHidList.ItemIndex = -1 then Exit;
lvHidParams.Items.Clear;
HidHandle:=CreateFile(PChar(lvHidList.ItemFocused.Caption),
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, 0, 0);
if HidHandle = INVALID_HANDLE_VALUE then begin
HidHandle:=CreateFile(PChar(lvHidList.ItemFocused.Caption), 0,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, 0, 0);
if HidHandle = INVALID_HANDLE_VALUE then begin
ShowMessage('Íå ìîãó îòêðûòü óñòðîéñòâî');
btnWrite.Enabled:=false;
btnRead.Enabled:=false;
Exit;
end;
btnWrite.Enabled:=false;
btnRead.Enabled:=true;
end else
begin
btnWrite.Enabled:=true;
btnRead.Enabled:=true;
end;
HidAttr.Size:=SizeOf(THIDDAttributes);
if not HidD_GetAttributes(HidHandle, HidAttr) then begin
ShowMessage('Íå ìîãó ïîëó÷èòü ñïèñîê àòðèáóòîâ');
end;
HidD_GetManufacturerString(HidHandle, buf, SizeOf(buf));
lvItem:=lvHidParams.Items.Add;
lvItem.Caption:='Ïðîèçâîäèò 29;ëü';
lvItem.SubItems.Add(buf);
HidD_GetProductString(HidHandle, buf, SizeOf(buf));
lvItem:=lvHidParams.Items.Add;
lvItem.Caption:='Ïðîäóêò';
lvItem.SubItems.Add(buf);
end;
procedure TForm1.FormActivate(Sender: TObject);
begin
LoadHid;
LoadSetupApi;
HidHandle:=0;
end;
procedure TForm1.btnWriteClick(Sender: TObject);
var
Buf : array [0..63] of byte;
p : pointer;
Written : Cardinal;
PreparsedData : PHIDPPreparsedData;
Caps : HIDP_CAPS;
i: integer;
begin
ToWrite:=2;
buf[0]:=$01;
buf[1]:=$02;
buf[2]:=$03;
buf[3]:=$04;
buf[4]:=$05;
buf[5]:=$06;
p:=@buf[0];
HidD_GetPreparsedData(HidHandle, PreparsedData);
HidP_GetCaps(PreparsedData, Caps);
ToWrite:=Caps.InputReportByteLength;
WriteFile(HidHandle, buf, ToWrite, Written, nil);
end;
end.
Процедура WriteFile завершается ошибкой ERROR_INVALID_PARAMETER. Прилагаемые примеры JVC работают. Вроде и делаю так же. Где-то что-то видимо не дочитал или недопонял.... Но по всякому пробовал. Какой параметр неправильный? С уважением, Алексей.
-
>Какой параметр неправильный? А если проверить их в точке останова перед функцией?
-
>HidHandle:=CreateFile(PChar(lvHidList.ItemFocused.Caption),GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ or FILE_SHARE_WRITE,nil, OPEN_EXISTING, 0, 0);
> if HidHandle = INVALID_HANDLE_VALUE then begin > HidHandle:=CreateFile(PChar(lvHidList.ItemFocused.Caption), 0,FILE_SHARE_READ or FILE_SHARE_WRITE,nil, OPEN_EXISTING, 0, 0);
> if HidHandle = INVALID_HANDLE_VALUE then begin
Это что - контрольный выстрел? Какая ветка срабатывает? Если та, которая открывает файл с dwDesiredAccess=0, то нечего удивляться, что WriteFile не работает.
-
Извиняюсь, что так долго - обстоятельства заставили отлучиться на пару дней. > Это что - контрольный выстрел? Какая ветка срабатывает? > Если та, которая открывает файл с dwDesiredAccess=0, то > нечего удивляться, что WriteFile не работает.
Срабатывает ветка: if HidHandle = INVALID_HANDLE_VALUE then begin
HidHandle:=CreateFile(PChar(lvHidList.ItemFocused.Caption), 0,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, 0, 0); То есть сначала открываю файл на чтение/запись. Если не получается, то только на чтение - в этом случае кнопка записи в устройство отключается:
btnWrite.Enabled:=false;
btnRead.Enabled:=true; > А если проверить их в точке останова перед функцией?
Проверял, ассемблером. Все параметры верные. В качестве буфера передается указатель на передаваемые данные.
-
Ой извиняюсь - не то скопипастил: Срабатывает ветка: HidHandle:=CreateFile(PChar(lvHidList.ItemFocused.Caption),
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, 0, 0);
-
что лежит в lvHidList.ItemFocused.Caption? "\\Device\bla-bla"? Если да, то такое CreateFile не откроет, через ZwOpenFile нужно, вот тут пример: http://rouse.drkb.ru/winapi.php#saferemove(.\sources\uProcessMMapDlg.pas:NormalizePath())
-
Проблема решена.
Изначально я использовал компонент TJvHidDeviceController, когда не получилось передать данные попробовал вышеуказанным способом. Эффект тот же.
Я не уделял внимание инициализации ReportID - нулевой байт буфера обмена. А данные начинаются с первого байта. Система работает при ReportID = 0. Сейчас пытаюсь понять что это за поле такое. Или по его значению определяется номер внутреннего устройства составного HID, или тип этого устройства (мышь, джойстик и т.д.).
Сейчас работаю с компонентой TJvHidDeviceController - полет нормальный.
Если кто знает про ReportID, подскажите. Буду благодарен.
С уважением, Алексей.
|