Dear anyone can help me in using
https://github.com/signal11/hidapi
https://github.com/libusb/hidapi
thanks
Deraman
how to use hidapi please help
Re: how to use hidapi please help
Your second link is the 'latest' version.
User_Russian did some work on this a while ago and created a module you may find useful.
see: https://www.purebasic.fr/english/viewto ... 58#p320558
User_Russian did some work on this a while ago and created a module you may find useful.
see: https://www.purebasic.fr/english/viewto ... 58#p320558
- It was too lonely at the top.
System : PB 6.21(x64) and Win 11 Pro (x64)
Hardware: AMD Ryzen 9 5900X w/64 gigs Ram, AMD RX 6950 XT Graphics w/16gigs Mem
System : PB 6.21(x64) and Win 11 Pro (x64)
Hardware: AMD Ryzen 9 5900X w/64 gigs Ram, AMD RX 6950 XT Graphics w/16gigs Mem
-
- Addict
- Posts: 1544
- Joined: Wed Nov 12, 2008 5:01 pm
- Location: Russia
Re: how to use hidapi please help
Dear I tried both options but was not satisfied that is why asking for this lib.
Thanks
Deraman
Thanks
Deraman
Re: how to use hidapi please help
I used User_Russians version as base,
I modifed it, because I needed also non blocking read and it was not possible to open different usage pages of one device.
But it is windows only.
I also tried the hidapi lib, but they are also still miss something what I need.
I adopted the HID tool of User_Russian to this version, but at the moment I have no access to this code.
I will add a demo at the end of the module.
The demo shows the principal of non blocking read with the possibility to write something to the device.
In a normal program this is inside of a thread, where you 'inject' the buffer to send via the thread parameters.
I modifed it, because I needed also non blocking read and it was not possible to open different usage pages of one device.
Code: Select all
DeclareModule HID
;-DeclareModule
Structure HID_CAPS
Usage.w
UsagePage.w
InputReportByteLength.w
OutputReportByteLength.w
FeatureReportByteLength.w
Reserved.w[17]
NumberLinkCollectionNodes.w
NumberInputButtonCaps.w
NumberInputValueCaps.w
NumberInputDataIndices.w
NumberOutputButtonCaps.w
NumberOutputValueCaps.w
NumberOutputDataIndices.w
NumberFeatureButtonCaps.w
NumberFeatureValueCaps.w
NumberFeatureDataIndices.w
EndStructure
Structure HID_DeviceInfo
VendorID.u
ProductID.u
VersionNumber.u
Usage.u
UsagePage.u
NumInputBuffers.u
InputReportByteLength.u
OutputReportByteLength.u
FeatureReportByteLength.u
Manufacturer$
Product$
SerialNumber$
DevicePath$
EndStructure
NewList DeviceInfoList.HID_DeviceInfo()
Structure HID_Attributes
VID.u
PID.u
VersionNumber.u
EndStructure
Declare.i Init()
Declare Close()
Declare.i OpenDevice(PID.u, VID.u, SerialNumber$="")
Declare.i OpenDeviceByPath(DevicePath$)
Declare.i OpenDeviceByPathNonBlocking(DevicePath$)
Declare CloseDevice(hDevice)
Declare.i TestDevice(PID.u, VID.u, SerialNumber$="")
Declare.i TestDeviceByPath(DevicePath$)
;Declare DeviceInfo(*Info.HID_DeviceInfo)
Declare DeviceInfo(List DeviceInfoList.HID_DeviceInfo())
Declare.l ReadDevice(hDevice, *Buffer, Len)
Declare.i ReadDeviceNonBlocking(hDevice, *Buffer, Len, *Overlapp.OVERLAPPED)
Declare.l WriteDevice(hDevice, *Buffer, Len)
Declare.i WriteDeviceNonBlocking(hDevice, *Buffer, Len, *Overlapp.OVERLAPPED)
Declare GetFeature(hDevice, *Buffer, Len)
Declare.i SetFeature(hDevice, *Buffer, Len)
Declare.i GetInputReport(hDevice, *Buffer, Len)
Declare.i SetOutputReport(hDevice, *Buffer, Len)
Declare.i GetCaps(hDevice, *Capabilities.HID_CAPS)
Declare.i GetAttributes(hDevice, *DeviceInfo.HID_Attributes)
Declare.i GetNumInputBuffers(hDevice)
Declare.s GetManufacturerString(hDevice)
Declare.s GetProductString(hDevice)
Declare.s GetSerialNumberString(hDevice)
Declare.s GetIndexedString(hDevice, Index)
EndDeclareModule
Module HID
EnableExplicit
Structure HIDD_ATTRIBUTES
Size.l
VendorID.u
ProductID.u
VersionNumber.w
EndStructure
Structure PSP_DEVICE_INTERFACE_DETAIL_DATA
cbSize.l
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
DevicePath.l
CompilerElse
DevicePath.c
CompilerEndIf
EndStructure
CompilerIf Not Defined(SP_DEVICE_INTERFACE_DATA, #PB_Structure)
Structure SP_DEVICE_INTERFACE_DATA
cbSize.l
InterfaceClassGuid.GUID
Flags.l
Reserved.l
EndStructure
CompilerEndIf
Prototype Prototype_HidD_GetHidGuid(*HidGuid.GUID)
Prototype.i Prototype_HidD_GetAttributes(*HidDeviceObject, *Attributes.HIDD_ATTRIBUTES)
Prototype.i Prototype_HidD_GetPreparsedData(*HidDeviceObject, *PreparsedData)
Prototype.i Prototype_HidP_GetCaps(*PreparsedData, *Capabilities.HID_CAPS)
Prototype.i Prototype_HidD_FreePreparsedData(PreparsedData)
Prototype.i Prototype_HidD_GetNumInputBuffers(HidHandle.i, *NumInputBuffers)
Prototype.i Prototype_HidD_GetManufacturerString(HidHandle.i, *Buffer, Len.l)
Prototype.i Prototype_HidD_GetProductString(HidHandle.i, *Buffer, Len.l)
Prototype.i Prototype_HidD_GetSerialNumberString(HidHandle.i, *Buffer, Len.l)
Prototype.i Prototype_HidD_GetIndexedString(HidHandle.i, Index, *Buffer, Len.l)
Prototype.i Prototype_HidD_GetFeature(HidHandle.i, *Buffer, Len.l)
Prototype.i Prototype_HidD_SetFeature(HidHandle.i, *Buffer, Len.l)
Prototype.i Prototype_HidD_GetInputReport(HidHandle.i, *Buffer, Len.l)
Prototype.i Prototype_HidD_SetOutputReport(HidHandle.i, *Buffer, Len.l)
Prototype.i Prototype_SetupDiEnumDeviceInterfaces(*DeviceInfoSet, DeviceInfoData, *InterfaceClassGuid.GUID, MemberIndex, *DeviceInterfaceData.SP_DEVICE_INTERFACE_DATA)
Prototype.i Prototype_SetupDiGetDeviceInterfaceDetail(*DeviceInfoSet, *DeviceInterfaceData.SP_DEVICE_INTERFACE_DATA, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize, *RequiredSize, *DeviceInfoData)
Global HidD_GetHidGuid.Prototype_HidD_GetHidGuid
Global HidD_GetAttributes.Prototype_HidD_GetAttributes
Global HidD_GetPreparsedData.Prototype_HidD_GetPreparsedData
Global HidD_FreePreparsedData.Prototype_HidD_FreePreparsedData
Global HidP_GetCaps.Prototype_HidP_GetCaps
Global HidD_GetInputReport.Prototype_HidD_GetInputReport
Global HidD_SetOutputReport.Prototype_HidD_SetOutputReport
Global HidD_GetFeature.Prototype_HidD_GetFeature
Global HidD_SetFeature.Prototype_HidD_SetFeature
Global _HidD_GetNumInputBuffers.Prototype_HidD_GetNumInputBuffers
Global _HidD_GetManufacturerString.Prototype_HidD_GetManufacturerString
Global _HidD_GetProductString.Prototype_HidD_GetProductString
Global _HidD_GetSerialNumberString.Prototype_HidD_GetSerialNumberString
Global _HidD_GetIndexedString.Prototype_HidD_GetIndexedString
Global SetupDiEnumDeviceInterfaces.Prototype_SetupDiEnumDeviceInterfaces
Global SetupDiGetDeviceInterfaceDetail.Prototype_SetupDiGetDeviceInterfaceDetail
Define.i HID_Lib, SetupAPI_Lib
Procedure.i Init()
Shared HID_Lib, SetupAPI_Lib
Protected Result.i
HID_Lib = OpenLibrary(#PB_Any, "hid.dll")
If HID_Lib
SetupAPI_Lib = OpenLibrary(#PB_Any, "setupapi.dll")
If SetupAPI_Lib
HidD_GetHidGuid = GetFunction(HID_Lib, "HidD_GetHidGuid")
HidD_GetAttributes = GetFunction(HID_Lib, "HidD_GetAttributes")
HidD_GetPreparsedData = GetFunction(HID_Lib, "HidD_GetPreparsedData")
HidD_FreePreparsedData = GetFunction(HID_Lib, "HidD_FreePreparsedData")
HidP_GetCaps = GetFunction(HID_Lib, "HidP_GetCaps")
HidD_GetInputReport = GetFunction(HID_Lib, "HidD_GetInputReport")
HidD_SetOutputReport = GetFunction(HID_Lib, "HidD_SetOutputReport")
HidD_GetFeature = GetFunction(HID_Lib, "HidD_GetFeature")
HidD_SetFeature = GetFunction(HID_Lib, "HidD_SetFeature")
_HidD_GetNumInputBuffers = GetFunction(HID_Lib, "HidD_GetNumInputBuffers")
_HidD_GetManufacturerString = GetFunction(HID_Lib, "HidD_GetManufacturerString")
_HidD_GetProductString = GetFunction(HID_Lib, "HidD_GetProductString")
_HidD_GetSerialNumberString = GetFunction(HID_Lib, "HidD_GetSerialNumberString")
_HidD_GetIndexedString = GetFunction(HID_Lib, "HidD_GetIndexedString")
SetupDiEnumDeviceInterfaces = GetFunction(SetupAPI_Lib, "SetupDiEnumDeviceInterfaces")
SetupDiGetDeviceInterfaceDetail = GetFunction(SetupAPI_Lib, "SetupDiGetDeviceInterfaceDetailW")
Result = #True
EndIf
EndIf
ProcedureReturn Result
EndProcedure
Procedure Close()
Shared HID_Lib, SetupAPI_Lib
If HID_Lib
FreeLibrary_(HID_Lib)
HID_Lib = 0
EndIf
If SetupAPI_Lib
FreeLibrary_(SetupAPI_Lib)
SetupAPI_Lib = 0
EndIf
EndProcedure
Procedure.i GetNumInputBuffers(hDevice)
Protected NumInputBuffers.i
If hDevice And _HidD_GetNumInputBuffers
_HidD_GetNumInputBuffers(hDevice, @NumInputBuffers)
EndIf
ProcedureReturn NumInputBuffers
EndProcedure
Procedure.s GetManufacturerString(hDevice)
Protected Result$, *mem
If hDevice And _HidD_GetManufacturerString
*mem = AllocateMemory(256)
If *mem
If _HidD_GetManufacturerString(hDevice, *mem, 252)
Result$ = PeekS(*mem, -1, #PB_Unicode)
EndIf
FreeMemory(*mem)
EndIf
EndIf
ProcedureReturn Result$
EndProcedure
Procedure.s GetProductString(hDevice)
Protected Result$, *mem
If hDevice And _HidD_GetProductString
*mem = AllocateMemory(256)
If *mem
If _HidD_GetProductString(hDevice, *mem, 252)
Result$ = PeekS(*mem, -1, #PB_Unicode)
EndIf
FreeMemory(*mem)
EndIf
EndIf
ProcedureReturn Result$
EndProcedure
Procedure.s GetSerialNumberString(hDevice)
Protected Result$, *mem
If hDevice And _HidD_GetSerialNumberString
*mem = AllocateMemory(256)
If *mem
If _HidD_GetSerialNumberString(hDevice, *mem, 252)
Result$ = PeekS(*mem, -1, #PB_Unicode)
EndIf
FreeMemory(*mem)
EndIf
EndIf
ProcedureReturn Result$
EndProcedure
Procedure.s GetIndexedString(hDevice, Index)
Protected Result$, *mem
If hDevice And _HidD_GetIndexedString
*mem = AllocateMemory(256)
If *mem
If _HidD_GetIndexedString(hDevice, Index, *mem, 252)
Result$ = PeekS(*mem, -1, #PB_Unicode)
EndIf
FreeMemory(*mem)
EndIf
EndIf
ProcedureReturn Result$
EndProcedure
Procedure.i Scan_HID_Devices(List InfoList.HID_DeviceInfo())
Protected HidGuid.Guid
Protected devInfoData.SP_DEVICE_INTERFACE_DATA
Protected Attributes.HIDD_ATTRIBUTES;, Security.SECURITY_ATTRIBUTES
Protected *detailData.PSP_DEVICE_INTERFACE_DETAIL_DATA
Protected Length.l, CurrentIndex.w, hDevInfo
Protected i, Result, DevicePath$
Protected Required, hDevice
Protected HIDP_CAPS.HID_CAPS
If HidD_GetHidGuid = 0 Or SetupDiEnumDeviceInterfaces = 0 Or SetupDiGetDeviceInterfaceDetail = 0 Or HidD_GetAttributes = 0
ProcedureReturn 0
EndIf
devInfoData\cbSize = SizeOf(SP_DEVICE_INTERFACE_DATA)
; Security\nLength=SizeOf(SECURITY_ATTRIBUTES)
; Security\bInheritHandle=1
; Security\lpSecurityDescriptor = 0
HidD_GetHidGuid(@HidGuid)
hDevInfo=SetupDiGetClassDevs_(@HidGuid, 0, 0, #DIGCF_PRESENT|#DIGCF_DEVICEINTERFACE)
If hDevInfo = 0
ProcedureReturn 0
EndIf
ClearList(InfoList())
For i = 0 To 255
;Repeat
Result = SetupDiEnumDeviceInterfaces(hDevInfo, 0, @HidGuid, i, @devInfoData)
If Result
Result = SetupDiGetDeviceInterfaceDetail(hDevInfo, @devInfoData, 0, 0,@Length, 0)
*detailData = AllocateMemory(Length)
*detailData\cbSize = SizeOf(PSP_DEVICE_INTERFACE_DETAIL_DATA)
Result = SetupDiGetDeviceInterfaceDetail(hDevInfo, @devInfoData, *detailData, Length + 1, @Required, #Null)
DevicePath$ = PeekS(@*detailData\DevicePath)
FreeMemory(*detailData)
;hDevice=CreateFile_(@DevicePath$, #GENERIC_READ|#GENERIC_WRITE, #FILE_SHARE_READ|#FILE_SHARE_WRITE, @Security, #OPEN_EXISTING, 0, 0)
hDevice = CreateFile_(@DevicePath$, #GENERIC_READ|#GENERIC_WRITE, #FILE_SHARE_READ|#FILE_SHARE_WRITE, #Null, #OPEN_EXISTING, #Null, #Null)
If hDevice <> #INVALID_HANDLE_VALUE
AddElement(InfoList())
InfoList()\DevicePath$ = DevicePath$
Attributes\Size = SizeOf(HIDD_ATTRIBUTES)
If HidD_GetAttributes(hDevice, @Attributes)
InfoList()\VendorID = Attributes\VendorID
InfoList()\ProductID = Attributes\ProductID
InfoList()\VersionNumber = Attributes\VersionNumber
InfoList()\Manufacturer$ = GetManufacturerString(hDevice)
InfoList()\Product$ = GetProductString(hDevice)
InfoList()\SerialNumber$ = GetSerialNumberString(hDevice)
InfoList()\NumInputBuffers = GetNumInputBuffers(hDevice)
If GetCaps(hDevice, @HIDP_CAPS)
InfoList()\Usage = HIDP_CAPS\Usage
InfoList()\UsagePage = HIDP_CAPS\UsagePage
InfoList()\InputReportByteLength = HIDP_CAPS\InputReportByteLength
InfoList()\OutputReportByteLength = HIDP_CAPS\OutputReportByteLength
InfoList()\FeatureReportByteLength = HIDP_CAPS\FeatureReportByteLength
EndIf
EndIf
CloseHandle_(hDevice)
EndIf
Else
Break
EndIf
;Debug i
; i + 1
;Until GetLastError_() = #ERROR_NO_MORE_ITEMS
Next i
SetupDiDestroyDeviceInfoList_(hDevInfo)
ProcedureReturn ListSize(InfoList())
EndProcedure
Procedure.i OpenDevice(PID.u, VID.u, SerialNumber$="")
Protected Handle.i
Protected NewList TmpList.HID_DeviceInfo()
If Scan_HID_Devices(TmpList())
ForEach TmpList()
If TmpList()\VendorID = VID And TmpList()\ProductID = PID
If SerialNumber$ <> ""
If TmpList()\SerialNumber$ = SerialNumber$
Handle = CreateFile_(@TmpList()\DevicePath$, #GENERIC_READ|#GENERIC_WRITE, #FILE_SHARE_READ|#FILE_SHARE_WRITE, #Null, #OPEN_EXISTING, #Null, #Null)
Break
EndIf
Else
Handle = CreateFile_(@TmpList()\DevicePath$, #GENERIC_READ|#GENERIC_WRITE, #FILE_SHARE_READ|#FILE_SHARE_WRITE, #Null, #OPEN_EXISTING, #Null, #Null)
Break
EndIf
EndIf
Next
EndIf
ProcedureReturn Handle
EndProcedure
Procedure.i OpenDeviceByPath(DevicePath$)
ProcedureReturn CreateFile_(@DevicePath$, #GENERIC_READ|#GENERIC_WRITE, #FILE_SHARE_READ|#FILE_SHARE_WRITE, #Null, #OPEN_EXISTING, #Null, #Null)
EndProcedure
Procedure.i OpenDeviceByPathNonBlocking(DevicePath$)
ProcedureReturn CreateFile_(@DevicePath$, #GENERIC_READ|#GENERIC_WRITE, #FILE_SHARE_READ|#FILE_SHARE_WRITE, #Null, #OPEN_EXISTING, #FILE_FLAG_OVERLAPPED, #Null)
EndProcedure
Procedure.i CloseDevice(hDevice)
If hDevice
ProcedureReturn CloseHandle_(hDevice)
Else
ProcedureReturn 0
EndIf
EndProcedure
Procedure.i TestDevice(PID.u, VID.u, SerialNumber$="")
Protected.i hHid, Result
hHid = OpenDevice(PID, VID, SerialNumber$)
If hHid
CloseDevice(hHid)
Result = #True
EndIf
ProcedureReturn Result
EndProcedure
Procedure.i TestDeviceByPath(DevicePath$)
Protected.i hHid, Result
hHid = OpenDeviceByPath(DevicePath$)
If hHid
CloseDevice(hHid)
Result = #True
EndIf
ProcedureReturn Result
EndProcedure
Procedure.i DeviceInfo(List InfoList.HID_DeviceInfo())
ClearList(InfoList())
Scan_HID_Devices(InfoList())
ProcedureReturn ListSize(InfoList())
EndProcedure
Procedure.l ReadDevice(hDevice, *Buffer, Len)
Protected BytesRead.l
If hDevice And *Buffer And Len
ReadFile_(hDevice, *Buffer, Len, @BytesRead, #Null)
EndIf
ProcedureReturn BytesRead
EndProcedure
Procedure.i ReadDeviceNonBlocking(hDevice, *Buffer, Len, *Overlapp.OVERLAPPED)
Protected BytesRead.l, Status.i
If hDevice And *Buffer And Len
Status = ReadFile_(hDevice, *Buffer, Len, @BytesRead, *Overlapp)
EndIf
ProcedureReturn Status
EndProcedure
Procedure.l WriteDevice(hDevice, *Buffer, Len)
Protected BytesWritten.l
If hDevice And *Buffer And Len
WriteFile_(hDevice, *Buffer, Len, @BytesWritten, #Null)
EndIf
ProcedureReturn BytesWritten
EndProcedure
Procedure.i WriteDeviceNonBlocking(hDevice, *Buffer, Len, *Overlapp.OVERLAPPED)
Protected BytesWritten.l, Status.i
If hDevice And *Buffer And Len
Status = WriteFile_(hDevice, *Buffer, Len, @BytesWritten, *Overlapp)
EndIf
ProcedureReturn Status
EndProcedure
Procedure.i GetFeature(hDevice, *Buffer, Len)
If hDevice And *Buffer And Len > 0 And HidD_GetFeature
ProcedureReturn HidD_GetFeature(hDevice, *Buffer, Len)
Else
ProcedureReturn 0
EndIf
EndProcedure
Procedure.i SetFeature(hDevice, *Buffer, Len)
If hDevice And *Buffer And Len > 0 And HidD_SetFeature
ProcedureReturn HidD_SetFeature(hDevice, *Buffer, Len)
Else
ProcedureReturn 0
EndIf
EndProcedure
Procedure.i GetInputReport(hDevice.i, *Buffer, Len.i)
If hDevice And *buffer And Len > 0 And HidD_GetInputReport
ProcedureReturn HidD_GetInputReport(hDevice, *Buffer, Len)
Else
ProcedureReturn 0
EndIf
EndProcedure
Procedure.i SetOutputReport(hDevice.i, *Buffer, Len.i)
If hDevice And *buffer And Len>0 And HidD_SetOutputReport
ProcedureReturn HidD_SetOutputReport(hDevice, *Buffer, Len)
Else
ProcedureReturn 0
EndIf
EndProcedure
Procedure.i GetCaps(hDevice, *Capabilities.HID_CAPS)
Protected.i result, PreparsedData
If hDevice And HidD_GetPreparsedData And HidP_GetCaps And HidD_FreePreparsedData
If HidD_GetPreparsedData(hDevice, @PreparsedData)
HidP_GetCaps(PreparsedData, *Capabilities)
HidD_FreePreparsedData(PreparsedData)
result = #True
EndIf
EndIf
ProcedureReturn result
EndProcedure
Procedure.i GetAttributes(hDevice, *DeviceInfo.HID_Attributes)
Protected Info.HIDD_ATTRIBUTES, Result.i
If hDevice And *DeviceInfo And HidD_GetAttributes
Info\Size = SizeOf(HIDD_ATTRIBUTES)
If HidD_GetAttributes(hDevice, @Info)
CopyMemory(@Info+OffsetOf(HIDD_ATTRIBUTES\VendorID), *DeviceInfo, SizeOf(HID_Attributes))
Result = #True
EndIf
EndIf
ProcedureReturn Result
EndProcedure
EndModule
;-Demo
CompilerIf #PB_Compiler_IsMainFile
CompilerIf Not #PB_Compiler_Thread
CompilerError "Enable thread save execution in compiler options!"
CompilerEndIf
EnableExplicit
Enumeration
#MainWindow
#DataWindow
EndEnumeration
Enumeration
#HID_DeviceList
#DataInputReport
#DataReadDevice
#DataReadDeviceNonBlocking
EndEnumeration
Enumeration #PB_Event_FirstCustomValue
#HID_Event_InputReportData
#HID_Event_ReadDeviceData
#HID_Event_ReadDeviceNonBlockingData
EndEnumeration
Structure ThreadParameter_Structure
Thread.i
Mutex.i
Semaphore.i
*DeviceInfo.HID::HID_DeviceInfo
Device.i
TxLen.i
Tx.a[10]
Rx$
Exit.i
EndStructure
Import "Kernel32.lib"
CancelIoEx(hFile.i, *lpOverlapped)
EndImport
Procedure Thread_GetInputReport(*Parameter.ThreadParameter_Structure)
Protected.a Byte
Protected.i OutLen, i, PostIt
Protected *InBuffer
*Parameter\Device = HID::OpenDeviceByPath(*Parameter\DeviceInfo\DevicePath$)
If *Parameter\Device
*InBuffer = AllocateMemory(*Parameter\DeviceInfo\InputReportByteLength)
If *InBuffer
Repeat
If TryLockMutex(*Parameter\Mutex)
If *Parameter\TxLen
HID::SetOutputReport(*Parameter\Device, @*Parameter\Tx, *Parameter\TxLen)
EndIf
UnlockMutex(*Parameter\Mutex)
EndIf
PokeA(*InBuffer, 0) ; the report which is requested
If HID::GetInputReport(*Parameter\Device, *InBuffer, MemorySize(*InBuffer))
*Parameter\Rx$ = ""
PostIt = #False
For i = 1 To MemorySize(*InBuffer)
Byte = PeekA(*InBuffer + i - 1)
If Byte <> 0
PostIt = #True
EndIf
*Parameter\Rx$ + RSet(Hex(Byte), 2, "0") + " "
Next i
If PostIt
PostEvent(#HID_Event_InputReportData, #DataWindow, 0)
WaitSemaphore(*Parameter\Semaphore)
EndIf
EndIf
Until *Parameter\Exit
FreeMemory(*InBuffer)
EndIf
HID::CloseDevice(*Parameter\Device)
EndIf
EndProcedure
Procedure Thread_ReadDevice(*Parameter.ThreadParameter_Structure)
Protected.i InLen, i
Protected *InBuffer
*Parameter\Device = HID::OpenDeviceByPath(*Parameter\DeviceInfo\DevicePath$)
If *Parameter\Device
*InBuffer = AllocateMemory(*Parameter\DeviceInfo\InputReportByteLength)
If *InBuffer
Repeat
InLen = HID::ReadDevice(*Parameter\Device, *InBuffer, MemorySize(*InBuffer))
If InLen
*Parameter\Rx$ = ""
For i = 1 To InLen
*Parameter\Rx$ + RSet(Hex(PeekA(*InBuffer + i - 1)), 2, "0") + " "
Next i
PostEvent(#HID_Event_ReadDeviceData, #DataWindow, 0)
WaitSemaphore(*Parameter\Semaphore)
EndIf
Until *Parameter\Exit
FreeMemory(*InBuffer)
EndIf
hid::CloseDevice(*Parameter\Device)
EndIf
EndProcedure
Procedure Thread_ReadDeviceNonBlocking(*Parameter.ThreadParameter_Structure)
Protected.i BytesTransferred, Result, i
Protected *InBuffer
Protected Overlapp.OVERLAPPED
*Parameter\Device = HID::OpenDeviceByPathNonBlocking(*Parameter\DeviceInfo\DevicePath$)
If *Parameter\Device
*InBuffer = AllocateMemory(*Parameter\DeviceInfo\InputReportByteLength)
If *InBuffer
Repeat
;Debug "non blocking"
If TryLockMutex(*Parameter\Mutex)
If *Parameter\TxLen
HID::WriteDeviceNonBlocking(*Parameter\Device, @*Parameter\Tx[0], *Parameter\TxLen, @Overlapp)
; wait until write is finished
While GetOverlappedResult_(*Parameter\Device, @Overlapp, @BytesTransferred, #False) = #ERROR_IO_INCOMPLETE
Delay(5)
Wend
EndIf
UnlockMutex(*Parameter\Mutex)
EndIf
Result = GetOverlappedResult_(*Parameter\Device, @Overlapp, @BytesTransferred, #False)
If Result <> #ERROR_IO_INCOMPLETE
If Result
If BytesTransferred > 0
*Parameter\Rx$ = ""
For i = 1 To BytesTransferred
*Parameter\Rx$ + RSet(Hex(PeekA(*InBuffer + i - 1)), 2, "0") + " "
Next i
PostEvent(#HID_Event_ReadDeviceNonBlockingData, #DataWindow, 0)
WaitSemaphore(*Parameter\Semaphore)
EndIf
HID::ReadDeviceNonBlocking(*Parameter\Device, *InBuffer, MemorySize(*InBuffer), @Overlapp)
EndIf
EndIf
Until *Parameter\Exit
FreeMemory(*InBuffer)
EndIf
HID::CloseDevice(*Parameter\Device)
EndIf
EndProcedure
;-Main
Define.i Device, BytesTransferred, Result, TxBytes, i, Event, Exit
Define Line$
Define *DeviceInfo
Define.ThreadParameter_Structure InputReportThread, ReadDeviceThread, ReadDeviceNonBlockingThread
NewList InfoList.HID::HID_DeviceInfo()
If HID::Init()
If HID::DeviceInfo(InfoList())
OpenWindow(#MainWindow, 0, 0, 1000, 400, "HID Demo", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
ListIconGadget(#HID_DeviceList, 10, 10, 980, 360, "VID", 40, #PB_ListIcon_FullRowSelect|#PB_ListIcon_AlwaysShowSelection)
AddGadgetColumn(#HID_DeviceList, 1, "PID", 40)
AddGadgetColumn(#HID_DeviceList, 2, "Manufacturer", 100)
AddGadgetColumn(#HID_DeviceList, 3, "Product", 150)
AddGadgetColumn(#HID_DeviceList, 4, "Page", 40)
AddGadgetColumn(#HID_DeviceList, 5, "In", 40)
AddGadgetColumn(#HID_DeviceList, 6, "Out", 40)
AddGadgetColumn(#HID_DeviceList, 7, "Path", 500)
i = 0
ForEach InfoList()
Line$ = RSet(Hex(InfoList()\VendorID), 4, "0") + #LF$
Line$ + RSet(Hex(InfoList()\ProductID), 4, "0") + #LF$
Line$ + InfoList()\Manufacturer$ + #LF$
Line$ + InfoList()\Product$ + #LF$
Line$ + RSet(Hex(InfoList()\UsagePage), 4, "0") + #LF$
Line$ + Str(InfoList()\InputReportByteLength) + #LF$
Line$ + Str(InfoList()\OutputReportByteLength) + #LF$
Line$ + InfoList()\DevicePath$
AddGadgetItem(#HID_DeviceList, i, Line$)
SetGadgetItemData(#HID_DeviceList, i, InfoList())
i + 1
Next
CreateStatusBar(0, WindowID(#MainWindow))
AddStatusBarField(120)
StatusBarText(0, 0, "Found: " + Str(ListSize(InfoList())), #PB_StatusBar_Center)
InputReportThread\Mutex = CreateMutex()
InputReportThread\Semaphore = CreateSemaphore()
ReadDeviceThread\Semaphore = CreateSemaphore()
ReadDeviceNonBlockingThread\Mutex = CreateMutex()
ReadDeviceNonBlockingThread\Semaphore = CreateSemaphore()
;-MainLoop
Repeat
Event = WaitWindowEvent()
Select EventWindow()
Case #MainWindow
Select Event
Case #PB_Event_CloseWindow
Exit = #True
Case #PB_Event_Gadget
Select EventGadget()
Case #HID_DeviceList
If EventType() = #PB_EventType_LeftDoubleClick
InputReportThread\Exit = #False
ReadDeviceThread\Exit = #False
ReadDeviceNonBlockingThread\Exit = #False
*DeviceInfo = GetGadgetItemData(#HID_DeviceList, GetGadgetState(#HID_DeviceList))
InputReportThread\DeviceInfo = *DeviceInfo
ReadDeviceThread\DeviceInfo = *DeviceInfo
ReadDeviceNonBlockingThread\DeviceInfo = *DeviceInfo
OpenWindow(#DataWindow, 0, 0, 640, 200, "HID Demo Data", #PB_Window_SystemMenu|#PB_Window_WindowCentered, WindowID(#MainWindow))
ListIconGadget(#DataInputReport, 10, 10, 200, 150, "Data", 170)
ListIconGadget(#DataReadDevice, 220, 10, 200, 150, "Data", 170)
ListIconGadget(#DataReadDeviceNonBlocking, 430, 10, 200, 150, "Data", 170)
InputReportThread\Thread = CreateThread(@Thread_GetInputReport(), @InputReportThread)
ReadDeviceThread\Thread = CreateThread(@Thread_ReadDevice(), @ReadDeviceThread)
ReadDeviceNonBlockingThread\Thread = CreateThread(@Thread_ReadDeviceNonBlocking(), @ReadDeviceNonBlockingThread)
EndIf
EndSelect
EndSelect
Case #DataWindow
Select Event
Case #HID_Event_InputReportData
AddGadgetItem(#DataInputReport, 0, InputReportThread\Rx$)
SignalSemaphore(InputReportThread\Semaphore)
Case #HID_Event_ReadDeviceData
AddGadgetItem(#DataReadDevice, 0, ReadDeviceThread\Rx$)
SignalSemaphore(ReadDeviceThread\Semaphore)
Case #HID_Event_ReadDeviceNonBlockingData
AddGadgetItem(#DataReadDeviceNonBlocking, 0, ReadDeviceNonBlockingThread\Rx$)
SignalSemaphore(ReadDeviceNonBlockingThread\Semaphore)
Case #PB_Event_CloseWindow
InputReportThread\Exit = #True
ReadDeviceThread\Exit = #True
ReadDeviceNonBlockingThread\Exit = #True
If IsThread(InputReportThread\Thread)
If WaitThread(InputReportThread\Thread, 1000) = 0
Debug "Need to kill InputReportThread"
KillThread(InputReportThread\Thread)
EndIf
EndIf
If IsThread(ReadDeviceThread\Thread)
CancelIoEx(ReadDeviceThread\Device, #Null) ; to cancel the blocking read
If WaitThread(ReadDeviceThread\Thread, 1000) = 0
Debug "Need to kill ReadDeviceThread"
KillThread(ReadDeviceThread\Thread)
EndIf
EndIf
If IsThread(ReadDeviceNonBlockingThread\Thread)
If WaitThread(ReadDeviceNonBlockingThread\Thread, 1000) = 0
Debug "Need to kill ReadDeviceNonBlockingThread"
KillThread(ReadDeviceNonBlockingThread\Thread)
EndIf
EndIf
CloseWindow(#DataWindow)
EndSelect
EndSelect
Until Exit
Else
MessageRequester("HID Demo", "No HID device found!")
EndIf
HID::Close()
EndIf
CompilerEndIf
I also tried the hidapi lib, but they are also still miss something what I need.
I adopted the HID tool of User_Russian to this version, but at the moment I have no access to this code.
I will add a demo at the end of the module.
The demo shows the principal of non blocking read with the possibility to write something to the device.
In a normal program this is inside of a thread, where you 'inject' the buffer to send via the thread parameters.
Re: how to use hidapi please help
I also showing a way to cancel a blocking read inside of a child thread.
To avoid a KillThread().
To avoid a KillThread().
- Kwai chang caine
- Always Here
- Posts: 5494
- Joined: Sun Nov 05, 2006 11:42 pm
- Location: Lyon - France
Re: how to use hidapi please help
That works here i see my three Usb DD
Thanks for sharing

Thanks for sharing


Not a destination