libusb 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,51 @@
1
+ # This file is part of Libusb for Ruby.
2
+ #
3
+ # Libusb for Ruby is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU Lesser General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # Libusb for Ruby is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public License
14
+ # along with Libusb for Ruby. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ require 'libusb/call'
17
+
18
+ module LIBUSB
19
+ class Interface < FFI::Struct
20
+ include Comparable
21
+
22
+ layout :altsetting, :pointer,
23
+ :num_altsetting, :int
24
+
25
+ def initialize(configuration, *args)
26
+ @configuration = configuration
27
+ super(*args)
28
+ end
29
+
30
+ # @return [Configuration] the configuration this interface belongs to.
31
+ attr_reader :configuration
32
+
33
+ def alt_settings
34
+ ifs = []
35
+ self[:num_altsetting].times do |i|
36
+ ifs << Setting.new(self, self[:altsetting] + i*Setting.size)
37
+ end
38
+ return ifs
39
+ end
40
+ alias settings alt_settings
41
+
42
+ # The {Device} this Interface belongs to.
43
+ def device() self.configuration.device end
44
+ # Return all endpoints of all alternative settings as Array of {Endpoint}s.
45
+ def endpoints() self.alt_settings.map {|d| d.endpoints }.flatten end
46
+
47
+ def <=>(o)
48
+ configuration<=>o.configuration
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,132 @@
1
+ # This file is part of Libusb for Ruby.
2
+ #
3
+ # Libusb for Ruby is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU Lesser General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # Libusb for Ruby is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public License
14
+ # along with Libusb for Ruby. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ require 'libusb/call'
17
+
18
+ module LIBUSB
19
+ class Setting < FFI::Struct
20
+ include Comparable
21
+
22
+ layout :bLength, :uint8,
23
+ :bDescriptorType, :uint8,
24
+ :bInterfaceNumber, :uint8,
25
+ :bAlternateSetting, :uint8,
26
+ :bNumEndpoints, :uint8,
27
+ :bInterfaceClass, :uint8,
28
+ :bInterfaceSubClass, :uint8,
29
+ :bInterfaceProtocol, :uint8,
30
+ :iInterface, :uint8,
31
+ :endpoint, :pointer,
32
+ :extra, :pointer,
33
+ :extra_length, :int
34
+
35
+ # Size of this descriptor (in bytes).
36
+ def bLength
37
+ self[:bLength]
38
+ end
39
+
40
+ # Descriptor type (0x04)
41
+ def bDescriptorType
42
+ self[:bDescriptorType]
43
+ end
44
+
45
+ # Number of this interface.
46
+ def bInterfaceNumber
47
+ self[:bInterfaceNumber]
48
+ end
49
+
50
+ # Value used to select this alternate setting for this interface.
51
+ def bAlternateSetting
52
+ self[:bAlternateSetting]
53
+ end
54
+
55
+ # Number of endpoints used by this interface (excluding the control endpoint).
56
+ def bNumEndpoints
57
+ self[:bNumEndpoints]
58
+ end
59
+
60
+ # USB-IF class code for this interface.
61
+ def bInterfaceClass
62
+ self[:bInterfaceClass]
63
+ end
64
+
65
+ # USB-IF subclass code for this interface, qualified by the {Setting#bInterfaceClass} value.
66
+ def bInterfaceSubClass
67
+ self[:bInterfaceSubClass]
68
+ end
69
+
70
+ # USB-IF protocol code for this interface, qualified by the {Setting#bInterfaceClass} and {Setting#bInterfaceSubClass} values.
71
+ def bInterfaceProtocol
72
+ self[:bInterfaceProtocol]
73
+ end
74
+
75
+ # Index of string descriptor describing this interface.
76
+ def iInterface
77
+ self[:iInterface]
78
+ end
79
+
80
+ # Extra descriptors.
81
+ #
82
+ # @return [String]
83
+ def extra
84
+ return if self[:extra].null?
85
+ self[:extra].read_string(self[:extra_length])
86
+ end
87
+
88
+ def initialize(interface, *args)
89
+ @interface = interface
90
+ super(*args)
91
+ end
92
+
93
+ # @return [Interface] the interface this setting belongs to.
94
+ attr_reader :interface
95
+
96
+ def endpoints
97
+ ifs = []
98
+ self[:bNumEndpoints].times do |i|
99
+ ifs << Endpoint.new(self, self[:endpoint] + i*Endpoint.size)
100
+ end
101
+ return ifs
102
+ end
103
+
104
+ def inspect
105
+ attrs = []
106
+ attrs << self.bAlternateSetting.to_s
107
+ devclass = LIBUSB.dev_string(self.bInterfaceClass, self.bInterfaceSubClass, self.bInterfaceProtocol)
108
+ attrs << devclass
109
+ desc = self.description
110
+ attrs << desc if desc != '?'
111
+ "\#<#{self.class} #{attrs.join(' ')}>"
112
+ end
113
+
114
+ # Return name of this interface as String.
115
+ def description
116
+ return @description if defined? @description
117
+ @description = device.try_string_descriptor_ascii(self.iInterface)
118
+ end
119
+
120
+ # The {Device} this Setting belongs to.
121
+ def device() self.interface.configuration.device end
122
+ # The {Configuration} this Setting belongs to.
123
+ def configuration() self.interface.configuration end
124
+
125
+ def <=>(o)
126
+ t = interface<=>o.interface
127
+ t = bInterfaceNumber<=>o.bInterfaceNumber if t==0
128
+ t = bAlternateSetting<=>o.bAlternateSetting if t==0
129
+ t
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,269 @@
1
+ # This file is part of Libusb for Ruby.
2
+ #
3
+ # Libusb for Ruby is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU Lesser General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # Libusb for Ruby is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public License
14
+ # along with Libusb for Ruby. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ require 'libusb/call'
17
+
18
+ module LIBUSB
19
+ # Abstract base class for USB transfers. Use
20
+ # {ControlTransfer}, {BulkTransfer}, {InterruptTransfer}, {IsochronousTransfer}
21
+ # to do transfers.
22
+ class Transfer
23
+ def initialize(args={})
24
+ args.each{|k,v| send("#{k}=", v) }
25
+ @buffer = nil
26
+ end
27
+ private :initialize
28
+
29
+ # Set the handle for the device to communicate with.
30
+ def dev_handle=(dev)
31
+ @dev_handle = dev
32
+ @transfer[:dev_handle] = @dev_handle.pHandle
33
+ end
34
+
35
+ # Timeout for this transfer in millseconds.
36
+ #
37
+ # A value of 0 indicates no timeout.
38
+ def timeout=(value)
39
+ @transfer[:timeout] = value
40
+ end
41
+
42
+ # Set the address of a valid endpoint to communicate with.
43
+ def endpoint=(endpoint)
44
+ endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
45
+ @transfer[:endpoint] = endpoint
46
+ end
47
+
48
+ # Set output data that should be sent.
49
+ def buffer=(data)
50
+ if !@buffer || data.bytesize>@buffer.size
51
+ free_buffer
52
+ @buffer = FFI::MemoryPointer.new(data.bytesize, 1, false)
53
+ end
54
+ @buffer.put_bytes(0, data)
55
+ @transfer[:buffer] = @buffer
56
+ @transfer[:length] = data.bytesize
57
+ end
58
+
59
+ # Retrieve the current data buffer.
60
+ def buffer
61
+ @transfer[:buffer].read_string(@transfer[:length])
62
+ end
63
+
64
+ # Clear the current data buffer.
65
+ def free_buffer
66
+ if @buffer
67
+ @buffer.free
68
+ @buffer = nil
69
+ @transfer[:buffer] = nil
70
+ @transfer[:length] = 0
71
+ end
72
+ end
73
+
74
+ # Allocate +len+ bytes of data buffer for input transfer.
75
+ #
76
+ # @param [Fixnum] len Number of bytes to allocate
77
+ # @param [String, nil] data some data to initialize the buffer with
78
+ def alloc_buffer(len, data=nil)
79
+ if !@buffer || len>@buffer.size
80
+ free_buffer
81
+ @buffer = FFI::MemoryPointer.new(len, 1, false)
82
+ end
83
+ @buffer.put_bytes(0, data) if data
84
+ @transfer[:buffer] = @buffer
85
+ @transfer[:length] = len
86
+ end
87
+
88
+ # The number of bytes actually transferred.
89
+ def actual_length
90
+ @transfer[:actual_length]
91
+ end
92
+
93
+ # Retrieve the data actually transferred.
94
+ #
95
+ # @param [Fixnum] offset optional offset of the retrieved data in the buffer.
96
+ def actual_buffer(offset=0)
97
+ @transfer[:buffer].get_bytes(offset, @transfer[:actual_length])
98
+ end
99
+
100
+ # Set the block that will be invoked when the transfer completes,
101
+ # fails, or is cancelled.
102
+ #
103
+ # @param [Proc] proc The block that should be called
104
+ def callback=(proc)
105
+ # Save proc to instance variable so that GC doesn't free
106
+ # the proc object before the transfer.
107
+ @callback_proc = proc do |pTrans|
108
+ proc.call(self)
109
+ end
110
+ @transfer[:callback] = @callback_proc
111
+ end
112
+
113
+ # The status of the transfer.
114
+ #
115
+ # Only for use within transfer callback function or after the callback was called.
116
+ #
117
+ # If this is an isochronous transfer, this field may read :TRANSFER_COMPLETED even if there
118
+ # were errors in the frames. Use the status field in each packet to determine if
119
+ # errors occurred.
120
+ def status
121
+ @transfer[:status]
122
+ end
123
+
124
+ # Submit a transfer.
125
+ #
126
+ # This function will fire off the USB transfer and then return immediately.
127
+ # This method can be called with block. It is called when the transfer completes,
128
+ # fails, or is cancelled.
129
+ def submit!(&block)
130
+ self.callback = block if block_given?
131
+
132
+ # puts "submit transfer #{@transfer.inspect} buffer: #{@transfer[:buffer].inspect} length: #{@transfer[:length].inspect} status: #{@transfer[:status].inspect} callback: #{@transfer[:callback].inspect} dev_handle: #{@transfer[:dev_handle].inspect}"
133
+
134
+ res = Call.libusb_submit_transfer( @transfer )
135
+ LIBUSB.raise_error res, "in libusb_submit_transfer" if res!=0
136
+ end
137
+
138
+ # Asynchronously cancel a previously submitted transfer.
139
+ #
140
+ # This function returns immediately, but this does not indicate cancellation is
141
+ # complete. Your callback function will be invoked at some later time with a
142
+ # transfer status of :TRANSFER_CANCELLED.
143
+ def cancel!
144
+ res = Call.libusb_cancel_transfer( @transfer )
145
+ LIBUSB.raise_error res, "in libusb_cancel_transfer" if res!=0
146
+ end
147
+
148
+ TransferStatusToError = {
149
+ :TRANSFER_ERROR => LIBUSB::ERROR_IO,
150
+ :TRANSFER_TIMED_OUT => LIBUSB::ERROR_TIMEOUT,
151
+ :TRANSFER_CANCELLED => LIBUSB::ERROR_INTERRUPTED,
152
+ :TRANSFER_STALL => LIBUSB::ERROR_PIPE,
153
+ :TRANSFER_NO_DEVICE => LIBUSB::ERROR_NO_DEVICE,
154
+ :TRANSFER_OVERFLOW => LIBUSB::ERROR_OVERFLOW,
155
+ }
156
+
157
+ # Submit the transfer and wait until the transfer completes or fails.
158
+ #
159
+ # A proper {LIBUSB::Error} is raised, in case the transfer did not complete.
160
+ def submit_and_wait!
161
+ completed = false
162
+ submit! do |tr2|
163
+ completed = true
164
+ end
165
+
166
+ until completed
167
+ begin
168
+ @dev_handle.device.context.handle_events
169
+ rescue ERROR_INTERRUPTED
170
+ next
171
+ rescue LIBUSB::Error
172
+ cancel!
173
+ until completed
174
+ @dev_handle.device.context.handle_events
175
+ end
176
+ raise
177
+ end
178
+ end
179
+
180
+ raise( TransferStatusToError[status] || ERROR_OTHER, "error #{status}") unless status==:TRANSFER_COMPLETED
181
+ end
182
+ end
183
+
184
+ class BulkTransfer < Transfer
185
+ def initialize(args={})
186
+ @transfer = Call::Transfer.new Call.libusb_alloc_transfer(0)
187
+ @transfer[:type] = TRANSFER_TYPE_BULK
188
+ @transfer[:timeout] = 1000
189
+ super
190
+ end
191
+ end
192
+
193
+ class ControlTransfer < Transfer
194
+ def initialize(args={})
195
+ @transfer = Call::Transfer.new Call.libusb_alloc_transfer(0)
196
+ @transfer[:type] = TRANSFER_TYPE_CONTROL
197
+ @transfer[:timeout] = 1000
198
+ super
199
+ end
200
+ end
201
+
202
+ class InterruptTransfer < Transfer
203
+ def initialize(args={})
204
+ @transfer = Call::Transfer.new Call.libusb_alloc_transfer(0)
205
+ @transfer[:type] = TRANSFER_TYPE_INTERRUPT
206
+ @transfer[:timeout] = 1000
207
+ super
208
+ end
209
+ end
210
+
211
+ class IsoPacket
212
+ def initialize(ptr, pkg_nr)
213
+ @packet = Call::IsoPacketDescriptor.new ptr
214
+ @pkg_nr = pkg_nr
215
+ end
216
+
217
+ def status
218
+ @packet[:status]
219
+ end
220
+
221
+ def length
222
+ @packet[:length]
223
+ end
224
+ def length=(len)
225
+ @packet[:length] = len
226
+ end
227
+
228
+ def actual_length
229
+ @packet[:actual_length]
230
+ end
231
+ end
232
+
233
+ class IsochronousTransfer < Transfer
234
+ def initialize(num_packets, args={})
235
+ @ptr = Call.libusb_alloc_transfer(num_packets)
236
+ @transfer = Call::Transfer.new @ptr
237
+ @transfer[:type] = TRANSFER_TYPE_ISOCHRONOUS
238
+ @transfer[:timeout] = 1000
239
+ @transfer[:num_iso_packets] = num_packets
240
+ super(args)
241
+ end
242
+
243
+ def num_packets
244
+ @transfer[:num_iso_packets]
245
+ end
246
+ def num_packets=(number)
247
+ @transfer[:num_iso_packets] = number
248
+ end
249
+
250
+ def [](nr)
251
+ IsoPacket.new( @ptr + Call::Transfer.size + nr*Call::IsoPacketDescriptor.size, nr)
252
+ end
253
+
254
+ # Convenience function to set the length of all packets in an
255
+ # isochronous transfer, based on {IsochronousTransfer#num_packets}.
256
+ def packet_lengths=(len)
257
+ ptr = @ptr + Call::Transfer.size
258
+ num_packets.times do
259
+ ptr.write_uint(len)
260
+ ptr += Call::IsoPacketDescriptor.size
261
+ end
262
+ end
263
+
264
+ # The actual_length field of the transfer is meaningless and should not
265
+ # be examined; instead you must refer to the actual_length field of
266
+ # each individual packet.
267
+ private :actual_length, :actual_buffer
268
+ end
269
+ end