Using libusb in linux
Using libusb in linux
Hi all,
I am trying to use libusb under linux to communicate with my PM3.
I thought someone here might be interested what I have found so far.
Linux will get hold of the usb device when it is plugged in so the first thing you must do in yur program is to call usb_detach_kernel_driver_np to be able to do anything yourself with the device. And to be able to make this call work you need to run the code under root privileges. This is not so good but this is what you get by doing it in user space I suppose.
When this is done you should be able to make queries about the device. As concept2 sdk documentation mentions that the endpoints used by the pm3 are so called interrupt endpoints I used the commands
usb_interrupt_write and usb_interrupt_read
to communicate with the PM3. Remember to get hold of the interface before you do this using the usb_claim_interface command.
This is about as far as I have come. I can get the command
usb_interrupt_write to work i.e. not fail by returning an error code BUT it seems the command does not reach the PM3 or something is wrong with the frames I send. For example sending the command
{0xF1 ,0x80 ,0x80 ,0xF2} = GET STATUS FRAME
I would expect that the PM3 would respond with the status but calling
usb_interrupt_read
just times out and no data is received.
My PM3 has firmware 97 and everything seems to work OK. Maybe someone can give me a hint what more is needed to get the PM3 to respond?
I am trying to use libusb under linux to communicate with my PM3.
I thought someone here might be interested what I have found so far.
Linux will get hold of the usb device when it is plugged in so the first thing you must do in yur program is to call usb_detach_kernel_driver_np to be able to do anything yourself with the device. And to be able to make this call work you need to run the code under root privileges. This is not so good but this is what you get by doing it in user space I suppose.
When this is done you should be able to make queries about the device. As concept2 sdk documentation mentions that the endpoints used by the pm3 are so called interrupt endpoints I used the commands
usb_interrupt_write and usb_interrupt_read
to communicate with the PM3. Remember to get hold of the interface before you do this using the usb_claim_interface command.
This is about as far as I have come. I can get the command
usb_interrupt_write to work i.e. not fail by returning an error code BUT it seems the command does not reach the PM3 or something is wrong with the frames I send. For example sending the command
{0xF1 ,0x80 ,0x80 ,0xF2} = GET STATUS FRAME
I would expect that the PM3 would respond with the status but calling
usb_interrupt_read
just times out and no data is received.
My PM3 has firmware 97 and everything seems to work OK. Maybe someone can give me a hint what more is needed to get the PM3 to respond?
Last edited by johroo on May 23rd, 2007, 4:54 pm, edited 1 time in total.
The PM3 is an HID device and as such its Interrupt IN/OUT endpoints expect data to follow the HID spec. That is:
1: The size of the transfer buffer (in both directions) should equal the size of one of the HID reports defined on the endpoint via the HID Report Descriptor.
2: On a device with multiple HID reports, the first byte must be the ID of the report you're sending.
3: (optionally) On Windows, when issuing a READ on an Interrupt IN endpoint, the first byte of the receive buffer must also contain the Report ID you're expecting. This is a signal to the kernel, not the device, and is probably irrelevant on Linux.
If you're willing to write a few hundred lines of code you could use the hiddev IOCTLs to communicate with the PM. You wouldn't be able to use libusb, but you wouldn't have to detach the kernel driver either. The benefit of using hiddev is that it gives you a real HID parser that tells you information about what reports are defined. If you want to stick with libusb you can try to also use its friend libhid. Not sure if their parser can handle the PM or not -- should be fine. The support for libhid seems dicey at best.
Mike
1: The size of the transfer buffer (in both directions) should equal the size of one of the HID reports defined on the endpoint via the HID Report Descriptor.
2: On a device with multiple HID reports, the first byte must be the ID of the report you're sending.
3: (optionally) On Windows, when issuing a READ on an Interrupt IN endpoint, the first byte of the receive buffer must also contain the Report ID you're expecting. This is a signal to the kernel, not the device, and is probably irrelevant on Linux.
If you're willing to write a few hundred lines of code you could use the hiddev IOCTLs to communicate with the PM. You wouldn't be able to use libusb, but you wouldn't have to detach the kernel driver either. The benefit of using hiddev is that it gives you a real HID parser that tells you information about what reports are defined. If you want to stick with libusb you can try to also use its friend libhid. Not sure if their parser can handle the PM or not -- should be fine. The support for libhid seems dicey at best.
Mike
Thank you for the very good information.
I fixed the code to comply with the report sizes and it worked on the first try . I used the report ID#1 which has size 20+1 for ID.
Command to PM3: 1 F1 80 80 F2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Answer from PM3: 2 F1 99 99 F2 33 30 30 31 31 36 37 34 30 2A F2 CC 1 0 98 F C5 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 D3 4F F2
Thanks again haboustak.
I have noticed another thing. When I issue commands to the PM3 and do not repect the usb interrupt frame time of 1ms I don't get an error message from the read function. Instead old data is returned. I wonder how do the concept2 SDK handle the usb hid interface restriction of reading only once every usb frame?
Is there a built in delay of 1ms after every command?
I cannot test this myself as I don't have any windows box.
I fixed the code to comply with the report sizes and it worked on the first try . I used the report ID#1 which has size 20+1 for ID.
Command to PM3: 1 F1 80 80 F2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Answer from PM3: 2 F1 99 99 F2 33 30 30 31 31 36 37 34 30 2A F2 CC 1 0 98 F C5 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 D3 4F F2
Thanks again haboustak.
I have noticed another thing. When I issue commands to the PM3 and do not repect the usb interrupt frame time of 1ms I don't get an error message from the read function. Instead old data is returned. I wonder how do the concept2 SDK handle the usb hid interface restriction of reading only once every usb frame?
Is there a built in delay of 1ms after every command?
I cannot test this myself as I don't have any windows box.
-
- Paddler
- Posts: 5
- Joined: May 8th, 2007, 5:03 am
Peewee1963,
The key difference between libusb on Mac and Linux is that you can't detach the kernel driver on the Mac. The function usb_detach_kernel_driver_np depends on kernel support and there isn't any on Mac. In fact, it was only added to Linux in a recent 2.6.x version.
johroo,
There's a historical post by Mark Lyons where he describes the typical update rate of the hardware at ~30-50msec. Maybe even 20 ms. I think a good portion of this is bus latency. Keep in mind that the Win32 SDK uses 120-byte reports exclusively, which requires two HID transactions in each direction.
http://www.c2forum.com/viewtopic.php?p=492#492
On an OS where you have an HID driver you don't need to worry about outpacing the HID spec because the driver respects that for you. The PM3 is a synchronous device, only one request at a time or it will error out, so you queue up a request and wait for it to finish. On Windows, you issue a write and then a following read will block until new data appears. On Mac, you issue an output transaction and wait for an event from the input queue. On Linux, you issue the HIDIOCSREPORT IOCTL and then select() the file descriptor for usage events that indicate HIDIOCGREPORT can be called.
Mike
The key difference between libusb on Mac and Linux is that you can't detach the kernel driver on the Mac. The function usb_detach_kernel_driver_np depends on kernel support and there isn't any on Mac. In fact, it was only added to Linux in a recent 2.6.x version.
johroo,
There's a historical post by Mark Lyons where he describes the typical update rate of the hardware at ~30-50msec. Maybe even 20 ms. I think a good portion of this is bus latency. Keep in mind that the Win32 SDK uses 120-byte reports exclusively, which requires two HID transactions in each direction.
http://www.c2forum.com/viewtopic.php?p=492#492
On an OS where you have an HID driver you don't need to worry about outpacing the HID spec because the driver respects that for you. The PM3 is a synchronous device, only one request at a time or it will error out, so you queue up a request and wait for it to finish. On Windows, you issue a write and then a following read will block until new data appears. On Mac, you issue an output transaction and wait for an event from the input queue. On Linux, you issue the HIDIOCSREPORT IOCTL and then select() the file descriptor for usage events that indicate HIDIOCGREPORT can be called.
Mike
-
- Paddler
- Posts: 5
- Joined: May 8th, 2007, 5:03 am
When I read out distance and time(in one ID#1 command) as fast as I can from the PM3 I get about 50 frames per second. Doing this I have to empty the usb buffer by doing 1ms interrupt reads until I get a timeout, otherwise I get old data. This usually takes about two reads. ~50 frames per second equals an updating time of about 20ms just as you suggest. This is a snapshot of a one second dump.
109.9 m @ 0:0:44:0
109.9 m @ 0:0:44:0
110.0 m @ 0:0:44:3
110.0 m @ 0:0:44:3
110.0 m @ 0:0:44:6
110.1 m @ 0:0:44:9
110.1 m @ 0:0:44:9
110.2 m @ 0:0:44:12
110.2 m @ 0:0:44:15
110.3 m @ 0:0:44:18
110.4 m @ 0:0:44:21
110.4 m @ 0:0:44:21
110.5 m @ 0:0:44:24
110.5 m @ 0:0:44:24
110.5 m @ 0:0:44:28
110.6 m @ 0:0:44:31
110.7 m @ 0:0:44:34
110.7 m @ 0:0:44:34
110.7 m @ 0:0:44:37
110.7 m @ 0:0:44:37
110.8 m @ 0:0:44:40
110.9 m @ 0:0:44:43
110.9 m @ 0:0:44:43
110.9 m @ 0:0:44:46
111.0 m @ 0:0:44:49
111.0 m @ 0:0:44:49
111.1 m @ 0:0:44:52
111.1 m @ 0:0:44:52
111.2 m @ 0:0:44:56
111.2 m @ 0:0:44:59
111.2 m @ 0:0:44:59
111.3 m @ 0:0:44:62
111.4 m @ 0:0:44:65
111.4 m @ 0:0:44:65
111.4 m @ 0:0:44:68
111.4 m @ 0:0:44:68
111.5 m @ 0:0:44:71
111.5 m @ 0:0:44:71
111.6 m @ 0:0:44:74
111.6 m @ 0:0:44:78
111.7 m @ 0:0:44:81
111.7 m @ 0:0:44:81
111.8 m @ 0:0:44:84
111.8 m @ 0:0:44:84
111.9 m @ 0:0:44:87
111.9 m @ 0:0:44:87
111.9 m @ 0:0:44:90
112.0 m @ 0:0:44:94
112.0 m @ 0:0:44:94
112.1 m @ 0:0:44:97
109.9 m @ 0:0:44:0
109.9 m @ 0:0:44:0
110.0 m @ 0:0:44:3
110.0 m @ 0:0:44:3
110.0 m @ 0:0:44:6
110.1 m @ 0:0:44:9
110.1 m @ 0:0:44:9
110.2 m @ 0:0:44:12
110.2 m @ 0:0:44:15
110.3 m @ 0:0:44:18
110.4 m @ 0:0:44:21
110.4 m @ 0:0:44:21
110.5 m @ 0:0:44:24
110.5 m @ 0:0:44:24
110.5 m @ 0:0:44:28
110.6 m @ 0:0:44:31
110.7 m @ 0:0:44:34
110.7 m @ 0:0:44:34
110.7 m @ 0:0:44:37
110.7 m @ 0:0:44:37
110.8 m @ 0:0:44:40
110.9 m @ 0:0:44:43
110.9 m @ 0:0:44:43
110.9 m @ 0:0:44:46
111.0 m @ 0:0:44:49
111.0 m @ 0:0:44:49
111.1 m @ 0:0:44:52
111.1 m @ 0:0:44:52
111.2 m @ 0:0:44:56
111.2 m @ 0:0:44:59
111.2 m @ 0:0:44:59
111.3 m @ 0:0:44:62
111.4 m @ 0:0:44:65
111.4 m @ 0:0:44:65
111.4 m @ 0:0:44:68
111.4 m @ 0:0:44:68
111.5 m @ 0:0:44:71
111.5 m @ 0:0:44:71
111.6 m @ 0:0:44:74
111.6 m @ 0:0:44:78
111.7 m @ 0:0:44:81
111.7 m @ 0:0:44:81
111.8 m @ 0:0:44:84
111.8 m @ 0:0:44:84
111.9 m @ 0:0:44:87
111.9 m @ 0:0:44:87
111.9 m @ 0:0:44:90
112.0 m @ 0:0:44:94
112.0 m @ 0:0:44:94
112.1 m @ 0:0:44:97
-
- Paddler
- Posts: 8
- Joined: September 26th, 2007, 7:16 am
- Location: Oxford, UK
- Contact: