ligo 0.1.0.beta → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  doc/
2
2
  pkg/
3
+ .yardoc
data/ChangeLog.md CHANGED
@@ -1,4 +1,3 @@
1
- ### 0.1.0 / 2012-12-06
2
-
3
- * Initial release:
1
+ ### 0.1.0 / 2012-12-24
4
2
 
3
+ * Initial release
data/Rakefile CHANGED
@@ -31,10 +31,30 @@ begin
31
31
  gem 'yard', '~> 0.8'
32
32
  require 'yard'
33
33
 
34
- YARD::Rake::YardocTask.new
34
+ YARD::Rake::YardocTask.new
35
35
  rescue LoadError => e
36
36
  task :yard do
37
37
  abort "Please run `gem install yard` to install YARD."
38
38
  end
39
39
  end
40
40
  task :doc => :yard
41
+
42
+ begin
43
+ gem 'yardstick', '~> 0.8.0'
44
+
45
+ require 'yardstick/rake/measurement'
46
+
47
+ Yardstick::Rake::Measurement.new(:yardstick_measure) do |measurement|
48
+ measurement.output = 'doc/measurement_report.txt'
49
+ end
50
+
51
+ require 'yardstick/rake/verify'
52
+
53
+ Yardstick::Rake::Verify.new do |verify|
54
+ verify.threshold = 100
55
+ end
56
+ rescue LoadError => e
57
+ task :yardstick do
58
+ abort "Please run `gem install yardstick` to install yardstick."
59
+ end
60
+ end
data/bin/ligo-sample CHANGED
@@ -46,9 +46,13 @@ eof
46
46
  loop do
47
47
  res = nil
48
48
  mutex.synchronize do
49
- output_string = dev.recv(1024)
50
- unless output_string.nil?
51
- puts "IN -- String received: #{output_string}"
49
+ begin
50
+ output_string = dev.read(1024, 200)
51
+ unless output_string.nil?
52
+ puts "IN -- String received: #{output_string}"
53
+ end
54
+ rescue LIBUSB::ERROR_TIMEOUT
55
+ # do nothing and proceed
52
56
  end
53
57
  end
54
58
  # get some time to write data if any
data/lib/ligo.rb CHANGED
@@ -20,15 +20,14 @@ require 'libusb'
20
20
 
21
21
  require 'ligo/version'
22
22
 
23
- # Ligo module.
24
- #
25
23
  # This module contains the Android Open Accessory Protocol utility classes to
26
24
  # enable custom USB I/O with AOAP-compatible devices.
27
25
  #
28
- # @see http://source.android.com/tech/accessories/aoap/aoa.html
29
26
  # @see http://source.android.com/tech/accessories/index.html
27
+ # @see http://source.android.com/tech/accessories/aoap/aoa.html
30
28
  # @see
31
29
  # http://developer.android.com/guide/topics/connectivity/usb/accessory.html
30
+ # @author Renaud AUBIN
32
31
  module Ligo
33
32
  require 'ligo/logging'
34
33
  require 'ligo/constants'
@@ -17,26 +17,121 @@
17
17
 
18
18
  module Ligo
19
19
 
20
+ # A virtual accessory to interact via usb with an android device according
21
+ # to the Android Open Accessory Protocol.
22
+ #
23
+ # @see http://source.android.com/tech/accessories/index.html
24
+ # @see http://source.android.com/tech/accessories/aoap/aoa.html
25
+ # @see
26
+ # http://developer.android.com/guide/topics/connectivity/usb/accessory.html
27
+ #
28
+ # @author Renaud AUBIN
29
+ # @api public
20
30
  class Accessory
21
31
  include Logging
22
32
 
23
- # http://stackoverflow.com/questions/2680523/dry-ruby-initialization-with-hash-argument
24
- attr_reader :id, :manufacturer, :model, :description, :version, :uri, :serial
25
-
33
+ # The default id used to initialize a new accessory if none is provided to
34
+ # the constructor
26
35
  DEFAULT_ID = {
27
36
  manufacturer: 'ligō',
28
37
  model: 'Demo',
29
38
  description: 'ligō virtual accessory',
30
39
  version: '1.0',
31
40
  uri: 'https://github.com/nibua-r/ligo#readme',
32
- serial: '6c6967c58d20312e30' # 'ligō 1.0'.each_byte {|c| print c.to_i.to_s(16), '' }
41
+ # 'ligō 1.0'.each_byte {|c| print c.to_i.to_s(16), '' }
42
+ serial: '6c6967c58d20312e30'
33
43
  }
34
44
 
45
+ # Returns the full identifying information hash
46
+ # @example
47
+ # accessory = Ligo::Accessory.new
48
+ # accessory.id
49
+ # # => {:manufacturer=>"ligō",
50
+ # # :model=>"Demo",
51
+ # # :description=>"ligō virtual accessory",
52
+ # # :version=>"1.0",
53
+ # # :uri=>"https://github.com/nibua-r/ligo#readme",
54
+ # # :serial=>"6c6967c58d20312e30"}
55
+ # @return [Hash<Symbol, String>] the full identifying information hash.
56
+ attr_reader :id
57
+
58
+ # Returns the `manufacturer name` identifying string
59
+ # @example
60
+ # accessory = Ligo::Accessory.new
61
+ # accessory.manufacturer
62
+ # # => "ligō"
63
+ # @return [String] the `manufacturer name` identifying string.
64
+ attr_reader :manufacturer
65
+
66
+ # Returns the `model name` identifying string
67
+ # @example
68
+ # accessory = Ligo::Accessory.new
69
+ # accessory.model
70
+ # # => "Demo"
71
+ # @return [String] the `model name` identifying string.
72
+ attr_reader :model
73
+
74
+ # Returns the `description` identifying string
75
+ # @example
76
+ # accessory = Ligo::Accessory.new
77
+ # accessory.description
78
+ # # => "ligō virtual accessory"
79
+ # @return [String] the `description` identifying string.
80
+ attr_reader :description
81
+
82
+ # Returns the `version` identifying string
83
+ # @example
84
+ # accessory = Ligo::Accessory.new
85
+ # accessory.version
86
+ # # => "1.0"
87
+ # @return [String] the `version` identifying string.
88
+ attr_reader :version
89
+
90
+ # Returns the `uri` identifying string
91
+ # @example
92
+ # acc = Ligo::Accessory.new
93
+ # acc.uri
94
+ # # => "https://github.com/nibua-r/ligo#readme"
95
+ # @return [String] the `uri` identifying string.
96
+ attr_reader :uri
97
+
98
+ # Returns the `serial` identifying string
99
+ # @example
100
+ # accessory = Ligo::Accessory.new
101
+ # accessory.serial
102
+ # # => "6c6967c58d20312e30"
103
+ # @return [String] the `serial` identifying string.
104
+ attr_reader :serial
105
+
106
+ # Returns a new {Accessory} initialized with the provided identification
107
+ #
108
+ # @param [Hash<Symbol, String>] id
109
+ # The accessory identifying information as a hash.
110
+ # @raise [ArgumentError] if the provided id is not a Hash or if one of the
111
+ # identifying string is missing.
112
+ # @example
113
+ # new_id =
114
+ # {
115
+ # manufacturer: 'MyVeryBigCompany Corp.',
116
+ # model: 'AwesomeProduct',
117
+ # description: 'Who cares about description! ← 😠',
118
+ # version: '0.0',
119
+ # uri: 'http://www.foo.bar/awesome_product',
120
+ # serial: '⚀⚁⚂⚃⚄⚅012345678'
121
+ # }
122
+ # accessory = Ligo::Accessory.new(new_id)
35
123
  def initialize(id = DEFAULT_ID)
36
124
 
37
- raise ArgumentError, '#new must be called with a Hash' unless id.is_a? Hash
125
+ unless id.is_a? Hash
126
+ raise ArgumentError, '#new must be called with a Hash'
127
+ end
128
+
129
+ required_ids = [:manufacturer,
130
+ :model, :description,
131
+ :version,
132
+ :uri,
133
+ :serial]
38
134
 
39
- required_ids = [:manufacturer, :model, :description, :version, :uri, :serial]
40
135
  required_ids.each do |sym|
41
136
  raise ArgumentError, "Missing argument: #{sym}" unless id.include? sym
42
137
  end
@@ -44,7 +139,9 @@ module Ligo
44
139
  id.each do |k, v|
45
140
  raise ArgumentError, "#{k} is not a String" unless v.is_a? String
46
141
  raise ArgumentError, "#{k} must not be empty" if v.empty?
47
- raise ArgumentError, "#{k} must contain at most 255 bytes" if v.bytesize > 255
142
+ if v.bytesize > 255
143
+ raise ArgumentError, "#{k} must contain at most 255 bytes"
144
+ end
48
145
  instance_variable_set "@#{k}", v unless v.nil?
49
146
  end
50
147
 
@@ -52,10 +149,27 @@ module Ligo
52
149
  logger.debug self.inspect
53
150
  end
54
151
 
152
+ # Returns {#id}.each
153
+ # @return block execution.
154
+ # @example
155
+ # accessory.each do |k,v|
156
+ # puts "#{k} = #{v}"
157
+ # end
158
+ # # manufacturer = ligō
159
+ # # model = Demo
160
+ # # description = ligō virtual accessory
161
+ # # version = 1.0
162
+ # # uri = https://github.com/nibua-r/ligo#readme
163
+ # # serial = 6c6967c58d20312e30
55
164
  def each(&block)
56
165
  @id.each(&block)
57
166
  end
58
167
 
168
+ # Returns {#id}.keys
169
+ # @return [Array] {#id}.keys.
170
+ # @example
171
+ # accessory.keys.inspect
172
+ # # => "[:manufacturer, :model, :description, :version, :uri, :serial]"
59
173
  def keys
60
174
  @id.keys
61
175
  end
data/lib/ligo/context.rb CHANGED
@@ -15,14 +15,20 @@
15
15
  # limitations under the License.
16
16
  #
17
17
 
18
- # TODO: Add a proper mention to libusb LGPL licensing since the following code
19
- # is a derivative work of Lars Kanis LIBUSB::Context.
20
-
21
18
  module Ligo
22
19
 
20
+ # This class is a derivative work of `LIBUSB::Context` as included in
21
+ # [LIBUSB](https://github.com/larskanis/libusb), written by Lars Kanis and
22
+ # released under the LGPLv3.
23
+ # @author Renaud AUBIN
24
+ # @api public
23
25
  class Context < LIBUSB::Context
24
26
  include LIBUSB
25
27
 
28
+ # @api private
29
+ # Returns the list of AOAP-compatible devices
30
+ # @return [Array<Ligo::Device>] the list of AOAP-compatible devices
31
+ # currently connected on the USB bus.
26
32
  def device_list
27
33
  pppDevs = FFI::MemoryPointer.new :pointer
28
34
  size = Call.libusb_get_device_list(@ctx, pppDevs)
@@ -37,7 +43,7 @@ module Ligo
37
43
  # Include only AOAP compatible devices
38
44
  pDevs << device if device.aoap?
39
45
  rescue LIBUSB::ERROR_ACCESS
40
- # TODO: do something about this exception, log at least!
46
+ # @todo Do something about this exception, log at least!
41
47
  end
42
48
  end
43
49
  end
data/lib/ligo/device.rb CHANGED
@@ -19,13 +19,49 @@ module Ligo
19
19
 
20
20
  require 'ligo/constants'
21
21
 
22
+ # This class provides a convenient wrapper class around `LIBUSB::Device` and
23
+ # implements the Android Open Accessory Protocol to interact with compatible
24
+ # devices.
25
+ #
26
+ # This class is a derivative work of `LIBUSB::Device` as included in
27
+ # [LIBUSB](https://github.com/larskanis/libusb), written by Lars Kanis and
28
+ # released under the LGPLv3.
29
+ # @author Renaud AUBIN
30
+ # @api public
22
31
  class Device < LIBUSB::Device
23
32
  include Logging
24
33
 
25
- # TODO: Document the attr!
26
- attr_reader :pDev, :pDevDesc
27
- attr_reader :aoap_version, :accessory, :in, :out, :handle
34
+ # @api private
35
+ attr_reader :pDev
28
36
 
37
+ # @api private
38
+ attr_reader :pDevDesc
39
+
40
+ # Returns the version of the AOA protocol that this device supports
41
+ # @return [Fixnum] the version of the AOA protocol that this device
42
+ # supports.
43
+ attr_reader :aoap_version
44
+
45
+ # Returns the associated {Accessory}
46
+ # @return [Accessory, nil] the associated accessory if any or nil.
47
+ attr_reader :accessory
48
+
49
+ # Returns the accessory mode input endpoint
50
+ # @return [LIBUSB::Endpoint, nil] the input endpoint or nil if the device is
51
+ # not in accessory mode.
52
+ attr_reader :in
53
+
54
+ # Returns the accessory mode output endpoint
55
+ # @return [LIBUSB::Endpoint, nil] the output endpoint or nil if the device
56
+ # is not in accessory mode.
57
+ attr_reader :out
58
+
59
+ # Returns the device handle
60
+ # @todo Improve the :handle doc
61
+ # @return [LIBUSB::DevHandle, nil] the device handle or nil.
62
+ attr_reader :handle
63
+
64
+ # @api private
29
65
  def initialize context, pDev
30
66
  @aoap_version = 0
31
67
  @accessory, @in, @out, @handle = nil, nil, nil, nil
@@ -48,6 +84,9 @@ module Ligo
48
84
  end
49
85
  end
50
86
 
87
+ # Opens an handle and claim the default interface for further operations
88
+ # @return [LIBUSB::DevHandle] the handle to operate on.
89
+ # @raise
51
90
  def open_and_claim
52
91
  @handle = open
53
92
  @handle.claim_interface(0)
@@ -55,6 +94,9 @@ module Ligo
55
94
  @handle
56
95
  end
57
96
 
97
+ # Finalizes the device (release and close)
98
+ # @return
99
+ # @raise [LIBUSB::ERROR_TIMEOUT] in case of timeout.
58
100
  def finalize
59
101
  if @handle
60
102
  @handle.release_interface(0)
@@ -62,7 +104,7 @@ module Ligo
62
104
  end
63
105
  end
64
106
 
65
- # Simple write method (blocking until timeout).
107
+ # Simple write method (blocking until timeout)
66
108
  # @param [Fixnum] buffer_size
67
109
  # The number of bytes expected to be received.
68
110
  # @param [Fixnum] timeout
@@ -74,8 +116,9 @@ module Ligo
74
116
  dataIn: buffer_size,
75
117
  timeout: timeout)
76
118
  end
119
+ alias_method :recv, :read
77
120
 
78
- # Simple write method (blocking until timeout).
121
+ # Simple write method (blocking until timeout)
79
122
  # @param [String] buffer
80
123
  # The buffer to be sent.
81
124
  # @param [Fixnum] timeout
@@ -87,32 +130,9 @@ module Ligo
87
130
  dataOut: buffer,
88
131
  timeout: timeout)
89
132
  end
133
+ alias_method :send, :write
90
134
 
91
- # Simple recv method.
92
- # @param [Fixnum] buffer_size
93
- # The buffer size of the received buffer.
94
- # @return [String] the received buffer (at most buffer_size bytes).
95
- def recv(buffer_size)
96
- begin
97
- handle.bulk_transfer(endpoint: @in,
98
- dataIn: buffer_size)
99
- rescue LIBUSB::ERROR_TIMEOUT
100
- nil
101
- # maybe we should implement a internal thread, a sleep and a retry
102
- end
103
- end
104
-
105
- # Simple send method.
106
- # @param [String] data
107
- # The data to be sent.
108
- # @return [Fixnum] the number of bytes sent.
109
- def send(data)
110
- # TODO: Add timeout param?
111
- handle.bulk_transfer(endpoint: @out, dataOut: data)
112
- end
113
-
114
- # Associate an AOAP compatible device with a virtual accessory and switch the Android device
115
- # to accessory mode.
135
+ # Associates with an accessory and switch to accessory mode
116
136
  #
117
137
  # Prepare an OAP compatible device to interact with a given {Ligo::Accessory}:
118
138
  # * Switch the current assigned device to accessory mode
@@ -153,8 +173,11 @@ module Ligo
153
173
  true
154
174
  end
155
175
 
176
+ # Switches to accessory mode
177
+ #
156
178
  # Send identifying string information to the device and request the device start up in accessory
157
179
  # mode.
180
+ # @return [true, false] true for success, false otherwise.
158
181
  def start_accessory_mode
159
182
  logger.debug 'start_accessory_mode'
160
183
  sn = self.serial_number
@@ -169,6 +192,8 @@ module Ligo
169
192
  wait_and_retrieve_by_serial(sn)
170
193
  end
171
194
 
195
+ # Sends a `set configuration` control transfer
196
+ #
172
197
  # Set the device's configuration to a value of 1 with a SET_CONFIGURATION (0x09) device
173
198
  # request.
174
199
  # @return [true, false] true for success, false otherwise.
@@ -193,14 +218,14 @@ module Ligo
193
218
  end
194
219
  end
195
220
 
196
- # Check if the current {Ligo::Device} is in accessory mode.
197
- # @return [true, false] true if the {Ligo::Device} is in accessory mode,
198
- # false otherwise.
221
+ # Check if the current {Device} is in accessory mode
222
+ # @return [true, false] true if the {Device} is in accessory mode, false
223
+ # otherwise.
199
224
  def accessory_mode?
200
225
  self.idVendor == GOOGLE_VID
201
226
  end
202
227
 
203
- # Check if the current {Ligo::Device} supports AOAP.
228
+ # Check if the current {Device} supports AOAP
204
229
  # @return [true, false] true if the {Ligo::Device} supports AOAP, false
205
230
  # otherwise.
206
231
  def aoap?
@@ -209,9 +234,8 @@ module Ligo
209
234
  @aoap_version >= 1
210
235
  end
211
236
 
212
- # Check if the current {Ligo::Device} is in UMS mode.
213
- # @return [true, false] true if the {Ligo::Device} is in UMS mode, false
214
- # otherwise.
237
+ # Check if the current {Device} is in UMS mode
238
+ # @return [true, false] true if the {Device} is in UMS mode, false otherwise
215
239
  def uas?
216
240
  if RUBY_PLATFORM=~/linux/i
217
241
  # http://cateee.net/lkddb/web-lkddb/USB_UAS.html
@@ -222,8 +246,11 @@ module Ligo
222
246
  end
223
247
  end
224
248
 
249
+ # Sends a `get protocol` control transfer
250
+ #
225
251
  # Send a 51 control request ("Get Protocol") to figure out if the device
226
- # supports the Android accessory protocol.
252
+ # supports the Android accessory protocol. We assume here that the device
253
+ # has not been opened.
227
254
  # @return [Fixnum] the AOAP protocol version supported by the device (0 for
228
255
  # no AOAP support).
229
256
  def get_protocol
@@ -243,7 +270,11 @@ module Ligo
243
270
  (res.size == 2 && version >= 1 ) ? version : 0
244
271
  end
245
272
 
246
- # Send identifying string information to the device.
273
+ # Sends identifying string information to the device
274
+ #
275
+ # We assume here that the device has already been opened.
276
+ # @api private
277
+ # @return
247
278
  def send_accessory_id
248
279
  logger.debug 'send_accessory_id'
249
280
  req_type = LIBUSB::ENDPOINT_OUT | LIBUSB::REQUEST_TYPE_VENDOR
@@ -260,7 +291,9 @@ module Ligo
260
291
  end
261
292
  private :send_accessory_id
262
293
 
263
- # Request the device start up in accessory mode
294
+ # Sends AOA protocol start command to the device
295
+ # @api private
296
+ # @return [Fixnum]
264
297
  def send_start
265
298
  logger.debug 'send_start'
266
299
  req_type = LIBUSB::ENDPOINT_OUT | LIBUSB::REQUEST_TYPE_VENDOR
@@ -270,7 +303,8 @@ module Ligo
270
303
  end
271
304
  private :send_start
272
305
 
273
- # Internal use only.
306
+ # @api private
307
+ # @return [true, false] true for success, false otherwise.
274
308
  def wait_and_retrieve_by_serial(sn)
275
309
  sleep REENUMERATION_DELAY
276
310
  # The device should now reappear on the usb bus with the Google vendor id.
@@ -283,6 +317,7 @@ module Ligo
283
317
  # Retrieve new pointers (check if the old ones should be dereferenced)
284
318
  @pDev = device.pDev
285
319
  @pDevDesc = device.pDevDesc
320
+ true
286
321
  else
287
322
  logger.error ['Failed to retrieve the device after switching to ',
288
323
  'accessory mode. This may be due to a lack of proper ',
@@ -291,6 +326,7 @@ module Ligo
291
326
  'SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ',
292
327
  'MODE="0666", GROUP="plugdev"'
293
328
  ].join
329
+ false
294
330
  end
295
331
  end
296
332
  private :wait_and_retrieve_by_serial
data/lib/ligo/logging.rb CHANGED
@@ -19,7 +19,7 @@ require 'logger'
19
19
 
20
20
  module Ligo
21
21
 
22
- # Logging module.
22
+ # Logging module
23
23
  #
24
24
  # This module enables to share the same logger between all the Ligo classes.
25
25
  module Logging
data/lib/ligo/version.rb CHANGED
@@ -17,5 +17,5 @@
17
17
 
18
18
  module Ligo
19
19
  # ligō version
20
- VERSION = "0.1.0.beta"
20
+ VERSION = "0.1.0"
21
21
  end
data/ligo.gemspec CHANGED
@@ -24,5 +24,6 @@ Gem::Specification.new do |gem|
24
24
  gem.add_development_dependency 'rspec', '~> 2.4'
25
25
  gem.add_development_dependency 'rubygems-tasks', '~> 0.2'
26
26
  gem.add_development_dependency 'yard', '~> 0.8'
27
+ gem.add_development_dependency 'yardstick', '~> 0.8.0'
27
28
  gem.add_development_dependency 'pry', '~> 0.9.10'
28
29
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ligo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.beta
5
- prerelease: 6
4
+ version: 0.1.0
5
+ prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Renaud AUBIN
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-22 00:00:00.000000000 Z
12
+ date: 2012-12-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: libusb
@@ -75,6 +75,22 @@ dependencies:
75
75
  - - ~>
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0.8'
78
+ - !ruby/object:Gem::Dependency
79
+ name: yardstick
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 0.8.0
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 0.8.0
78
94
  - !ruby/object:Gem::Dependency
79
95
  name: pry
80
96
  requirement: !ruby/object:Gem::Requirement
@@ -137,9 +153,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
137
153
  required_rubygems_version: !ruby/object:Gem::Requirement
138
154
  none: false
139
155
  requirements:
140
- - - ! '>'
156
+ - - ! '>='
141
157
  - !ruby/object:Gem::Version
142
- version: 1.3.1
158
+ version: '0'
143
159
  requirements: []
144
160
  rubyforge_project:
145
161
  rubygems_version: 1.8.23