>>Assuming there are no other bugs in the libusbxhid library, for writing data 
>>you have to guess the reportType (in, out, feature) and reportNum parameter 
>>and set the report data buffer correctly (first byte is the report number) 
>>for your device. Have a look at similar devices.

I don't know if there is a bug or not... but I "Think" I have the information I 
need.  I found this device documented here:
https://github.com/rubienr/machinekit/tree/feature-xhc-whb04b-6/src/hal/user_comps/xhc-whb04b-6

it states:  "Data transmitted is packed as 7 bytes plus a constant leading byte 
0x06 which is the report ID. The data exclusive report ID reads as follows:"
this matches the python code I was trying to duplicate...  so I send a $06 then 
7 bytes of data  at a time.  It also describes the data structure as well.

The C code at 
https://github.com/rubienr/machinekit/blob/feature-xhc-whb04b-6/src/hal/user_comps/xhc-whb04b-6/usb.cc
Uses libusb... here is the relevant section:  It's in C but it's commented 
pretty well..  and describes the exact parameters passed to 
libusb_control_transfer

void Usb::sendDisplayData()
{
    outputPackageBuffer.asBlocks.init(&outputPackageData);
    if (mIsSimulationMode)
   {
        *verboseTxOut << "out   0x" << outputPackageBuffer.asBlocks << endl <<
                      std::dec << "out   size " << 
sizeof(outputPackageBuffer.asBlockArray) << "B " << outputPackageData
                      << endl;
    }

    for (size_t idx = 0; idx < (sizeof(outputPackageBuffer.asBlockArray) / 
sizeof(UsbOutPackageBlockFields)); idx++)
    {
        UsbOutPackageBlock& block = outputPackageBuffer.asBlockArray[idx];
        size_t blockSize = sizeof(UsbOutPackageBlock);
        // see also
        // http://www.beyondlogic.org/usbnutshell/usb6.shtml
        // http://libusb.sourceforge.net/api-1.0/group__desc.html
        // http://libusb.sourceforge.net/api-1.0/group__misc.html
        int    r         = libusb_control_transfer(deviceHandle,
            // send to hid descriptor: bmRequestType == LIBUSB_DT_HID == 0x21 
== (interface | endpoint)
                                                   LIBUSB_DT_HID,
            // bRequest == LIBUSB_REQUEST_SET_CONFIGURATION == 0x09 == set 
configuration
                                                   
LIBUSB_REQUEST_SET_CONFIGURATION,
            // wValue: if bRequest == LIBUSB_REQUEST_SET_CONFIGURATION the 
configuration value
                                                   0x0306,
            // wIndex, device interface number
                                                   0x00,
            // data to transmit
                                                   block.asBuffer.asBytes,
            // wLength, data length
                                                   blockSize,
            // transfer timeout[ms]
                                                   0);

        if (r < 0)
        {
            std::cerr << "transmission failed, try to reconnect ..." << endl;
            setDoReconnect(true);
            return;
        }
    }
}


So I tried with libusbxhid: 
libusbhid_set_report(device_context, HID_REPORT_TYPE_FEATURE, $6 , 8 , 
WhB04_Packet )
and I get  control transfer to usb device failed!

so inside function libusbhid_set_report, I put a bunch of writelns to show what 
is being passed to libusb_control_transfer:
  Writeln('device handle =');
  Writeln('bmRequestType = $', inttohex(LIBUSB_CONTROL_REQUEST_TYPE_OUT,4));
  Writeln('bRequest      = $', inttohex(HID_SET_REPORT,4)                 );
  Writeln('wValue        = $', inttohex((reportType << 8) or reportNum,4) );
  Writeln('wIndex        = $', 0                                          );
  Writeln('data          = ',  '$'+Inttohex(report_data[0],2),' 
$'+Inttohex(report_data[1],2),' $'+Inttohex(report_data[2],2),' 
$'+Inttohex(report_data[3],2),' $'+Inttohex(report_data[4],2),' 
$'+Inttohex(report_data[5],2),
                              ' $'+Inttohex(report_data[6],2),' 
$'+Inttohex(report_data[7],2));
  Writeln('wLength       = $', Inttohex(reportLen,2)                      );
  Writeln('timeout       = $', 0                                          );
  
Result:=libusb_control_transfer(hid_device_context.usb_device_handle,LIBUSB_CONTROL_REQUEST_TYPE_OUT{????},HID_SET_REPORT,(reportType
 << 8) or reportNum, 0{interface_num}, @report_data, 
reportLen{sizeof(data)},0{no timeout});

Suspend
06  FD  FE  FF  01  02  03  04
device handle =
bmRequestType = $0021
bRequest      = $0009
wValue        = $0306
wIndex        = $0
data          = $06 $FD $FE $FF $01 $02 $03 $04
wLength       = $08
timeout       = $0
control transfer to usb device failed!
-1
It shows I'm getting the same values for everything....  but yet it's still 
failing.  I have this attempt on my fork at 
https://github.com/Zaaphod/libusbxhid



I'm not sure it's libusbxhid though.. because I also can't get it to work with 
pas-libusb  I can run test3controlasync.pas with my device and it does send a 
request to the device and retrieves some information from it... so I modified 
that program (test3controlasync_2.pas)  to just pass the same paramaters as 
above and then it doesn't work anymore... here's the output from 
test3controlasync_2.pas

Running 
"i:\programming\pas-libusb_test_dll\src\examples\test3controlasync_2.exe "
Submitting control transfer
Finished Transfer, Data = 38, Status = 0, ActualLength = 18
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor            $10CE
  idProduct           $EB93
  bcdDevice            1.00
  iManufacturer           1
  iProduct                0
  iSerialNumber           0
  bNumConfigurations      1
Done.
CT.bmRequestType = 21
CT.bRequest      = 09
CT.wValue        = 306
CT.wIndex        = 00
CT.wLength       = 07
CT.Timeout       = 00
Submitting control transfer
USB Error: Submit: LIBUSB_ERROR_IO: LIBUSB_ERROR_IO  

So it worked for the first information request (the default one including with 
the original test2controlasync.pas) , but not for my attempted request..  this 
leads me to believe that I have something wrong and  it's not a bug...  but I'm 
lost as to what it might be..  my attempt is on my fork here: 
https://github.com/Zaaphod/pas-libusb/blob/Hack/src/examples/test3controlasync_2.pas

 
>> One thing I'm really not sure how to handle with threads is this....  ok so 
>> I have my main fast read thread going in the tightest loop possible... but 
>> now I want to write something to the display (assuming I ever figure that 
>> out and don't just put a sticker over the display and look at the screen 
>> instead :D  )  It seems I would have to stop reading to get a chance to 
>> write something..  I did a little test and I can do  a suspend(Thread_ID) 
>> and resume(Thread_ID)  but what if it's in the middle of a read.. but only 
>> got 6 of the 8 bytes when I do the suspend??  Now I am not really ready to 
>> write..... so what method can I use to do a 
>> suspend_thread_just_before_the_next_read_happens() ?  so that when the 
>> thread is suspended, the read is completed and the buffer updated.. etc.. 
>> and the USB system and libusb are all ready for me to send my write 
>> commands?  Resuming would be no problem.. because it was suspended at the 
>> correct position.. I can just resume when I am done with the write and 
>> everything should be fine.

>My guess is that it would be better to leave the time sensitive read 
>thread to do the fast reads and immediate calculations and leave writing 
>to the device screen in a separate thread (even main thread), with a 
>lower update frequency!

Yes, that was what I was attempting to describe.. but I can't write to the usb 
device if the read thread happens to be in the middle of a read... so how do I 
pause the read thread at the correct time so it's not partially in the middle 
of reading a packet, and I can't read again until I'm done writing.  I figure I 
can just check for some period of time of idle handwheel input before I stop 
the read thread and do the write then start the read thread again, because only 
the handwheel produces such a large stream of data.. but still I’m not sure how 
to make sure I stop it at the correct time.

James
_______________________________________________
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

Reply via email to