Конференция "WinAPI" » HID устройства в Delphi
 
  • Alex Eisner © (07.10.11 11:34) [0]
    Здравствуйте.
    Изучаю 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
       { Private declarations }
     public
       { Public declarations }
     end;

    var
     Form1: TForm1;

    implementation

    {$R *.dfm}

    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;

     //&#207;&#240;&#238;&#232;&#231;&#226;&#238;&#228;&#232;&#242;&#229;&#235;&#252;
     HidD_GetManufacturerString(HidHandle, buf, SizeOf(buf));
     lvItem:=lvHidParams.Items.Add;
     lvItem.Caption:='Ïðîèçâîäèò 29;ëü';
     lvItem.SubItems.Add(buf);

     //&#207;&#240;&#238;&#228;&#243;&#234;&#242;
     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);
    //  ReadFile(HidHandle, buf, ToWrite, Written, nil);

    end;

    end.



    Процедура WriteFile завершается ошибкой ERROR_INVALID_PARAMETER.

    Прилагаемые примеры JVC работают. Вроде и делаю так же.
    Где-то что-то видимо не дочитал или недопонял.... Но по всякому пробовал.

    Какой параметр неправильный?

    С уважением, Алексей.
  • MBo © (07.10.11 14:41) [1]
    >Какой параметр неправильный?
    А если проверить их в точке останова перед функцией?
  • miek (07.10.11 15:46) [2]
    >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 не работает.
  • Alex Eisner © (09.10.11 15:55) [3]
    Извиняюсь, что так долго - обстоятельства заставили отлучиться на пару дней.


    > Это что - контрольный выстрел? Какая ветка срабатывает?
    > Если та, которая открывает файл с 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;




    > А если проверить их в точке останова перед функцией?

    Проверял, ассемблером. Все параметры верные. В качестве буфера передается указатель на передаваемые данные.
  • Alex Eisner © (09.10.11 15:56) [4]
    Ой извиняюсь - не то скопипастил:

    Срабатывает ветка:
    HidHandle:=CreateFile(PChar(lvHidList.ItemFocused.Caption),
                          GENERIC_READ or GENERIC_WRITE,
                          FILE_SHARE_READ or FILE_SHARE_WRITE,
                          nil, OPEN_EXISTING, 0, 0);

  • Rouse_ © (10.10.11 19:30) [5]
    что лежит в lvHidList.ItemFocused.Caption? "\\Device\bla-bla"?
    Если да, то такое CreateFile не откроет, через ZwOpenFile нужно, вот тут пример: http://rouse.drkb.ru/winapi.php#saferemove
    (.\sources\uProcessMMapDlg.pas:NormalizePath())
  • Alex Eisner © (11.10.11 10:10) [6]
    Проблема решена.

    Изначально я использовал компонент TJvHidDeviceController, когда не получилось передать данные попробовал вышеуказанным способом. Эффект тот же.

    Я не уделял  внимание инициализации  ReportID - нулевой байт буфера обмена. А данные начинаются с первого байта. Система работает при ReportID = 0. Сейчас пытаюсь понять что это за поле такое. Или по его значению определяется номер внутреннего устройства составного HID, или тип этого устройства (мышь, джойстик и т.д.).

    Сейчас работаю с компонентой TJvHidDeviceController - полет нормальный.

    Если кто знает про ReportID, подскажите. Буду благодарен.

    С уважением, Алексей.
 
Конференция "WinAPI" » HID устройства в Delphi
Есть новые Нет новых   [134430   +2][b:0][p:0.005]