原创 Delphi USB Bulk USB Driver Interface

2009-3-19 21:56 5051 7 7 分类: 软件与OS

unit usbdriver;


{
CTRL EndPoint 0 - Read/Write
BULK EndPoint 1 - Read Only
BULK EndPoint 2 - Write Only
}


interface


uses
  Windows, SysUtils;


type
  THDEVINFO = THANDLE;


type
  // types for asynchronous calls
  TOperationKind = (okWrite, okRead);
  TAsync = record
    Overlapped: TOverlapped;
    Kind: TOperationKind;
    Data: Pointer;
    Size: Integer;
  end;
  PAsync = ^TAsync;


//------------------------------------------------------------------------------
// GUID
//------------------------------------------------------------------------------
type
  P_GUID_ = ^_GUID_;
  _GUID_ = record
    Data1: DWord;
    Data2: word;
    Data3: word;
    Data4: array [0..7] of Byte;
  end;


const


  USB_DRIVER_GUID : _GUID_ = ( //bulkusb.sys from w2k3 ddk bulkusr.h
    Data1 : $BCFD69CB;
    Data2 : $5B89;
    Data3 : $44C8;
    Data4 : ($95, $6c, $3F, $B6, $46, $80, $B5, $7A));


//------------------------------------------------------------------------------
// SP_DEVICE_INTERFACE_DETAIL_DATA_A, *PSP_DEVICE_INTERFACE_DETAIL_DATA_A;
//------------------------------------------------------------------------------
  type
    P_SP_INTERF_DETAIL_ = ^_SP_INTERF_DETAIL_;
    _SP_INTERF_DETAIL_ = packed record
      cbSize: DWord;
      DevPath: char;
    end;


//------------------------------------------------------------------------------
// SP_DEVICE_INTERFACE_DATA, *PSP_DEVICE_INTERFACE_DATA;
//------------------------------------------------------------------------------
  type
    P_SP_INTERF_ = ^_SP_INTERF_;
    _SP_INTERF_ = record
      cbSize: DWord;
      Guid: _GUID_;
      Flags: DWord;
      Reserve: Pointer;
    end;



//------------------------------------------------------------------------------
// SP_DEVINFO_DATA, *PSP_DEVINFO_DATA;
//------------------------------------------------------------------------------
  type
    P_SP_INFO_ = ^_SP_INFO_;
    _SP_INFO_ = record
      cbSize: DWord;
      Guid: _GUID_;
      DevInst: DWord;
      Reserve: DWord;
    end;


 


//------------------------------------------------------------------------------
//HANDLES for usb BulkIn/BulkOut
//------------------------------------------------------------------------------
var
  hMyDevice       : THANDLE;
  hMyDevPipeIn    : THANDLE;
  hMyDevPipeOut   : THANDLE;


const
  PipeInName  : string = '\Pipe00';
  PipeOutName : string = '\Pipe01';


function usbOpenMyDevice() : boolean;
procedure usbCloseMyDevice();


function usbOpenMyDevPipeOut() : boolean;
function usbOpenMyDevPipeIn() : boolean;


procedure usbCloseMyDevPipeOut();
procedure usbCloseMyDevPipeIn();


//with HMyDevPipeIn always
function usbRead(TimeOut : DWord; dwCount : DWord; var Buffer): integer;


//with HMyDevPipeOut always
function usbWrite(TimeOut : DWord; dwCount : DWord; const Buffer): integer;


implementation


function SetupDiGetClassDevsA(Guid: P_GUID_; Enumrator: PChar; hPar: THANDLE;
  Flags: DWord ): THANDLE; stdcall; external 'SETUPAPI.DLL';


function SetupDiEnumDeviceInterfaces(DevInfo: THANDLE; InfoData: P_SP_INFO_;
  Guid: P_GUID_; Index: DWord; DevInterfD: P_SP_INTERF_ )
    : bool; stdcall; external 'SETUPAPI.DLL';


function SetupDiDestroyDeviceInfoList( hPar: THANDLE )
  : bool; stdcall; external 'SETUPAPI.DLL';


function SetupDiGetDeviceInterfaceDetailA( DevInfo: THANDLE;
  InterData: P_SP_INTERF_; InfoDetail: P_SP_INTERF_DETAIL_; DetailSize: DWord;
    ReqSize: PDWord; InfoData: P_SP_INFO_ )
      : bool; stdcall; external 'SETUPAPI.DLL';


//------------------------------------------------------------------------------
// use SetupDiGetClassDevsA
//------------------------------------------------------------------------------
const DIGCF_DEFAULT         = $001;
const DIGCF_PRESENT         = $002;
const DIGCF_ALLCLASSES      = $004;
const DIGCF_PROFILE         = $008;
const DIGCF_DEVICEINTERFACE = $010;


//------------------------------------------------------------------------------
// initialization of PAsync variables used in asynchronous calls
//------------------------------------------------------------------------------
procedure InitAsync(var AsyncPtr: PAsync);
begin
  New(AsyncPtr);
  with AsyncPtr^ do
  begin
    FillChar(Overlapped, SizeOf(TOverlapped), 0);
    Overlapped.hEvent := CreateEvent(nil, True, FALSE, nil);
    Data := nil;
    Size := 0;
  end;
end;


//------------------------------------------------------------------------------
// clean-up of PAsync variable
//------------------------------------------------------------------------------
procedure DoneAsync(var AsyncPtr: PAsync);
begin
  with AsyncPtr^ do
  begin
    CloseHandle(Overlapped.hEvent);
    if Data <> nil then
      FreeMem(Data);
  end;
  Dispose(AsyncPtr);
  AsyncPtr := nil;
end;


//------------------------------------------------------------------------------
// prepare PAsync variable for read/write operation
//------------------------------------------------------------------------------
procedure PrepareAsync(AKind: TOperationKind; const Buffer;
  Count: Integer; AsyncPtr: PAsync);
begin
  with AsyncPtr^ do
  begin
    Kind := AKind;
    if Data <> nil then
      FreeMem(Data);
    GetMem(Data, Count);
    Move(Buffer, Data^, Count);
    Size := Count;
  end;
end;


//------------------------------------------------------------------------------
// wait for asynchronous operation to end : TimeOut : Result = -1
//------------------------------------------------------------------------------
function WaitForAsync(hReadOrWrite : THandle; TimeOut : DWord; var AsyncPtr: PAsync): Integer;
var
  BytesTrans, Signaled: DWORD;
  Success: Boolean;
begin
  result := -1;                 //Signaled = WAIT_OBJECT_TIMEOUT
  if WAIT_OBJECT_0 <> WaitForSingleObject(AsyncPtr^.Overlapped.hEvent, TimeOut) then Exit;
  if not GetOverlappedResult(hReadOrWrite, AsyncPtr^.Overlapped, BytesTrans, False) then Exit;
  Result := BytesTrans;
end;


//------------------------------------------------------------------------------
// perform asynchronous write operation
//------------------------------------------------------------------------------
function WriteAsync(hWrite : THandle; const Buffer; Count: Integer; var AsyncPtr: PAsync): Integer;
var
  Success: Boolean;
  BytesTrans: DWORD;
begin
  result := -1;
 
  PrepareAsync(okWrite, Buffer, Count, AsyncPtr);


  Success := WriteFile(hWrite, Buffer, Count, BytesTrans, @AsyncPtr^.Overlapped)
    or (GetLastError = ERROR_IO_PENDING);


  //if Device is not present -- Success is FALSE !   
  if not Success then Exit;
 
  Result := BytesTrans; //if WriteFile is Complete at once
end;



//------------------------------------------------------------------------------
// perform synchronous write operation
//------------------------------------------------------------------------------
function Write(hWrite : THandle; TimeOut : DWord; const Buffer; Count: Integer): Integer;
var
  AsyncPtr: PAsync;
begin
  InitAsync(AsyncPtr);
  try
    Result := WriteAsync(hWrite, Buffer, Count, AsyncPtr);
    if Result = Count then Exit;


    Result := WaitForAsync(hWrite, TimeOut, AsyncPtr);
  finally
    DoneAsync(AsyncPtr);
  end;
end;


//------------------------------------------------------------------------------
// perform asynchronous read operation
//------------------------------------------------------------------------------
function ReadAsync(hRead : THandle; var Buffer; Count: Integer; var AsyncPtr: PAsync): Integer;
var
  ErrorCode : DWord;
  BytesTrans: DWORD;
begin
  result := -1;


  AsyncPtr^.Kind := okRead;
  //PrepareAsync(okRead, Buffer, Count, AsyncPtr);


  if not ReadFile(hRead, Buffer, Count, BytesTrans, @AsyncPtr^.Overlapped) then
  begin
    ErrorCode := GetLastError;
    if (ErrorCode <> ERROR_IO_PENDING) then
    begin
      //ShowMessage(SysErrorMessage(GetLastError));
      Exit;
    end;
  end;


  Result := BytesTrans;
end;


//------------------------------------------------------------------------------
// perform synchronous read operation
//------------------------------------------------------------------------------
function Read(hRead : THandle; TimeOut : DWord; var Buffer; Count: Integer): Integer;
var
  AsyncPtr: PAsync;
begin
  InitAsync(AsyncPtr);
  try
    ReadAsync(hRead, Buffer, Count, AsyncPtr);
    Result := WaitForAsync(hRead, TimeOut, AsyncPtr);
  finally
    DoneAsync(AsyncPtr);
  end;
end;



//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
function OpenOneDevice(
  hDevInfo : THDEVINFO;
  DevInfoData : P_SP_INTERF_;
  sDevNameBuf : PChar) : THANDLE;
var
  iReqLen : DWord;
  iDevDataLen : DWord;
  pDevData : P_SP_INTERF_DETAIL_;
begin
  Result := INVALID_HANDLE_VALUE;


  iReqLen := 0;
  SetupDiGetDeviceInterfaceDetailA(
    hDevInfo, DevInfoData, nil, 0, @iReqLen, nil);


  iDevDataLen := iReqLen; //sizeof(SP_FNCLASS_DEVICE_DATA) + 512;
  try
    GetMem(pDevData, iDevDataLen);
  except
    SetupDiDestroyDeviceInfoList(hDevInfo);
    exit;
  end;
  pDevData.cbSize := sizeof(_SP_INTERF_DETAIL_);


  if not SetupDiGetDeviceInterfaceDetailA(
    hDevInfo, DevInfoData, pDevData, iDevDataLen, @iReqLen, nil) then
  begin
    FreeMem(pDevData);
    SetupDiDestroyDeviceInfoList(hDevInfo);
    exit;
  end;
  StrCopy( sDevNameBuf, @pDevData.DevPath );


  Result := CreateFile(sDevNameBuf,
    GENERIC_READ or GENERIC_WRITE,
    FILE_SHARE_READ or FILE_SHARE_WRITE,
    nil, OPEN_EXISTING, 0, 0);


  FreeMem(pDevData);
  SetupDiDestroyDeviceInfoList(hDevInfo);
end;


//------------------------------------------------------------------------------
function OpenUsbDevice(const pGuid: P_GUID_;
  sDevNameBuf: PChar) : THANDLE;
var
  hDevInfo : THDEVINFO;
  deviceInfoData : _SP_INTERF_;
  nGuessCount : DWord;
  iDevIndex : DWord;
begin
  Result := INVALID_HANDLE_VALUE;
  hDevInfo := SetupDiGetClassDevsA(
    pGuid, nil, 0, DIGCF_PRESENT or DIGCF_DEVICEINTERFACE);
  deviceInfoData.cbSize := sizeof (_SP_INTERF_);
  nGuessCount := $8000;
  for iDevIndex := 0 to nGuessCount-1 do
  begin
    if SetupDiEnumDeviceInterfaces(
      hDevInfo, nil, pGuid, iDevIndex, @deviceInfoData) then
    begin
      Result := OpenOneDevice(hDevInfo, @deviceInfoData, sDevNameBuf);
      if Result <> INVALID_HANDLE_VALUE then
        break
    end
    //No more items
    else if GetLastError() = ERROR_NO_MORE_ITEMS then
        break;
  end;
  SetupDiDestroyDeviceInfoList(hDevInfo);
end;


//------------------------------------------------------------------------------
function GetUsbDeviceFileName(const pGuid: P_GUID_;
  sDevNameBuf: PChar) : boolean;
var
  hDev : THANDLE;
begin
  Result := False;
  hDev := OpenUsbDevice(pGuid, sDevNameBuf);
  if hDev <> INVALID_HANDLE_VALUE then
  begin
    CloseHandle(hDev);
    Result := True;
  end;
end;



//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
function OpenMyDeviceEx() : THANDLE;
var
  DeviceName : string;
begin
  SetLength(DeviceName, 1024);
  Result := OpenUsbDevice(@USB_DRIVER_GUID, PChar(DeviceName));  // USB_DRIVER_GUID
end;


//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
procedure CloseMyDeviceEx(hDev : THANDLE);
begin
  try
    if hDev <> INVALID_HANDLE_VALUE then
      CloseHandle(hDev);
  except
  end;
end;


//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
function OpenMyDevPipe(PipeName : string) : THANDLE;
var
  completeDeviceName : string;
  completeDevicePipeName : string;
begin
  Result := INVALID_HANDLE_VALUE;
  SetLength(completeDeviceName, 1024);
  SetLength(completeDevicePipeName, 1024);
  if GetUsbDeviceFileName(@USB_DRIVER_GUID, PChar(completeDeviceName)) then
  begin
    completeDevicePipeName := StrPas(PChar(completeDeviceName)) + PipeName;
    Result := CreateFile(
      PChar(completeDevicePipeName),
      GENERIC_READ or GENERIC_WRITE,
      FILE_SHARE_READ or FILE_SHARE_WRITE,
      nil, OPEN_EXISTING, 0, 0);
  end;
end;


//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
function OpenMyDevPipeAsync(PipeName : string) : THANDLE;
var
  completeDeviceName : string;
  completeDevicePipeName : string;
begin
  Result := INVALID_HANDLE_VALUE;
  SetLength(completeDeviceName, 1024);
  SetLength(completeDevicePipeName, 1024);
  if GetUsbDeviceFileName(@USB_DRIVER_GUID, PChar(completeDeviceName)) then
  begin
    completeDevicePipeName := StrPas(PChar(completeDeviceName)) + PipeName;
    Result := CreateFile(
      PChar(completeDevicePipeName),
      GENERIC_READ or GENERIC_WRITE,
      FILE_SHARE_READ or FILE_SHARE_WRITE,
      nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);  //FILE_FLAG_OVERLAPPED
  end;
end;


 


//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
procedure CloseMyDevPipe(hPipe : THANDLE);
begin
  try
    if hPipe <> INVALID_HANDLE_VALUE then
      CloseHandle(hPipe);
  except
  end;
end;


//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
function DeviceConnected() : boolean;
var
  hMyDev : THandle;
begin
  hMyDev := OpenMyDeviceEx();
  Result :=  hMyDev <> INVALID_HANDLE_VALUE;
  CloseMyDeviceEx(hMyDev);
end;


//------------------------------------------------------------------------------
//uses hMyDevPipeOut always
//------------------------------------------------------------------------------
function usbWrite(TimeOut : DWord; dwCount : DWord; const Buffer): integer;
begin
  Result := usbdriver.Write(hMyDevPipeOut, TimeOut, Buffer, dwCount);
end;


//------------------------------------------------------------------------------
//uses hMyDevPipeIn always
//------------------------------------------------------------------------------
function usbRead(TimeOut : DWord; dwCount : DWord; var Buffer): integer;  
begin
  Result := 0;
  while Result = 0  do
  begin
    Result := usbdriver.Read(hMyDevPipeIn, TimeOut, Buffer, dwCount);
  end;    // while
end;



function usbOpenMyDevice() : boolean;
begin
  result := False;


  hMyDevice := INVALID_HANDLE_VALUE;
  hMyDevice := OpenMyDeviceEx();
  if hMyDevice = INVALID_HANDLE_VALUE then Exit;


  result := TRUE;
end;


procedure usbCloseMyDevice();
begin
  if hMyDevice <> INVALID_HANDLE_VALUE then
    CloseHandle(hMyDevice);
end;


function usbOpenMyDevPipeOut() : boolean;
begin
  result := False;


  hMyDevPipeOut := INVALID_HANDLE_VALUE;
  hMyDevPipeOut := OpenMyDevPipeAsync(PipeOutName);
  if hMyDevPipeOut = INVALID_HANDLE_VALUE then Exit;


  result := TRUE;
end;


function usbOpenMyDevPipeIn() : boolean;
begin
  result := False;


  hMyDevPipeIn := INVALID_HANDLE_VALUE;
  hMyDevPipeIn := OpenMyDevPipeAsync(PipeInName);
  if hMyDevPipeIn = INVALID_HANDLE_VALUE then Exit;


  result := TRUE;
end;



procedure usbCloseMyDevPipeOut();
begin
  if hMyDevPipeOut <> INVALID_HANDLE_VALUE then
    CloseMyDevPipe(hMyDevPipeOut);
end;


procedure usbCloseMyDevPipeIn();
begin
  if hMyDevPipeIn <> INVALID_HANDLE_VALUE then
    CloseMyDevPipe(hMyDevPipeIn);
end;



end.


 


/////////////////////////////////////////////////////////////////


unit Unit1;


interface


uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;


type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;


var
  Form1: TForm1;


implementation


uses usbdriver;


{$R *.dfm}


var
  Stop : boolean;


procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
  BulkBuffer : array[0..65535-1] of byte;
  BulkBuffer2 : array[0..65535-1] of byte;
  WriteCount, ReadCount : integer;
begin
  for I := 0 to 65535 - 1 do    // Iterate
  begin
    BulkBuffer := i;
  end;    // for


  i := 0;
  if usbOpenMyDevice() then
      if usbOpenMyDevPipeOut() then
        if usbOpenMyDevPipeIn() then
  begin
    Stop := FALSE;
    while (not Stop) and (i < 65536 ) do
    begin
      Application.ProcessMessages ;


      i := i + 1;


      WriteCount := usbWrite(1000, 65535, BulkBuffer);
      if WriteCount = -1 then
        break;


      ReadCount := usbRead(1000, 65536, BulkBuffer2);
      if ReadCount = -1 then
        break;


    end;    // while


    usbCloseMyDevPipeIn();
    usbCloseMyDevPipeOut();
    usbCloseMyDevice();
  end;


end;


procedure TForm1.Button2Click(Sender: TObject);
begin
  Stop := TRUE;
end;


end.

文章评论0条评论)

登录后参与讨论
我要评论
0
7
关闭 站长推荐上一条 /2 下一条