mikeobrien / HidLibrary

This library enables you to enumerate and communicate with Hid compatible USB devices in .NET.
MIT License
586 stars 228 forks source link

ReadReport loosing data #77

Open DevLocus opened 7 years ago

DevLocus commented 7 years ago

It seems like ReadReport is loosing data when a lot of data is sent to the Host in a short amount of time. In my case about 60KB to 100KB is being sent at full speed on a USB 2.0 port in high speed mode. This is likely because the buffer is too small and the ReadReport function takes too long. I see there is a HidFastReadDevice with a faster read function, but no way to create an instance of the class. There is also nothing exposed in the OpenDevice function to allow overriding the default buffer size to fit the application.

What is the best fix for this? Do I need to download the source code and change it myself?

amullins83 commented 7 years ago

The latest code on the master branch includes the HidFastReadEnumerator class that will instantiateHidFastReadDevice objects.

DevLocus commented 7 years ago

I ending up adding the below code to the HidDevices.cs file to get around the issue. It turned out the buffer was too small and this code allows me to change the buffer to a more reasonable number for my application.

public int InputBuffer { get { int i = 0; NativeMethods.HidD_GetNumInputBuffers(Handle, ref i); return i; } set { if (value > 31) { NativeMethods.HidD_SetNumInputBuffers(Handle, value); } else { throw new ArgumentOutOfRangeException(string.Concat(value, " is too low of a value.")); } } }

vostrenkov commented 4 years ago

I have similar issue with fast incoming data. My device sends reports with two different ReportId, each report sending cycle is 5ms. But host PC lose some of them: image I'd say it is HID device issue, but i can see all reports coming in Wireshark. I use HidFastReadDevice and FastReadReport, but not sure if i do it right:

        static public void Connect(HidDevice device)
        {
            hidDevice = device;

            HidFastReadEnumerator enumerator = new HidFastReadEnumerator();
            fastDevice = (HidFastReadDevice)enumerator.GetDevice(hidDevice.DevicePath);

            if (!fastDevice.IsOpen)
            {
                fastDevice.OpenDevice();

                hidDevice.MonitorDeviceEvents = true;
                hidDevice.Inserted += HidDeviceAddedEventHandler;
                hidDevice.Removed += HidDeviceRemovedEventHandler;

                fastDevice.MonitorDeviceEvents = false;
                fastDevice.FastReadReport(ReadReportCallback);
            }
        }

        static private void ReadReportCallback(HidReport report)
        {
            HidReport hr = report;

            // wait for new packet
            if (fastDevice.IsConnected)
            {
                fastDevice.FastReadReport(ReadReportCallback);
            }

            Console.WriteLine("Report " + hr.ReportId + " received " + Environment.TickCount);
            // raise event for received packet
            PacketReceived?.Invoke(hr);
        }
amullins83 commented 4 years ago

The purpose of the "Fast" subclass was to avoid checking "IsConnected" every time a packet comes in. The check is fairly slow (I can't remember why, I haven't touched this in years). I would say try it without the IsConnected check.

Also, why are you turning MonitorDeviceEvents on and off?

vostrenkov commented 4 years ago

Thank you for the fast answer. I have tried this without checking IsConnected and looks like receiving works better though my GUI is stalling when HID device connected. I guess i should find a way to run all HID stuff in other thread to fix it.

I thought DeviceEvents are different for instances of HidDevice and HidFastReadDevice (and HidDevice is passed to the event as argument) so i decided to monitor plugging/unplugging through hidDevice (HidDevice instance) while reading/writing is managed through fastDevice (HidFastReadDevice instance). It seem not working quite good but i want to reach proper report receiving first