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.
- 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
|