[fpc-pascal] USB Human Interface Devices

James Richters james at productionautomation.net
Sun Aug 18 18:05:20 CEST 2019


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


More information about the fpc-pascal mailing list