Closed manvir-singh closed 8 years ago
Should you be providing a slice with 64 bytes of data instead of an empty slice?
Isn't read_control
suppose to write the response into data
?
From the docs
If the return value is Ok(n), then buf is populated with n bytes of data.
I think @goertzenator is right. It can't allocate more space for a slice, and an empty slice doesn't have anywhere to store the read data. It will pass the slice's pointer and a length of zero to libusb_control_transfer
, which probably returns LIBUSB_ERROR_INVALID_PARAM
. This crate's read_control
method merely translates that error to an enum.
To read into a Vec, you need to give it a capacity and then obtain a mutable slice that matches the vec's capacity. as_mut_slice()
returns a slice for only the part of the Vec that is filled.
Try something like this:
let mut vec = Vec::<u8>::with_capacity(64);
let buf = unsafe {
slice::from_raw_parts_mut(vec.as_mut_ptr(), vec.capacity())
};
Then don't forget to call vec.set_len()
to update the vec's length after reading.
You would have to use a non-empty slice in that case. Try pushing some data into that Vec first.
But you've just made me see the actual issue here: you are calling control_read but specifying an OUT (write) command.
edit: grammar
I tried this. I still get the same error. Using Direction::In
or Direction::Out
does not seem to change anything, both give me the same error.
let mut vec: Vec<u8> = Vec::<u8>::with_capacity(64);
let buf = unsafe {
slice::from_raw_parts_mut(vec.as_mut_ptr(), vec.capacity())
};
handle.read_control(
request_type(Direction::In, RequestType::Class, Recipient::Interface),
0x09,
0x0200,
0x0000,
buf,
Duration::from_secs(1)
).expect("Cant get data");
println!("Done");
That trace frame you listed shows an OUT command, so you should be using write_control()
and Direction::OUT
(and forming appropriate data to send to the device, if any).
@dcuddeback , this problem reveals a usability issue in read_control()
and write_control()
. The underlying libusb
has just single control function, but you had to split it up on the Rust wrapper for const/mut data purposes. In the Rust functions it is easy to specify incorrect direction
, but this can be implied by the function call. Perhaps the request_type
parameter should be unrolled such that a call looks like this...
handle.read_control(
RequestType::Class,
Recipient::Interface,
0x09,
0x0200,
0x0000,
buf,
Duration::from_secs(1)
).expect("Cant get data");
@dcuddeback Success using write_control
with Direction::OUT
worked. Only problem I have is I dont know what data is being sent to the device. Do you happen to know how I can obtain this information?
USB packet that was intercepted: This is the packet I'm trying to recreate in libusb-rs
Frame 7: 36 bytes on wire (288 bits), 36 bytes captured (288 bits) on interface 0
Interface id: 0 (-)
Encapsulation type: USB packets with USBPcap header (153)
Arrival Time: Apr 8, 2016 13:31:00.973567000 Pacific Daylight Time
[Time shift for this packet: 0.000000000 seconds]
Epoch Time: 1460147460.973567000 seconds
[Time delta from previous captured frame: 0.000000000 seconds]
[Time delta from previous displayed frame: 0.000000000 seconds]
[Time since reference or first frame: 0.002000000 seconds]
Frame Number: 7
Frame Length: 36 bytes (288 bits)
Capture Length: 36 bytes (288 bits)
[Frame is marked: False]
[Frame is ignored: False]
[Protocols in frame: usb]
USB URB
[Source: host]
[Destination: 6.1.0]
USBPcap pseudoheader length: 28
IRP ID: 0xffffe001f87be680
IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
URB Function: URB_FUNCTION_CLASS_INTERFACE (0x001b)
IRP information: 0x00, Direction: FDO -> PDO
0000 000. = Reserved: 0x00
.... ...0 = Direction: FDO -> PDO (0x00)
URB bus id: 6
Device address: 1
Endpoint: 0x00, Direction: OUT
0... .... = Direction: OUT (0)
.000 0000 = Endpoint value: 0
URB transfer type: URB_CONTROL (0x02)
Packet Data Length: 8
[Response in: 8]
Control transfer stage: Setup (0)
[bInterfaceClass: Unknown (0xffff)]
URB setup
bmRequestType: 0x21
0... .... = Direction: Host-to-device
.01. .... = Type: Class (0x01)
...0 0001 = Recipient: Interface (0x01)
bRequest: 9
wValue: 0x0200
wIndex: 0 (0x0000)
wLength: 64
What device are you talking to? It is a class request so maybe that class is documented somewhere.
I was unable to find any docs. Corsair h80i: http://www.corsair.com/en-ca/hydro-series-h80i-high-performance-liquid-cpu-cooler
@dcuddeback I think I found the bytes that are sent.
03 2E 09 01
Then the rest 60 bytes contain 00
So is this how i would send this data?
let mut vec: Vec<u8> = Vec::new();
vec.resize(64, 0x00);
vec.push(0x03);
vec.push(0x2E);
vec.push(0x09);
vec.push(0x01);
handle.write_control(
request_type(Direction::Out, RequestType::Class, Recipient::Interface),
9,
0x0200,
0x0000,
vec.as_slice(),
Duration::from_secs(1)
).expect("Cant get data");
@Programming4life Maybe try to do the resize()
after pushing the other four values so that they're at the beginning of your buffer:
let mut vec: Vec<u8> = Vec::new();
vec.push(0x03);
vec.push(0x2E);
vec.push(0x09);
vec.push(0x01);
vec.resize(64, 0x00);
I think the way you have it will send a buffer of 68 bytes, where the first 64 bytes are 0.
It works! @goertzenator @dcuddeback Thank you both for the help I really appreciate it.
I keep getting
"InvalidParam"
I have no idea what I am doing wrong here. I know a param is incorrect but witch one is it?Part of my code:
Info about the usb device I'm trying to talk with: