Author Topic: How to "poll" the InputReport  (Read 16317 times)

jglawrence

  • Member
  • ***
  • Posts: 13
How to "poll" the InputReport
« on: June 24, 2011, 02:30:06 pm »
Hello,

I'm trying to find a way to write code that will display an input report in my application when the USB device has one ready to send.  I am using HID drivers.

I am using VS2005 and started off with Jan Axelson's Visual C++ HID USB application.

So far I am using the code below which uses a button that the user clicks to activate.  While this is running the application becomes mostly unusable though (busy reading input reports), it looks for reports even when there are none available, and preferably there would not need to be a button click at all.  The user would open the program and from then on, if the device has an input report ready, it displays it to the user.

My current code for "accomplishing" this:
void CUsbhidiocDlg::OnBnClickedcontrx()
{
   //Try defining new receive function that polls only the input reports
   ReadInputReport();

   //Enable the timer to cause periodic exchange of reports.
   //The second parameter is the number of milliseconds between report requests.

   SetTimer(ID_CLOCK_TIMER, 10000, NULL);
}


Thanks for any and all help!
« Last Edit: June 24, 2011, 03:19:54 pm by jglawrence »

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: How to "poll" the InputReport
« Reply #1 on: June 24, 2011, 11:37:33 pm »
The HID driver continuously polls for Input data and stores received reports in a buffer. ReadFile retrieves data from the buffer; it doesn't cause the device to send data. The application doesn't know in advance if data is ready. To keep from blocking, use a thread that attempts to read data continuously and notifies the main thread when data is available.

Jan

jglawrence

  • Member
  • ***
  • Posts: 13
Re: How to "poll" the InputReport
« Reply #2 on: July 01, 2011, 12:12:11 pm »
I'll have to read about programming with multiple threads, that is a new topic for me but sounds like the best solution.

I am trying to understand exactly what HidD_SetNumInputBuffers does.  This is how I assume it now, please correct me if I am wrong.
It allows you to collect X amount of input reports from your device at once by instructing Windows to store X amount of input reports in the HID driver input buffer.  I would guess your readfile buffer would then have to be long enough to accept X amount of input reports which can be found by (input report length) * X = readfile buffer array size.

Is this correct?

Thanks!

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: How to "poll" the InputReport
« Reply #3 on: July 01, 2011, 12:31:43 pm »
Yes, HidD_SetNumInputBuffers sets the size of the HID driver's buffer in units of reports (8 means the buffer can store 8 reports). An application can still read reports one at a time if it wants to and if it can do so fast enough to get them all (assuming it's important to get every report). Using a big buffer and retrieving multiple reports at once if available is quicker.

Jan

jglawrence

  • Member
  • ***
  • Posts: 13
Re: How to "poll" the InputReport
« Reply #4 on: July 01, 2011, 12:59:47 pm »
I suppose I could use HidD_SetNumInputBuffers in combination with ReadFileEx to get all input reports when they're available as soon as they're available?

The thing I don't understand, and this is probably because of my lack of knowledge dealing with multiple thread, is what notifies the main or calling thread that there is an input report ready?  Is it ReadFileEx itself or do you have to have a check inside the thread as to whether or not ReadFileEx returned successfully and if it did, notify the calling thread?

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: How to "poll" the InputReport
« Reply #5 on: July 01, 2011, 03:01:36 pm »
The completion routine you specified when calling ReadFileEx runs.

Jan

jglawrence

  • Member
  • ***
  • Posts: 13
Re: How to "poll" the InputReport
« Reply #6 on: July 05, 2011, 06:19:36 pm »
I've created a thread for my program however I am running into a lot of "Debug Assertion Failed" errors when trying to call MFC controls from the thread.  For instance, if I call ReadInputReport() from the thread I created, it will fail in the DisplayLastError function when the function sets the text for the listbox.

I am including the code in which I declare my thread and define it below.  If you could help me located a better place for this code that can avoid these issues that would be great!
Thanks!
Declaration of thread:

class CUsbhidiocDlg : public CDialog
{
// Construction
public:
   CUsbhidiocDlg(CWnd* pParent = NULL);   // standard constructor

// Dialog Data
   //{{AFX_DATA(CUsbhidiocDlg)
   enum { IDD = IDD_USBHIDIOC_DIALOG };
   CEdit m_BytesRX;
   CEdit   m_InputReportBufferSize;
   CEdit m_BytesToSend;
   CButton   m_Continuous;
   CListBox   m_BytesReceived;
   CListBox   m_ResultsList;
   CButton   m_Once;
   CString   m_ResultsString;
   CString   m_strBytesReceived;
   CString m_strReceivedData;
   int      m_ReportType;
   BOOL   m_UseControlTransfersOnly;
   CString   m_ProductIDString;
   CString   m_VendorIDString;
   static void _cdecl Thread1( PVOID pdwC );
...


CUsbhidiocDlg::CUsbhidiocDlg(CWnd* pParent /*=NULL*/) : CDialog(CUsbhidiocDlg::IDD, pParent)
{
   //{{AFX_DATA_INIT(CUsbhidiocDlg)
   m_ResultsString = _T("");
   m_strBytesReceived = _T("");
   //m_BytesToSend   = _T("");
   m_strReceivedData      = _T("");
   m_ReportType = 0;
   m_UseControlTransfersOnly = FALSE;
   m_ProductIDString = _T("5346");
   m_VendorIDString = _T("B6A");
   //m_InputReportBufferSize = _T("64");
   //}}AFX_DATA_INIT
   // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
   m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
   hThread1 = _beginthread( Thread1, 0, this );
}


My thread:

void _cdecl CUsbhidiocDlg::Thread1( PVOID pdwC )
{
   
   CUsbhidiocDlg *pDlg;
   pDlg = (CUsbhidiocDlg *)pdwC;

   while(TRUE) {
      WaitForSingleObject(hEventObject, INFINITE);
      ResetEvent(hEventObject);
      pDlg->ReadInputReport(pDlg);
   }
}

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: How to "poll" the InputReport
« Reply #7 on: July 06, 2011, 09:59:05 am »
A search on

mfc thread dialog

might bring some helpful discussions.

Jan