Closed Boscop closed 6 years ago
@Boscop Interesting. So the libusb documentation says it returns:
LIBUSB_ERROR_OVERFLOW
if the device offered more data
but only for bulk and interrupt transfers. http://libusb.sourceforge.net/api-1.0/packetoverflow.html also suggests it's only an issue for bulk/interrupt transfers. Getting the list of languages is a control transfer.
read_languages()
uses a 256 byte buffer to read the language IDs, which should be enough because the descriptor's length is encoded as a byte (max value 255): http://www.beyondlogic.org/usbnutshell/usb5.shtml#StringDescriptors.
I'm guessing you could get it to work by increasing the buffer size beyond a certain point, but I'd like to understand the root cause. If you get it to work that way, I'd be curious to know the minimum buffer size for it to work and what the length of the returned data is.
Have you tried with more than one operating system? Based on the other tickets you've opened, I'm assuming you're trying this on Windows with the MSVC toolchain. Do you get the same result on Linux?
I will test it more extensively, for now I commented out the call to read_languages()
in read_device()
from the example, and now I get this output:
Active configuration: 1
Reading from endpoint: Endpoint { config: 1, iface: 0, setting: 0, address: 129 }
- kernel driver? false
could not read from endpoint: Input/Output Error
No readable bulk endpoint
But it should be possible to read from the device (keyboard), someone did it here: https://github.com/sverrirs/CorsairK95/blob/master/CorsairK95.NET/K95Tester/K95Device.cs#L187-L237 (from this blog post)
What am I doing wrong?
I'm trying to port this to rust (sending LED data to the RGB keyboard).
I'm doing the exact same thing as that lib now, but for me, calling write_control()
always returns Err(Io)
, why? How can I get more info about the cause of the error?
This is my code:
extern crate libusb;
#[macro_use] extern crate smart_default;
use std::time::Duration;
fn main() {
let (vid, pid) = (0x1B1C, 0x1B11);
match libusb::Context::new() {
Ok(mut context) => {
match open_device(&mut context, vid, pid) {
Some((mut device, device_desc, mut handle)) => {
let mut kbd = K95::new();
kbd.set_led(CLK_F1, 255, 0, 0);
println!("{:?}", kbd.flush(&mut handle));
}
None => println!("could not find device {:04x}:{:04x}", vid, pid)
}
},
Err(e) => panic!("could not initialize libusb: {}", e)
}
}
#[derive(SmartDefault)]
struct K95 {
#[default = "[0; 144]"]
red_val: [u8; 144],
#[default = "[0; 144]"]
grn_val: [u8; 144],
#[default = "[0; 144]"]
blu_val: [u8; 144],
#[default = "[[0; 64]; 5]"]
data_pkt: [[u8; 64]; 5],
}
impl K95 {
fn new() -> Self {
let mut s = Self::default();
s.data_pkt[0][0] = 0x7F;
s.data_pkt[0][1] = 0x01;
s.data_pkt[0][2] = 0x3C;
s.data_pkt[1][0] = 0x7F;
s.data_pkt[1][1] = 0x02;
s.data_pkt[1][2] = 0x3C;
s.data_pkt[2][0] = 0x7F;
s.data_pkt[2][1] = 0x03;
s.data_pkt[2][2] = 0x3C;
s.data_pkt[3][0] = 0x7F;
s.data_pkt[3][1] = 0x04;
s.data_pkt[3][2] = 0x24;
s.data_pkt[4][0] = 0x07;
s.data_pkt[4][1] = 0x27;
s.data_pkt[4][4] = 0xD8;
s
}
fn set_led(&mut self, key: CorsairLedId, r: u8, g: u8, b: u8) {
let key_code = KEYMAP_US[key as usize] as usize;
if key_code == 0xFF { return; }
// For some reason rgb values are only 0-7? Not quite 16.8 million colours...
// 256 / 32 = 8
self.red_val[key_code] = 7 - (r >> 5);
self.grn_val[key_code] = 7 - (g >> 5);
self.blu_val[key_code] = 7 - (b >> 5);
}
fn flush(&mut self, handle: &mut libusb::DeviceHandle) -> libusb::Result<()> {
// Perform USB control message to keyboard
//
// Request Type: 0x21
// Request: 0x09
// Value 0x0300
// Index: 0x03
// Size: 64
for i in 0..60 {
self.data_pkt[0][i+4] = self.red_val[i*2+1] << 4 | self.red_val[i*2];
}
for i in 0..12 {
self.data_pkt[1][i+4] = self.red_val[i*2+121] << 4 | self.red_val[i*2+120];
}
for i in 0..48 {
self.data_pkt[1][i+16] = self.grn_val[i*2+1] << 4 | self.grn_val[i*2];
}
for i in 0..24 {
self.data_pkt[2][i+4] = self.grn_val[i*2+97] << 4 | self.grn_val[i*2+96];
}
for i in 0..36 {
self.data_pkt[2][i+28] = self.blu_val[i*2+1] << 4 | self.blu_val[i*2];
}
for i in 0..36 {
self.data_pkt[3][i+4] = self.blu_val[i*2+73] << 4 | self.blu_val[i*2+72];
}
let timeout = Duration::from_secs(1);
handle.write_control(0x21, 0x09, 0x0300, 0x03, &self.data_pkt[0], timeout)?;
handle.write_control(0x21, 0x09, 0x0300, 0x03, &self.data_pkt[1], timeout)?;
handle.write_control(0x21, 0x09, 0x0300, 0x03, &self.data_pkt[2], timeout)?;
handle.write_control(0x21, 0x09, 0x0300, 0x03, &self.data_pkt[3], timeout)?;
handle.write_control(0x21, 0x09, 0x0300, 0x03, &self.data_pkt[4], timeout)?;
Ok(())
}
}
I'm always getting Err(Io)
on the first call to write_control()
.
(Btw, here is another program that writes the LED data successfully.)
@Boscop Did you ever get to the bottom of the issue you're having? I can't tell from your comments whether you're reporting a bug or not, and you didn't answer any of my questions. I don't have the time to read through all the code you've pasted to help you debug your program. If you've found a bug in this library, would you mind pasting a minimal code sample to reproduce the issue? This ticket isn't actionable as is.
Sorry, I didn't get to the bottom yet, was busy with other things...
I think the cause of this IO error could be same as the one I'm getting when trying to open the keyboard with the hidapi crate: https://github.com/signal11/hidapi/issues/247#issuecomment-161152387
It's a security problem if a normally-privileged application can keystroke-log the system keyboard. Windows won't allow you to open a keyboard with hidd.dll.
It appears that values over 255 are problematic on windows:
I'm trying to use the
read_device()
function from the example, but read_languages() returns Err(Overflow). Why?Btw, the device I'm trying to read is a Corsair K95 RGB keyboard: