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.
149 150 151 |
# File 'lib/libusb/transfer.rb', line 149 def allow_device_memory @allow_device_memory end |
#dev_handle ⇒ Object
The handle for the device to communicate with.
70 71 72 |
# File 'lib/libusb/transfer.rb', line 70 def dev_handle @dev_handle end |
Instance Method Details
#actual_buffer(offset = 0) ⇒ Object
Retrieve the data actually transferred.
182 183 184 |
# File 'lib/libusb/transfer.rb', line 182 def actual_buffer(offset=0) @transfer[:buffer].get_bytes(offset, @transfer[:actual_length]) end |
#actual_length ⇒ Object
The number of bytes actually transferred.
129 130 131 |
# File 'lib/libusb/transfer.rb', line 129 def actual_length @transfer[:actual_length] end |
#alloc_buffer(len, data = nil) ⇒ Object
Allocate len
bytes of data buffer for input transfer.
121 122 123 124 125 126 |
# File 'lib/libusb/transfer.rb', line 121 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.
102 103 104 |
# File 'lib/libusb/transfer.rb', line 102 def buffer @transfer[:buffer].read_string(@transfer[:length]) end |
#buffer=(data) ⇒ Object
Set output data that should be sent.
94 95 96 97 98 99 |
# File 'lib/libusb/transfer.rb', line 94 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.
190 191 192 193 194 195 196 197 |
# File 'lib/libusb/transfer.rb', line 190 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.
229 230 231 232 |
# File 'lib/libusb/transfer.rb', line 229 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.
87 88 89 90 |
# File 'lib/libusb/transfer.rb', line 87 def endpoint=(endpoint) endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress @transfer[:endpoint] = endpoint end |
#free_buffer ⇒ Object
Clear the current data buffer.
107 108 109 110 111 112 113 114 |
# File 'lib/libusb/transfer.rb', line 107 def free_buffer if @buffer @buffer.free @buffer = nil @transfer[:buffer] = nil @transfer[:length] = 0 end end |
#memory_type ⇒ Object
154 155 156 157 158 159 160 |
# File 'lib/libusb/transfer.rb', line 154 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.
206 207 208 |
# File 'lib/libusb/transfer.rb', line 206 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.
215 216 217 218 219 220 221 222 |
# File 'lib/libusb/transfer.rb', line 215 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.
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
# File 'lib/libusb/transfer.rb', line 246 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 Exception 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.
272 273 274 275 276 |
# File 'lib/libusb/transfer.rb', line 272 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.
82 83 84 |
# File 'lib/libusb/transfer.rb', line 82 def timeout @transfer[:timeout] end |
#timeout=(value) ⇒ Object
Set timeout for this transfer in millseconds.
A value of 0 indicates no timeout.
75 76 77 |
# File 'lib/libusb/transfer.rb', line 75 def timeout=(value) @transfer[:timeout] = value end |