Class: LIBUSB::Transfer

Inherits:
Object
  • Object
show all
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.

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 Method Summary collapse

Instance Method Details

#actual_buffer(offset = 0) ⇒ Object

Retrieve the data actually transferred.

Parameters:

  • offset (Fixnum) (defaults to: 0)

    optional offset of the retrieved data in the buffer.



102
103
104
# File 'lib/libusb/transfer.rb', line 102

def actual_buffer(offset=0)
  @transfer[:buffer].get_bytes(offset, @transfer[:actual_length])
end

#actual_lengthObject

The number of bytes actually transferred.



95
96
97
# File 'lib/libusb/transfer.rb', line 95

def actual_length
  @transfer[:actual_length]
end

#alloc_buffer(len, data = nil) ⇒ Object

Allocate len bytes of data buffer for input transfer.

Parameters:

  • len (Fixnum)

    Number of bytes to allocate

  • data (String, nil) (defaults to: nil)

    some data to initialize the buffer with



84
85
86
87
88
89
90
91
92
# File 'lib/libusb/transfer.rb', line 84

def alloc_buffer(len, data=nil)
  if !@buffer || len>@buffer.size
    free_buffer
    @buffer = FFI::MemoryPointer.new(len, 1, false)
  end
  @buffer.put_bytes(0, data) if data
  @transfer[:buffer] = @buffer
  @transfer[:length] = len
end

#bufferObject

Retrieve the current data buffer.



66
67
68
# File 'lib/libusb/transfer.rb', line 66

def buffer
  @transfer[:buffer].read_string(@transfer[:length])
end

#buffer=(data) ⇒ Object

Set output data that should be sent.



55
56
57
58
59
60
61
62
63
# File 'lib/libusb/transfer.rb', line 55

def buffer=(data)
  if !@buffer || data.bytesize>@buffer.size
    free_buffer
    @buffer = FFI::MemoryPointer.new(data.bytesize, 1, false)
  end
  @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.

Parameters:

  • proc (Proc)

    The block that should be called



110
111
112
113
114
115
116
117
# File 'lib/libusb/transfer.rb', line 110

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.



149
150
151
152
# File 'lib/libusb/transfer.rb', line 149

def cancel!
  res = Call.libusb_cancel_transfer( @transfer )
  LIBUSB.raise_error res, "in libusb_cancel_transfer" if res!=0
end

#dev_handle=(dev) ⇒ Object

Set the handle for the device to communicate with.



36
37
38
39
# File 'lib/libusb/transfer.rb', line 36

def dev_handle=(dev)
  @dev_handle = dev
  @transfer[:dev_handle] = @dev_handle.pHandle
end

#endpoint=(endpoint) ⇒ Object

Set the address of a valid endpoint to communicate with.



49
50
51
52
# File 'lib/libusb/transfer.rb', line 49

def endpoint=(endpoint)
  endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
  @transfer[:endpoint] = endpoint
end

#free_bufferObject

Clear the current data buffer.



71
72
73
74
75
76
77
78
# File 'lib/libusb/transfer.rb', line 71

def free_buffer
  if @buffer
    @buffer.free
    @buffer = nil
    @transfer[:buffer] = nil
    @transfer[:length] = 0
  end
end

#statusObject

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.



126
127
128
# File 'lib/libusb/transfer.rb', line 126

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.



135
136
137
138
139
140
141
142
# File 'lib/libusb/transfer.rb', line 135

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_waitObject

Submit the transfer and wait until the transfer completes or fails.

Inspect #status to check for transfer errors.



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/libusb/transfer.rb', line 166

def submit_and_wait
  @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.

Raises:



190
191
192
193
194
# File 'lib/libusb/transfer.rb', line 190

def submit_and_wait!
  submit_and_wait

  raise( TransferStatusToError[status] || ERROR_OTHER, "error #{status}") unless status==:TRANSFER_COMPLETED
end

#timeout=(value) ⇒ Object

Timeout for this transfer in millseconds.

A value of 0 indicates no timeout.



44
45
46
# File 'lib/libusb/transfer.rb', line 44

def timeout=(value)
  @transfer[:timeout] = value
end