sphero 1.4.1 → 1.5.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5499fdac118804bb652308ee12b8660d8e08d4bf
4
+ data.tar.gz: 1fd2ef026bcefc25ca15de2b712b4a78a595e2db
5
+ SHA512:
6
+ metadata.gz: e148d39135d1c173e20eca97869e8342e02731a07d3ef4f9b0b928797ec1b675a9b6517e3cf11e90a75fe5ce942879eacaf0b3dbd4e928346694a7e174301e23
7
+ data.tar.gz: 6f24b58cbd89d6c0b3465486ba4051cd7a3917e6ad58cba38377795fedf53379f1db91e1bf83d6d07e9925fafa3c271b4db768394cfaa44586802cb34e925947
@@ -37,3 +37,9 @@
37
37
  * 1 enhancement
38
38
 
39
39
  * Add constants FORWARD, BACKWARD, RIGHT, & LEFT for quick directionality
40
+
41
+ === 1.5.0 / 2014-02-06
42
+
43
+ * Many enhancements and bugfixes
44
+
45
+ * Been too long since our last changelog entry. Many bugfixes and enhancements.
@@ -2,6 +2,8 @@
2
2
 
3
3
  * http://github.com/hybridgroup/sphero
4
4
 
5
+ [![Build Status](https://travis-ci.org/hybridgroup/sphero.png?branch=master)](https://travis-ci.org/hybridgroup/sphero)
6
+
5
7
  ## DESCRIPTION:
6
8
 
7
9
  A ruby gem for controlling your Sphero ball. Sends commands over the TTY
@@ -101,7 +103,7 @@ You may now access the sphero from `/dev/rfcomm0`
101
103
 
102
104
  ## INSTALL:
103
105
 
104
- * gem install hybridgroup-sphero
106
+ * gem install sphero
105
107
 
106
108
  ## LICENSE:
107
109
 
@@ -3,7 +3,7 @@ require 'sphero/response'
3
3
  require 'thread'
4
4
 
5
5
  class Sphero
6
- VERSION = '1.4.1'
6
+ VERSION = '1.5.0'
7
7
 
8
8
  FORWARD = 0
9
9
  RIGHT = 90
@@ -12,7 +12,7 @@ class Sphero
12
12
 
13
13
  DEFAULT_RETRIES = 3
14
14
 
15
- attr_accessor :connection_types, :messages
15
+ attr_accessor :connection_types, :messages, :packets, :response_queue, :responses
16
16
 
17
17
  class << self
18
18
  def start(dev, &block)
@@ -47,9 +47,23 @@ class Sphero
47
47
  @seq = 0x00
48
48
  @lock = Mutex.new
49
49
  @messages = Queue.new
50
+ @packets = Queue.new
51
+ @response_queue = Queue.new
52
+ @responses = []
53
+ Thread.new {
54
+ loop do
55
+ write @packets.pop
56
+ end
57
+ }
58
+ Thread.new {
59
+ loop do
60
+ @responses << @response_queue.pop
61
+ end
62
+ }
50
63
  end
51
64
 
52
65
  def close
66
+ return if @sp.nil? || @sp.closed?
53
67
  begin
54
68
  stop
55
69
  rescue Exception => e
@@ -60,39 +74,53 @@ class Sphero
60
74
  end
61
75
 
62
76
  def ping
63
- write Request::Ping.new(@seq)
77
+ packet = Request::Ping.new(@seq)
78
+ queue_packet packet
79
+ return sync_response packet.seq
64
80
  end
65
81
 
66
82
  def version
67
- write Request::GetVersioning.new(@seq)
83
+ packet = Request::GetVersioning.new(@seq)
84
+ queue_packet packet
85
+ return sync_response packet.seq
68
86
  end
69
87
 
70
88
  def bluetooth_info
71
- write Request::GetBluetoothInfo.new(@seq)
89
+ packet = Request::GetBluetoothInfo.new(@seq)
90
+ queue_packet packet
91
+ return sync_response packet.seq
92
+ end
93
+
94
+ # This retrieves the "user LED color" which is stored in the config block
95
+ # (which may or may not be actively driven to the RGB LED).
96
+ def user_led
97
+ packet = Request::GetRGB.new(@seq)
98
+ queue_packet packet
99
+ return sync_response packet.seq
72
100
  end
73
101
 
74
102
  def auto_reconnect= time_s
75
- write Request::SetAutoReconnect.new(@seq, time_s)
103
+ queue_packet Request::SetAutoReconnect.new(@seq, limit1(time_s) )
76
104
  end
77
105
 
78
106
  def auto_reconnect
79
- write(Request::GetAutoReconnect.new(@seq)).time
107
+ queue_packet(Request::GetAutoReconnect.new(@seq)).time
80
108
  end
81
109
 
82
110
  def disable_auto_reconnect
83
- write Request::SetAutoReconnect.new(@seq, 0, 0x00)
111
+ queue_packet Request::SetAutoReconnect.new(@seq, 0, flag(false) )
84
112
  end
85
113
 
86
114
  def power_state
87
- write Request::GetPowerState.new(@seq)
115
+ queue_packet Request::GetPowerState.new(@seq)
88
116
  end
89
117
 
90
118
  def sphero_sleep wakeup = 0, macro = 0
91
- write Request::Sleep.new(@seq, wakeup, macro)
119
+ queue_packet Request::Sleep.new(@seq, limit2(wakeup), limit1(macro) )
92
120
  end
93
121
 
94
122
  def roll speed, heading, state = true
95
- write Request::Roll.new(@seq, speed, heading, state ? 0x01 : 0x00)
123
+ queue_packet Request::Roll.new(@seq, limit1(speed), degrees(heading), flag(state) )
96
124
  end
97
125
 
98
126
  def stop
@@ -100,7 +128,11 @@ class Sphero
100
128
  end
101
129
 
102
130
  def heading= h
103
- write Request::Heading.new(@seq, h)
131
+ queue_packet Request::Heading.new(@seq, degrees(h) )
132
+ end
133
+
134
+ def stabilization= on
135
+ queue_packet Request::Stabilization.new(@seq, on)
104
136
  end
105
137
 
106
138
  def color colorname, persistant = false
@@ -109,23 +141,18 @@ class Sphero
109
141
  end
110
142
 
111
143
  def rgb r, g, b, persistant = false
112
- write Request::SetRGB.new(@seq, r, g, b, persistant ? 0x01 : 0x00)
144
+ queue_packet Request::SetRGB.new(@seq, limit1(r), limit1(g), limit1(b), flag(persistant) )
113
145
  end
114
146
 
115
- # This retrieves the "user LED color" which is stored in the config block
116
- # (which may or may not be actively driven to the RGB LED).
117
- def user_led
118
- write Request::GetRGB.new(@seq)
119
- end
120
147
 
121
148
  # Brightness 0x00 - 0xFF
122
149
  def back_led_output= h
123
- write Request::SetBackLEDOutput.new(@seq, h)
150
+ queue_packet Request::SetBackLEDOutput.new(@seq, limit1(h) )
124
151
  end
125
152
 
126
153
  # Rotation Rate 0x00 - 0xFF
127
154
  def rotation_rate= h
128
- write Request::SetRotationRate.new(@seq, h)
155
+ queue_packet Request::SetRotationRate.new(@seq, limit1(h))
129
156
  end
130
157
 
131
158
  # just a nicer alias for Ruby's own sleep
@@ -137,21 +164,82 @@ class Sphero
137
164
 
138
165
  # configure power notification messages
139
166
  def set_power_notification enable=true
140
- write Request::SetPowerNotification.new(@seq, enable ? 0x01 : 0x00)
167
+ queue_packet Request::SetPowerNotification.new(@seq, flag(enable) )
141
168
  end
142
169
 
143
170
  # configure data streaming notification messages
144
171
  def set_data_streaming n, m, mask, pcnt, mask2
145
- write Request::SetDataStreaming.new(@seq, n, m, mask, pcnt, mask2)
172
+ queue_packet Request::SetDataStreaming.new(@seq, limit2(n), limit2(m),
173
+ limit4(mask), limit1(pcnt), limit4(mask2) )
146
174
  end
147
175
 
148
176
  # configure collision detection messages
149
177
  def configure_collision_detection meth, x_t, y_t, x_spd, y_spd, dead
150
- write Request::ConfigureCollisionDetection.new(@seq, meth, x_t, y_t, x_spd, y_spd, dead)
178
+ queue_packet Request::ConfigureCollisionDetection.new(@seq, limit1(meth),
179
+ limit1(x_t), limit1(y_t),
180
+ limit1(x_spd), limit1(y_spd),
181
+ limit1(dead) )
151
182
  end
152
-
183
+
153
184
  private
154
-
185
+
186
+ def sync_response seq
187
+ 100.times do
188
+ @responses.each do |response|
189
+ if response.seq == seq
190
+ @responses.delete(response)
191
+ return response
192
+ end
193
+ end
194
+ sleep 0.001
195
+ end
196
+ return nil
197
+ end
198
+
199
+ def limit(value, max)
200
+ return nil if value.nil?
201
+
202
+ value = value.to_i
203
+ if value < 0
204
+ 0
205
+ elsif value > max
206
+ max
207
+ else
208
+ value
209
+ end
210
+ end
211
+
212
+ def wrap(value, max)
213
+ value && (value.to_i % max)
214
+ end
215
+
216
+ def degrees(value)
217
+ wrap value, 360
218
+ end
219
+
220
+ def limit1(value)
221
+ limit value, 0xFF
222
+ end
223
+
224
+ def limit2(value)
225
+ limit value, 0xFFFF
226
+ end
227
+
228
+ def limit4(value)
229
+ limit value, 0xFFFFFFFF
230
+ end
231
+
232
+ def flag(value)
233
+ case value
234
+ when true
235
+ 0x01
236
+ when false
237
+ 0x00
238
+ else
239
+ value
240
+ end
241
+ end
242
+
155
243
  def is_windows?
156
244
  os = RUBY_PLATFORM.split("-")[1]
157
245
  if (os == 'mswin' or os == 'bccwin' or os == 'mingw' or os == 'mingw32')
@@ -173,25 +261,26 @@ class Sphero
173
261
  puts "Please 'gem install hybridgroup-serialport' for serial port support."
174
262
  end
175
263
 
264
+ def queue_packet packet
265
+ @packets << packet
266
+ end
267
+
176
268
  def write packet
177
269
  header, body = nil
178
270
 
179
- IO.select([], [@sp], [], 20)
180
-
271
+ IO.select([], [@sp], [], 1)
181
272
  @lock.synchronize do
182
273
  @sp.write packet.to_str
183
274
  @seq += 1
184
275
  end
185
-
186
- IO.select([@sp], [], [], 20)
276
+ IO.select([@sp], [], [], 1)
187
277
  header = read_header(true)
188
278
  body = read_body(header.last, true) if header
189
-
190
279
  # pick off asynch packets and store, till we get to the message response
191
280
  while header && Response.async?(header)
192
281
  messages << Response::AsyncResponse.response(header, body)
193
282
 
194
- IO.select([@sp], [], [], 20)
283
+ IO.select([@sp], [], [], 1)
195
284
  header = read_header(true)
196
285
  if header
197
286
  body = read_body(header.last, true)
@@ -203,7 +292,7 @@ class Sphero
203
292
  response = packet.response header, body
204
293
 
205
294
  if response.success?
206
- response
295
+ @response_queue << response
207
296
  else
208
297
  raise "Unable to write to Sphero!"
209
298
  end
@@ -3,7 +3,7 @@ class Sphero
3
3
  SOP1 = 0xFF
4
4
  SOP2 = 0xFF
5
5
 
6
- attr_reader :data
6
+ attr_reader :data, :seq
7
7
 
8
8
  def initialize seq, data = []
9
9
  @seq = seq
@@ -89,7 +89,7 @@ class Sphero
89
89
  end
90
90
  end
91
91
 
92
- class Heading < Request
92
+ class Heading < Sphero
93
93
  def initialize seq, heading
94
94
  super(seq, [heading])
95
95
  @cid = 0x01
@@ -101,6 +101,18 @@ class Sphero
101
101
  end
102
102
  end
103
103
 
104
+ class Stabilization < Sphero
105
+ def initialize seq, on
106
+ super(seq, [on ? 1 : 0])
107
+ @cid = 0x02
108
+ end
109
+
110
+ private
111
+ def packet_body
112
+ @data.pack 'C'
113
+ end
114
+ end
115
+
104
116
  class Sleep < Request
105
117
  def initialize seq, wakeup, macro
106
118
  super(seq, [wakeup, macro])
@@ -114,7 +126,7 @@ class Sphero
114
126
  end
115
127
  end
116
128
 
117
- class SetPowerNotification < Sphero
129
+ class SetPowerNotification < Request
118
130
  def initialize seq, enable
119
131
  super(seq, [enable])
120
132
  @cid = 0x21
@@ -23,49 +23,55 @@ class TestSphero < MiniTest::Unit::TestCase
23
23
  end
24
24
 
25
25
  def test_ping
26
- Sphero::Request::Ping.expects(:new).with(@seq)
27
- @sphero.expects(:write)
26
+ packet = mock 'packet'
27
+ packet.stubs(:seq).returns(@seq)
28
+ Sphero::Request::Ping.expects(:new).with(@seq).returns(packet)
29
+ @sphero.expects(:queue_packet).returns(packet)
28
30
  @sphero.ping
29
31
  end
30
32
 
31
33
  def test_version
32
- Sphero::Request::GetVersioning.expects(:new).with(@seq)
33
- @sphero.expects(:write)
34
+ packet = mock 'packet'
35
+ packet.stubs(:seq).returns(@seq)
36
+ Sphero::Request::GetVersioning.expects(:new).with(@seq).returns(packet)
37
+ @sphero.expects(:queue_packet).returns(packet)
34
38
  @sphero.version
35
39
  end
36
40
 
37
41
  def test_bluetooth_info
38
- Sphero::Request::GetBluetoothInfo.expects(:new).with(@seq)
39
- @sphero.expects(:write)
42
+ packet = mock 'packet'
43
+ packet.stubs(:seq).returns(@seq)
44
+ Sphero::Request::GetBluetoothInfo.expects(:new).with(@seq).returns(packet)
45
+ @sphero.expects(:queue_packet).returns(packet)
40
46
  @sphero.bluetooth_info
41
47
  end
42
48
 
43
49
  def test_auto_reconnect=
44
- @time_s = "10"
50
+ @time_s = 10
45
51
  Sphero::Request::SetAutoReconnect.expects(:new).with(@seq, @time_s)
46
- @sphero.expects(:write)
52
+ @sphero.expects(:queue_packet)
47
53
  @sphero.auto_reconnect = @time_s
48
54
  end
49
55
 
50
56
  def test_auto_reconnect
51
- @time_s = "10"
57
+ @time_s = 10
52
58
  packet = mock 'packet'
53
59
  packet.stubs(:time).returns(@time_s)
54
60
 
55
61
  Sphero::Request::GetAutoReconnect.expects(:new).with(@seq)
56
- @sphero.expects(:write).returns(packet)
62
+ @sphero.expects(:queue_packet).returns(packet)
57
63
  assert_equal @sphero.auto_reconnect, @time_s
58
64
  end
59
65
 
60
66
  def test_disable_auto_reconnect
61
67
  Sphero::Request::SetAutoReconnect.expects(:new).with(@seq, 0, 0x00)
62
- @sphero.expects(:write)
68
+ @sphero.expects(:queue_packet)
63
69
  @sphero.disable_auto_reconnect
64
70
  end
65
71
 
66
72
  def test_power_state
67
73
  Sphero::Request::GetPowerState.expects(:new).with(@seq)
68
- @sphero.expects(:write)
74
+ @sphero.expects(:queue_packet)
69
75
  @sphero.power_state
70
76
  end
71
77
 
@@ -73,19 +79,73 @@ class TestSphero < MiniTest::Unit::TestCase
73
79
  wakeup = 1
74
80
  macro = 2
75
81
  Sphero::Request::Sleep.expects(:new).with(@seq, wakeup, macro)
76
- @sphero.expects(:write)
82
+ @sphero.expects(:queue_packet)
77
83
  @sphero.sphero_sleep wakeup, macro
78
84
  end
79
85
 
86
+ def test_stabilization
87
+ Sphero::Request::Stabilization.expects(:new).with(@seq, true)
88
+ @sphero.expects(:queue_packet)
89
+ @sphero.stabilization = true
90
+ end
91
+
80
92
  def test_roll
81
93
  speed = 1
82
94
  heading = 2
83
95
  state = 1
84
96
  Sphero::Request::Roll.expects(:new).with(@seq, speed, heading, state)
85
- @sphero.expects(:write)
97
+ @sphero.expects(:queue_packet)
86
98
  @sphero.roll speed, heading, true
87
99
  end
88
100
 
101
+ def test_roll_upper_limit
102
+ heading = 2
103
+ state = 1
104
+ Sphero::Request::Roll.expects(:new).with(@seq, 255, heading, state)
105
+ @sphero.expects(:queue_packet)
106
+ @sphero.roll 300, heading, true
107
+ end
108
+
109
+ def test_roll_lower_limit
110
+ heading = 2
111
+ state = 1
112
+ Sphero::Request::Roll.expects(:new).with(@seq, 0, heading, state)
113
+ @sphero.expects(:queue_packet)
114
+ @sphero.roll( -10, heading, true )
115
+ end
116
+
117
+ def test_roll_limit_conversion
118
+ heading = 2
119
+ state = 1
120
+ Sphero::Request::Roll.expects(:new).with(@seq, 123, heading, state)
121
+ @sphero.expects(:queue_packet)
122
+ @sphero.roll 123.4, heading, true
123
+ end
124
+
125
+ def test_roll_upper_wrap
126
+ speed = 3
127
+ state = 1
128
+ Sphero::Request::Roll.expects(:new).with(@seq, speed, 1, state)
129
+ @sphero.expects(:queue_packet)
130
+ @sphero.roll speed, 361, true
131
+ end
132
+
133
+ def test_roll_lower_wrap
134
+ speed = 3
135
+ state = 1
136
+ Sphero::Request::Roll.expects(:new).with(@seq, speed, 359, state)
137
+ @sphero.expects(:queue_packet)
138
+ @sphero.roll( speed, -1, true )
139
+ end
140
+
141
+ def test_roll_limit_wrap
142
+ speed = 3
143
+ state = 1
144
+ Sphero::Request::Roll.expects(:new).with(@seq, speed, 123, state)
145
+ @sphero.expects(:queue_packet)
146
+ @sphero.roll speed, 123.4, true
147
+ end
148
+
89
149
  def test_stop
90
150
  @sphero.expects(:roll).with(0, 0)
91
151
  @sphero.stop
metadata CHANGED
@@ -1,20 +1,32 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sphero
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.1
5
- prerelease:
4
+ version: 1.5.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Hybrid Group
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-07-25 00:00:00.000000000 Z
11
+ date: 2014-02-06 00:00:00.000000000 Z
13
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: minitest
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
14
27
  - !ruby/object:Gem::Dependency
15
28
  name: rdoc
16
29
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
30
  requirements:
19
31
  - - ~>
20
32
  - !ruby/object:Gem::Version
@@ -22,7 +34,6 @@ dependencies:
22
34
  type: :development
23
35
  prerelease: false
24
36
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
37
  requirements:
27
38
  - - ~>
28
39
  - !ruby/object:Gem::Version
@@ -30,7 +41,6 @@ dependencies:
30
41
  - !ruby/object:Gem::Dependency
31
42
  name: hoe
32
43
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
44
  requirements:
35
45
  - - ~>
36
46
  - !ruby/object:Gem::Version
@@ -38,15 +48,13 @@ dependencies:
38
48
  type: :development
39
49
  prerelease: false
40
50
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
51
  requirements:
43
52
  - - ~>
44
53
  - !ruby/object:Gem::Version
45
54
  version: '3.6'
46
- description: ! 'A ruby gem for controlling your Sphero ball. Sends commands over
47
- the TTY
48
-
49
- provided by the bluetooth connection.'
55
+ description: |-
56
+ A ruby gem for controlling your Sphero ball. Sends commands over the TTY
57
+ provided by the bluetooth connection.
50
58
  email:
51
59
  - sphero@hybridgroup.com
52
60
  executables:
@@ -58,6 +66,7 @@ extra_rdoc_files:
58
66
  - README.markdown
59
67
  files:
60
68
  - .autotest
69
+ - .gemtest
61
70
  - CHANGELOG.rdoc
62
71
  - Manifest.txt
63
72
  - README.markdown
@@ -68,9 +77,9 @@ files:
68
77
  - lib/sphero/response.rb
69
78
  - test/test_sphero.rb
70
79
  - test/test_sphero_request.rb
71
- - .gemtest
72
80
  homepage: http://github.com/hybridgroup/sphero
73
81
  licenses: []
82
+ metadata: {}
74
83
  post_install_message:
75
84
  rdoc_options:
76
85
  - --main
@@ -78,23 +87,21 @@ rdoc_options:
78
87
  require_paths:
79
88
  - lib
80
89
  required_ruby_version: !ruby/object:Gem::Requirement
81
- none: false
82
90
  requirements:
83
- - - ! '>='
91
+ - - '>='
84
92
  - !ruby/object:Gem::Version
85
93
  version: 1.9.2
86
94
  required_rubygems_version: !ruby/object:Gem::Requirement
87
- none: false
88
95
  requirements:
89
- - - ! '>='
96
+ - - '>='
90
97
  - !ruby/object:Gem::Version
91
98
  version: '0'
92
99
  requirements: []
93
100
  rubyforge_project: sphero
94
- rubygems_version: 1.8.24
101
+ rubygems_version: 2.2.1
95
102
  signing_key:
96
- specification_version: 3
103
+ specification_version: 4
97
104
  summary: A ruby gem for controlling your Sphero ball
98
105
  test_files:
99
- - test/test_sphero.rb
100
106
  - test/test_sphero_request.rb
107
+ - test/test_sphero.rb