EEVblog Electronics Community Forum

Products => Computers => Programming => Topic started by: franrgb on September 14, 2020, 07:15:36 pm

Title: Libusb in Qt creator
Post by: franrgb on September 14, 2020, 07:15:36 pm
Hi everybody, how are you?

I was working on adapting a project to work libusb with Qt using an microcontroller as a device. the project in question is this link:

https://wiki.kucia.net/doku.php?id=projects:qtusb

I wrote an email to the owner of the project and for reasons of time I recommended this forum.
It works correctly, but it has limitations that are the reason why I am here today.

the code uses to write:
Code: [Select]
libusb_bulk_transfer(this->APK, 0x01, buf, sizeof(buf), &bytes, 100); // escribir en endpoint

and to read:
Code: [Select]
libusb_bulk_transfer(this->APK, 0x81, buf, sizeof(buf), &bytes, 100); // leer el endpoint

The idea is to try to connect a slot through which a function can be called to read when the host own the buffer.

In other libraries uses like:

Code: [Select]
connect(puerto, [b]SIGNAL(readyRead())[/b], this, SLOT(intRs232()));
or:
Code: [Select]
connect(timer, SIGNAL(timeout()), this, SLOT(intTimer()));

in this way you do not need to ask the microcontroller to send data, but rather, constantly receive frames, but, I did not find information about libusb signals

I need help from the Qt and libusb side because the microcontroller code works and does not affect the problem itself.

kind regards from Argentina.

More information:
Host side:
Desktop Qt 5.14.2 MinGW 64-bit (C++)
USB Bulk using libusb
Windows 10

Device side:
MPLAB X - XC8
Microchip PIC18F2550
Without USB libraries
Title: Re: Libusb in Qt creator
Post by: janoc on September 14, 2020, 09:01:24 pm
Hello,

That signal/slot mechanism is totally Qt specific. Other libraries don't use it, that's why you didn't find any information on libusb signals - there aren't any.

If you want to use libusb in this manner, you will need to make a wrapper around it that will read the data from the device using libusb API and generate the signals whenever new data is received.

One way to do it would be to run a QTimer instance, on every timeout do a non-blocking USB read and if you have received the data you are waiting for, emit a signal.

Or you could run the libusb code in a separate thread - but then be very careful and make sure to read the part of Qt documentation on signals and slots across threads or you could have nasty bugs.
Title: Re: Libusb in Qt creator
Post by: franrgb on September 24, 2020, 05:14:00 pm
Thank you very much @janoc for your answer. I am currently working with the QTimer, I just thought it could be improved.
In GitHub there is a QTUSB library, I did not start to review it, but maybe it will solve this compatibility of Slots.

if interrupt is used instead of buck, then sync problems could occur if you repeatedly have to query whether data was received.
or does the interupt method only work with host -> device communications?


Least important query:

Do you know why Windows does not take the icons or labels from the feature-descriptor? I pass the icon path as "2 - unicode string with environment variables" like everyone else does, but it doesn't seem to take effect. I thought as a quick test, assign an icon as binary format, but I don't know if it is supported.

if the binary format supports icons, passing the icon directly from the MCU and not having to know the path of the dlls seems like a very good idea.

Long ago I wrote a RAW converting application that I used to convert .ccs to .js files for ESP8266., a matter of trying to make it work.

attached:
(https://i.ibb.co/MSz7RvX/putH.png) (https://ibb.co/MSz7RvX)

thanks again for your time. successes!
Title: Re: Libusb in Qt creator
Post by: janoc on September 24, 2020, 09:10:36 pm
if interrupt is used instead of buck, then sync problems could occur if you repeatedly have to query whether data was received.
or does the interupt method only work with host -> device communications?

Interrupt vs bulk are not something you can arbitrarily choose, that is defined by the device you are attempting to talk to. Interrupt is also a misnomer because all USB is based on the host controller repeatedly polling the attached devices. It has nothing to do with CPU interrupts but with things such as bandwidth and latency guarantees.

The differences are explained here:
https://www.beyondlogic.org/usbnutshell/usb4.shtml (https://www.beyondlogic.org/usbnutshell/usb4.shtml)

Least important query:

Do you know why Windows does not take the icons or labels from the feature-descriptor? I pass the icon path as "2 - unicode string with environment variables" like everyone else does, but it doesn't seem to take effect. I thought as a quick test, assign an icon as binary format, but I don't know if it is supported.

if the binary format supports icons, passing the icon directly from the MCU and not having to know the path of the dlls seems like a very good idea.

AFAIK, the standard descriptors don't provide means to supply any icons. The icon that the OS shows depends on the device class that the descriptor declares and possibly any HID descriptor if it is a HID device (keyboard vs mouse vs joystick, etc.).

Microsoft has defined some Microsoft-specific extensions which apparently can handle icons but that is Windows specific nonstandard hack. See here for documentation:

https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors (https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors)

No idea how well that is supported - Windows isn't exactly known for following standards, so even though something is legal and correct according to the USB spec, it may not work with Windows unless you do it in the exactly one specific way that Windows understands (e.g. HID descriptors in Windows are notorious for this).
Title: Re: Libusb in Qt creator
Post by: Nominal Animal on September 25, 2020, 01:35:55 am
The simplest option is to use one or two QThread (https://doc.qt.io/qt-5/qthread.html)s.
One QThread reads from the device.  Whenever it has a complete block or multiple blocks of data, it emits the data using a Qt signal. 
The other QThread writes to the device.  It implements a slot that writes data to the device.
Both of these are trivial "worker" threads, with a suitable skeleton shown in the QThread documentation.

For query-response communications, without asynchronous responses from the device (i.e., the device won't send any data except as a response to a query), you implement a single QThread.  Comparing to the QThread worker example, you implement the slot (doWork() in the example) to do one query-response round, with the response emitted as a signal.

Anticipated question: Why the need for separate threads?

If the query-response comms are done in the main thread, nothing else can happen during the query-response cycle.

Technically, you can do the two-QThread solution with writes to the device in the main thread, but buffering may become an issue.  Depending on the underlying libusb implementation, the write may block until all data has been sent to the device.

Obviously, the continuous read/receive thread must be a separate thread, so that you can use a blocking read/receive for the data.  (This also maximizes the read/receive bandwidth on most OSes; you should be able to do full high-speed USB (480 Mbit/s, or about 49 Mbytes/second), on almost any host hardware.)

There is some overhead in Qt signal/slot mechanism, so you'll want to carefully consider how small/large chunks of data you deliver in each signal/slot call.  To maximize bandwidth, I'd target 10 to 100 signal calls per second; to minimize latency (for smaller amounts of data), I would consider up to 1000 signal calls per second.  Anything above is waste of resources, really.
Title: Re: Libusb in Qt creator
Post by: franrgb on September 25, 2020, 06:52:21 pm
Hello, thanks for answering.

Microsoft has defined some Microsoft-specific extensions which apparently can handle icons but that is Windows specific nonstandard hack. See here for documentation:
https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors (https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors)

I read the documentation you mention, I am not very clear on how to implement it, I cannot find examples, the host does not request the OS 2.0, I suppose that the header has to be sent in the feature descriptors like WINUSB descriptor ID. I will read more carefully.

(https://i.ibb.co/tc0Sdjq/uDebu.png) (https://ibb.co/tc0Sdjq)
(https://i.ibb.co/hmZdfsM/Sin-t-tulo.png) (https://ibb.co/hmZdfsM)

The simplest option is to use one or two QThread (https://doc.qt.io/qt-5/qthread.html)s.

Hi! thanks for joining! I never worked with Qthreads, I'm going to find out how to implement something simple before using it on USB.

Did ever use MOS 2.0 descriptors?

I hope they are well, greetings from AR
Title: Re: Libusb in Qt creator
Post by: janoc on September 25, 2020, 07:17:55 pm
Hello, thanks for answering.

I read the documentation you mention, I am not very clear on how to implement it, I cannot find examples, the host does not request the OS 2.0, I suppose that the header has to be sent in the feature descriptors like WINUSB descriptor ID. I will read more carefully.


Sorry, can't help you with this one, I have never implemented a device that used these extensions. I don't think I have even seen one like that before.

Personally, I wouldn't bother, because this is liable to get broken whenever Microsoft updates something. Furthermore, it is not needed for the correct functioning of your device. Focus on getting the device actually working, that is going to both much more complex to do (especially given that you don't seem to have much experience here) and more important than whether or not Windows shows your custom icon.