-
Notifications
You must be signed in to change notification settings - Fork 84
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
First try rusb-async #143
base: master
Are you sure you want to change the base?
First try rusb-async #143
Conversation
Co-authored-by: Ryan Butler <thebutlah@gmail.com> Co-authored-by: Kevin Mehall <km@kevinmehall.net>
Does this work for isochronous transfers? https://github.com/JJTech0130/easycap-rs/blob/master/src/streaming.rs is my code, but it's just printing 0s |
Hi. Thank you for trying the current api. I haven't tested isochronous endpoints. What operating system are you trying on? |
macOS. I’m trying to port https://github.com/JJTech0130/easycap to Rust, it used libusb from Python. |
Oh it looks like I've implemented the isochronous API incorrectly. I'll try to fix it as soon as I have time. Possibly this week |
I completely forgot that isochronous transfer is different from other. Need more time to think how to implement better api for them. Because for iso we should return list of packet |
pub unsafe fn submit_control_raw(&mut self, buffer: Vec<u8>) -> Result<()> { | ||
// Safety: If transfer is submitted, it is pushed onto `pending` where it will be | ||
// dropped before `device` is freed. | ||
unsafe { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not really that knowledgeable in unsafe rust, but when I patched in a modified version while trying to fix isochronous transfers, rustc
warned me that an unsafe {
block is not necessary because it's an unsafe fn
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
Turns out it's called a "struct hack": to make the last member of the struct have a variable size. |
Yes it's C struct hack and it's work in rust for repr C struct. Example bellow use libusb1_sys as ffi;
use std::ptr::NonNull;
fn main() {
unsafe {
let ptr =
NonNull::new(ffi::libusb_alloc_transfer(5)).expect("Could not allocate transfer!");
let transfer: *mut ffi::libusb_transfer = ptr.as_ptr();
(*transfer).num_iso_packets = 5;
ffi::libusb_set_iso_packet_lengths(ptr.as_ptr(), (200 / 5) as u32);
for i in 0..(*transfer).num_iso_packets {
let len = (*transfer)
.iso_packet_desc
.get_unchecked_mut(i as usize)
.length;
println!("len of #{i} is {len}")
}
}
} |
This is what I came up with yesterday, forgot to add it here: /// Prerequisite: must be an isochronous transfer
fn iso_packet_descriptors(&self) -> &[ffi::libusb_iso_packet_descriptor] {
assert!(self.transfer().transfer_type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS);
// The packet descriptors are stored using the "C99 struct hack":
// Basically, there is a zero sized array at the end of the struct
// and the struct is allocated with extra memory added to the end
// the size of the extra memory goes to the last element of the struct
unsafe {
let addr = addr_of!(self.transfer().iso_packet_desc)
.cast::<ffi::libusb_iso_packet_descriptor>();
slice::from_raw_parts(addr, self.transfer().num_iso_packets as usize)
}
} |
Looks good. Are you try this with iso? I don't have device with iso endpoint, so I can't test. |
Yes, the reason I want to use |
I’m wondering how you want to implement this: should isochronous transfers have their own poll function, with a different return type, or just have one function that can return multiple types? |
I am still not sure. Maybe enum or something that contain enum inside. Also pool should process only one endpoint or we should pass transfer into user data. |
This comment was marked as outdated.
This comment was marked as outdated.
Also, I think that the |
It's really hard to do. Because libusb it completion based is really hard to do safe wrapper. If you not see this post https://without.boats/blog/io-uring/ I strong recommend read it first. |
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
Y’know what, I’m going to stop trying to restructure it. I’m realizing that I can’t keep using OOP principles here… not sure what the alternative is though… |
So, I'm seeing several things. One of which, is there isn't actually a way to tell what transfer is what, is there? |
Maybe an enum TransferType {
Bulk { endpoint: u8 },
Control { request_type: u8, request: u8, value: u16, index: u16 },
Isochronous { endpoint: u8, num_packets: u32 },
} If we passed that to UserData, it would be available on the other end, and we could keep track of what transfer it was. Would also allow for a quick re-submit. |
let length = data.len() as u16; | ||
|
||
ffi::libusb_fill_control_setup( | ||
buf.as_mut_ptr() as *mut u8, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's with the as *mut u8
? Shouldn't .as_mut_ptr()
return that already?
index: u16, | ||
data: &[u8], | ||
) -> Self { | ||
let mut buf = Vec::with_capacity(data.len() + LIBUSB_CONTROL_SETUP_SIZE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sooo... how is data actually used? You create the buffer with it's length, and you pass it's length to control_setup
, but where do you actually copy it into the buffer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm working on the other part of my refactor for iso transfers right now, but someone on the Rust discord suggested boxed slices instead of this weird Vec stuff.
BTW I don't think the length is ever updated either, so all the data in the buffer is in the reserved portion (as it's only written to by the FFI function which doesn't know about Vecs
Also oops totally forgot about implementing Interrupt transfers... |
@a1ien can you make
|
Hi. Sure, but i want little rewrite this approach. I found a few more omissions. I try to find time and make new release at the end of October. |
@a1ien Sorry to bother you, but I just wondered if you were going to work on this soon? |
Sorry for delay. I little busy on my new work. I will try to find time within a month. |
Just wondering what it the test device used. I am trying to modify the example to suit the Cypress EZ-USB FX3 bulksrcsink example. Now read_device seems to work but not read_async.
|
rusb-async also published on crates-io https://crates.io/crates/rusb-async