[fpc-pascal] USB Human Interface Devices

Stefan V. Pantazi svpantazi at gmail.com
Sun Aug 18 21:11:33 CEST 2019


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!

On 8/18/19 12:05 PM, James Richters wrote:
> I have a question about USB data transfer.. but it's going to take some explanation...
> 
> I've been doing more testing with my device and Libusbxhid.  Here's the device: https://www.amazon.com/gp/product/B07M5ZY1P2
> 
> I have all the inputs working,  still have to figure out how to output to the LCD...  I've implemented a test program that shows what button I have pressed, and it also processes the switches and handwheel properly...  The hand wheel has 100 indents on it, and if I rotated it clockwise, it gives me a positive count, and if I rotate it counter-clockwise, it gives me two's compliment representation of a negative count, it only sends a single byte, and the number it sends is the number of ticks since the last time it reported....  so it would have to be read at least every 127 ticks.
> 
> ok.. so I got that all working but then I discovered an issue...  I thought the count on the hand wheel was the number of ticks since the last time I got the report... because if I turn the when very slow, I only get 1 or -1... but if I turn it faster, I get larger numbers... but once I got it reporting the total count... I found that if I start with the wheel at the 0 mark, and turn it really slow, it will count exactly 100 times when it returns to the zero point.. but if I got at even a slow (but not ridiculous) speed, then the count would come up short, and if I turned it fast, it would come up really short...
> 
> So I tried a test,  and disabled the writeln to the console... and now it is much more accurate.. at slow and medium speeds it is exact but at really fast speeds it is still slightly short.  So I thought this would be a great use for a thread!   So I looked into it.. and I guess in windows I don't even need a unit to run a thread.. I just need to define a function and do a BeginThread() to run the function in a thread... well I didn't think it would be THAT easy.. but yes it works!   Now I'm going to have threads everywhere LOL.  I have the thread running the tightest possible loop to just read the data and store it in the fastest way possible so it can get back to reading again... then outside the thread I read the variables once every 5 seconds and just put where it is... well this improved things greatly, and I will probably use the thread method in the final program... but one thing is still bugging me... it's just not 100% exact all the time, even with the thread method, I still miss count here and there...
> 
> So back to the in-line code with writeln's of a minute...   I tried another test... this time I read the device as normal, then I put a huge delay in.. 5 seconds or so, then I started reading it again.. now if my previous theory was correct, then I should be able to give up to 127 pulses during the delay and it would show the total since the last report... but that's not what happened.. it just forgets about whatever happened during the delay....I was careful to only do 1/2 rotation which would be about 50 pulses so I know I didn't make it overflow.... so this behavior makes me think I am not reading it the correct way.... it's like it sends the report out every so often whether I am reading it or not.. and when I do read it I get whatever count it is since the last OUTPUT, even if I missed the last output... also if I push a button and release it during the delay, I have no indication it was ever pressed.
> 
> So my question is..  does this behavior suggest that the device is expecting some other transfer method that would guarantee synchronization?   I see in pas-libusb there are test2controlsync and test test3controlasync  I'm curious if synchronous transfer would be the way to communicate with the device that would guarantee no data loss.  I don't really understand how either of these work, but one is sync and the other is async, so I thought maybe sync was more the method I should be using.   My program in libusbxhid is using:
> 
> hidReportData[reportIdx].dataLen:=libusbhid_interrupt_read(device_context,$81{endpoint},{out}hidReportData[reportIdx].hid_data,64{report length, varies by device}, {timeout=}3000);
> 
> Maybe it's not either of those.. but some other method where the device pushes data into a buffer whenever it wants that I can then read.. or something like that?  Or maybe the interrupt read is the best I can do?  Is there any way to give my read thread to have a higher priority or something like that?
> 
> Any thoughts?
> 
> 
> 
> James
> _______________________________________________
> fpc-pascal maillist  -  fpc-pascal at lists.freepascal.org
> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
> 

-- 
_______________________________________________________


More information about the fpc-pascal mailing list