libusb 0.2.2-x86-mingw32 → 0.3.0-x86-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/.travis.yml +10 -0
- data/.yardopts +6 -1
- data/Gemfile +16 -0
- data/{History.txt → History.md} +28 -16
- data/README.md +144 -0
- data/Rakefile +28 -24
- data/ext/extconf.rb +33 -0
- data/lib/libusb.rb +2 -3
- data/lib/libusb/call.rb +49 -7
- data/lib/libusb/compat.rb +15 -9
- data/lib/libusb/configuration.rb +15 -3
- data/lib/libusb/constants.rb +19 -6
- data/lib/libusb/context.rb +181 -3
- data/lib/libusb/dev_handle.rb +91 -40
- data/lib/libusb/endpoint.rb +41 -14
- data/lib/libusb/eventmachine.rb +183 -0
- data/lib/libusb/transfer.rb +21 -8
- data/lib/libusb/version_gem.rb +19 -0
- data/lib/libusb/{version.rb → version_struct.rb} +0 -0
- data/libusb.gemspec +31 -0
- data/test/test_libusb_compat.rb +1 -1
- data/test/test_libusb_compat_mass_storage.rb +2 -2
- data/test/test_libusb_descriptors.rb +1 -1
- data/test/test_libusb_event_machine.rb +118 -0
- data/test/test_libusb_iso_transfer.rb +6 -1
- data/test/test_libusb_mass_storage.rb +9 -3
- data/test/test_libusb_mass_storage2.rb +1 -1
- data/test/test_libusb_structs.rb +45 -0
- data/test/test_libusb_threads.rb +89 -0
- data/test/test_libusb_version.rb +4 -0
- metadata +44 -44
- data/.autotest +0 -23
- data/.gemtest +0 -0
- data/Manifest.txt +0 -3
- data/README.rdoc +0 -115
- data/test/test_libusb_keyboard.rb +0 -50
data/lib/libusb/compat.rb
CHANGED
@@ -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
|
-
|
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
|
-
[
|
119
|
+
[default_bus]
|
112
120
|
end
|
113
121
|
|
114
|
-
def USB.devices;
|
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
|
-
|
129
|
+
default_bus
|
122
130
|
end
|
123
131
|
|
124
132
|
def USB.each_device_by_class(devclass, subclass=nil, protocol=nil)
|
125
|
-
devs =
|
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;
|
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;
|
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
|
data/lib/libusb/configuration.rb
CHANGED
@@ -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
|
-
|
119
|
-
attrs << "
|
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(' ')}>"
|
data/lib/libusb/constants.rb
CHANGED
@@ -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
|
75
|
-
[0x08, 0x02, 0x50, "MassStorage ATAPI
|
76
|
-
[0x08, 0x03, 0x50, "MassStorage QIC-157
|
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
|
79
|
-
[0x08, 0x06, 0x50, "MassStorage SCSI
|
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
|
-
"
|
148
|
+
"Unknown(%02x,%02x,%02x)" % [base_class, sub_class, protocol]
|
136
149
|
end
|
137
150
|
end
|
138
151
|
end
|
data/lib/libusb/context.rb
CHANGED
@@ -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
|
-
|
86
|
-
|
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
|
data/lib/libusb/dev_handle.rb
CHANGED
@@ -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
|
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
|
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 [
|
249
|
-
# @
|
250
|
-
# @
|
251
|
-
# @
|
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
|
-
|
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
|
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
|
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
|
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 [
|
309
|
-
# @
|
310
|
-
# @
|
311
|
-
# @
|
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
|
-
|
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
|
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 [
|
353
|
-
# @
|
354
|
-
# @
|
355
|
-
# @
|
356
|
-
# @
|
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
|
-
# @
|
383
|
+
# @option args [Fixnum] :dataIn the number of bytes expected to receive with an ingoing transfer
|
359
384
|
# (excluding setup packet)
|
360
|
-
# @
|
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
|
-
|
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
|
420
|
+
submit_transfer(tr, dataIn, CONTROL_SETUP_SIZE, &block)
|
421
|
+
end
|
391
422
|
|
392
|
-
|
393
|
-
|
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.
|
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
|