1

Topic: HidSharp write: 'Operation failed early: The parameter is incorrect'

Hello,

I have a USB scanner for bar codes/QR codes/MRZ.
I have a user manual from the manufacturer, which contains a set of QR codes that allow me to configure the device.
For example by scanning the following values:

$>:S01010F.<$ (Enter Setup)
$>: S0F0516.<$ (USB HID POS)
$>:S01000F.<$ (Exit Setup)

I was able to switch the device to "USB HID POS" mode. (default mode being "USB HID-KBW" in which the scanner behaves like a keyboard)
In this mode I am able to read scanned data using the HidSharp library.

However I also need to be able to change the settings of the device programmatically. But when I call stream.Write, I always get the following exception:

System.IO.IOException: 'Operation failed early: The parameter is incorrect'

Stack trace:
at HidSharp.Platform.Windows.NativeMethods.OverlappedOperation(IntPtr ioHandle, IntPtr eventHandle, Int32 eventTimeout, IntPtr closeEventHandle, Boolean overlapResult, NativeOverlapped* overlapped, UInt32& bytesTransferred)

There's an inner exception that just says Win32Exception: 'The parameter is incorrect' (no stack trace)

Info about the device:

// hdev.ToString() + " | " + hdev.DevicePath
Linux 3.10.14 with dwc2-gadget hidpos 00000000 (VID 4619, PID 33287, version 3.10) | \\?\hid#vid_120b&pid_8207#7&52366e0&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}

(the device itself has "Linux" in the name, I'm currently running Windows 10)

The following is an enumeration over the device's Reports:

Max Lengths: Input 64, Output 64, Feature 0
Serial Ports:
1 device items found.
Usage: 8C0001 9175041
Input: ReportID=2, Length=64, Items=1
63 Elements x 8 Bits, Units: None, Expected Usage Type: 0, Flags: Variable, BufferedBytes, Usages: 8C00FE 9175294
Output: ReportID=4, Length=64, Items=1
63 Elements x 8 Bits, Units: None, Expected Usage Type: 0, Flags: Variable, Relative, Nonlinear, Volatile, Usages: 8C0000 9175040

What I'm trying to do:

Assuming the device supports receiving setup commands, and that these are the same as the commands from the QR codes, I've been trying to send the following commands to the device (one at a time):

01010F (Enter Setup)
0C0814 (Set external illumination to "Always on")
01000F (Exit Setup)

NOTE: I've tried sending it in the format $>:S01010F.<$ and S01010F, but I suspect those are just some tags telling the QR parser it's a command, and the actual command is the 6 digit hex string.

I've tried creating the input buffer diretly:
var enterSetupBuffer = Encoding.ASCII.GetBytes("01010F");

I've tried creating a byte array of size 64 and setting the first few bytes in the array:
var someBuffer = new byte[64];
someBuffer[0] = 0x01;
someBuffer[1] = 0x01;
someBuffer[2] = 0x0F;
(and some variations on this)

no matter what I do, I get the same error: Operation failed early: The parameter is incorrect.
Some more details: I try to write using the HidStream.Write(buffer). I attempt the write before I start reading from the device. stream.CanWrite is returning true.

As you've probably guessed, I'm not good with hardware. I'm primarily a business application developer. All my attempts so far have been pretty much guesswork. I don't even know if it's the device rejecting my attempts at communication, or if there's something else I don't even know about tripping me up before the data is even sent to the device.

Any help would be greatly appreciated.

2

Re: HidSharp write: 'Operation failed early: The parameter is incorrect'

The first byte of any HID packet is its Report ID.
(The only exception, on a hardware level, is when Report ID is 0, but HIDSharp abstracts out that so you don't need to worry about it.)
So if the Output Report is Report ID 4, to target that Report ID, the first byte of your packet needs to be 4. This is why it says "63 elements" but the packet length is 64.

https://usb.org/sites/default/files/pos1_02.pdf might be worth downloading, but probably won't help you. Usage 8C0000 on the Output Report means 'undefined', so presumably the formatting is specific to the scanner, but at any rate if you start your packets with 4, it'll at least get past Windows and to the scanner.

Good luck with it.

God bless.

James

3

Re: HidSharp write: 'Operation failed early: The parameter is incorrect'

Hi, thank you for your response. I had already been told about the Report ID on StackOverfow, and by setting the Report ID I managed to write to the scanner without getting an exception. However, no matter what I did I wasn't able to get the device to change its settings.

I contacted the device manufacturer, they provided a Linux library that translates string commands from the user guide (like $>: S0F0516.<$) and sends them to the device. It works great.

However, I have another potential problem. I'm using continuous read based on your code under

#elif THREAD_POOL_RECEIVED_EVENT_APPROACH
in HidSharp.Test

Task.Run(() =>
{
    using (hidStream)
    {
        var inputReportBuffer = new byte[dev.GetMaxInputReportLength()];
        var inputReceiver = reportDescriptor.CreateHidDeviceInputReceiver();
        var inputParser = deviceItem.CreateDeviceItemInputParser();

        inputReceiver.Received += (sender, e) =>
        {
            Report report;
            while (inputReceiver.TryRead(inputReportBuffer, 0, out report))
            {
                RaiseReadEvent(Encoding.Default.GetString(inputReportBuffer));

            }
        };
        inputReceiver.Start(hidStream);
        while (!ct.IsCancellationRequested)
        {
            Thread.Sleep(1000);
        }
    }
}, ct);

I made some modifications, as I want it to run indefinitely, until I stop it.

During testing I found out it's mostly OK to send commands to the scanner while the read loop is active. However if I play around with it too much, sometimes it breaks. Scanned data stops coming to the inputReceiver, and starts being spat into the console. In this state even stopping and restarting the read loop doesn't help, I have to kill the application and restart it.

Do you have any idea what's causing this? Do you think it's because if I try long enough, I manage to hit a time window where I write to the device just as it's trying to read?

In any case, my new plan is as follows:
The read loop won't run all the time, just when a scan is expected (which I guess I should have done from the start). My new process:

1. Make sure the read loop is deactivated
2. Write to scanner (Beeper ON, lights ON)
3. Activate read loop
...
4. Deactivate read loop
5. Write to scanner (Beeper OFF, lights OFF) 

I hope this will help prevent my issues. 

I would also like to ask about the Thread.Sleep() bit. Your sample has Thread.Sleep(2000), I changed it my code to 1000ms. I don't remember my reasoning behind it. Do you think I could go even lower? I want to send the cancellation token before every write just to be on the safe side, and I don't want to wait 1 second. Is 500ms OK? How about 200 or 100? Will it cause performance issues? Why did you choose 2 seconds?

Finally, now that I've described what I'm doing and how, do you have any other advice or insight?

Thank you.