PORTS Forum
Ports and Interfaces => USB => Topic started by: sd on January 16, 2019, 09:08:12 pm
-
Hi Jan,
I'm here again asking for your help! I'm trying to develop host application on Windows 10 machine for my Bluetooth Low Energy HID Device. I am referring to https://docs.microsoft.com/en-us/uwp/api/windows.devices.humaninterfacedevice.hiddevice. Everything works upto the enumeration part. But SendOutputReportAsync() isnt actually sending data to my ble hid device. [https://docs.microsoft.com/en-us/uwp/api/windows.devices.humaninterfacedevice.hidoutputreport] Please guide me on how do I proceed ahead or some direction on how to write host application from scratch. Am I looking into the wrong place? I can confirm that the firmware works because I tested it with nrfConnect software.
-
Use whatever debugging tools you have to isolate the problem.
In the host application, use single-stepping, watch variables, error codes, etc. to monitor what is happening.
A protocol analyzer will show if the host is sending Output reports on the bus.
The host may use interrupt or control transfers to send Output reports depending on whether the HID has an interrupt OUT endpoint.
-
Sure. Will generic_hid_cs_62 code work with BLE HID device? I can see declarations & definitions nicely explained in the book. Code compiles error-free and also the generated GUI finds the BLE HID device, but how do I make it send/receive reports?
-
On the host side:
If using WriteFile or Filestreams for Output reports, be sure the buffer matches the size of a defined Output report + 1. The first byte should contain the report ID. Use zero if no report IDs defined.
If using ReadFile or Filestreams for Input reports, be sure the buffer is at least as large as the largest defined Input report + 1. The first received byte will contain the report ID, zero if no report IDs defined.
On the device side:
Be sure the IN endpoint is configured to send data on receiving an IN token packet.
Be sure the OUT endpoint is configured to receive data on receiving an OUT token packet.
How to do this varies with the chip architecture.
-
Thank you for this important tip!! So I changed report id = 1 in RequestToSendOutputReport() and got the output as shown in attachment. But I do not see this data on my BLE HID device. What do you think could be the problem? Also in the comments for functions used for input report, it is mentioned that it assumes report id =0. So where do I change the report id used for input report?
-
The report ID is the first byte in the buffer.
Be sure the OUT endpoint is configured to receive data on receiving an OUT token packet.
-
Hi Jan,
I'm able to receive data from BLE HID device on Windows machine using nrfConnect & SimpleHIDWrite as shown the attached images. But how different is generic_hid_cs_v62 code? Do you think I can make any changes in this code instead of firmware?
-
With a hardware-based protocol analyzer, you can view any differences on the bus between the working and nonworking code.
Otherwise, use any debugging tools you have to verify that the complete data is going out on the bus and the device storing the received data.
-
I tried debugging and inserting some debug statements but its not really helping. Can you give me a direction to write an API for BLE HID device from scratch?
-
In addition to my code, my HID page has links to HID host code from other sources:
http://www.janaxelson.com/hidpage.htm
-
I have 3rd and 5th editions of your book. I have pasted the code which I'm trying to use with my BLE HID device. The pasted vendor ID & product ID are the original ones, practically its different. The commented part gives errors on Windows 10. The handle to BLE device is not getting fetched.
#include <iostream>
#include <windows.h>
#include <hidclass.h>
#include <hidsdi.h>
#include <setupapi.h>
#include <devguid.h>
#include <regstr.h>
#pragma comment(lib,"hid")
int main()
{
GUID HidGuid;
HidD_GetHidGuid(&HidGuid);
HANDLE DeviceInfoSet;
DeviceInfoSet = SetupDiGetClassDevs(&HidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
BOOLEAN Result;
SP_DEVICE_INTERFACE_DATA MyDeviceInterfaceData;
MyDeviceInterfaceData.cbSize = sizeof(MyDeviceInterfaceData);
DWORD MemberIndex = 0;
Result = SetupDiEnumDeviceInterfaces(DeviceInfoSet, 0, &HidGuid, MemberIndex, &MyDeviceInterfaceData);
PSP_DEVICE_INTERFACE_DETAIL_DATA DetailData;
ULONG Length;
Result = SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, &MyDeviceInterfaceData, NULL, 0, &Length, NULL);
DetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(Length);
DetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
Result = SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, &MyDeviceInterfaceData, DetailData, Length, &Length, NULL);
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
HANDLE DeviceHandle;
DeviceHandle = CreateFile(DetailData->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, 0, NULL);
CloseHandle(DeviceHandle);
/*HDEVNOTIFY DeviceNotificationHandle;
DEV_BROADCAST_DEVICEINTERFACE DevBroadcastDeviceInterface;
DevBroadcastDeviceInterface.dbcc_size = sizeof(DevBroadcastDeviceInterface);
DevBroadcastDeviceInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
DevBroadcastDeviceInterface.dbcc_classguid = HidGuid;
DeviceNotificationHandle = RegisterDeviceNotification(m_hWnd, &DevBroadcastDeviceInterface, DEVICE_NOTIFY_WINDOW_HANDLE);
BOOL CUsbhidiocDlg::OnDeviceChange(WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
case DBT_DEVICEARRIVAL:
// Find out if the device path name matches wParam. If yes, perform any tasks required on device attachment.
return TRUE;
case DBT_DEVICEREMOVECOMPLETE:
// Find out if the device path name matches wParam. If yes, perform any tasks required on device removal.
return TRUE;
default:
return TRUE;
}
}
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
if (lpdb->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
{
PDEV_BROADCAST_DEVICEINTERFACE lpdbi = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
CString DeviceNameString;
DeviceNameString = lpdbi->dbcc_name;
if((DeviceNameString.CompareNoCase(DetailData > DevicePath)) == 0)
{
// The names match.
}
else
{
// It’s a different device.
}
}
UnregisterDeviceNotification(DeviceNotificationHandle);*/
HIDD_ATTRIBUTES Attributes;
Attributes.Size = sizeof(Attributes);
Result = HidD_GetAttributes(DeviceHandle, &Attributes);
const unsigned int VendorID = 0x0925;
const unsigned int ProductID = 0x1234;
if (Attributes.VendorID == VendorID)
{
if (Attributes.ProductID == ProductID)
{
std::cout << "The Vendor ID and Product ID match.";
}
else
{
std::cout << "The Product ID doesn't match.";
CloseHandle(DeviceHandle); // Close the handle.
}
}
else
{
std::cout << "The Vendor ID doesn't match.";
CloseHandle(DeviceHandle); // Close the handle.
}
}
I'm also getting an error --->>>> Exception thrown at 0x1F60E78A in api1.exe: 0xC0000008: An invalid handle was specified.
-
It looks like you are closing the handle immediately after requesting it:
DeviceHandle = CreateFile(DetailData->DevicePath, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, 0, NULL);
CloseHandle(DeviceHandle);
-
I tried commenting that but does not work.
Also if I comment the CloseHandle here, I do not get exception error.
std::cout << "The Vendor ID doesn't match.";
CloseHandle(DeviceHandle); // Close the handle.
But I am not able to detect my device by polling against vendorId & productId.
-
Earlier you said you were detecting the device with my example code? So I suggest comparing your code with that.
-
Hey Jan,
I could easily understand and play with your Visual C++ code snippets in 3rd edition. But I cannot compile your visual C++ code put up on the website. Also I cannot think of making any changes to the Visual C# code, so I decided to rewrite everything starting from basics, that way I can get a clear understanding and find where the problem actually lies instead of working in loops and hitting a dead end. I made some progress. Here is my simple code -
#include <iostream>
#include <windows.h>
#include <hidclass.h>
#include <hidsdi.h>
#include <setupapi.h>
#include <devguid.h>
#include <regstr.h>
#pragma comment(lib,"hid")
int main()
{
GUID HidGuid;
HidD_GetHidGuid(&HidGuid);
//HANDLE DeviceInfoSet;
HDEVINFO DeviceInfoSet;
DeviceInfoSet = SetupDiGetClassDevs(&HidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
/**/
if(DeviceInfoSet== INVALID_HANDLE_VALUE)
return NULL;
SP_DEVICE_INTERFACE_DATA MyDeviceInterfaceData;
MyDeviceInterfaceData.cbSize = sizeof(MyDeviceInterfaceData);
SP_DEVINFO_DATA dd;
dd.cbSize = sizeof(SP_DEVINFO_DATA);
HANDLE DeviceHandle=NULL;
for (DWORD MemberIndex = 0; SetupDiEnumDeviceInterfaces(DeviceInfoSet, 0, &HidGuid, MemberIndex, &MyDeviceInterfaceData); MemberIndex++)
{
SP_DEVICE_INTERFACE_DETAIL_DATA DetailData;
DetailData.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
DWORD Length = 0;
if (!SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, &MyDeviceInterfaceData, NULL, 0, &Length, NULL))
{
int err = GetLastError();
if (err == ERROR_NO_MORE_ITEMS)
break;
PSP_DEVICE_INTERFACE_DETAIL_DATA pInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)GlobalAlloc(GPTR, Length);
pInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (!SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, &MyDeviceInterfaceData, pInterfaceDetailData, Length, &Length, &dd))
break;
DeviceHandle = CreateFile(pInterfaceDetailData->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, 0, NULL);
HIDD_ATTRIBUTES Attributes;
Attributes.Size = sizeof(Attributes);
HidD_GetAttributes(DeviceHandle, &Attributes);
const unsigned int VendorID = 0x1F38;
const unsigned int ProductID = 0x0100;
if (Attributes.VendorID == VendorID)
{
if (Attributes.ProductID == ProductID)
{
std::cout << "The Vendor ID and Product ID match.";
std::cout << "\nDeviceHandle: " << DeviceHandle;
std::cout << "\nVendor ID: " << Attributes.VendorID;
std::cout << "\nProduct ID: " << Attributes.ProductID;
std::cout << "\nVersionNumber: " << Attributes.VersionNumber;
std::cout << "\nSize: " << Attributes.Size;
PHIDP_PREPARSED_DATA PreparsedData;
HidD_GetPreparsedData(DeviceHandle, &PreparsedData);
HIDP_CAPS Capabilities;
HidP_GetCaps(PreparsedData, &Capabilities);
std::cout << "\nUsage: " << Capabilities.Usage;
std::cout << "\nUsagePage: " << Capabilities.UsagePage;
std::cout << "\nInputReportByteLength: " << Capabilities.InputReportByteLength;
std::cout << "\nOutputReportByteLength: " << Capabilities.OutputReportByteLength;
std::cout << "\nNumberLinkCollectionNodes: " << Capabilities.NumberLinkCollectionNodes;
std::cout << "\nNumberInputButtonCaps: " << Capabilities.NumberInputButtonCaps;
std::cout << "\nNumberInputValueCaps: " << Capabilities.NumberInputValueCaps;
std::cout << "\nNumberInputDataIndices: " << Capabilities.NumberInputDataIndices;
std::cout << "\nNumberOutputButtonCaps: " << Capabilities.NumberOutputButtonCaps;
std::cout << "\nNumberOutputValueCaps: " << Capabilities.NumberOutputValueCaps;
std::cout << "\nNumberOutputDataIndices: " << Capabilities.NumberOutputDataIndices;
CHAR InputReportBuffer[3];
DWORD BytesRead;
DWORD Result;
HANDLE hEventObject;
OVERLAPPED HIDOverlapped;
hEventObject = CreateEvent((LPSECURITY_ATTRIBUTES)NULL, FALSE, TRUE, NULL);
HIDOverlapped.hEvent = hEventObject;
HIDOverlapped.Offset = 0;
HIDOverlapped.OffsetHigh = 0;
// Set the first byte in the buffer to the Report ID.
InputReportBuffer[0] = 0;
HANDLE ReadHandle = CreateFile(pInterfaceDetailData->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); //NULL, NULL);
if (ReadHandle == INVALID_HANDLE_VALUE)
std::cout << "\ncould not open";
else
std::cout << "\nopened";
Result = ReadFile(ReadHandle, InputReportBuffer, Capabilities.InputReportByteLength, &BytesRead, (LPOVERLAPPED)&HIDOverlapped); //NULL);
Result = WaitForSingleObject(hEventObject, 3000);
switch (Result)
{
case WAIT_OBJECT_0:
{
std::cout << "\nBytesRead: " << BytesRead;
std::cout << "\nInputReportBuffer: " << InputReportBuffer;
// Success;
// Use the report data;
break;
}
case WAIT_TIMEOUT:
{
std::cout << "\nBytesRead: " << BytesRead;
std::cout << "\nInputReportBuffer: " << InputReportBuffer;
// Timeout error;
//Cancel the read operation.
CancelIo(ReadHandle);
break;
}
default:
{
std::cout << "\nBytesRead: " << BytesRead;
std::cout << "\nInputReportBuffer: " << InputReportBuffer;
// Undefined error;
//Cancel the read operation.
CancelIo(ReadHandle);
break;
}
}
}
}
GlobalFree(pInterfaceDetailData);
}
}
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
}
I am able to obtain handle to my device but not able to read any data. Upto CreateFile() everything works fine. Also how can I get information about endpoint/s? Is there any HID function for that?
I tried using
1. Result = HidD_GetInputReport(ReadHandle, InputReportBuffer, Capabilities.InputReportByteLength);
if (Result)
std::cout << "\nsuccess";
else
std::cout << "\nfail";
2. Result = ReadFile(ReadHandle, InputReportBuffer, Capabilities.InputReportByteLength, &BytesRead, NULL); //(LPOVERLAPPED)&HIDOverlapped);
if (Result)
{
std::cout << "\nBytesRead: " << BytesRead;
std::cout << "\nInputReportBuffer[1]" << InputReportBuffer[1];
std::cout << "\nInputReportBuffer[2]" << InputReportBuffer[2];
std::cout << "\nInputReportBuffer[3]" << InputReportBuffer[3];
}
else
std::cout << "\nfail1";
Both print out 'fail'. I also tried changing InputReportBuffer[0] to 0 and 1, just in case.
-
HidP_GetCaps returns report information, which is all you should need to read reports:
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/hidpi/nf-hidpi-hidp_getcaps
HidD_GetInputReport requires device support for a Get Report control transfer.
The ReadFile buffer should be as long as the longest Input report + 1 byte.
The error code for the failure might help isolate the problem.
-
Cool Thanks!
I need to use HidD_GetInputReport(). So by device support you mean from the host side or BLE device? I'm pretty sure my BLE device sends Input reports using control transfers. When InputReportBuffer[0] = 0, I received an error code of 87 (which is I guess ERROR_INVALID_PARAMETER). When InputReportBuffer[0] = 1, I received an error code of 122 (which is I guess ERROR_INSUFFICIENT_BUFFER).
If I use ReadFile(), I received an error code of 997 (ERROR_IO_PENDING).
I have pasted my new code & output. What is NumberInputValueCaps? Is it the number of endpoints? How do I use Get Report control transfer? Is there anything I'm missing out in my code? I also tried setting last 2 parameters in CreateFile() to NULL but did not work.
#include <iostream>
#include <windows.h>
#include <hidclass.h>
#include <hidsdi.h>
#include <setupapi.h>
#include <devguid.h>
#include <regstr.h>
#pragma comment(lib,"hid")
int main()
{
GUID HidGuid;
HidD_GetHidGuid(&HidGuid);
//HANDLE DeviceInfoSet;
HDEVINFO DeviceInfoSet;
DeviceInfoSet = SetupDiGetClassDevs(&HidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if(DeviceInfoSet== INVALID_HANDLE_VALUE)
return NULL;
SP_DEVICE_INTERFACE_DATA MyDeviceInterfaceData;
MyDeviceInterfaceData.cbSize = sizeof(MyDeviceInterfaceData);
SP_DEVINFO_DATA dd;
dd.cbSize = sizeof(SP_DEVINFO_DATA);
HANDLE DeviceHandle=NULL;
for (DWORD MemberIndex = 0; SetupDiEnumDeviceInterfaces(DeviceInfoSet, 0, &HidGuid, MemberIndex, &MyDeviceInterfaceData); MemberIndex++)
{
SP_DEVICE_INTERFACE_DETAIL_DATA DetailData;
DetailData.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
DWORD Length = 0;
if (!SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, &MyDeviceInterfaceData, NULL, 0, &Length, NULL))
{
int err = GetLastError();
if (err == ERROR_NO_MORE_ITEMS)
break;
PSP_DEVICE_INTERFACE_DETAIL_DATA pInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)GlobalAlloc(GPTR, Length);
pInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (!SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, &MyDeviceInterfaceData, pInterfaceDetailData, Length, &Length, &dd))
break;
DeviceHandle = CreateFile(pInterfaceDetailData->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, 0, NULL);
HIDD_ATTRIBUTES Attributes;
Attributes.Size = sizeof(Attributes);
HidD_GetAttributes(DeviceHandle, &Attributes);
const unsigned int VendorID = 0x1F38;
const unsigned int ProductID = 0x0100;
if (Attributes.VendorID == VendorID)
{
if (Attributes.ProductID == ProductID)
{
std::cout << "The Vendor ID and Product ID match.";
std::cout << "\nDeviceHandle: " << DeviceHandle;
std::cout << "\nVendor ID: " << Attributes.VendorID;
std::cout << "\nProduct ID: " << Attributes.ProductID;
std::cout << "\nVersionNumber: " << Attributes.VersionNumber;
std::cout << "\nSize: " << Attributes.Size;
PHIDP_PREPARSED_DATA PreparsedData;
HidD_GetPreparsedData(DeviceHandle, &PreparsedData);
HIDP_CAPS Capabilities;
HidP_GetCaps(PreparsedData, &Capabilities);
std::cout << "\nUsage: " << Capabilities.Usage;
std::cout << "\nUsagePage: " << Capabilities.UsagePage;
std::cout << "\nInputReportByteLength: " << Capabilities.InputReportByteLength;
std::cout << "\nOutputReportByteLength: " << Capabilities.OutputReportByteLength;
std::cout << "\nNumberLinkCollectionNodes: " << Capabilities.NumberLinkCollectionNodes;
std::cout << "\nNumberInputButtonCaps: " << Capabilities.NumberInputButtonCaps;
std::cout << "\nNumberInputValueCaps: " << Capabilities.NumberInputValueCaps;
std::cout << "\nNumberInputDataIndices: " << Capabilities.NumberInputDataIndices;
std::cout << "\nNumberOutputButtonCaps: " << Capabilities.NumberOutputButtonCaps;
std::cout << "\nNumberOutputValueCaps: " << Capabilities.NumberOutputValueCaps;
std::cout << "\nNumberOutputDataIndices: " << Capabilities.NumberOutputDataIndices;
CHAR InputReportBuffer[3];
DWORD BytesRead;
DWORD Result;
HANDLE hEventObject;
OVERLAPPED HIDOverlapped;
hEventObject = CreateEvent((LPSECURITY_ATTRIBUTES)NULL, FALSE, TRUE, NULL);
HIDOverlapped.hEvent = hEventObject;
HIDOverlapped.Offset = 0;
HIDOverlapped.OffsetHigh = 0;
InputReportBuffer[0] = 0; // Report Id
HANDLE ReadHandle = CreateFile(pInterfaceDetailData->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); //NULL, NULL);
if (ReadHandle == INVALID_HANDLE_VALUE)
std::cout << "\ncould not open"; //printf("Warning: CreateFile failed: %d\n", GetLastError());
else
std::cout << "\nopened";
Result = HidD_GetInputReport(ReadHandle, InputReportBuffer, Capabilities.InputReportByteLength);
DWORD err = GetLastError();
std::cout << "\nerr: " << err;
if (Result)
{
std::cout << "\nSuccess";
for (int i = 0; i < Capabilities.InputReportByteLength; i++)
{
std::cout << "\nInput Report Data: " << InputReportBuffer[i];
}
}
else
std::cout << "\nFailed to get report";
}
}
GlobalFree(pInterfaceDetailData);
}
}
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
}
-
HidD_GetInputReport requires device/firmware support for a Get Report control transfer.
ERROR_INVALID_PARAMETER suggests there is something wrong with the parameters your function is passing.
ERROR_INSUFFICIENT_BUFFER says your buffer is too small, must be at least as large as the largest Input report + 1.
ERROR_IO_PENDING suggests the host isn't receiving data.
NumberInputValueCaps defined here:
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/hidpi/ns-hidpi-_hidp_caps
A HID always has 1 interrupt IN endpoint and may have 1 interrupt OUT endpoint.
HidD_GetInputReport initiates a Get Report control transfer.
-
Thanks! As most of the times I end up getting ERROR_INVALID_PARAMETER, so how do I solve it? How do I define the 2nd parameter to be passed in HidD_GetInputReport()? I tried using malloc for InputReportBuffer & also tried using as a pointer, but nothing seems to work according to definition of HidD_GetInputReport().
-
see
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/hidsdi/nf-hidsdi-hidd_getinputreport
My code passes a pointer to a byte array.
The final parameter should be the length of that buffer + 1.
-
Right so how do I do that in Visual C++? I tried different declarations as below but could not get through. I had also included that +1 factor.
1.
const unsigned char a = 0;
const unsigned char *InputReportBuffer;
InputReportBuffer = &a;
2.
unsigned char InputReportBuffer[20];
memset(InputReportBuffer, 0, 20);
3.
ULONG bufferSize;
bufferSize = sizeof(Capabilities.InputReportByteLength);
PUCHAR InputReportBuffer = (PUCHAR) malloc(bufferSize);
if (!InputReportBuffer)
{
printf("malloc failed\n");
}
-
see if this helps
https://github.com/Microsoft/Windows-driver-samples/blob/master/hid/vhidmini2/app/testvhid.c
-
Hey Jan, during my google searches I had stumbled upon this code and I played with it but I'm getting the same 87 & 122 errors.
Also WriteFile is successfully sending data to BLE device but I cant see it on the device. Why so?
Will reading raw data help?
Even your code generic_Hid_cs_v62 does not work with BLE HID custom device.
-
If the data is going out on the bus, be sure the HID's interrupt OUT endpoint is configured to accept data. How to do that varies with the chip architecture. Use whatever debugging tools you have to find out what happens when data arrives at the device.
InputReportBuffer[0] should equal the report ID for the desired report or zero if report IDs not used.
-
Hey Jan,
Everything works now! I just had one more question to ask, how do I send 20 byte output report? I know that I should assign values in outputReportBuffer but in the UI only a byte is being sent.
-
Perhaps your function call is passing only the first byte of the array, not the full array.
-
Sorry my bad. I was using your code - generic_hid_cs_v62. So in that I'm able to read 20 bytes of input report. Please guide me on how to send 20 bytes output report.
-
The Microsoft example above should work.