Author Topic: SendOutputReportAsync not sending data to ble hid device  (Read 25804 times)

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: SendOutputReportAsync not sending data to ble hid device
« Reply #15 on: February 01, 2019, 10:20:10 am »
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.

sd

  • Member
  • ***
  • Posts: 17
Re: SendOutputReportAsync not sending data to ble hid device
« Reply #16 on: February 01, 2019, 02:32:35 pm »
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.

Code: [Select]
#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);
}
« Last Edit: February 01, 2019, 04:34:31 pm by sd »

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: SendOutputReportAsync not sending data to ble hid device
« Reply #17 on: February 02, 2019, 11:57:58 am »
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.

sd

  • Member
  • ***
  • Posts: 17
Re: SendOutputReportAsync not sending data to ble hid device
« Reply #18 on: February 02, 2019, 04:54:21 pm »
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().

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: SendOutputReportAsync not sending data to ble hid device
« Reply #19 on: February 03, 2019, 12:29:54 pm »
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.

sd

  • Member
  • ***
  • Posts: 17
Re: SendOutputReportAsync not sending data to ble hid device
« Reply #20 on: February 03, 2019, 01:08:39 pm »
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");
}

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research

sd

  • Member
  • ***
  • Posts: 17
Re: SendOutputReportAsync not sending data to ble hid device
« Reply #22 on: February 04, 2019, 03:41:13 pm »
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.
« Last Edit: February 05, 2019, 06:10:11 pm by sd »

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: SendOutputReportAsync not sending data to ble hid device
« Reply #23 on: February 06, 2019, 11:01:16 am »
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.

sd

  • Member
  • ***
  • Posts: 17
Re: SendOutputReportAsync not sending data to ble hid device
« Reply #24 on: February 07, 2019, 08:06:03 pm »
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.

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: SendOutputReportAsync not sending data to ble hid device
« Reply #25 on: February 08, 2019, 09:57:21 am »
Perhaps your function call is passing only the first byte of the array, not the full array.

sd

  • Member
  • ***
  • Posts: 17
Re: SendOutputReportAsync not sending data to ble hid device
« Reply #26 on: February 08, 2019, 01:25:21 pm »
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.

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: SendOutputReportAsync not sending data to ble hid device
« Reply #27 on: February 09, 2019, 07:48:25 pm »
The Microsoft example above should work.