[fpc-pascal] USB Human Interface Devices

James Richters james at productionautomation.net
Sun Aug 18 21:58:58 CEST 2019


As far as reading it goes, things are going pretty well.. I still have yet to write to the display.. I can't get any of my attempts to send data to it to be successful at all.. I get "control transfer to usb device failed!"

Thanks for the advice on a thread safe queue!  

For the moment I've been trying to do the math inside thread reading the usb device... it's pretty simple, and that allows me to read the totals at any time.. but I can see what you mean that if I just read the device and dump everything into maybe some kind of ring buffer without bothering to try to process it at all, and increment the buffer position then it could be ready to read again even faster.  I could have my other slow process crunch the buffer.   I have two of these devices, one is wireless, the other has a USB cable attached to it.. they both work a little differently.. the wireless one only responds to my interrupt read when some data has been generated... the wired version always responds to my request whether any data has been generated  or not.  For that one I would have to do a compare on the data to see if anything changed before adding to the buffer otherwise the buffer would always be overrun.  

Still I can't image my math is taking very long.. here is what I am doing:
	Read device
	If wheel moved then add wheel counts to appropriate variable then read device
	Else
	Update other variables if they changed then read device
So when the wheel is moving I have very few instructions between reads.. I don't bother checking for buttons or anything else.. I just keep accumulating the total, and that's all I care about, and then I read again.. I only bother with the buttons if the wheel didn't move.

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.

I also still am hoping to find a method of making the device wait for me to read it... even with threads in my program, the operating system could go off and do something that takes all the processor time for a second and I would just not know about events that happened during that time.

James


-----Original Message-----
From: fpc-pascal <fpc-pascal-bounces at lists.freepascal.org> On Behalf Of Stefan V. Pantazi
Sent: Sunday, August 18, 2019 3:12 PM
To: fpc-pascal at lists.freepascal.org
Subject: Re: [fpc-pascal] USB Human Interface Devices

James,

 From the looks of it you made good progress reading the hardware and using a dedicated thread for it. Congrats! Seems you're in the thick of it now ready to get the minute details sorted out.

Anyway, just a heads up that concurrent programming (threads, synchronization, etc) has many pitfalls.

My armchair guess is that your program is just not reading fast enough to keep up with the rate of data that the hardware is generated. Having time sensitive code in a separate thread is a good idea but you should also store the report data in an adequately sized and thread safe data structure such as a thread-safe list/queue. FreePascal has something you could use
(https://www.freepascal.org/docs-html/rtl/classes/tthreadlist.html) and although dynamically allocated, it may be fast enough for your purposes. 
Thread safety is crucial to avoid multiple threads overwriting the data structures they share. The way I see it, your timing sensitive hardware reading thread would fill up the queue and then, every so often, your main thread would consume the data from it. You have to also imagine mechanisms to check that one can keep up with the other and signal errors when that is not the case.

Hope this helps, and good luck!


More information about the fpc-pascal mailing list