libusb 0.2.2-x86-mingw32 → 0.3.0-x86-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -37,7 +37,15 @@ require 'forwardable'
37
37
  # * Exceptions are different between ruby-usb and libusb and they don't get converted
38
38
  # * libusb-1.0 doesn't explicitly manage USB-buses, so only one Bus is used currently
39
39
  module USB
40
- DefaultContext = LIBUSB::Context.new
40
+ @default_context = nil
41
+ def self.default_context
42
+ @default_context ||= LIBUSB::Context.new
43
+ end
44
+
45
+ @default_bus = nil
46
+ def self.default_bus
47
+ @default_bus ||= Bus.new(default_context)
48
+ end
41
49
 
42
50
  USB_CLASS_PER_INTERFACE = LIBUSB::CLASS_PER_INTERFACE
43
51
  USB_CLASS_AUDIO = LIBUSB::CLASS_AUDIO
@@ -108,21 +116,21 @@ module USB
108
116
 
109
117
 
110
118
  def USB.busses
111
- [DefaultBus]
119
+ [default_bus]
112
120
  end
113
121
 
114
- def USB.devices; DefaultContext.devices.map{|c| Device.new(c) }; end
122
+ def USB.devices; default_context.devices.map{|c| Device.new(c) }; end
115
123
  def USB.configurations() USB.devices.map {|d| d.configurations }.flatten end
116
124
  def USB.interfaces() USB.configurations.map {|d| d.interfaces }.flatten end
117
125
  def USB.settings() USB.interfaces.map {|d| d.settings }.flatten end
118
126
  def USB.endpoints() USB.settings.map {|d| d.endpoints }.flatten end
119
127
 
120
128
  def USB.find_bus(n)
121
- DefaultBus
129
+ default_bus
122
130
  end
123
131
 
124
132
  def USB.each_device_by_class(devclass, subclass=nil, protocol=nil)
125
- devs = DefaultContext.devices :bClass=>devclass, :bSubClass=>subclass, :bProtocol=>protocol
133
+ devs = default_context.devices :bClass=>devclass, :bSubClass=>subclass, :bProtocol=>protocol
126
134
  devs.each do |dev|
127
135
  yield Device.new(dev)
128
136
  end
@@ -147,8 +155,6 @@ module USB
147
155
  end
148
156
  end
149
157
 
150
- DefaultBus = Bus.new(DefaultContext)
151
-
152
158
  def USB.dev_string(base_class, sub_class, protocol)
153
159
  LIBUSB.dev_string(base_class, sub_class, protocol)
154
160
  end
@@ -184,7 +190,7 @@ module USB
184
190
  end
185
191
  end
186
192
 
187
- def bus; DefaultBus; end
193
+ def bus; default_bus; end
188
194
  def configurations; @dev.configurations.map{|c| Configuration.new(c) }; end
189
195
  def interfaces; @dev.interfaces.map{|c| Interface.new(c) }; end
190
196
  def settings; @dev.settings.map{|c| Setting.new(c) }; end
@@ -207,7 +213,7 @@ module USB
207
213
  @cd<=>o.instance_variable_get(:@cd)
208
214
  end
209
215
 
210
- def bus; DefaultBus; end
216
+ def bus; default_bus; end
211
217
  def device() Device.new(@cd.device) end
212
218
  def interfaces; @cd.interfaces.map{|c| Interface.new(c) }; end
213
219
  def settings() self.interfaces.map {|d| d.settings }.flatten end
@@ -69,10 +69,23 @@ module LIBUSB
69
69
  # * Bit 4..0: Reserved, set to 0.
70
70
  #
71
71
  # @return [Integer]
72
+ #
73
+ # @see #self_powered?
74
+ # @see #remote_wakeup?
72
75
  def bmAttributes
73
76
  self[:bmAttributes]
74
77
  end
75
78
 
79
+ # @return [Boolean]
80
+ def self_powered?
81
+ bmAttributes & 0b1000000 != 0
82
+ end
83
+
84
+ # @return [Boolean]
85
+ def remote_wakeup?
86
+ bmAttributes & 0b100000 != 0
87
+ end
88
+
76
89
  # Maximum power consumption of the USB device from this bus in this configuration when the device is fully opreation.
77
90
  #
78
91
  # @return [Integer] Maximum Power Consumption in 2mA units
@@ -115,9 +128,8 @@ module LIBUSB
115
128
  def inspect
116
129
  attrs = []
117
130
  attrs << self.bConfigurationValue.to_s
118
- bits = self.bmAttributes
119
- attrs << "SelfPowered" if (bits & 0b1000000) != 0
120
- attrs << "RemoteWakeup" if (bits & 0b100000) != 0
131
+ attrs << "SelfPowered" if self_powered?
132
+ attrs << "RemoteWakeup" if remote_wakeup?
121
133
  desc = self.description
122
134
  attrs << desc if desc != '?'
123
135
  "\#<#{self.class} #{attrs.join(' ')}>"
@@ -29,7 +29,17 @@ module LIBUSB
29
29
 
30
30
  # Base class of libusb errors
31
31
  class Error < RuntimeError
32
+ # The data already transferred before the exception was raised
33
+ # @return [Fixnum] Number of bytes sent for an outgoing transfer
34
+ # @return [String] Received data for an ingoing transfer
35
+ attr_reader :transferred
36
+
37
+ def initialize(msg=nil, transferred=nil)
38
+ super(msg)
39
+ @transferred = transferred
40
+ end
32
41
  end
42
+
33
43
  # @private
34
44
  ErrorClassForResult = {}
35
45
 
@@ -60,6 +70,9 @@ module LIBUSB
60
70
  ISO_SYNC_TYPE_MASK = 0x0C
61
71
  ISO_USAGE_TYPE_MASK = 0x30
62
72
 
73
+ POLLIN = 1
74
+ POLLOUT = 4
75
+
63
76
 
64
77
  # http://www.usb.org/developers/defined_class
65
78
  # @private
@@ -71,12 +84,12 @@ module LIBUSB
71
84
  [0x06, 0x01, 0x01, "StillImaging"],
72
85
  [0x06, nil, nil, "Image"],
73
86
  [0x07, nil, nil, "Printer"],
74
- [0x08, 0x01, nil, "MassStorage RBC Bluk-Only"],
75
- [0x08, 0x02, 0x50, "MassStorage ATAPI Bluk-Only"],
76
- [0x08, 0x03, 0x50, "MassStorage QIC-157 Bluk-Only"],
87
+ [0x08, 0x01, nil, "MassStorage RBC Bulk-Only"],
88
+ [0x08, 0x02, 0x50, "MassStorage ATAPI Bulk-Only"],
89
+ [0x08, 0x03, 0x50, "MassStorage QIC-157 Bulk-Only"],
77
90
  [0x08, 0x04, nil, "MassStorage UFI"],
78
- [0x08, 0x05, 0x50, "MassStorage SFF-8070i Bluk-Only"],
79
- [0x08, 0x06, 0x50, "MassStorage SCSI Bluk-Only"],
91
+ [0x08, 0x05, 0x50, "MassStorage SFF-8070i Bulk-Only"],
92
+ [0x08, 0x06, 0x50, "MassStorage SCSI Bulk-Only"],
80
93
  [0x08, nil, nil, "MassStorage"],
81
94
  [0x09, 0x00, 0x00, "Full speed Hub"],
82
95
  [0x09, 0x00, 0x01, "Hi-speed Hub with single TT"],
@@ -132,7 +145,7 @@ module LIBUSB
132
145
  elsif desc = CLASS_CODES_HASH1[base_class]
133
146
  desc + " (%02x,%02x)" % [sub_class, protocol]
134
147
  else
135
- "Unkonwn(%02x,%02x,%02x)" % [base_class, sub_class, protocol]
148
+ "Unknown(%02x,%02x,%02x)" % [base_class, sub_class, protocol]
136
149
  end
137
150
  end
138
151
  end
@@ -18,11 +18,64 @@ require 'libusb/call'
18
18
  module LIBUSB
19
19
  # Class representing a libusb session.
20
20
  class Context
21
+ class Pollfd
22
+ include Comparable
23
+
24
+ def initialize(fd, events=0)
25
+ @fd, @events = fd, events
26
+ end
27
+
28
+ def <=>(other)
29
+ @fd <=> other.fd
30
+ end
31
+
32
+ # @return [IO] IO object bound to the file descriptor.
33
+ def io
34
+ IO.new @fd
35
+ end
36
+
37
+ # @return [Integer] Numeric file descriptor
38
+ attr_reader :fd
39
+
40
+ # @return [Integer] Event flags to poll for
41
+ attr_reader :events
42
+
43
+ # @return [Boolean] True if the file descriptor has to be observed for incoming/readable data
44
+ def pollin?
45
+ @events & POLLIN != 0
46
+ end
47
+
48
+ # @return [Boolean] True if the file descriptor has to be observed for outgoing/writeable data
49
+ def pollout?
50
+ @events & POLLOUT != 0
51
+ end
52
+
53
+ def inspect
54
+ "\#<#{self.class} fd:#{@fd}#{' POLLIN' if pollin?}#{' POLLOUT' if pollout?}>"
55
+ end
56
+ end
57
+
58
+ class CompletionFlag < FFI::Struct
59
+ layout :completed, :int
60
+
61
+ def completed?
62
+ self[:completed] != 0
63
+ end
64
+
65
+ def completed=(flag)
66
+ self[:completed] = flag ? 1 : 0
67
+ end
68
+ end
69
+
70
+
21
71
  # Initialize libusb context.
22
72
  def initialize
23
73
  m = FFI::MemoryPointer.new :pointer
24
- Call.libusb_init(m)
74
+ res = Call.libusb_init(m)
75
+ LIBUSB.raise_error res, "in libusb_init" if res!=0
25
76
  @ctx = m.read_pointer
77
+ @on_pollfd_added = nil
78
+ @on_pollfd_removed = nil
26
79
  end
27
80
 
28
81
  # Deinitialize libusb.
@@ -66,6 +119,7 @@ module LIBUSB
66
119
  def device_list
67
120
  pppDevs = FFI::MemoryPointer.new :pointer
68
121
  size = Call.libusb_get_device_list(@ctx, pppDevs)
122
+ LIBUSB.raise_error size, "in libusb_get_device_list" if size<0
69
123
  ppDevs = pppDevs.read_pointer
70
124
  pDevs = []
71
125
  size.times do |devi|
@@ -82,8 +136,41 @@ module LIBUSB
82
136
  # This method must be called when libusb is running asynchronous transfers.
83
137
  # This gives libusb the opportunity to reap pending transfers,
84
138
  # invoke callbacks, etc.
85
- def handle_events
86
- res = Call.libusb_handle_events(@ctx)
139
+ #
140
+ # If a zero timeout is passed, this function will handle any already-pending
141
+ # events and then immediately return in non-blocking style.
142
+ #
143
+ # If a non-zero timeout is passed and no events are currently pending, this
144
+ # method will block waiting for events to handle up until the specified timeout.
145
+ # If an event arrives or a signal is raised, this method will return early.
146
+ #
147
+ # If the parameter completion_flag is used, then after obtaining the event
148
+ # handling lock this function will return immediately if the flag is set to completed.
149
+ # This allows for race free waiting for the completion of a specific transfer.
150
+ # See source of {Transfer#submit_and_wait} for a use case of completion_flag.
151
+ #
152
+ # @param [Integer, nil] timeout the maximum time (in millseconds) to block waiting for
153
+ # events, or 0 for non-blocking mode
154
+ # @param [Context::CompletionFlag, nil] completion_flag CompletionFlag to check
155
+ def handle_events(timeout=nil, completion_flag=nil)
156
+ if completion_flag && !completion_flag.is_a?(Context::CompletionFlag)
157
+ raise ArgumentError, "completion_flag is not a CompletionFlag"
158
+ end
159
+ if timeout
160
+ timeval = Call::Timeval.new
161
+ timeval.in_ms = timeout
162
+ res = if Call.respond_to?(:libusb_handle_events_timeout_completed)
163
+ Call.libusb_handle_events_timeout_completed(@ctx, timeval, completion_flag)
164
+ else
165
+ Call.libusb_handle_events_timeout(@ctx, timeval)
166
+ end
167
+ else
168
+ res = if Call.respond_to?(:libusb_handle_events_completed)
169
+ Call.libusb_handle_events_completed(@ctx, completion_flag )
170
+ else
171
+ Call.libusb_handle_events(@ctx)
172
+ end
173
+ end
87
174
  LIBUSB.raise_error res, "in libusb_handle_events" if res<0
88
175
  end
89
176
 
@@ -123,5 +210,96 @@ module LIBUSB
123
210
  ( !filter_hash[:bcdDevice] || [filter_hash[:bcdDevice]].flatten.include?(dev.bcdDevice) )
124
211
  end
125
212
  end
213
+
214
+
215
+ # Retrieve a list of file descriptors that should be polled by your main
216
+ # loop as libusb event sources.
217
+ #
218
+ # As file descriptors are a Unix-specific concept, this function is not
219
+ # available on Windows and will always return +nil+.
220
+ #
221
+ # @return [Array<Pollfd>] list of Pollfd objects,
222
+ # +nil+ on error,
223
+ # +nil+ on platforms where the functionality is not available
224
+ def pollfds
225
+ ppPollfds = Call.libusb_get_pollfds(@ctx)
226
+ return nil if ppPollfds.null?
227
+ offs = 0
228
+ pollfds = []
229
+ while !(pPollfd=ppPollfds.get_pointer(offs)).null?
230
+ pollfd = Call::Pollfd.new pPollfd
231
+ pollfds << Pollfd.new(pollfd[:fd], pollfd[:events])
232
+ offs += FFI.type_size :pointer
233
+ end
234
+ # ppPollfds has to be released by free() -> give the GC this job
235
+ ppPollfds.autorelease = true
236
+ pollfds
237
+ end
238
+
239
+ # Determine the next internal timeout that libusb needs to handle.
240
+ #
241
+ # You only need to use this function if you are calling poll() or select() or
242
+ # similar on libusb's file descriptors yourself - you do not need to use it if
243
+ # you are calling {#handle_events} directly.
244
+ #
245
+ # You should call this function in your main loop in order to determine how long
246
+ # to wait for select() or poll() to return results. libusb needs to be called
247
+ # into at this timeout, so you should use it as an upper bound on your select() or
248
+ # poll() call.
249
+ #
250
+ # When the timeout has expired, call into {#handle_events} (perhaps
251
+ # in non-blocking mode) so that libusb can handle the timeout.
252
+ #
253
+ # This function may return zero. If this is the
254
+ # case, it indicates that libusb has a timeout that has already expired so you
255
+ # should call {#handle_events} immediately. A return code
256
+ # of +nil+ indicates that there are no pending timeouts.
257
+ #
258
+ # On some platforms, this function will always returns +nil+ (no pending timeouts).
259
+ # See libusb's notes on time-based events.
260
+ #
261
+ # @return [Float, nil] the timeout in seconds
262
+ def next_timeout
263
+ timeval = Call::Timeval.new
264
+ res = Call.libusb_get_next_timeout @ctx, timeval
265
+ LIBUSB.raise_error res, "in libusb_get_next_timeout" if res<0
266
+ res == 1 ? timeval.in_s : nil
267
+ end
268
+
269
+ # Register a notification block for file descriptor additions.
270
+ #
271
+ # This block will be invoked for every new file descriptor that
272
+ # libusb uses as an event source.
273
+ #
274
+ # Note that file descriptors may have been added even before you register these
275
+ # notifiers (e.g. at {Context#initialize} time).
276
+ #
277
+ # @yieldparam [Pollfd] pollfd The added file descriptor is yielded to the block
278
+ def on_pollfd_added &block
279
+ @on_pollfd_added = proc do |fd, events, _|
280
+ pollfd = Pollfd.new fd, events
281
+ block.call pollfd
282
+ end
283
+ Call.libusb_set_pollfd_notifiers @ctx, @on_pollfd_added, @on_pollfd_removed, nil
284
+ end
285
+
286
+ # Register a notification block for file descriptor removals.
287
+ #
288
+ # This block will be invoked for every removed file descriptor that
289
+ # libusb uses as an event source.
290
+ #
291
+ # Note that the removal notifier may be called during {Context#exit}
292
+ # (e.g. when it is closing file descriptors that were opened and added to the poll
293
+ # set at {Context#initialize} time). If you don't want this, overwrite the notifier
294
+ # immediately before calling {Context#exit}.
295
+ #
296
+ # @yieldparam [Pollfd] pollfd The removed file descriptor is yielded to the block
297
+ def on_pollfd_removed &block
298
+ @on_pollfd_removed = proc do |fd, _|
299
+ pollfd = Pollfd.new fd
300
+ block.call pollfd
301
+ end
302
+ Call.libusb_set_pollfd_notifiers @ctx, @on_pollfd_added, @on_pollfd_removed, nil
303
+ end
126
304
  end
127
305
  end
@@ -228,6 +228,14 @@ module LIBUSB
228
228
 
229
229
  # Perform a USB bulk transfer.
230
230
  #
231
+ # When called without a block, the transfer is done synchronously - so all events are handled
232
+ # internally and the sent/received data will be returned after completion or an exception will be raised.
233
+ #
234
+ # When called with a block, the method returns immediately after submitting the transfer.
235
+ # You then have to ensure, that {Context#handle_events} is called properly. As soon as the
236
+ # transfer is completed, the block is called with the sent/received data in case of success
237
+ # or the exception instance in case of failure.
238
+ #
231
239
  # The direction of the transfer is inferred from the direction bits of the
232
240
  # endpoint address.
233
241
  #
@@ -235,25 +243,31 @@ module LIBUSB
235
243
  # expecting to receive. If less data arrives than expected, this function will
236
244
  # return that data.
237
245
  #
238
- # You should also check the returned number of bytes for bulk writes. Not all of the
246
+ # You should check the returned number of bytes for bulk writes. Not all of the
239
247
  # data may have been written.
240
248
  #
241
- # Also check transferred bytes when dealing with a timeout error code. libusb may have
249
+ # Also check {Error#transferred} when dealing with a timeout exception. libusb may have
242
250
  # to split your transfer into a number of chunks to satisfy underlying O/S
243
251
  # requirements, meaning that the timeout may expire after the first few chunks
244
252
  # have completed. libusb is careful not to lose any data that may have been
245
253
  # transferred; do not assume that timeout conditions indicate a complete lack of
246
254
  # I/O.
247
255
  #
248
- # @param [Endpoint, Fixnum] :endpoint the (address of a) valid endpoint to communicate with
249
- # @param [String] :dataOut the data to send with an outgoing transfer
250
- # @param [Fixnum] :dataIn the number of bytes expected to receive with an ingoing transfer
251
- # @param [Fixnum] :timeout timeout (in millseconds) that this function should wait before giving
256
+ # @param [Hash] args
257
+ # @option args [Endpoint, Fixnum] :endpoint the (address of a) valid endpoint to communicate with
258
+ # @option args [String] :dataOut the data to send with an outgoing transfer
259
+ # @option args [Fixnum] :dataIn the number of bytes expected to receive with an ingoing transfer
260
+ # @option args [Fixnum] :timeout timeout (in millseconds) that this function should wait before giving
252
261
  # up due to no response being received. For an unlimited timeout, use value 0. Defaults to 1000 ms.
253
262
  #
254
263
  # @return [Fixnum] Number of bytes sent for an outgoing transfer
255
264
  # @return [String] Received data for an ingoing transfer
256
- def bulk_transfer(args={})
265
+ # @return [self] When called with a block
266
+ #
267
+ # @yieldparam [String, Integer, LIBUSB::Error] result result of the transfer is yielded to the block,
268
+ # when the asynchronous transfer has finished
269
+ # @raise [ArgumentError, LIBUSB::Error] in case of failure
270
+ def bulk_transfer(args={}, &block)
257
271
  timeout = args.delete(:timeout) || 1000
258
272
  endpoint = args.delete(:endpoint) || raise(ArgumentError, "no endpoint given")
259
273
  endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
@@ -275,17 +289,19 @@ module LIBUSB
275
289
  tr.alloc_buffer(dataIn)
276
290
  end
277
291
 
278
- tr.submit_and_wait!
279
-
280
- if dataOut
281
- tr.actual_length
282
- else
283
- tr.actual_buffer
284
- end
292
+ submit_transfer(tr, dataIn, 0, &block)
285
293
  end
286
294
 
287
295
  # Perform a USB interrupt transfer.
288
296
  #
297
+ # When called without a block, the transfer is done synchronously - so all events are handled
298
+ # internally and the sent/received data will be returned after completion or an exception will be raised.
299
+ #
300
+ # When called with a block, the method returns immediately after submitting the transfer.
301
+ # You then have to ensure, that {Context#handle_events} is called properly. As soon as the
302
+ # transfer is completed, the block is called with the sent/received data in case of success
303
+ # or the exception instance in case of failure.
304
+ #
289
305
  # The direction of the transfer is inferred from the direction bits of the
290
306
  # endpoint address.
291
307
  #
@@ -293,10 +309,10 @@ module LIBUSB
293
309
  # are expecting to receive. If less data arrives than expected, this function will
294
310
  # return that data.
295
311
  #
296
- # You should also check the returned number of bytes for interrupt writes. Not all of
312
+ # You should check the returned number of bytes for interrupt writes. Not all of
297
313
  # the data may have been written.
298
314
  #
299
- # Also check transferred when dealing with a timeout error code. libusb may have
315
+ # Also check {Error#transferred} when dealing with a timeout exception. libusb may have
300
316
  # to split your transfer into a number of chunks to satisfy underlying O/S
301
317
  # requirements, meaning that the timeout may expire after the first few chunks
302
318
  # have completed. libusb is careful not to lose any data that may have been
@@ -305,15 +321,21 @@ module LIBUSB
305
321
  #
306
322
  # The default endpoint bInterval value is used as the polling interval.
307
323
  #
308
- # @param [Endpoint, Fixnum] :endpoint the (address of a) valid endpoint to communicate with
309
- # @param [String] :dataOut the data to send with an outgoing transfer
310
- # @param [Fixnum] :dataIn the number of bytes expected to receive with an ingoing transfer
311
- # @param [Fixnum] :timeout timeout (in millseconds) that this function should wait before giving
324
+ # @param [Hash] args
325
+ # @option args [Endpoint, Fixnum] :endpoint the (address of a) valid endpoint to communicate with
326
+ # @option args [String] :dataOut the data to send with an outgoing transfer
327
+ # @option args [Fixnum] :dataIn the number of bytes expected to receive with an ingoing transfer
328
+ # @option args [Fixnum] :timeout timeout (in millseconds) that this function should wait before giving
312
329
  # up due to no response being received. For an unlimited timeout, use value 0. Defaults to 1000 ms.
313
330
  #
314
331
  # @return [Fixnum] Number of bytes sent for an outgoing transfer
315
332
  # @return [String] Received data for an ingoing transfer
316
- def interrupt_transfer(args={})
333
+ # @return [self] When called with a block
334
+ #
335
+ # @yieldparam [String, Integer, LIBUSB::Error] result result of the transfer is yielded to the block,
336
+ # when the asynchronous transfer has finished
337
+ # @raise [ArgumentError, LIBUSB::Error] in case of failure
338
+ def interrupt_transfer(args={}, &block)
317
339
  timeout = args.delete(:timeout) || 1000
318
340
  endpoint = args.delete(:endpoint) || raise(ArgumentError, "no endpoint given")
319
341
  endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
@@ -335,34 +357,42 @@ module LIBUSB
335
357
  tr.alloc_buffer(dataIn)
336
358
  end
337
359
 
338
- tr.submit_and_wait!
339
-
340
- if dataOut
341
- tr.actual_length
342
- else
343
- tr.actual_buffer
344
- end
360
+ submit_transfer(tr, dataIn, 0, &block)
345
361
  end
346
362
 
347
363
  # Perform a USB control transfer.
348
364
  #
365
+ # When called without a block, the transfer is done synchronously - so all events are handled
366
+ # internally and the sent/received data will be returned after completion or an exception will be raised.
367
+ #
368
+ # When called with a block, the method returns immediately after submitting the transfer.
369
+ # You then have to ensure, that {Context#handle_events} is called properly. As soon as the
370
+ # transfer is completed, the block is called with the sent/received data in case of success
371
+ # or the exception instance in case of failure.
372
+ #
349
373
  # The direction of the transfer is inferred from the +:bmRequestType+ field of the
350
374
  # setup packet.
351
375
  #
352
- # @param [Fixnum] :bmRequestType the request type field for the setup packet
353
- # @param [Fixnum] :bRequest the request field for the setup packet
354
- # @param [Fixnum] :wValue the value field for the setup packet
355
- # @param [Fixnum] :wIndex the index field for the setup packet
356
- # @param [String] :dataOut the data to send with an outgoing transfer, it
376
+ # @param [Hash] args
377
+ # @option args [Fixnum] :bmRequestType the request type field for the setup packet
378
+ # @option args [Fixnum] :bRequest the request field for the setup packet
379
+ # @option args [Fixnum] :wValue the value field for the setup packet
380
+ # @option args [Fixnum] :wIndex the index field for the setup packet
381
+ # @option args [String] :dataOut the data to send with an outgoing transfer, it
357
382
  # is appended to the setup packet
358
- # @param [Fixnum] :dataIn the number of bytes expected to receive with an ingoing transfer
383
+ # @option args [Fixnum] :dataIn the number of bytes expected to receive with an ingoing transfer
359
384
  # (excluding setup packet)
360
- # @param [Fixnum] :timeout timeout (in millseconds) that this function should wait before giving
385
+ # @option args [Fixnum] :timeout timeout (in millseconds) that this function should wait before giving
361
386
  # up due to no response being received. For an unlimited timeout, use value 0. Defaults to 1000 ms.
362
387
  #
363
388
  # @return [Fixnum] Number of bytes sent (excluding setup packet) for outgoing transfer
364
389
  # @return [String] Received data (without setup packet) for ingoing transfer
365
- def control_transfer(args={})
390
+ # @return [self] When called with a block
391
+ #
392
+ # @yieldparam [String, Integer, LIBUSB::Error] result result of the transfer is yielded to the block,
393
+ # when the asynchronous transfer has finished
394
+ # @raise [ArgumentError, LIBUSB::Error] in case of failure
395
+ def control_transfer(args={}, &block)
366
396
  bmRequestType = args.delete(:bmRequestType) || raise(ArgumentError, "param :bmRequestType not given")
367
397
  bRequest = args.delete(:bRequest) || raise(ArgumentError, "param :bRequest not given")
368
398
  wValue = args.delete(:wValue) || raise(ArgumentError, "param :wValue not given")
@@ -387,12 +417,33 @@ module LIBUSB
387
417
  tr.buffer = [bmRequestType, bRequest, wValue, wIndex, dataOut.bytesize, dataOut].pack('CCvvva*')
388
418
  end
389
419
 
390
- tr.submit_and_wait!
420
+ submit_transfer(tr, dataIn, CONTROL_SETUP_SIZE, &block)
421
+ end
391
422
 
392
- if dataIn
393
- tr.actual_buffer(CONTROL_SETUP_SIZE)
423
+ private
424
+ def submit_transfer(tr, dataIn, offset)
425
+ if block_given?
426
+ tr.submit! do
427
+ res = dataIn ? tr.actual_buffer(offset) : tr.actual_length
428
+
429
+ if tr.status==:TRANSFER_COMPLETED
430
+ yield res
431
+ else
432
+ exception = Transfer::TransferStatusToError[tr.status] || ERROR_OTHER
433
+
434
+ yield exception.new("error #{tr.status}", res)
435
+ end
436
+ end
437
+ self
394
438
  else
395
- tr.actual_length
439
+ tr.submit_and_wait
440
+
441
+ res = dataIn ? tr.actual_buffer(offset) : tr.actual_length
442
+
443
+ unless tr.status==:TRANSFER_COMPLETED
444
+ raise((Transfer::TransferStatusToError[tr.status] || ERROR_OTHER).new("error #{tr.status}", res))
445
+ end
446
+ res
396
447
  end
397
448
  end
398
449
  end