ligo 0.1.0.beta → 0.1.0

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