[fpc-pascal] USB Human Interface Devices

Johann Glaser Johann.Glaser at gmx.at
Tue Aug 13 22:58:31 CEST 2019


Hi James!

Am Montag, den 12.08.2019, 20:20 -0400 schrieb James Richters:
> > > Ah, I see. You declared EP as Plibusb_endpoint_descriptor (i.e.,
> > > the pointer to an endpoint descriptor record), while in the
> > > original code it is a USBEndpointDescriptor (i.e., the record
> > > itself).
> > > Your version is more memory efficient but uses "ugly pointer-
> > > arithmetic" by taking the address of an array element. However,
> > > just keep it as you implemented it.
>
> Well that wasn’t my idea,  I was trying to get it to compile and I
> saw the existing function:
> // helper function for method below, this can't be a local function
> Function
> MyEndpointMatch(EP:Plibusb_endpoint_descriptor;Data:Pointer):Boolean;
> Var bEndpointAddress : Byte;
> Begin
>   bEndpointAddress := (PtrUInt(Data) shr 0) and $FF;
>   Result := (EP^.bEndpointAddress = bEndpointAddress);
> End;
>
> 	It compiled and had the pointer, so I stuck a pointer in the
> one I was having a problem with and it compiled.... it was just a
> guess at how to get it to compile honestly. I figured that the other
> code had it so maybe something to do with the way things are defined
> now require it to be a pointer.. without the pointer it gives errors.

Yes, yes, no worries! That was no criticism, just a (hopefully)
objective description of what I saw in the code. :-)

> > > While reviewing your changes, I found a few small things.
> > > Could you please keep the indenting and coding style as the
> > > existing code? This is especially for the constant and type
> > > declarations around TLibUsbPseudoHIDInterface (IIRC the
> > > >>keywords Type and Const should start at character 1, therefore
> > > you also should un-indent the 6+3 constants and the P/THIDReport
> > > record (except its final "End;" by 2 spaces.
>
> 	Yes, I will keep the indenting and coding style the same, No
> problem, I adjusted this as you requested.  I'll go through later and
> see if there are any other things I missed.. most of what I've done
> is cutting and pasting, but I'll keep it consistent.

Great, thanks! And there is no hurry.

> > > Secondly, in your improved TLibUsbInterface.FindEndpoint, please
> > > revert the capitalization and indenting changes (i.e., capital
> > > "Function", "For", ..., and "do" and "then" in the same line, ...
> > > IMHO the only changed lines in comparison to the original code
> > > should be the extra variable EP, its assignment without range
> > > checks, and its use in MatchFunc and Exit.
> That was code the Jean sent me to get it to work under windows, but I
> wend an retrieved the original function and re-did the modifications
> to match the formatting.  It compiles fine without turning off range
> check, but I think there was some reason why Jean had to put them in
> there.. I'll leave it out for now unless we figure out why they were
> needed.

You can just keep in the range checking. I think I should have done
this from the beginning, but never used range checking, therefore never
thought of it.

> > > And thirdly, you introduced a class type
> > > TLibUsbInterruptInEndpoint, which is IMHO unused. If its so,
> > > please remove it. I like to avoid clutter. :-)
> 	I guess you are talking about line
> 128:   TLibUsbInterruptInEndpoint   = class; ?
>               When I copied over { TUSBPseudoHIDInterface } and then
> renamed everything I needed it to be able to compile
> 	Line 211:    FIntrEndpoint : TLibUsbInterruptInEndpoint;
>               Without it I was getting libusboop.pas(212,21) Error:
> Identifier not found "TLibUsbInterruptInEndpoint"
>               So I went back to usb.pas and copied that line over to
> prevent this error... perhaps I have it in the wrong place??

Let me have a closer look. :-)

Ah, sorry, it was my fault. I should have looked at the complete file,
not just the diff. :-)

Please keep the forward declaration in.

> > > Apart form these cosmetic things, thank you very much for your
> > > effort!
>    	No problem,  please let me know if I missed anything,  I'm
> happy to make it conform to the coding standards.  I’m a little
> confused by the capitalization, for example sometimes it's
> LibUsb,  sometimes it's Libusb.. I'm trying to figure out when the U
> is capitated and when it is not.... maybe it should always be one way
> or the other?  Please continue to correct me on anything you see.

That's probably my own lazyness. However, at least in libusboop.pas,
all declarations use LibUsb (capital 'U') everywhere. And in libusb.pas
its "libusb" (all small letters) except the unit name itself.

> > > I'm looking forward hearing from you your success when accessing
> > > a HID device (or call for help :-) ).
>
> 	Well..... since you asked... I'm having a real challenge trying
> to figure out how I can use all this to access my device... I'm just
> not familiar with this kind of programming... constructors,
> destructors, and all this inherited stuff, it's not what I am used
> to, I never have anything like that.. I know how to program in Turbo
> Pascal for DOS pretty much and normal in-line console style
> programming, but very little of anything past that, so a lot of this
> just goes over my head.
> 	On top of that, I really don't understand USB communications at
> all, I have written programs with all kinds of features, programs
> that send e-mails, communicate over ethernet and serial connections,
> Modbus, etc... but this USB stuff is just not making any sense to
> me... and it seems like the python code I have as an example is so
> simple... you open the device, send and receive some stuff and close
> it...  but I don't really know python either, so I really don't
> understand everything going on there...

Regarding USB, I've recommended some EMails ago to read the first
chapter of the AN2131 EZ-USB TRM. That really got me into USB.

>      	I still don't really see how to open and close the device or
> how to send or receive anything from it...  I'm struggling to see how
> the somewhat simple looking functions in HB04.py can be
> implemented....

It seems that libusb-1.0 as well as pas-libusb (incl. the OOP wrapper)
are much nearer to the hardware than the Python stuff.

> I'm trying to use one of the examples to just open and close the
> device, but I am not successful with that,    Here is what I am
> trying to do:
>
> I ran Test1library.pas and got the following:
>
> Running "i:\programming\pas-libusb_test_dll\src\examples\test1library.exe "
> Using libusb(x) v1.0.22.11312
> Found 14 devices:
>   Bus   1 Device   0: ID 8086:A36D,  port:   0, Speed: Unknown
>   Bus   1 Device   5: ID 8087:0AAA,  port:  14, port path from HCD: 0, Speed: 12 Mbit/s (USB FullSpeed)
>   Bus   1 Device  33: ID 0424:2734,  port:   1, port path from HCD: 0->1, Speed: 480 Mbit/s (USB HighSpeed)
>   Bus   1 Device   7: ID 1B1C:0C15,  port:   2, port path from HCD: 0->9, Speed: 12 Mbit/s (USB FullSpeed)
>   Bus   1 Device  16: ID 10CE:EB93,  port:   4, port path from HCD: 0, Speed: 12 Mbit/s (USB FullSpeed)
>   Bus   1 Device   3: ID 05E3:0610,  port:   9, port path from HCD: 0, Speed: 480 Mbit/s (USB HighSpeed)
>   Bus   1 Device  18: ID 04E8:61F5,  port:  19, port path from HCD: 0, Speed: unknown (4)
>   Bus   1 Device   4: ID 1B1C:0C10,  port:  10, port path from HCD: 0, Speed: 12 Mbit/s (USB FullSpeed)
>   Bus   1 Device  25: ID 0424:274C,  port:   5, port path from HCD: 0->1->1, Speed: 480 Mbit/s (USB HighSpeed)
>   Bus   1 Device  34: ID 047D:1020,  port:   3, port path from HCD: 0->1->1, Speed: 1.5 Mbit/s (USB LowSpeed)
>   Bus   1 Device  26: ID 1B1C:1B4F,  port:   4, port path from HCD: 0->1->1, Speed: 12 Mbit/s (USB FullSpeed)
>   Bus   1 Device  12: ID 1A40:0101,  port:   1, port path from HCD: 0, Speed: 480 Mbit/s (USB HighSpeed)
>   Bus   1 Device  14: ID 0C45:7403,  port:   2, port path from HCD: 0->1, Speed: 12 Mbit/s (USB FullSpeed)
>   Bus   1 Device  30: ID 10C4:EA60,  port:   5, port path from HCD: 0, Speed: 12 Mbit/s (USB FullSpeed)
>
> The one I want to try to use is this one:
>   Bus   1 Device  16: ID 10CE:EB93,  port:   4, port path from HCD: 0, Speed: 12 Mbit/s (USB FullSpeed)
> I assume that $10CE and $EB93 are the Vid and Pid??

Exactly!

> I tried plugging those into the following test program:
>
> program test_open_WHB04B;
>
> {$mode objfpc}{$H+}
>
> uses
>     Classes,SysUtils,MyDevice,LibUsbOop,LibUsbUtil;
>
> procedure WHB04B_Device;
> const
>      WHB04B_VID= $10CE;
>      WHB04B_PID= $EB93;
> var
>    Context   : TLibUsbContext;
>    TheDevice : TMyDevice;

IMHO you should _not_ use "MyDevice", because thats just a lousy demo
of a hypothetical device with a built-in EZ-USB chip (you remember,
without ROM or Flash). It downloads the firmware and then talks to that
demo firmware.

> function CreateMatch: TLibUsbDeviceMatchVidPid;
>    begin
>       Result:= TLibUsbDeviceMatchVidPid.Create( Context, WHB04B_VID,
> WHB04B_PID);
>    end;
> begin
>      Context := TLibUsbContext.Create;
>      try
>         TheDevice := TMyDevice.Create( Context, CreateMatch, '',
> CreateMatch);
>      except
>        on E : Exception do
>          Begin
>            WriteLn('Couldn''t connect to device: ',E.Message);
>            Halt(1);
>          End;
>      End;
>      WriteLn('Successfully connected to USB device
> ',IntToHex(WHB04B_VID,4),':',IntToHex(WHB04B_PID,4));
>      WriteLn('Version:        ',TheDevice.GetVersion);
>      WriteLn('Version String: ',TheDevice.GetVersionString);
>      WriteLn('Status:         ',TheDevice.GetStatus);
>
>      while true
>      do
>        Write( TheDevice.ReadString);
>
>      TheDevice.Free;
>      Context.Free;
> end;
>
> begin
>      WHB04B_Device;
> End.
>
>
> When I run it I get:
> Running "i:\programming\pas-
> libusb_test_dll\src\examples\test_open_whb04b.exe "
> Couldn't connect to device: Access violation

Would be interesting where this is coming from. It seems, Windows
doesn't allow you to open that device. It could be, that Windows wants
some "driver" (AFAIK just a .ini file). Or it could be that Windows saw
that this is a USB HID device and now some Windows default HID driver
is hogging that device.

Unfortunately I don't know anything of Windows, so I can't help here.

> When I try any of the other devices in the list I get:
> Running "i:\programming\pas-
> libusb_test_dll\src\examples\test_open.exe "
> Couldn't connect to device: Open: LIBUSB_ERROR_NO_DEVICE
>
> What am I missing here?  Why can't I get this to work?

Please consult my EMail from last Saturday with the attached snapi.pas.

You can basically use the TSNAPIDevice and remove everything you don't
need. :-)

The important thing is the constructor, where the PseudoHID interface
is allocated.

And then you can use the PseudoHID interface methods like SetReport,
... to communicate with the device.

In the hb04.py code I also see some "normal" read() and write() calls.
AFAIK these are not covered by the standard HID. So we would have to
find out what that Python easyhid is doing and then use the appropriate
pas-libusb functions.

Bye
  Hansi




More information about the fpc-pascal mailing list