Discussion:
[Libusb-devel] libusb and writefile
Pedro Gouveia
2010-06-08 19:42:21 UTC
Permalink
Hei,

I am trying to develop a new driver for usb device. The device is an
Endurance R/C PCTx.
They give away a sample code to start programming for this device. The
problem is that this code is for windows machines, and I want to port it for
linux.

I already initialized the device with libusb, and the device is claimed by
my program with no problem.

The problem that I found, and I would like your help is that on windows
code, they use a function WriteFile to write an array of chars into the
device, and I've been trying to do the same with libusb, but until now it
didn't work.

CHAR OutputReport[10]; //Holds the data
to be sent to the PCTx or Servo Controller
OutputReport[0] = 0; //do not remove, must be 0

OutputReport[1] = delay1; //ch1
OutputReport[2] = delay2; //ch2
OutputReport[3] = delay3; //ch3

OutputReport[4] = delay4; //ch4
OutputReport[5] = delay5; //ch5
OutputReport[6] = delay6; //ch6

OutputReport[7] = delay7; //ch7
OutputReport[8] = delay8; //ch8
OutputReport[9] = delay9; //ch9

if(!WriteFile(DeviceHandle, OutputReport,
Capabilities.OutputReportByteLength, &BytesWritten, NULL)) {
CloseHandle(DeviceHandle);
connected = false;
return false;
}

Here's my last tested code:
char cmd[10];
cmd[0] = 1;
cmd[1] = 1;
cmd[2] = 1;
cmd[3] = 1;
cmd[4] = 1;
cmd[5] = 1;
cmd[6] = 1;
cmd[7] = 1;
cmd[8] = 1;
cmd[9] = 1;
//int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int
size, int timeout);
ret = usb_bulk_write(_hDevice, 0x01, const void *cmd, 10, 50);
cout <<"value of write: "<< ret<<endl;

Thanks,
Pedro
Xiaofan Chen
2010-06-08 23:20:54 UTC
Permalink
Post by Pedro Gouveia
I already initialized the device with libusb, and the device is claimed by
my program with no problem.
The problem that I found, and I would like your help is that on windows
code, they use a function WriteFile to write an array of chars into the
device, and I've been trying to do the same with libusb, but until now it
didn't work.
Could you point the place to the Windows code?

It seems to me that your device is an HID type. What is the
output of "lsusb -vvv"? If that is the case, did you detach the
kernel HID driver?

ret = usb_bulk_write(_hDevice, 0x01, const void *cmd, 10, 50);

And you may want to use usb_interrupt_write() instead in
the case of HID and 50 may be too short for timeout.

What is the error you encounter?
--
Xiaofan http://mcuee.blogspot.com
Tim Roberts
2010-06-08 23:36:03 UTC
Permalink
Post by Pedro Gouveia
I am trying to develop a new driver for usb device. The device is an
Endurance R/C PCTx.
They give away a sample code to start programming for this device. The
problem is that this code is for windows machines, and I want to port
it for linux.
I already initialized the device with libusb, and the device is
claimed by my program with no problem.
The problem that I found, and I would like your help is that on
windows code, they use a function WriteFile to write an array of chars
into the device, and I've been trying to do the same with libusb, but
until now it didn't work.
WriteFile is a Win32 API, equivalent to the Liinux "write" function. I
say that only so you are aware that this isn't a custom API provided by
the vendor.

Where did the DeviceHandle come from? If it is a handle to a custom
driver, then we have absolutely no idea what they are doing with the
buffer inside their driver. Your code implies that it is a HID report;
if so, then it is certainly not going to be a bulk pipe.
--
Tim Roberts, ***@probo.com
Providenza & Boekelheide, Inc.
Pedro Gouveia
2010-06-09 14:35:07 UTC
Permalink
It's the first time I'm developing a driver... I'm doing it more based on
attempt and result.. And it's not working...

I'm using this device in my university to control RC (radio control) Robots
through my computer. What it does is send the values of each of the channels
of the RC (1,2,3,4,5,6,7,8,9) directly to the servo (probably this is not
important.. but just to put you in context)

You can find all the sourcecode for the device in here:
http://www.endurance-rc.com/media/c++_example_vspj.zip

the schematics:
Loading Image...


This is the code I developed till now:
void controller::initialize()
{
struct usb_bus *bus;
struct usb_device *dev;

bool bFound = false;

usb_init();
usb_set_debug(2);
usb_find_busses();
usb_find_devices();

// find the device on the usb bus
for (bus = usb_busses; bus && !bFound; bus = bus->next) {
for (dev = bus->devices; dev && !bFound; dev = dev->next) {
if (dev->descriptor.idVendor == VendorID &&
dev->descriptor.idProduct == ProductID) {
std::cout << "Found endurance R/C PCTx,
attempting to open ...";
_hDevice = usb_open(dev);
if (_hDevice) {
std::cout <<"Success\n";
bFound = true;
} else {
throw DevOpenError();
}
}
}
}

if (!bFound) {
throw DevNotFoundError();
}

#if defined(LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP) &&
(LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP == 1)
if
(usb_detach_kernel_driver_np(_hDevice,dev->config->interface->altsetting->bInterfaceNumber)
!= 0) {
cout << "PTP_OpenDevice: couldn't kick the kernel
out;continuing anyway...\n";
}
#endif


int ret;
ret = usb_set_configuration(_hDevice, 0x1);
if (ret != 0) {
throw DevOpenError();
}
cout << "Configuration set..\n";

ret = usb_claim_interface(_hDevice, 0x0);
if (ret != 0) {
throw DevOpenError();
}
cout << "Device claimed..\n";
}




void controller::finalize()
{
if (_hDevice) {
usb_release_interface(_hDevice, 0x0);
usb_close(_hDevice);
}
}

bool controller::write(string data)
{
int ret;

/* unsigned char *cmd = new unsigned char[10]; //data to write */

char cmd[10];
cmd[0] = 1;
cmd[1] = 1;
cmd[2] = 1;
cmd[3] = 1;
cmd[4] = 1;
cmd[5] = 1;
cmd[6] = 1;
cmd[7] = 1;
cmd[8] = 1;
cmd[9] = 1;
ret = usb_interrupt_write(_hDevice, 0x01, cmd, 10, 0);
cout <<"value of write: "<< ret<<endl;
return ret;
}

This is the lsusb -vvvv of my device:

Bus 007 Device 002: ID 0925:1299 Lakeview Research
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 32
idVendor 0x0925 Lakeview Research
idProduct 0x1299
bcdDevice 0.01
iManufacturer 1 Endurance R/C
iProduct 2 PCTx
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 41
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 0 No Subclass
bInterfaceProtocol 0 None
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.01
bCountryCode 0 Not supported
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 47
Report Descriptors:
** UNAVAILABLE **
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0020 1x 32 bytes
bInterval 10
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0020 1x 32 bytes
bInterval 10
Device Status: 0x0001
Self Powered

Once again, thanks a for the help!
Pedro
Post by Tim Roberts
Post by Pedro Gouveia
I am trying to develop a new driver for usb device. The device is an
Endurance R/C PCTx.
They give away a sample code to start programming for this device. The
problem is that this code is for windows machines, and I want to port
it for linux.
I already initialized the device with libusb, and the device is
claimed by my program with no problem.
The problem that I found, and I would like your help is that on
windows code, they use a function WriteFile to write an array of chars
into the device, and I've been trying to do the same with libusb, but
until now it didn't work.
WriteFile is a Win32 API, equivalent to the Liinux "write" function. I
say that only so you are aware that this isn't a custom API provided by
the vendor.
Where did the DeviceHandle come from? If it is a handle to a custom
driver, then we have absolutely no idea what they are doing with the
buffer inside their driver. Your code implies that it is a HID report;
if so, then it is certainly not going to be a bulk pipe.
--
Providenza & Boekelheide, Inc.
------------------------------------------------------------------------------
ThinkGeek and WIRED's GeekDad team up for the Ultimate
GeekDad Father's Day Giveaway. ONE MASSIVE PRIZE to the
http://p.sf.net/sfu/thinkgeek-promo
_______________________________________________
Libusb-devel mailing list
https://lists.sourceforge.net/lists/listinfo/libusb-devel
Tim Roberts
2010-06-09 17:32:33 UTC
Permalink
Post by Pedro Gouveia
It's the first time I'm developing a driver... I'm doing it more based
on attempt and result.. And it's not working...
I'm using this device in my university to control RC (radio control)
Robots through my computer. What it does is send the values of each of
the channels of the RC (1,2,3,4,5,6,7,8,9) directly to the servo
(probably this is not important.. but just to put you in context)
This is a HID device. There is often more to the protocol than just
blasting out bytes to the interrupt endpoint. HID reports need to have
a report ID as the first byte (unless there is only one report type).
Plus, there might be other setup requests that have to be sent before
its ready.

You might consider installing a software USB sniffer on the Windows side
to see if you can capture the entire transaction. That might give you a
better idea of what's happening at the lowest level.
--
Tim Roberts, ***@probo.com
Providenza & Boekelheide, Inc.
Tim Roberts
2010-06-09 19:57:49 UTC
Permalink
But, if I have the source code (for windows), would it be enough?
That all depends on the driver(s) that the Windows code is using. If it
is a custom driver, then we have no clue what that WriteFile actually
does. The driver could be turning that into multiple USB requests.
Anyway... if it's an HID as you say... can I use libusb? Or I need to
use libhid?
You CAN use libusb, although it might be easier to use libhid. In
Windows, it's often easier to use the HID library, but I don't have
experience with libhid on Linux.
Any more information I can read about this subject?
Also I can ask all this information to the seller.
The HID class specification is downloadable from the USB forum at
www.usb.org, but that may be overkill for what you're doing.

The vendor is likely to say "just look at our Windows sample, it works."
--
Tim Roberts, ***@probo.com
Providenza & Boekelheide, Inc.
Pedro Gouveia
2010-06-09 23:19:39 UTC
Permalink
Ok, sorry I thought WriteFile was a pretty known library for windows.

But that gave me some new ideas, I'm gonna compile the code in windows and
debug each of the settings of this writefile function.

WriteFile is part of WDK (Windows driver kit).
And here the syntax:

BOOL WINAPI WriteFile(__in HANDLE hFile,
__in LPCVOID lpBuffer,
__in DWORD nNumberOfBytesToWrite,
__out_opt LPDWORD lpNumberOfBytesWritten,

__inout_opt LPOVERLAPPED lpOverlapped
);

From: http://msdn.microsoft.com/en-us/library/aa365747%28VS.85%29.aspx

I thought libusb was a layer on top of libhid.. but now I see I was wrong...
And how can I bee sure that libhid will be enough for my purpose? Is there
anything you recommend me to read in the distinction between both libraries?

Thanks
Pedro
Post by Tim Roberts
But, if I have the source code (for windows), would it be enough?
That all depends on the driver(s) that the Windows code is using. If it
is a custom driver, then we have no clue what that WriteFile actually
does. The driver could be turning that into multiple USB requests.
Anyway... if it's an HID as you say... can I use libusb? Or I need to
use libhid?
You CAN use libusb, although it might be easier to use libhid. In
Windows, it's often easier to use the HID library, but I don't have
experience with libhid on Linux.
Any more information I can read about this subject?
Also I can ask all this information to the seller.
The HID class specification is downloadable from the USB forum at
www.usb.org, but that may be overkill for what you're doing.
The vendor is likely to say "just look at our Windows sample, it works."
--
Providenza & Boekelheide, Inc.
------------------------------------------------------------------------------
ThinkGeek and WIRED's GeekDad team up for the Ultimate
GeekDad Father's Day Giveaway. ONE MASSIVE PRIZE to the
http://p.sf.net/sfu/thinkgeek-promo
_______________________________________________
Libusb-devel mailing list
https://lists.sourceforge.net/lists/listinfo/libusb-devel
Xiaofan Chen
2010-06-09 23:33:59 UTC
Permalink
Post by Pedro Gouveia
I thought libusb was a layer on top of libhid.. but now I see I was wrong...
And how can I bee sure that libhid will be enough for my purpose? Is there
anything you recommend me to read in the distinction between both libraries?
libhid is not well suitable here. You'd better stick with libusb.
In fact, libhid is more suitable for real HID device like some UPS.
Its strong point is the HID report parser.

I tend to believe your device is more a custom HID device.
In that case, libhid does not offer any advantages.
--
Xiaofan http://mcuee.blogspot.com
Pete Batard
2010-06-09 23:53:20 UTC
Permalink
I'd agree with Xiaofan there.

The reason why the original sample uses WriteFile() is because this is
one way of writing reports to HID devices, as documented here:
http://msdn.microsoft.com/en-us/library/ff543402%28v=VS.85%29.aspx

The other way is to use HidD_SetOutputReport().

Libusb should support the writing of the same report as the original
sample, except you need to remove the first byte, as this is the report
ID, which is not something you should have to concern yourself with on
Linux.

Therefore the output report you are after should really be really 9
bytes long (not 10) and your code should go something like this:

char cmd[9];
cmd[0] = 1;
cmd[1] = 1;
cmd[2] = 1;
cmd[3] = 1;
cmd[4] = 1;
cmd[5] = 1;
cmd[6] = 1;
cmd[7] = 1;
cmd[8] = 1;
ret = usb_bulk_write(_hDevice, 0x01, const void *cmd, 9, 50);
cout <<"value of write: "<< ret<<endl;

Regards,

/Pete
Xiaofan Chen
2010-06-10 01:14:53 UTC
Permalink
Post by Xiaofan Chen
Post by Pedro Gouveia
I thought libusb was a layer on top of libhid.. but now I see I was wrong...
And how can I bee sure that libhid will be enough for my purpose? Is there
anything you recommend me to read in the distinction between both libraries?
libhid is not well suitable here. You'd better stick with libusb.
In fact, libhid is more suitable for real HID device like some UPS.
Its strong point is the HID report parser.
I tend to believe your device is more a custom HID device.
In that case, libhid does not offer any advantages.
Moreover, libusb can be used for your application under
Linux. The thing is that you need to infer the protocol
from the Windows source code and maybe make use of
sniffing to confirm that the data on the wire is the same
as you think.
--
Xiaofan http://mcuee.blogspot.com
Xiaofan Chen
2010-06-21 23:01:08 UTC
Permalink
Is there a sniffing for win7?
Or which works on a virtual machine (may be it doesn't make sense...)
Or which sniffing do u recommend? What information do I need?
(Sorry for the delay on response... )
For Win7, I am not so sure. The commercial ones should work.
Most of them offer 1month evaluation period.
Eg: http://www.sourcequest.com/ (Never tried it).

I have not tried Win7's ETW and the open source parser from Microsoft.
http://blogs.msdn.com/b/usbcoreblog/archive/2010/03/17/new-whitepaper-on-usb-event-tracing.aspx
http://nmparsers.codeplex.com/
--
Xiaofan http://mcuee.blogspot.com
Pete Batard
2010-06-21 23:11:36 UTC
Permalink
Also:

http://blogs.msdn.com/b/usbcoreblog/archive/2009/12/04/etw-in-the-windows-7-usb-core-stack.aspx
http://blogs.msdn.com/b/usbcoreblog/archive/2009/12/21/answering-the-question-what-s-wrong-with-my-device-using-usb-etw.aspx

Regards,

/Pete
Graeme Gill
2010-06-22 00:28:41 UTC
Permalink
Post by Xiaofan Chen
For Win7, I am not so sure. The commercial ones should work.
Most of them offer 1month evaluation period.
Eg: http://www.sourcequest.com/ (Never tried it).
I'd imagine that snoopypro will still work if you boot with F8.

Graeme Gill.
Xiaofan Chen
2010-06-22 00:57:35 UTC
Permalink
Post by Graeme Gill
Post by Xiaofan Chen
For Win7, I am not so sure. The commercial ones should work.
Most of them offer 1month evaluation period.
Eg: http://www.sourcequest.com/ (Never tried it).
I'd imagine that snoopypro will still work if you boot with F8.
Not so sure about SnoopyPro and I have not tried it under
Win 7 (my one is x64).

SniffUSB 2.0 is for sure not working under Vista/Win7 even though
it works under XP and XP64 according to the author.
http://www.pcausa.com/Utilities/UsbSnoop/
--
Xiaofan http://mcuee.blogspot.com
Graeme Gill
2010-06-22 01:49:11 UTC
Permalink
Post by Xiaofan Chen
Not so sure about SnoopyPro and I have not tried it under
Win 7 (my one is x64).
Yep, works fine on Vista 32 bit if booted with F8 and
run as administrator. Of course to run on 64 bit a 64 bit
UsbSnoop.sys would have to be built and used.

Graeme Gill.

Tim Roberts
2010-06-09 23:36:56 UTC
Permalink
Post by Pedro Gouveia
Ok, sorry I thought WriteFile was a pretty known library for windows.
It's not a library. It is a core part of the Windows API. It is THE
primary method for getting data into drivers. However, it is completely
up to the individual driver to decide what "write" means. When you
write to a file, or to a printer, it's pretty clear what "write" means.
When you write to a device, it's not as obvious.
Post by Pedro Gouveia
But that gave me some new ideas, I'm gonna compile the code in windows
and debug each of the settings of this writefile function.
WriteFile is part of WDK (Windows driver kit).
No. It's a part of the Windows API. It doesn't matter from what
direction you look at the parameters to WriteFile. The driver will
translate your WriteFile buffer into USB requests, but you cannot know
beforehand how the driver is going to do that translation, unless the
documentation has told you so. The only way for you to learn that is to
use a software USB sniffer to listen to the packets going out. Since
you're trying to reverse-engineer this interface for Linux, that does
not seem like an unreasonable strategy for you.
Post by Pedro Gouveia
I thought libusb was a layer on top of libhid.. but now I see I was
wrong... And how can I bee sure that libhid will be enough for my
purpose? Is there anything you recommend me to read in the distinction
between both libraries?
I don't know libhid. Hopefully, one of the other responders here can
provide a more useful answer.
--
Tim Roberts, ***@probo.com
Providenza & Boekelheide, Inc.
Xiaofan Chen
2010-06-10 01:12:37 UTC
Permalink
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 No Subclass
      bInterfaceProtocol      0 None
      iInterface              0
          bLength                 9
          bDescriptorType        33
          bcdHID               1.01
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      47
           ** UNAVAILABLE **
You have to detach the kernel hid driver in order for
lsusb to print out the HID report descriptor.

From there we will know whether report ID is used
or not.

I will tend to guess that report ID is not used, and
you can try Pete's suggestion.


--
Loading...