USB Human Interface Devices

classic Classic list List threaded Threaded
165 messages Options
1 ... 3456789
Reply | Threaded
Open this post in threaded view
|

Re: USB Human Interface Devices

Zaaphod
Oops,  I got mixed up.. it's usb.pas that isn't used anymore... I changed LibUsb to stdcall and not it compiles again.. but I still get he access violation with stdcall.

James


> from the copy of your github, looks like libusboop.pas has a uses statement for libusb.pas; so libusb.pas is still used

> https://github.com/Zaaphod/pas-libusb/blob/Hack/src/libusboop.pas (line 30)

>Uses
>   Classes, SysUtils, LibUsb;

_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: USB Human Interface Devices

Stefan V. Pantazi
Is the segfault in the same place or has it changed?

To debug further, you have to compare sizes of data structures, field
types and function call parameter types between the libusb 1.0 and the
old libusb0.1. - any mismatch could result in a segfault.


On 8/17/19 3:51 PM, James Richters wrote:

> Oops,  I got mixed up.. it's usb.pas that isn't used anymore... I changed LibUsb to stdcall and not it compiles again.. but I still get he access violation with stdcall.
>
> James
>
>
>> from the copy of your github, looks like libusboop.pas has a uses statement for libusb.pas; so libusb.pas is still used
>
>> https://github.com/Zaaphod/pas-libusb/blob/Hack/src/libusboop.pas (line 30)
>
>> Uses
>>    Classes, SysUtils, LibUsb;
>
> _______________________________________________
> fpc-pascal maillist  -  [hidden email]
> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
>

--
_______________________________________________________
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: USB Human Interface Devices

Johann Glaser
In reply to this post by Jean SUZINEAU
Hi!

Am Samstag, den 17.08.2019, 16:16 +0200 schrieb Jean SUZINEAU:

> Le 17/08/2019 à 15:00, James Richters a écrit :
> > Function TLibUsbInterface.FindEndpoint(MatchFunc :
> > TLibUsbEndpointMatchMethod) : Plibusb_endpoint_descriptor;
> > MatchFunc(ED) is where the access violation occurs, but I can’t
> > trace any further because I can’t find the function MatchFunc()   I
> > just don’t understand where the actual function is.
>
> MatchFunc is a parameter (its type is TLibUsbEndpointMatchMethod) of
> TLibUsbInterface.FindEndpoint.
> To find which function is actually called, you should trace back
> where TLibUsbInterface.FindEndpoint is called and what function is
> provided as parameter MatchFunc.
> It's likely you'll have to "climb up" through several calls, may be
> that TLibUsbInterface.FindEndpoint has itself a parameter MatchFunc
> If you use the debugger, the callstack and a breakpoint just before
> the offending call to MatchFunc should help you to find from where
> comes your MatchFunc.
> I wouldn't be surprised that it resolves somewhere to an overridden
> method Match of an instance of a class derived from
> TLibUsbDeviceMatchClass, likely TLibUsbDeviceMatchVidPid.Match,
> TLibUsbDeviceMatchVidPidSerial.Match or
> TLibUsbInterfaceMatchNumAlt.Match from unit libusbutil.pas
> This can sound difficult  for you at the beginning if you're not too
> much accustomed with variables of type procedure and inheritance, but
> after a few practice it's not that complicated.

Thanks Jean for the explanation! The MatchFunc is a so called
"callback". I've chosen this pattern to allow to implement flexible
filter functions when searching for devices, interfaces, endpoints, ...

As far as I can see, you are using TMyDevice in mydevice.pas. This unit
is specifically implemented for the EZ-USB chips (Cypress AN2131),
which do not have Flash or ROM, but only SRAM. The driver has to
download the firmware before the real communication. This specific
behavior is demonstrated in mydevice.pas. Therefore it is only of
limited use for your device.

One action of TMyDevice.Create is to open an interface and then two
bulk endpoints (see lines 141-145 in your "Hack" branch. The interface
can be opened (hence you see an 'e' in your output. Then wants to open
the endpoint 2 (line 143) using
TLibUsbInterface.FindEndpoint(bEndpointAddress : Byte) at
libusboop.pas:1099. This calls via some detours the function where
you've added the WriteLns.

Actually all these functions should reside cleanly in the Pascal world
and there are no calls to libusb functions, therefore I wouldn't expect
any calling convention troubles here.

Could you please remove the try-except block in
testopendevic_vidpid2.pas and compile with debug line info to get the
full exception backtrace incl. line numbers?

Thanks
  Hansi


_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: USB Human Interface Devices

Zaaphod
I commented out all the try & except stuff and ran it.. I get this output:


Running "i:\programming\pas-libusb_test_dll\src\examples\testopendevic_vidpid2.exe "
start
1
2
a05472131
a10CEEB93
b
c
FALSE  8086  10CE  A36D  EB93
FALSE  8087  10CE  0AAA  EB93
FALSE  0424  10CE  2734  EB93
FALSE  1D50  10CE  6015  EB93
FALSE  1B1C  10CE  0C15  EB93
TRUE  10CE  10CE  EB93  EB93
FALSE  05E3  10CE  0610  EB93
FALSE  04E8  10CE  61F5  EB93
FALSE  1B1C  10CE  0C10  EB93
FALSE  0424  10CE  274C  EB93
FALSE  047D  10CE  1020  EB93
FALSE  1B1C  10CE  1B4F  EB93
FALSE  1A40  10CE  0101  EB93
FALSE  0C45  10CE  7403  EB93
FALSE  10C4  10CE  EA60  EB93
d
e
N
P
L
H1
I
I2
Q
R
K
M
O1
An unhandled exception occurred at $000000010002D0BB:
EAccessViolation: Access violation
  $000000010002D0BB  CREATE,  line 1330 of libusboop.pas
  $000000010002B3AB
  $0000000100001942  main,  line 75 of ../../pas-libusb_test_dll/src/examples/testopendevic_vidpid2.pas
  $0000000100001AF6  main,  line 96 of ../../pas-libusb_test_dll/src/examples/testopendevic_vidpid2.pas
  $0000000100010040
  $00000001000017F0
  $00007FFB66D07E94
  $00007FFB675FA251




>>Could you please remove the try-except block in testopendevic_vidpid2.pas and compile with debug line info to get the full exception backtrace incl. line numbers?
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: USB Human Interface Devices

Johann Glaser
Hi!

Am Samstag, den 17.08.2019, 18:00 -0400 schrieb James Richters:
> I commented out all the try & except stuff and ran it.. I get this
> output:

Could you please "git push" the source code to Github so that the line
numbers match the output? At least in line 1330 of libusboop.pas there
is no Create. Please ensure that the version on Github is the very same
version where you executed the program and got the line numbers.

Thanks
  Hansi

> Running "i:\programming\pas-
> libusb_test_dll\src\examples\testopendevic_vidpid2.exe "
> start
> 1
> 2
> a05472131
> a10CEEB93
> b
> c
> FALSE  8086  10CE  A36D  EB93
> FALSE  8087  10CE  0AAA  EB93
> FALSE  0424  10CE  2734  EB93
> FALSE  1D50  10CE  6015  EB93
> FALSE  1B1C  10CE  0C15  EB93
> TRUE  10CE  10CE  EB93  EB93
> FALSE  05E3  10CE  0610  EB93
> FALSE  04E8  10CE  61F5  EB93
> FALSE  1B1C  10CE  0C10  EB93
> FALSE  0424  10CE  274C  EB93
> FALSE  047D  10CE  1020  EB93
> FALSE  1B1C  10CE  1B4F  EB93
> FALSE  1A40  10CE  0101  EB93
> FALSE  0C45  10CE  7403  EB93
> FALSE  10C4  10CE  EA60  EB93
> d
> e
> N
> P
> L
> H1
> I
> I2
> Q
> R
> K
> M
> O1
> An unhandled exception occurred at $000000010002D0BB:
> EAccessViolation: Access violation
>   $000000010002D0BB  CREATE,  line 1330 of libusboop.pas
>   $000000010002B3AB
>   $0000000100001942  main,  line 75 of ../../pas-
> libusb_test_dll/src/examples/testopendevic_vidpid2.pas
>   $0000000100001AF6  main,  line 96 of ../../pas-
> libusb_test_dll/src/examples/testopendevic_vidpid2.pas
>   $0000000100010040
>   $00000001000017F0
>   $00007FFB66D07E94
>   $00007FFB675FA251
>
>
>
>
> > > Could you please remove the try-except block in
> > > testopendevic_vidpid2.pas and compile with debug line info to get
> > > the full exception backtrace incl. line numbers?
> _______________________________________________
> fpc-pascal maillist  -  [hidden email]
> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: USB Human Interface Devices

Zaaphod
I just pushed it.

>Could you please "git push" the source code to Github so that the line numbers match the output? At least in line 1330 of libusboop.pas there is no Create. Please ensure that the
>version on Github is the very same version where you executed the program and got the line numbers.

Thanks
  Hansi

> Running "i:\programming\pas-
> libusb_test_dll\src\examples\testopendevic_vidpid2.exe "
> start
> 1
> 2
> a05472131
> a10CEEB93
> b
> c
> FALSE  8086  10CE  A36D  EB93
> FALSE  8087  10CE  0AAA  EB93
> FALSE  0424  10CE  2734  EB93
> FALSE  1D50  10CE  6015  EB93
> FALSE  1B1C  10CE  0C15  EB93
> TRUE  10CE  10CE  EB93  EB93
> FALSE  05E3  10CE  0610  EB93
> FALSE  04E8  10CE  61F5  EB93
> FALSE  1B1C  10CE  0C10  EB93
> FALSE  0424  10CE  274C  EB93
> FALSE  047D  10CE  1020  EB93
> FALSE  1B1C  10CE  1B4F  EB93
> FALSE  1A40  10CE  0101  EB93
> FALSE  0C45  10CE  7403  EB93
> FALSE  10C4  10CE  EA60  EB93
> d
> e
> N
> P
> L
> H1
> I
> I2
> Q
> R
> K
> M
> O1
> An unhandled exception occurred at $000000010002D0BB:
> EAccessViolation: Access violation
>   $000000010002D0BB  CREATE,  line 1330 of libusboop.pas
>   $000000010002B3AB
>   $0000000100001942  main,  line 75 of ../../pas-
> libusb_test_dll/src/examples/testopendevic_vidpid2.pas
>   $0000000100001AF6  main,  line 96 of ../../pas-
> libusb_test_dll/src/examples/testopendevic_vidpid2.pas
>   $0000000100010040
>   $00000001000017F0
>   $00007FFB66D07E94
>   $00007FFB675FA251
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: USB Human Interface Devices

Zaaphod
In reply to this post by Johann Glaser
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  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: USB Human Interface Devices

Stefan V. Pantazi
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  -  [hidden email]
> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
>

--
_______________________________________________________
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: USB Human Interface Devices

Zaaphod
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 <[hidden email]> On Behalf Of Stefan V. Pantazi
Sent: Sunday, August 18, 2019 3:12 PM
To: [hidden email]
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!
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: USB Human Interface Devices

Stefan V. Pantazi

On 8/18/19 3:58 PM, James Richters wrote:
> 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!"

Assuming there are no other bugs in the libusbxhid library, for writing
data you have to guess the reportType (in, out, feature) and reportNum
parameter and set the report data buffer correctly (first byte is the
report number) for your device. Have a look at similar devices.

>
> 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.

My guess is that it would be better to leave the time sensitive read
thread to do the fast reads and immediate calculations and leave writing
to the device screen in a separate thread (even main thread), with a
lower update frequency!

>
> 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.

If an operating system were realtime that should not happen. This is why
LinuxCNC uses the realtime extensions (http://linuxcnc.org/)

Some devices have multiple functional modes that can be selected by
writing their appropriate settings/registers. For example, a graphic
tablet I used before has a finger input mode (really becomes a trackpad)
and a pen mode (uses the stylus, as usual). For more complex devices,
guessing such things is less practical, you really need knowledge of the
device or similar ones.


>
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: USB Human Interface Devices

Zaaphod
>>Assuming there are no other bugs in the libusbxhid library, for writing data you have to guess the reportType (in, out, feature) and reportNum parameter and set the report data buffer correctly (first byte is the report number) for your device. Have a look at similar devices.

I don't know if there is a bug or not... but I "Think" I have the information I need.  I found this device documented here:
https://github.com/rubienr/machinekit/tree/feature-xhc-whb04b-6/src/hal/user_comps/xhc-whb04b-6

it states:  "Data transmitted is packed as 7 bytes plus a constant leading byte 0x06 which is the report ID. The data exclusive report ID reads as follows:"
this matches the python code I was trying to duplicate...  so I send a $06 then 7 bytes of data  at a time.  It also describes the data structure as well.

The C code at https://github.com/rubienr/machinekit/blob/feature-xhc-whb04b-6/src/hal/user_comps/xhc-whb04b-6/usb.cc
Uses libusb... here is the relevant section:  It's in C but it's commented pretty well..  and describes the exact parameters passed to libusb_control_transfer

void Usb::sendDisplayData()
{
    outputPackageBuffer.asBlocks.init(&outputPackageData);
    if (mIsSimulationMode)
   {
        *verboseTxOut << "out   0x" << outputPackageBuffer.asBlocks << endl <<
                      std::dec << "out   size " << sizeof(outputPackageBuffer.asBlockArray) << "B " << outputPackageData
                      << endl;
    }

    for (size_t idx = 0; idx < (sizeof(outputPackageBuffer.asBlockArray) / sizeof(UsbOutPackageBlockFields)); idx++)
    {
        UsbOutPackageBlock& block = outputPackageBuffer.asBlockArray[idx];
        size_t blockSize = sizeof(UsbOutPackageBlock);
        // see also
        // http://www.beyondlogic.org/usbnutshell/usb6.shtml
        // http://libusb.sourceforge.net/api-1.0/group__desc.html
        // http://libusb.sourceforge.net/api-1.0/group__misc.html
        int    r         = libusb_control_transfer(deviceHandle,
            // send to hid descriptor: bmRequestType == LIBUSB_DT_HID == 0x21 == (interface | endpoint)
                                                   LIBUSB_DT_HID,
            // bRequest == LIBUSB_REQUEST_SET_CONFIGURATION == 0x09 == set configuration
                                                   LIBUSB_REQUEST_SET_CONFIGURATION,
            // wValue: if bRequest == LIBUSB_REQUEST_SET_CONFIGURATION the configuration value
                                                   0x0306,
            // wIndex, device interface number
                                                   0x00,
            // data to transmit
                                                   block.asBuffer.asBytes,
            // wLength, data length
                                                   blockSize,
            // transfer timeout[ms]
                                                   0);

        if (r < 0)
        {
            std::cerr << "transmission failed, try to reconnect ..." << endl;
            setDoReconnect(true);
            return;
        }
    }
}


So I tried with libusbxhid:
libusbhid_set_report(device_context, HID_REPORT_TYPE_FEATURE, $6 , 8 , WhB04_Packet )
and I get  control transfer to usb device failed!

so inside function libusbhid_set_report, I put a bunch of writelns to show what is being passed to libusb_control_transfer:
  Writeln('device handle =');
  Writeln('bmRequestType = $', inttohex(LIBUSB_CONTROL_REQUEST_TYPE_OUT,4));
  Writeln('bRequest      = $', inttohex(HID_SET_REPORT,4)                 );
  Writeln('wValue        = $', inttohex((reportType << 8) or reportNum,4) );
  Writeln('wIndex        = $', 0                                          );
  Writeln('data          = ',  '$'+Inttohex(report_data[0],2),' $'+Inttohex(report_data[1],2),' $'+Inttohex(report_data[2],2),' $'+Inttohex(report_data[3],2),' $'+Inttohex(report_data[4],2),' $'+Inttohex(report_data[5],2),
                              ' $'+Inttohex(report_data[6],2),' $'+Inttohex(report_data[7],2));
  Writeln('wLength       = $', Inttohex(reportLen,2)                      );
  Writeln('timeout       = $', 0                                          );
  Result:=libusb_control_transfer(hid_device_context.usb_device_handle,LIBUSB_CONTROL_REQUEST_TYPE_OUT{????},HID_SET_REPORT,(reportType << 8) or reportNum, 0{interface_num}, @report_data, reportLen{sizeof(data)},0{no timeout});

Suspend
06  FD  FE  FF  01  02  03  04
device handle =
bmRequestType = $0021
bRequest      = $0009
wValue        = $0306
wIndex        = $0
data          = $06 $FD $FE $FF $01 $02 $03 $04
wLength       = $08
timeout       = $0
control transfer to usb device failed!
-1
It shows I'm getting the same values for everything....  but yet it's still failing.  I have this attempt on my fork at https://github.com/Zaaphod/libusbxhid



I'm not sure it's libusbxhid though.. because I also can't get it to work with pas-libusb  I can run test3controlasync.pas with my device and it does send a request to the device and retrieves some information from it... so I modified that program (test3controlasync_2.pas)  to just pass the same paramaters as above and then it doesn't work anymore... here's the output from test3controlasync_2.pas

Running "i:\programming\pas-libusb_test_dll\src\examples\test3controlasync_2.exe "
Submitting control transfer
Finished Transfer, Data = 38, Status = 0, ActualLength = 18
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor            $10CE
  idProduct           $EB93
  bcdDevice            1.00
  iManufacturer           1
  iProduct                0
  iSerialNumber           0
  bNumConfigurations      1
Done.
CT.bmRequestType = 21
CT.bRequest      = 09
CT.wValue        = 306
CT.wIndex        = 00
CT.wLength       = 07
CT.Timeout       = 00
Submitting control transfer
USB Error: Submit: LIBUSB_ERROR_IO: LIBUSB_ERROR_IO  

So it worked for the first information request (the default one including with the original test2controlasync.pas) , but not for my attempted request..  this leads me to believe that I have something wrong and  it's not a bug...  but I'm lost as to what it might be..  my attempt is on my fork here:
https://github.com/Zaaphod/pas-libusb/blob/Hack/src/examples/test3controlasync_2.pas

 
>> 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.

>My guess is that it would be better to leave the time sensitive read
>thread to do the fast reads and immediate calculations and leave writing
>to the device screen in a separate thread (even main thread), with a
>lower update frequency!

Yes, that was what I was attempting to describe.. but I can't write to the usb device if the read thread happens to be in the middle of a read... so how do I pause the read thread at the correct time so it's not partially in the middle of reading a packet, and I can't read again until I'm done writing.  I figure I can just check for some period of time of idle handwheel input before I stop the read thread and do the write then start the read thread again, because only the handwheel produces such a large stream of data.. but still I’m not sure how to make sure I stop it at the correct time.

James
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: USB Human Interface Devices

Marc Santhoff-2
Hi James,

are you really sure the WHB04B-6 is exactly the same as your WHB04B-4 viewn to
the USB API?

If those thingys come with a dll, maybe you can compare the header files?
If there is no header file you could ask the manufacturer for it. If they made
a programm using that dll, there must be a header file.

HTH somehow...

--
Marc Santhoff <[hidden email]>
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: USB Human Interface Devices

Stefan V. Pantazi
In reply to this post by Zaaphod
>> My guess is that it would be better to leave the time sensitive read
>> thread to do the fast reads and immediate calculations and leave writing
>> to the device screen in a separate thread (even main thread), with a
>> lower update frequency!
>
> Yes, that was what I was attempting to describe.. but I can't write to the usb device if the read thread happens to be in the middle of a read... so how do I pause the read thread at the correct time so it's not partially in the middle of reading a packet, and I can't read again until I'm done writing.  I figure I can just check for some period of time of idle handwheel input before I stop the read thread and do the write then start the read thread again, because only the handwheel produces such a large stream of data.. but still I’m not sure how to make sure I stop it at the correct time.

I do not get why should you stop the read thread, when that is the
actual advantage of having multiple threads. While the read thread is
busily reading input in a buffer/queue/what have you, you are free
within limits) to do whatever you need to do (e.g., output to LCD
display, do calculations) in the other threads, including the main
thread, after which, you can get back to consuming and processing the
(hopefully only slightly larger now) data from the read thread
buffer/queue. After you figured writing to the LCD screen you could try
writing random data to it while reading and processing handwheel and
button input *at the same time*. Hope this makes sense.



_______________________________________________________
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: USB Human Interface Devices

Zaaphod
In reply to this post by Marc Santhoff-2
They come with a little CD, but not much really useful on them.. mostly instructions on how to get them to work with Mach3.  But the manual does cover both models.  The only difference is one has a selection switch for 4 axis and the other has one for 6 axis,  but the 4 axis version shows 6 axis on the LCD so I think everything else is identical even the firmware.  The manual does have a dll on it called ShuttlePro.dll  I have no idea what to do with that... they don't include any program at all, just instructions for mach3.  The documentation is very poor and there is no support at all on how to access it..   I'm just going on what everyone else has kind of figured out plus what I could figure out from just pushing the buttons on it.

There's a readme in the same folder as ShuttlePro.dll:

ShuttlePro.dll is the Driver of HB04BX for MACH3 cnc control system.
You could externd the IO input with our wireless handle.To do reset,start,stop etc.
The handle is just like
ShuttlePRO,you coul do jog mpg and step with the handle.
In all,you could control much things if you had our wireless HB04Bx.

installation:
first you must install mach3 and then insert HB04Bx handle usb controller.then  install the
batteries to HB04Bx handle's cell box.
1.You should copy the ShuttlePro.dll to Mach3\plugins\ directroy;
2.M930.m1s is the probez file.You should copy the it to  Mach3\macros\Mach3Mill directroy;
3.M990.m1s is the ref all home file.You should copy the it to  Mach3\macros\Mach3Mill directroy;
4.m933 is go to zero work macro,You should copy the it to  Mach3\macros\Mach3Mill directroy;
5.you  could change the macro file M930.m1s ,M990.m1s, m933 to satisfy your cnc system;

It seems to indicate the designation after the B is not important to the operation..  W is for wireless and they are HB04Bx  (either -4 or -6 as far as I know.. maybe there is a -3 as well)  

I have no idea what the DLL could possibly be for though

James

-----Original Message-----
From: fpc-pascal <[hidden email]> On Behalf Of Marc Santhoff
Sent: Sunday, August 18, 2019 9:12 PM
To: [hidden email]
Subject: Re: [fpc-pascal] USB Human Interface Devices

Hi James,

are you really sure the WHB04B-6 is exactly the same as your WHB04B-4 viewn to the USB API?

If those thingys come with a dll, maybe you can compare the header files?
If there is no header file you could ask the manufacturer for it. If they made a programm using that dll, there must be a header file.

HTH somehow...

--
Marc Santhoff <[hidden email]>
_______________________________________________
fpc-pascal maillist  -  [hidden email] https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: USB Human Interface Devices

Zaaphod
In reply to this post by Stefan V. Pantazi
My concern was that I could not read and write at the exact same time....

-----Original Message-----
From: fpc-pascal <[hidden email]> On Behalf Of Stefan V. Pantazi
Sent: Sunday, August 18, 2019 9:32 PM
To: [hidden email]
Subject: Re: [fpc-pascal] USB Human Interface Devices

>> My guess is that it would be better to leave the time sensitive read
>> thread to do the fast reads and immediate calculations and leave
>> writing to the device screen in a separate thread (even main thread),
>> with a lower update frequency!
>
> Yes, that was what I was attempting to describe.. but I can't write to the usb device if the read thread happens to be in the middle of a read... so how do I pause the read thread at the correct time so it's not partially in the middle of reading a packet, and I can't read again until I'm done writing.  I figure I can just check for some period of time of idle handwheel input before I stop the read thread and do the write then start the read thread again, because only the handwheel produces such a large stream of data.. but still I’m not sure how to make sure I stop it at the correct time.

I do not get why should you stop the read thread, when that is the actual advantage of having multiple threads. While the read thread is busily reading input in a buffer/queue/what have you, you are free within limits) to do whatever you need to do (e.g., output to LCD display, do calculations) in the other threads, including the main thread, after which, you can get back to consuming and processing the (hopefully only slightly larger now) data from the read thread buffer/queue. After you figured writing to the LCD screen you could try writing random data to it while reading and processing handwheel and button input *at the same time*. Hope this makes sense.



_______________________________________________________
_______________________________________________
fpc-pascal maillist  -  [hidden email] https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: USB Human Interface Devices

Marc Santhoff-2
In reply to this post by Marc Santhoff-2
On Mon, 2019-08-19 at 03:11 +0200, Marc Santhoff wrote:
> Hi James,
>
> are you really sure the WHB04B-6 is exactly the same as your WHB04B-4 viewn to
> the USB API?
>
> If those thingys come with a dll, maybe you can compare the header files?
> If there is no header file you could ask the manufacturer for it. If they made
> a programm using that dll, there must be a header file.

Oh, it's chinese - forget about getting any information.

Did you read there

https://github.com/rubienr/machinekit/tree/feature-xhc-whb04b-6/src/hal/user_comps/xhc-whb04b-6#findings

that the axis dial has to be switched on for the display to be updated?

> HTH somehow...
>
> --
> Marc Santhoff <[hidden email]>
> _______________________________________________
> fpc-pascal maillist  -  [hidden email]
> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
--
Marc Santhoff <[hidden email]>
--
Marc Santhoff <[hidden email]>
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: USB Human Interface Devices

Zaaphod
Yes, I did see that... it happens that before I found that page I had it on one of the axis anyway because if you switch it to off  the handwheel gets disabled.   I'm not sure why I am getting an IO error trying to send data to the device.. I'm not sure if it's Windows, or FPC, or the method I am trying to use.. etc..  I also don't have a lot of devices that even have a way to output anything to them... most are input devices.  So I bought some usb-relays... those seem to have more documentation available, maybe I'll learn something when those come in.  One thing that just confuses me is the first byte of data being sent as the report number.. I'm not sure I'm understanding that correctly, but it seems to be the only way it will work at all.

James

>Oh, it's chinese - forget about getting any information.
>Did you read there
>https://github.com/rubienr/machinekit/tree/feature-xhc-whb04b-6/src/hal/user_comps/xhc-whb04b-6#findings
>that the axis dial has to be switched on for the display to be updated?
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: USB Human Interface Devices

Zaaphod
I've been reading about libusb here:
https://www.cs.unm.edu/~hjelmn/libusb_hotplug_api/group__syncio.html

some things I just don't really understand, I'm hoping someone can explain:

The wValue, wIndex and wLength fields values should be given in host-endian byte order.    
What does host-endian byte order mean??

wLength
the length field for the setup packet. The data buffer should be at least this size.

What is this length supposed to be?  I've been using the length of the data I'm trying to send... so trying to send 8 bytes, I made it 8... but maybe it's wanting some other length?

It seems to me that there would be little point in asking for this value if it was always just the length of the data field because the function could just get len(data) on it's own, so why bother passing something so obvious as a parameter...  this leads me to wonder if this length needs to be something else?  

James
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: USB Human Interface Devices

Marc Santhoff-2
On Mon, 2019-08-19 at 04:24 -0400, James Richters wrote:
> I've been reading about libusb here:
> https://www.cs.unm.edu/~hjelmn/libusb_hotplug_api/group__syncio.html
>
> some things I just don't really understand, I'm hoping someone can explain:

I can't help with the details, but these sites are very informative,
especially the first one is nicely readable, the other has lots of details:

http://www.usbmadesimple.co.uk/index.html
https://www.beyondlogic.org/usbnutshell/usb1.shtml


> The wValue, wIndex and wLength fields values should be given in host-endian
> byte order.
> What does host-endian byte order mean??
>
> wLength
> the length field for the setup packet. The data buffer should be at least
> this size.
>
> What is this length supposed to be?  I've been using the length of the data
> I'm trying to send... so trying to send 8 bytes, I made it 8... but maybe
> it's wanting some other length?
>
> It seems to me that there would be little point in asking for this value if
> it was always just the length of the data field because the function could
> just get len(data) on it's own, so why bother passing something so obvious
> as a parameter...  this leads me to wonder if this length needs to be
> something else?
>
> James
> _______________________________________________
> fpc-pascal maillist  -  [hidden email]
> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
--
Marc Santhoff <[hidden email]>
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: USB Human Interface Devices

wkitty42
In reply to this post by Zaaphod
On 8/19/19 4:24 AM, James Richters wrote:
> I've been reading about libusb here:
> https://www.cs.unm.edu/~hjelmn/libusb_hotplug_api/group__syncio.html
>
> some things I just don't really understand, I'm hoping someone can explain:
>
> The wValue, wIndex and wLength fields values should be given in host-endian byte order.
> What does host-endian byte order mean??


if your machine is little endian, then you set those values in little endian...
if your machine is big endian, then you use that...

intel/amd PC systems are generally little endian...

https://en.wikipedia.org/wiki/Endianness

--
  NOTE: No off-list assistance is given without prior approval.
        *Please keep mailing list traffic on the list unless*
        *a signed and pre-paid contract is in effect with us.*
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
1 ... 3456789