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.
@@ -47,18 +47,31 @@ module LIBUSB
47
47
  # * Bits 7: Direction 0 = Out, 1 = In (Ignored for Control Endpoints)
48
48
  #
49
49
  # @return [Integer]
50
+ #
51
+ # @see #endpoint_number
52
+ # @see #direction
50
53
  def bEndpointAddress
51
54
  self[:bEndpointAddress]
52
55
  end
53
56
 
57
+ # @return [Integer]
58
+ def endpoint_number
59
+ bEndpointAddress & 0b1111
60
+ end
61
+
62
+ # @return [Symbol] Either +:in+ or +:out+
63
+ def direction
64
+ bEndpointAddress & ENDPOINT_IN == 0 ? :out : :in
65
+ end
66
+
54
67
  # Attributes which apply to the endpoint when it is configured using the {Configuration#bConfigurationValue}.
55
68
  #
56
- # * Bits 0..1: Transfer Type
69
+ # * Bits 1..0: Transfer Type
57
70
  # * 00 = Control
58
71
  # * 01 = Isochronous
59
72
  # * 10 = Bulk
60
73
  # * 11 = Interrupt
61
- # * Bits 2..7: are reserved. If Isochronous endpoint,
74
+ # * Bits 7..2: are reserved. If Isochronous endpoint,
62
75
  # * Bits 3..2: Synchronisation Type (Iso Mode)
63
76
  # * 00 = No Synchonisation
64
77
  # * 01 = Asynchronous
@@ -71,10 +84,34 @@ module LIBUSB
71
84
  # * 11 = Reserved
72
85
  #
73
86
  # @return [Integer]
87
+ #
88
+ # @see #transfer_type
89
+ # @see #usage_type
90
+ # @see #synchronization_type
74
91
  def bmAttributes
75
92
  self[:bmAttributes]
76
93
  end
77
94
 
95
+ TransferTypes = [:control, :isochronous, :bulk, :interrupt]
96
+ # @return [Symbol] One of {TransferTypes}
97
+ def transfer_type
98
+ TransferTypes[bmAttributes & 0b11]
99
+ end
100
+
101
+ SynchronizationTypes = [:no_synchronization, :asynchronous, :adaptive, :synchronous]
102
+ # @return [Symbol] One of {SynchronizationTypes}
103
+ def synchronization_type
104
+ return unless transfer_type == :isochronous
105
+ SynchronizationTypes[(bmAttributes & 0b1100) >> 2]
106
+ end
107
+
108
+ UsageTypes = [:data, :feedback, :implicit_feedback, :unknown]
109
+ # @return [Symbol] One of {UsageTypes}
110
+ def usage_type
111
+ return unless transfer_type == :isochronous
112
+ UsageTypes[(bmAttributes & 0b110000) >> 4]
113
+ end
114
+
78
115
  # Maximum Packet Size this endpoint is capable of sending or receiving
79
116
  def wMaxPacketSize
80
117
  self[:wMaxPacketSize]
@@ -117,18 +154,8 @@ module LIBUSB
117
154
  attr_reader :setting
118
155
 
119
156
  def inspect
120
- endpoint_address = self.bEndpointAddress
121
- num = endpoint_address & 0b00001111
122
- inout = (endpoint_address & 0b10000000) == 0 ? "OUT" : "IN "
123
- bits = self.bmAttributes
124
- transfer_type = %w[Control Isochronous Bulk Interrupt][0b11 & bits]
125
- type = [transfer_type]
126
- if transfer_type == 'Isochronous'
127
- synchronization_type = %w[NoSynchronization Asynchronous Adaptive Synchronous][(0b1100 & bits) >> 2]
128
- usage_type = %w[Data Feedback ImplicitFeedback ?][(0b110000 & bits) >> 4]
129
- type << synchronization_type << usage_type
130
- end
131
- "\#<#{self.class} #{num} #{inout} #{type.join(" ")}>"
157
+ type = [transfer_type, synchronization_type, usage_type].compact
158
+ "\#<#{self.class} #{endpoint_number} #{direction} #{type.join(" ")}>"
132
159
  end
133
160
 
134
161
  # The {Device} this Endpoint belongs to.
@@ -0,0 +1,183 @@
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'
17
+ require 'eventmachine'
18
+
19
+ module LIBUSB
20
+ class Context
21
+ # Register libusb's file descriptors and timeouts to EventMachine.
22
+ #
23
+ # @example
24
+ # require 'libusb/eventmachine'
25
+ # context = LIBUSB::Context.new
26
+ # EventMachine.run do
27
+ # context.eventmachine_register
28
+ # end
29
+ #
30
+ # @see
31
+ # DevHandle#eventmachine_bulk_transfer
32
+ # DevHandle#eventmachine_control_transfer
33
+ # DevHandle#eventmachine_interrupt_transfer
34
+ def eventmachine_register
35
+ @eventmachine_attached_fds = {}
36
+ @eventmachine_timer = nil
37
+
38
+ pollfds = self.pollfds
39
+ if pollfds
40
+ pollfds.each do |pollfd|
41
+ eventmachine_add_pollfd(pollfd)
42
+ end
43
+
44
+ self.on_pollfd_added do |pollfd|
45
+ eventmachine_add_pollfd(pollfd)
46
+ end
47
+
48
+ self.on_pollfd_removed do |pollfd|
49
+ eventmachine_rm_pollfd(pollfd)
50
+ end
51
+ else
52
+ # Libusb pollfd API is not available on this platform.
53
+ # Use simple polling timer, instead:
54
+ EventMachine.add_periodic_timer(0.01) do
55
+ @eventmachine_timer = self.handle_events 0
56
+ end
57
+ end
58
+ end
59
+
60
+ def eventmachine_unregister
61
+ @eventmachine_timer.cancel if @eventmachine_timer
62
+ @eventmachine_attached_fds.each do |fd, watcher|
63
+ watcher.detach
64
+ end
65
+ end
66
+
67
+ class EMPollfdHandler < EventMachine::Connection
68
+ def initialize
69
+ @callbacks = []
70
+ super
71
+ end
72
+
73
+ def on_need_handle_events(&block)
74
+ @callbacks << block
75
+ end
76
+
77
+ def need_handle_events
78
+ @callbacks.each do |cb|
79
+ cb.call
80
+ end
81
+ end
82
+ alias notify_readable need_handle_events
83
+ alias notify_writable need_handle_events
84
+ end
85
+
86
+ private
87
+ def eventmachine_add_pollfd(pollfd)
88
+ conn = EventMachine.watch(pollfd.io, EMPollfdHandler)
89
+ conn.notify_readable = pollfd.pollin?
90
+ conn.notify_writable = pollfd.pollout?
91
+ cb = proc do
92
+ if @eventmachine_timer
93
+ @eventmachine_timer.cancel
94
+ @eventmachine_timer = nil
95
+ end
96
+
97
+ self.handle_events 0
98
+ timeout = self.next_timeout
99
+ # puts "libusb new timeout: #{timeout.inspect}"
100
+ if timeout
101
+ @eventmachine_timer = EventMachine.add_timer(timeout, &cb)
102
+ end
103
+ end
104
+ conn.on_need_handle_events(&cb)
105
+
106
+ @eventmachine_attached_fds[pollfd.fd] = conn
107
+ # puts "libusb pollfd added: #{pollfd.inspect}"
108
+ end
109
+
110
+ def eventmachine_rm_pollfd(pollfd)
111
+ @eventmachine_attached_fds[pollfd.fd].detach
112
+ # puts "libusb pollfd removed: #{pollfd.inspect}"
113
+ end
114
+ end
115
+
116
+ class DevHandle
117
+ class EMTransfer
118
+ include EM::Deferrable
119
+
120
+ def initialize(opts, dev_handle, transfer_method)
121
+ dev_handle.send(transfer_method, opts) do |res|
122
+ EM.next_tick do
123
+ if res.kind_of?(LIBUSB::Error)
124
+ fail res
125
+ else
126
+ succeed res
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+
133
+ # Execute an eventmachine driven USB interrupt transfer.
134
+ #
135
+ # @see Context#eventmachine_register
136
+ # DevHandle#interrupt_transfer
137
+ def eventmachine_interrupt_transfer(opts={})
138
+ eventmachine_transfer(opts, :interrupt_transfer)
139
+ end
140
+
141
+ # Execute an eventmachine driven USB bulk transfer.
142
+ #
143
+ # @example
144
+ # tr = devh.eventmachine_bulk_transfer( :endpoint => 0x02, :dataOut => "data" )
145
+ # tr.callback do |data|
146
+ # puts "sent: #{data.inspect}"
147
+ # end
148
+ # tr.errback do |ex|
149
+ # puts "send-err: #{ex}"
150
+ # end
151
+ #
152
+ # @see Context#eventmachine_register
153
+ # DevHandle#bulk_transfer
154
+ def eventmachine_bulk_transfer(opts={})
155
+ eventmachine_transfer(opts, :bulk_transfer)
156
+ end
157
+
158
+ # Execute an eventmachine driven USB control transfer.
159
+ #
160
+ # @example
161
+ # tr = devh.eventmachine_control_transfer(
162
+ # :bmRequestType=>ENDPOINT_IN|REQUEST_TYPE_CLASS|RECIPIENT_INTERFACE,
163
+ # :bRequest=>0x01,
164
+ # :wValue=>0, :wIndex=>0, :dataIn=>1 )
165
+ # tr.callback do |data|
166
+ # puts "recved: #{data.inspect}"
167
+ # end
168
+ # tr.errback do |ex|
169
+ # puts "recv-err: #{ex}"
170
+ # end
171
+ #
172
+ # @see Context#eventmachine_register
173
+ # DevHandle#control_transfer
174
+ def eventmachine_control_transfer(opts={})
175
+ eventmachine_transfer(opts, :control_transfer)
176
+ end
177
+
178
+ private
179
+ def eventmachine_transfer(opts, method)
180
+ EMTransfer.new opts, self, method
181
+ end
182
+ end
183
+ end
@@ -19,10 +19,16 @@ module LIBUSB
19
19
  # Abstract base class for USB transfers. Use
20
20
  # {ControlTransfer}, {BulkTransfer}, {InterruptTransfer}, {IsochronousTransfer}
21
21
  # to do transfers.
22
+ #
23
+ # There are convenience methods for {DevHandle#bulk_transfer}, {DevHandle#control_transfer}
24
+ # and {DevHandle#interrupt_transfer}, that fit for most use cases.
25
+ # Using {Transfer} derived classes directly, however, is needed for isochronous transfers and
26
+ # allows a more advanced buffer management.
22
27
  class Transfer
23
28
  def initialize(args={})
24
29
  args.each{|k,v| send("#{k}=", v) }
25
30
  @buffer = nil
31
+ @completion_flag = Context::CompletionFlag.new
26
32
  end
27
33
  private :initialize
28
34
 
@@ -156,26 +162,33 @@ module LIBUSB
156
162
 
157
163
  # Submit the transfer and wait until the transfer completes or fails.
158
164
  #
159
- # A proper {LIBUSB::Error} is raised, in case the transfer did not complete.
160
- def submit_and_wait!
161
- completed = false
165
+ # Inspect {#status} to check for transfer errors.
166
+ def submit_and_wait
167
+ @completion_flag.completed = false
162
168
  submit! do |tr2|
163
- completed = true
169
+ @completion_flag.completed = true
164
170
  end
165
171
 
166
- until completed
172
+ until @completion_flag.completed?
167
173
  begin
168
- @dev_handle.device.context.handle_events
174
+ @dev_handle.device.context.handle_events nil, @completion_flag
169
175
  rescue ERROR_INTERRUPTED
170
176
  next
171
177
  rescue LIBUSB::Error
172
178
  cancel!
173
- until completed
174
- @dev_handle.device.context.handle_events
179
+ until @completion_flag.completed?
180
+ @dev_handle.device.context.handle_events nil, @completion_flag
175
181
  end
176
182
  raise
177
183
  end
178
184
  end
185
+ end
186
+
187
+ # Submit the transfer and wait until the transfer completes or fails.
188
+ #
189
+ # A proper {LIBUSB::Error} is raised, in case the transfer did not complete.
190
+ def submit_and_wait!
191
+ submit_and_wait
179
192
 
180
193
  raise( TransferStatusToError[status] || ERROR_OTHER, "error #{status}") unless status==:TRANSFER_COMPLETED
181
194
  end
@@ -0,0 +1,19 @@
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
+ module LIBUSB
17
+ # Library version of libusb for Ruby
18
+ VERSION = "0.3.0"
19
+ end
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "libusb/version_gem"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "libusb"
7
+ s.version = LIBUSB::VERSION
8
+ s.authors = ["Lars Kanis"]
9
+ s.email = ["lars@greiz-reinsdorf.de"]
10
+ s.homepage = "http://github.com/larskanis/libusb"
11
+ s.summary = %q{Access USB devices from Ruby via libusb-1.0}
12
+ s.description = %q{LIBUSB is a Ruby binding that gives Ruby programmers access to arbitrary USB devices}
13
+ s.rdoc_options = %w[--main README.md --charset=UTF-8]
14
+
15
+ s.rubyforge_project = "libusb"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ s.extensions = ['ext/extconf.rb']
22
+
23
+ # travis currently runs a slightly older version of rbx,
24
+ # that needs a special ffi version.
25
+ unless ENV['TRAVIS'] && defined?(RUBY_ENGINE) && RUBY_ENGINE=='rbx'
26
+ s.add_runtime_dependency 'ffi', '>= 1.0'
27
+ end
28
+
29
+ s.add_development_dependency 'rake-compiler', '>= 0.6'
30
+ s.add_development_dependency 'bundler'
31
+ end
@@ -68,7 +68,7 @@ class TestLibusbCompat < Test::Unit::TestCase
68
68
  assert_equal config_desc, ep.configuration, "backref should be correct"
69
69
  assert_equal dev, ep.device, "backref should be correct"
70
70
 
71
- assert_operator 0, :<, ep.wMaxPacketSize, "packet size should be > 0"
71
+ assert_operator 0, :<=, ep.wMaxPacketSize, "packet size should be > 0"
72
72
  end
73
73
  end
74
74
  end
@@ -16,7 +16,7 @@
16
16
  require "test/unit"
17
17
  require "libusb/compat"
18
18
 
19
- class TestLibusbCompat < Test::Unit::TestCase
19
+ class TestLibusbCompatMassStorage < Test::Unit::TestCase
20
20
  include USB
21
21
 
22
22
  attr_accessor :devh
@@ -30,7 +30,7 @@ class TestLibusbCompat < Test::Unit::TestCase
30
30
  USB.each_device_by_class(USB_CLASS_MASS_STORAGE, 0x06, 0x50){|dev| devs << dev }
31
31
 
32
32
  dev = devs.last
33
- abort "no mass storage device found" unless dev
33
+ skip "no mass storage device found" unless dev
34
34
  devh = dev.open
35
35
  if RUBY_PLATFORM=~/linux/i
36
36
  data = " "*1000
@@ -101,7 +101,7 @@ class TestLibusbDescriptors < Test::Unit::TestCase
101
101
  assert_equal 5, ep.bDescriptorType
102
102
  assert_kind_of Integer, ep.bEndpointAddress
103
103
  assert_kind_of Integer, ep.bmAttributes
104
- assert_operator 0, :<, ep.wMaxPacketSize, "packet size should be > 0"
104
+ assert_operator 0, :<=, ep.wMaxPacketSize, "packet size should be > 0"
105
105
  assert_kind_of Integer, ep.bInterval
106
106
  assert_kind_of Integer, ep.bRefresh
107
107
  assert_kind_of Integer, ep.bSynchAddress
@@ -0,0 +1,118 @@
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 "test/unit"
17
+ require "libusb"
18
+ require "libusb/eventmachine"
19
+ require "eventmachine"
20
+
21
+ class TestLibusbEventMachine < Test::Unit::TestCase
22
+ include LIBUSB
23
+ BOMS_GET_MAX_LUN = 0xFE
24
+
25
+ attr_accessor :context
26
+ attr_accessor :device
27
+ attr_accessor :devh
28
+ attr_accessor :endpoint_in
29
+ attr_accessor :endpoint_out
30
+
31
+ def setup
32
+ @context = Context.new
33
+ @context.debug = 3
34
+
35
+ @device = context.devices( :bClass=>CLASS_MASS_STORAGE, :bSubClass=>[0x06,0x01], :bProtocol=>0x50 ).last
36
+ skip "no mass storage device found" unless @device
37
+
38
+ @endpoint_in = @device.endpoints.find{|ep| ep.bEndpointAddress&ENDPOINT_IN != 0 }
39
+ @endpoint_out = @device.endpoints.find{|ep| ep.bEndpointAddress&ENDPOINT_IN == 0 }
40
+ @devh = @device.open
41
+
42
+ if RUBY_PLATFORM=~/linux/i && devh.kernel_driver_active?(0)
43
+ devh.detach_kernel_driver(0)
44
+ end
45
+ devh.claim_interface(0)
46
+
47
+ # clear any pending data
48
+ devh.clear_halt(endpoint_in)
49
+ end
50
+
51
+ def teardown
52
+ end
53
+
54
+ def em_run
55
+ EventMachine.run do
56
+ @context.eventmachine_register
57
+
58
+ EventMachine.add_shutdown_hook do
59
+ @devh.release_interface(0) if @devh
60
+ @devh.close if @devh
61
+ @context.eventmachine_unregister
62
+ end
63
+
64
+ yield
65
+ end
66
+ end
67
+
68
+
69
+ def test_bulk_transfer
70
+ em_run do
71
+ ticks = 0
72
+ tr = devh.eventmachine_bulk_transfer(
73
+ :endpoint => @endpoint_in,
74
+ :timeout => 1500,
75
+ :dataIn => 123 )
76
+ # puts "started usb transfer #{tr}"
77
+
78
+ tr.callback do |data|
79
+ # puts "recved: #{data.inspect}"
80
+
81
+ assert false, "the bulk transfer shouldn't succeed"
82
+ EventMachine.stop
83
+ end
84
+ tr.errback do |text|
85
+ # puts "recv-err: #{text}"
86
+ assert true, "the bulk transfer should fail"
87
+
88
+ assert_operator ticks, :>=, 4
89
+ EventMachine.stop
90
+ end
91
+
92
+ EventMachine.add_periodic_timer(0.333) do
93
+ ticks += 1
94
+ end
95
+ end
96
+ end
97
+
98
+ def test_event_loop
99
+ em_run do
100
+ tr = devh.eventmachine_control_transfer(
101
+ :bmRequestType=>ENDPOINT_IN|REQUEST_TYPE_CLASS|RECIPIENT_INTERFACE,
102
+ :bRequest=>BOMS_GET_MAX_LUN,
103
+ :wValue=>0, :wIndex=>0, :dataIn=>1 )
104
+
105
+ # puts "started usb transfer #{tr}"
106
+ tr.callback do |data|
107
+ # puts "recved: #{data.inspect}"
108
+ assert true, "the control transfer should succeed"
109
+ EventMachine.stop
110
+ end
111
+ tr.errback do |text|
112
+ # puts "recv-err: #{text}"
113
+ assert false, "the control transfer shouldn't fail"
114
+ EventMachine.stop
115
+ end
116
+ end
117
+ end
118
+ end