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@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
--
_______________________________________________________
_______________________________________________
fpc-pascal maillist - fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal