Class: LIBUSB::Transfer
- Inherits:
-
Object
- Object
- LIBUSB::Transfer
- Defined in:
- lib/libusb/transfer.rb
Overview
Abstract base class for USB transfers. Use ControlTransfer, BulkTransfer, InterruptTransfer, IsochronousTransfer to do transfers.
There are convenience methods for DevHandle#bulk_transfer, DevHandle#control_transfer and DevHandle#interrupt_transfer, that fit for most use cases. Using Transfer derived classes directly, however, is needed for isochronous transfers and allows a more advanced buffer management.
Direct Known Subclasses
BulkStreamTransfer, BulkTransfer, ControlTransfer, InterruptTransfer, IsochronousTransfer
Defined Under Namespace
Classes: ZeroCopyMemory
Constant Summary collapse
- TransferStatusToError =
{ :TRANSFER_ERROR => LIBUSB::ERROR_IO, :TRANSFER_TIMED_OUT => LIBUSB::ERROR_TIMEOUT, :TRANSFER_CANCELLED => LIBUSB::ERROR_INTERRUPTED, :TRANSFER_STALL => LIBUSB::ERROR_PIPE, :TRANSFER_NO_DEVICE => LIBUSB::ERROR_NO_DEVICE, :TRANSFER_OVERFLOW => LIBUSB::ERROR_OVERFLOW, }
Instance Attribute Summary collapse
-
#allow_device_memory ⇒ Object
Try to use persistent device memory.
-
#dev_handle ⇒ Object
The handle for the device to communicate with.
Instance Method Summary collapse
-
#actual_buffer(offset = 0) ⇒ Object
Retrieve the data actually transferred.
-
#actual_length ⇒ Object
The number of bytes actually transferred.
-
#alloc_buffer(len, data = nil) ⇒ Object
Allocate
len
bytes of data buffer for input transfer. -
#buffer ⇒ Object
Retrieve the current data buffer.
-
#buffer=(data) ⇒ Object
Set output data that should be sent.
-
#callback=(proc) ⇒ Object
Set the block that will be invoked when the transfer completes, fails, or is cancelled.
-
#cancel! ⇒ Object
Asynchronously cancel a previously submitted transfer.
-
#endpoint=(endpoint) ⇒ Object
Set the address of a valid endpoint to communicate with.
-
#free_buffer ⇒ Object
Clear the current data buffer.
- #memory_type ⇒ Object
-
#status ⇒ Object
The status of the transfer.
-
#submit!(&block) ⇒ Object
Submit a transfer.
-
#submit_and_wait ⇒ Object
Submit the transfer and wait until the transfer completes or fails.
-
#submit_and_wait! ⇒ Object
Submit the transfer and wait until the transfer completes or fails.
-
#timeout ⇒ Object
Get timeout for this transfer in millseconds.
-
#timeout=(value) ⇒ Object
Set timeout for this transfer in millseconds.
Instance Attribute Details
#allow_device_memory ⇒ Object
Try to use persistent device memory.
If enabled, attempts to allocate a block of persistent DMA memory suitable for transfers against the given device. The memory is allocated by #alloc_buffer or #buffer=. If unsuccessful, ordinary user space memory will be used.
Using this memory instead of regular memory means that the host controller can use DMA directly into the buffer to increase performance, and also that transfers can no longer fail due to kernel memory fragmentation.
It requires libusb-1.0.21 and Linux-4.6 to be effective, but it can safely be enabled on other systems.
Note that this type of memory is bound to the #dev_handle=. So even if the DevHandle is closed, the memory is still accessable and the device is locked. It is free’d by the garbage collector eventually, but in order to close the device deterministic, it is required to call #free_buffer on all LIBUSB::Transfers which use persistent device memory.
145 146 147 |
# File 'lib/libusb/transfer.rb', line 145 def allow_device_memory @allow_device_memory end |
#dev_handle ⇒ Object
The handle for the device to communicate with.
66 67 68 |
# File 'lib/libusb/transfer.rb', line 66 def dev_handle @dev_handle end |
Instance Method Details
#actual_buffer(offset = 0) ⇒ Object
Retrieve the data actually transferred.
178 179 180 |
# File 'lib/libusb/transfer.rb', line 178 def actual_buffer(offset=0) @transfer[:buffer].get_bytes(offset, @transfer[:actual_length]) end |
#actual_length ⇒ Object
The number of bytes actually transferred.
125 126 127 |
# File 'lib/libusb/transfer.rb', line 125 def actual_length @transfer[:actual_length] end |
#alloc_buffer(len, data = nil) ⇒ Object
Allocate len
bytes of data buffer for input transfer.
117 118 119 120 121 122 |
# File 'lib/libusb/transfer.rb', line 117 def alloc_buffer(len, data=nil) ensure_enough_buffer(len) @buffer.put_bytes(0, data) if data @transfer[:buffer] = @buffer @transfer[:length] = len end |
#buffer ⇒ Object
Retrieve the current data buffer.
98 99 100 |
# File 'lib/libusb/transfer.rb', line 98 def buffer @transfer[:buffer].read_string(@transfer[:length]) end |
#buffer=(data) ⇒ Object
Set output data that should be sent.
90 91 92 93 94 95 |
# File 'lib/libusb/transfer.rb', line 90 def buffer=(data) ensure_enough_buffer(data.bytesize) @buffer.put_bytes(0, data) @transfer[:buffer] = @buffer @transfer[:length] = data.bytesize end |
#callback=(proc) ⇒ Object
Set the block that will be invoked when the transfer completes, fails, or is cancelled.
186 187 188 189 190 191 192 193 |
# File 'lib/libusb/transfer.rb', line 186 def callback=(proc) # Save proc to instance variable so that GC doesn't free # the proc object before the transfer. @callback_proc = proc do |pTrans| proc.call(self) end @transfer[:callback] = @callback_proc end |
#cancel! ⇒ Object
Asynchronously cancel a previously submitted transfer.
This function returns immediately, but this does not indicate cancellation is complete. Your callback function will be invoked at some later time with a transfer status of :TRANSFER_CANCELLED.
225 226 227 228 |
# File 'lib/libusb/transfer.rb', line 225 def cancel! res = Call.libusb_cancel_transfer( @transfer ) LIBUSB.raise_error res, "in libusb_cancel_transfer" if res!=0 end |
#endpoint=(endpoint) ⇒ Object
Set the address of a valid endpoint to communicate with.
83 84 85 86 |
# File 'lib/libusb/transfer.rb', line 83 def endpoint=(endpoint) endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress @transfer[:endpoint] = endpoint end |
#free_buffer ⇒ Object
Clear the current data buffer.
103 104 105 106 107 108 109 110 |
# File 'lib/libusb/transfer.rb', line 103 def free_buffer if @buffer @buffer.free @buffer = nil @transfer[:buffer] = nil @transfer[:length] = 0 end end |
#memory_type ⇒ Object
150 151 152 153 154 155 156 |
# File 'lib/libusb/transfer.rb', line 150 def memory_type case @buffer when ZeroCopyMemory then :device_memory when FFI::MemoryPointer then :user_space else nil end end |
#status ⇒ Object
The status of the transfer.
Only for use within transfer callback function or after the callback was called.
If this is an isochronous transfer, this field may read :TRANSFER_COMPLETED even if there were errors in the frames. Use the status field in each packet to determine if errors occurred.
202 203 204 |
# File 'lib/libusb/transfer.rb', line 202 def status @transfer[:status] end |
#submit!(&block) ⇒ Object
Submit a transfer.
This function will fire off the USB transfer and then return immediately. This method can be called with block. It is called when the transfer completes, fails, or is cancelled.
211 212 213 214 215 216 217 218 |
# File 'lib/libusb/transfer.rb', line 211 def submit!(&block) self.callback = block if block_given? # puts "submit transfer #{@transfer.inspect} buffer: #{@transfer[:buffer].inspect} length: #{@transfer[:length].inspect} status: #{@transfer[:status].inspect} callback: #{@transfer[:callback].inspect} dev_handle: #{@transfer[:dev_handle].inspect}" res = Call.libusb_submit_transfer( @transfer ) LIBUSB.raise_error res, "in libusb_submit_transfer" if res!=0 end |
#submit_and_wait ⇒ Object
Submit the transfer and wait until the transfer completes or fails.
Inspect #status to check for transfer errors.
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/libusb/transfer.rb', line 242 def submit_and_wait raise ArgumentError, "#{self.class}#dev_handle not set" unless @dev_handle @completion_flag.completed = false submit! do |tr2| @completion_flag.completed = true end until @completion_flag.completed? begin @dev_handle.device.context.handle_events nil, @completion_flag rescue ERROR_INTERRUPTED next rescue LIBUSB::Error cancel! until @completion_flag.completed? @dev_handle.device.context.handle_events nil, @completion_flag end raise end end end |
#submit_and_wait! ⇒ Object
Submit the transfer and wait until the transfer completes or fails.
A proper Error is raised, in case the transfer did not complete.
268 269 270 271 272 |
# File 'lib/libusb/transfer.rb', line 268 def submit_and_wait! submit_and_wait raise( TransferStatusToError[status] || ERROR_OTHER, "error #{status}") unless status==:TRANSFER_COMPLETED end |
#timeout ⇒ Object
Get timeout for this transfer in millseconds.
A value of 0 indicates no timeout.
78 79 80 |
# File 'lib/libusb/transfer.rb', line 78 def timeout @transfer[:timeout] end |
#timeout=(value) ⇒ Object
Set timeout for this transfer in millseconds.
A value of 0 indicates no timeout.
71 72 73 |
# File 'lib/libusb/transfer.rb', line 71 def timeout=(value) @transfer[:timeout] = value end |