libusb 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. data/.gitignore +8 -0
  2. data/.travis.yml +10 -0
  3. data/.yardopts +6 -1
  4. data/Gemfile +16 -0
  5. data/{History.txt → History.md} +28 -16
  6. data/README.md +144 -0
  7. data/Rakefile +28 -24
  8. data/ext/extconf.rb +33 -0
  9. data/ext/libusbx-1.0.14/AUTHORS +50 -0
  10. data/ext/libusbx-1.0.14/COPYING +504 -0
  11. data/ext/libusbx-1.0.14/ChangeLog +139 -0
  12. data/ext/libusbx-1.0.14/INSTALL +234 -0
  13. data/ext/libusbx-1.0.14/Makefile.am +23 -0
  14. data/ext/libusbx-1.0.14/Makefile.in +803 -0
  15. data/ext/libusbx-1.0.14/NEWS +2 -0
  16. data/ext/libusbx-1.0.14/PORTING +94 -0
  17. data/ext/libusbx-1.0.14/README +28 -0
  18. data/ext/libusbx-1.0.14/THANKS +7 -0
  19. data/ext/libusbx-1.0.14/TODO +2 -0
  20. data/ext/libusbx-1.0.14/aclocal.m4 +9480 -0
  21. data/ext/libusbx-1.0.14/compile +143 -0
  22. data/ext/libusbx-1.0.14/config.guess +1501 -0
  23. data/ext/libusbx-1.0.14/config.h.in +116 -0
  24. data/ext/libusbx-1.0.14/config.sub +1705 -0
  25. data/ext/libusbx-1.0.14/configure +14818 -0
  26. data/ext/libusbx-1.0.14/configure.ac +230 -0
  27. data/ext/libusbx-1.0.14/depcomp +630 -0
  28. data/ext/libusbx-1.0.14/doc/Makefile.am +9 -0
  29. data/ext/libusbx-1.0.14/doc/Makefile.in +380 -0
  30. data/ext/libusbx-1.0.14/doc/doxygen.cfg.in +1288 -0
  31. data/ext/libusbx-1.0.14/examples/Makefile.am +18 -0
  32. data/ext/libusbx-1.0.14/examples/Makefile.in +596 -0
  33. data/ext/libusbx-1.0.14/examples/dpfp.c +506 -0
  34. data/ext/libusbx-1.0.14/examples/dpfp_threaded.c +544 -0
  35. data/ext/libusbx-1.0.14/examples/ezusb.c +616 -0
  36. data/ext/libusbx-1.0.14/examples/ezusb.h +107 -0
  37. data/ext/libusbx-1.0.14/examples/fxload.c +261 -0
  38. data/ext/libusbx-1.0.14/examples/getopt/getopt.c +1060 -0
  39. data/ext/libusbx-1.0.14/examples/getopt/getopt.h +180 -0
  40. data/ext/libusbx-1.0.14/examples/getopt/getopt1.c +188 -0
  41. data/ext/libusbx-1.0.14/examples/listdevs.c +63 -0
  42. data/ext/libusbx-1.0.14/examples/xusb.c +1036 -0
  43. data/ext/libusbx-1.0.14/install-sh +520 -0
  44. data/ext/libusbx-1.0.14/libusb-1.0.pc.in +11 -0
  45. data/ext/libusbx-1.0.14/libusb/Makefile.am +56 -0
  46. data/ext/libusbx-1.0.14/libusb/Makefile.in +721 -0
  47. data/ext/libusbx-1.0.14/libusb/core.c +1951 -0
  48. data/ext/libusbx-1.0.14/libusb/descriptor.c +731 -0
  49. data/ext/libusbx-1.0.14/libusb/io.c +2450 -0
  50. data/ext/libusbx-1.0.14/libusb/libusb-1.0.def +126 -0
  51. data/ext/libusbx-1.0.14/libusb/libusb-1.0.rc +59 -0
  52. data/ext/libusbx-1.0.14/libusb/libusb.h +1506 -0
  53. data/ext/libusbx-1.0.14/libusb/libusbi.h +910 -0
  54. data/ext/libusbx-1.0.14/libusb/os/darwin_usb.c +1807 -0
  55. data/ext/libusbx-1.0.14/libusb/os/darwin_usb.h +169 -0
  56. data/ext/libusbx-1.0.14/libusb/os/linux_usbfs.c +2569 -0
  57. data/ext/libusbx-1.0.14/libusb/os/linux_usbfs.h +149 -0
  58. data/ext/libusbx-1.0.14/libusb/os/openbsd_usb.c +727 -0
  59. data/ext/libusbx-1.0.14/libusb/os/poll_posix.h +10 -0
  60. data/ext/libusbx-1.0.14/libusb/os/poll_windows.c +747 -0
  61. data/ext/libusbx-1.0.14/libusb/os/poll_windows.h +114 -0
  62. data/ext/libusbx-1.0.14/libusb/os/threads_posix.c +80 -0
  63. data/ext/libusbx-1.0.14/libusb/os/threads_posix.h +50 -0
  64. data/ext/libusbx-1.0.14/libusb/os/threads_windows.c +211 -0
  65. data/ext/libusbx-1.0.14/libusb/os/threads_windows.h +87 -0
  66. data/ext/libusbx-1.0.14/libusb/os/windows_usb.c +4369 -0
  67. data/ext/libusbx-1.0.14/libusb/os/windows_usb.h +979 -0
  68. data/ext/libusbx-1.0.14/libusb/sync.c +321 -0
  69. data/ext/libusbx-1.0.14/libusb/version.h +18 -0
  70. data/ext/libusbx-1.0.14/libusb/version_nano.h +1 -0
  71. data/ext/libusbx-1.0.14/ltmain.sh +9636 -0
  72. data/ext/libusbx-1.0.14/missing +376 -0
  73. data/lib/libusb.rb +2 -3
  74. data/lib/libusb/call.rb +49 -7
  75. data/lib/libusb/compat.rb +15 -9
  76. data/lib/libusb/configuration.rb +15 -3
  77. data/lib/libusb/constants.rb +19 -6
  78. data/lib/libusb/context.rb +181 -3
  79. data/lib/libusb/dev_handle.rb +91 -40
  80. data/lib/libusb/endpoint.rb +41 -14
  81. data/lib/libusb/eventmachine.rb +183 -0
  82. data/lib/libusb/transfer.rb +21 -8
  83. data/lib/libusb/version_gem.rb +19 -0
  84. data/lib/libusb/{version.rb → version_struct.rb} +0 -0
  85. data/libusb.gemspec +31 -0
  86. data/test/test_libusb_compat.rb +1 -1
  87. data/test/test_libusb_compat_mass_storage.rb +2 -2
  88. data/test/test_libusb_descriptors.rb +1 -1
  89. data/test/test_libusb_event_machine.rb +118 -0
  90. data/test/test_libusb_iso_transfer.rb +6 -1
  91. data/test/test_libusb_mass_storage.rb +9 -3
  92. data/test/test_libusb_mass_storage2.rb +1 -1
  93. data/test/test_libusb_structs.rb +45 -0
  94. data/test/test_libusb_threads.rb +89 -0
  95. data/test/test_libusb_version.rb +4 -0
  96. metadata +109 -44
  97. data/.autotest +0 -23
  98. data/.gemtest +0 -0
  99. data/Manifest.txt +0 -3
  100. data/README.rdoc +0 -115
  101. data/test/test_libusb_keyboard.rb +0 -50
@@ -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