sphero 1.0.0 → 1.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +33 -0
- data/Manifest.txt +1 -0
- data/README.markdown +66 -2
- data/Rakefile +3 -3
- data/lib/sphero.rb +307 -33
- data/lib/sphero/request.rb +96 -86
- data/lib/sphero/response.rb +118 -3
- data/test/test_sphero.rb +97 -6
- data/test/test_sphero_request.rb +15 -0
- metadata +13 -43
data/CHANGELOG.rdoc
CHANGED
@@ -4,3 +4,36 @@
|
|
4
4
|
|
5
5
|
* Birthday!
|
6
6
|
|
7
|
+
=== 1.0.1 / 2012-10-28
|
8
|
+
|
9
|
+
* 3 minor fixes/enhancements
|
10
|
+
|
11
|
+
* Works with Ruby 1.9.2 for us regular folks
|
12
|
+
* Sphero.start method to endlessly retry when connecting
|
13
|
+
* I think heading might work again, not too sure
|
14
|
+
|
15
|
+
=== 1.1.0 / 2013-01-04
|
16
|
+
|
17
|
+
* 3 enhancements
|
18
|
+
|
19
|
+
* Pass a block to Sphero.start for DSL-awesomeness
|
20
|
+
* Use Sphero#keep_going as a nicer alias for Ruby's sleep command
|
21
|
+
* Add some additional test coverage
|
22
|
+
|
23
|
+
=== 1.1.2 / 2013-01-07
|
24
|
+
|
25
|
+
* 1 bugfix
|
26
|
+
|
27
|
+
* Correct Sphero#keep_going to call Kernel sleep method correctly
|
28
|
+
|
29
|
+
=== 1.1.3 / 2013-01-07
|
30
|
+
|
31
|
+
* 1 enhancement/bugfix depending on how you look at it
|
32
|
+
|
33
|
+
* Change Sphero#sleep to Sphero#sphero_sleep to distingish naive call to Kernel sleep
|
34
|
+
|
35
|
+
=== 1.1.4 / 2013-01-10
|
36
|
+
|
37
|
+
* 1 enhancement
|
38
|
+
|
39
|
+
* Add constants FORWARD, BACKWARD, RIGHT, & LEFT for quick directionality
|
data/Manifest.txt
CHANGED
data/README.markdown
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# sphero
|
2
2
|
|
3
|
-
* http://github.com/
|
3
|
+
* http://github.com/hybridgroup/sphero
|
4
4
|
|
5
5
|
## DESCRIPTION:
|
6
6
|
|
@@ -13,6 +13,51 @@ provided by the bluetooth connection.
|
|
13
13
|
|
14
14
|
## SYNOPSIS:
|
15
15
|
|
16
|
+
You can easily start your Sphero and send it commands like this:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
Sphero.start '/dev/tty.Sphero-YBW-RN-SPP' do
|
20
|
+
roll 60, FORWARD
|
21
|
+
keep_going 3
|
22
|
+
|
23
|
+
roll 60, RIGHT
|
24
|
+
keep_going 3
|
25
|
+
|
26
|
+
roll 60, BACKWARD
|
27
|
+
keep_going 3
|
28
|
+
|
29
|
+
roll 60, LEFT
|
30
|
+
keep_going 3
|
31
|
+
|
32
|
+
stop
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
Here is another example:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
Sphero.start "/dev/tty.Sphero-PRG-RN-SPP" do
|
40
|
+
ping
|
41
|
+
|
42
|
+
# Roll 0 degrees, speed 125
|
43
|
+
roll(125, 0)
|
44
|
+
|
45
|
+
# Turn 360 degrees, 30 degrees at a time
|
46
|
+
0.step(360, 30) { |h|
|
47
|
+
h = 0 if h == 360
|
48
|
+
|
49
|
+
# Set the heading to h degrees
|
50
|
+
heading = h
|
51
|
+
keep_going 1
|
52
|
+
}
|
53
|
+
|
54
|
+
keep_going 1
|
55
|
+
stop
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
59
|
+
Here is a another way to do the same thing as the previos example, via just normal method calls instead of the DSL:
|
60
|
+
|
16
61
|
```ruby
|
17
62
|
s = Sphero.new "/dev/tty.Sphero-PRG-RN-SPP"
|
18
63
|
s.ping
|
@@ -32,19 +77,38 @@ sleep 1
|
|
32
77
|
s.stop
|
33
78
|
```
|
34
79
|
|
80
|
+
## Pairing sphero with ubuntu
|
81
|
+
Add your user to the `dialout` group
|
82
|
+
```
|
83
|
+
$ sudo usermod -a -G dialout <user>
|
84
|
+
```
|
85
|
+
Then logout or restart your computer. Once your user is logged back in, pair the sphero with the ubuntu bluetooth manager.
|
86
|
+
|
87
|
+
Once paired, you may now bind your sphero to a rfcomm port
|
88
|
+
```
|
89
|
+
$ sudo hcitool scan
|
90
|
+
Scanning ...
|
91
|
+
<address> Sphero
|
92
|
+
$ sudo rfcomm bind /dev/rfcomm0 <address> 1
|
93
|
+
```
|
94
|
+
|
95
|
+
You may now access the sphero from `/dev/rfcomm0`
|
96
|
+
|
35
97
|
## REQUIREMENTS:
|
36
98
|
|
37
99
|
* A Sphero ball connected to your computer
|
100
|
+
* Supports MRI 1.9.2/1.9.3 and Rubinius 2.0rc1 for sure...
|
38
101
|
|
39
102
|
## INSTALL:
|
40
103
|
|
41
|
-
* gem install sphero
|
104
|
+
* gem install hybridgroup-sphero
|
42
105
|
|
43
106
|
## LICENSE:
|
44
107
|
|
45
108
|
(The MIT License)
|
46
109
|
|
47
110
|
Copyright (c) 2012 Aaron Patterson
|
111
|
+
Copyright (c) 2012-2013 The Hybrid Group
|
48
112
|
|
49
113
|
Permission is hereby granted, free of charge, to any person obtaining
|
50
114
|
a copy of this software and associated documentation files (the
|
data/Rakefile
CHANGED
@@ -4,19 +4,19 @@ require 'rubygems'
|
|
4
4
|
require 'hoe'
|
5
5
|
|
6
6
|
Hoe.plugins.delete :rubyforge
|
7
|
+
Hoe.plugins.delete :flog
|
7
8
|
Hoe.plugin :minitest
|
8
9
|
Hoe.plugin :gemspec # `gem install hoe-gemspec`
|
9
10
|
Hoe.plugin :git # `gem install hoe-git`
|
10
11
|
|
11
12
|
Hoe.spec 'sphero' do
|
12
|
-
developer('
|
13
|
+
developer('Hybrid Group', 'sphero@hybridgroup.com')
|
13
14
|
self.readme_file = 'README.markdown'
|
14
15
|
self.history_file = 'CHANGELOG.rdoc'
|
15
16
|
self.extra_rdoc_files = FileList['*.{rdoc,markdown}']
|
16
|
-
self.extra_deps << ['serialport']
|
17
17
|
|
18
18
|
self.spec_extras = {
|
19
|
-
:required_ruby_version => '>= 1.9.
|
19
|
+
:required_ruby_version => '>= 1.9.2'
|
20
20
|
}
|
21
21
|
end
|
22
22
|
|
data/lib/sphero.rb
CHANGED
@@ -1,16 +1,62 @@
|
|
1
|
-
require 'serialport'
|
2
1
|
require 'sphero/request'
|
3
2
|
require 'sphero/response'
|
4
3
|
require 'thread'
|
5
4
|
|
6
5
|
class Sphero
|
7
|
-
VERSION = '1.
|
6
|
+
VERSION = '1.4.1'
|
7
|
+
|
8
|
+
FORWARD = 0
|
9
|
+
RIGHT = 90
|
10
|
+
BACKWARD = 180
|
11
|
+
LEFT = 270
|
12
|
+
|
13
|
+
DEFAULT_RETRIES = 3
|
14
|
+
|
15
|
+
attr_accessor :connection_types, :messages
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def start(dev, &block)
|
19
|
+
retries_left = DEFAULT_RETRIES
|
20
|
+
begin
|
21
|
+
sphero = self.new dev
|
22
|
+
if (block_given?)
|
23
|
+
begin
|
24
|
+
sphero.instance_eval(&block)
|
25
|
+
ensure
|
26
|
+
sphero.close
|
27
|
+
end
|
28
|
+
return nil
|
29
|
+
end
|
30
|
+
return sphero
|
31
|
+
rescue Errno::EBUSY
|
32
|
+
puts retries_left
|
33
|
+
retries_left = retries_left - 1
|
34
|
+
retry unless retries_left < 0
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
8
38
|
|
9
39
|
def initialize dev
|
10
|
-
|
40
|
+
if dev.is_a?(String)
|
41
|
+
initialize_serialport dev
|
42
|
+
else
|
43
|
+
@sp = dev
|
44
|
+
end
|
45
|
+
|
11
46
|
@dev = 0x00
|
12
47
|
@seq = 0x00
|
13
48
|
@lock = Mutex.new
|
49
|
+
@messages = Queue.new
|
50
|
+
end
|
51
|
+
|
52
|
+
def close
|
53
|
+
begin
|
54
|
+
stop
|
55
|
+
rescue Exception => e
|
56
|
+
puts e.message
|
57
|
+
ensure
|
58
|
+
@sp.close
|
59
|
+
end
|
14
60
|
end
|
15
61
|
|
16
62
|
def ping
|
@@ -41,7 +87,7 @@ class Sphero
|
|
41
87
|
write Request::GetPowerState.new(@seq)
|
42
88
|
end
|
43
89
|
|
44
|
-
def
|
90
|
+
def sphero_sleep wakeup = 0, macro = 0
|
45
91
|
write Request::Sleep.new(@seq, wakeup, macro)
|
46
92
|
end
|
47
93
|
|
@@ -57,6 +103,11 @@ class Sphero
|
|
57
103
|
write Request::Heading.new(@seq, h)
|
58
104
|
end
|
59
105
|
|
106
|
+
def color colorname, persistant = false
|
107
|
+
color = COLORS[colorname]
|
108
|
+
rgb color[:r], color[:g], color[:b], persistant
|
109
|
+
end
|
110
|
+
|
60
111
|
def rgb r, g, b, persistant = false
|
61
112
|
write Request::SetRGB.new(@seq, r, g, b, persistant ? 0x01 : 0x00)
|
62
113
|
end
|
@@ -77,18 +128,76 @@ class Sphero
|
|
77
128
|
write Request::SetRotationRate.new(@seq, h)
|
78
129
|
end
|
79
130
|
|
131
|
+
# just a nicer alias for Ruby's own sleep
|
132
|
+
def keep_going(duration)
|
133
|
+
Kernel::sleep duration
|
134
|
+
end
|
135
|
+
|
136
|
+
## async messages
|
137
|
+
|
138
|
+
# configure power notification messages
|
139
|
+
def set_power_notification enable=true
|
140
|
+
write Request::SetPowerNotification.new(@seq, enable ? 0x01 : 0x00)
|
141
|
+
end
|
142
|
+
|
143
|
+
# configure data streaming notification messages
|
144
|
+
def set_data_streaming n, m, mask, pcnt, mask2
|
145
|
+
write Request::SetDataStreaming.new(@seq, n, m, mask, pcnt, mask2)
|
146
|
+
end
|
147
|
+
|
148
|
+
# configure collision detection messages
|
149
|
+
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)
|
151
|
+
end
|
152
|
+
|
80
153
|
private
|
154
|
+
|
155
|
+
def is_windows?
|
156
|
+
os = RUBY_PLATFORM.split("-")[1]
|
157
|
+
if (os == 'mswin' or os == 'bccwin' or os == 'mingw' or os == 'mingw32')
|
158
|
+
true
|
159
|
+
else
|
160
|
+
false
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def initialize_serialport dev
|
165
|
+
require 'serialport'
|
166
|
+
@sp = SerialPort.new dev, 115200, 8, 1, SerialPort::NONE
|
167
|
+
if is_windows?
|
168
|
+
@sp.read_timeout=1000
|
169
|
+
@sp.write_timeout=0
|
170
|
+
@sp.initial_byte_offset=5
|
171
|
+
end
|
172
|
+
rescue LoadError
|
173
|
+
puts "Please 'gem install hybridgroup-serialport' for serial port support."
|
174
|
+
end
|
81
175
|
|
82
176
|
def write packet
|
83
|
-
header = nil
|
84
|
-
|
177
|
+
header, body = nil
|
178
|
+
|
179
|
+
IO.select([], [@sp], [], 20)
|
85
180
|
|
86
181
|
@lock.synchronize do
|
87
182
|
@sp.write packet.to_str
|
88
183
|
@seq += 1
|
184
|
+
end
|
185
|
+
|
186
|
+
IO.select([@sp], [], [], 20)
|
187
|
+
header = read_header(true)
|
188
|
+
body = read_body(header.last, true) if header
|
89
189
|
|
90
|
-
|
91
|
-
|
190
|
+
# pick off asynch packets and store, till we get to the message response
|
191
|
+
while header && Response.async?(header)
|
192
|
+
messages << Response::AsyncResponse.response(header, body)
|
193
|
+
|
194
|
+
IO.select([@sp], [], [], 20)
|
195
|
+
header = read_header(true)
|
196
|
+
if header
|
197
|
+
body = read_body(header.last, true)
|
198
|
+
else
|
199
|
+
body = nil
|
200
|
+
end
|
92
201
|
end
|
93
202
|
|
94
203
|
response = packet.response header, body
|
@@ -96,38 +205,203 @@ class Sphero
|
|
96
205
|
if response.success?
|
97
206
|
response
|
98
207
|
else
|
99
|
-
raise
|
208
|
+
raise "Unable to write to Sphero!"
|
100
209
|
end
|
101
210
|
end
|
102
|
-
end
|
103
211
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
212
|
+
def read_header(blocking=false)
|
213
|
+
header = nil
|
214
|
+
begin
|
215
|
+
data = read_next_chunk(5, blocking)
|
216
|
+
return nil unless data
|
217
|
+
header = data.unpack 'C5'
|
218
|
+
rescue Errno::EBUSY
|
219
|
+
retry
|
220
|
+
rescue Exception => e
|
221
|
+
puts e.message
|
222
|
+
puts e.backtrace.inspect
|
223
|
+
retry
|
224
|
+
end
|
110
225
|
|
111
|
-
|
112
|
-
|
113
|
-
}
|
226
|
+
header
|
227
|
+
end
|
114
228
|
|
115
|
-
|
116
|
-
|
117
|
-
|
229
|
+
def read_body(len, blocking=false)
|
230
|
+
data = nil
|
231
|
+
begin
|
232
|
+
data = read_next_chunk(len, blocking)
|
233
|
+
return nil unless data && data.length == len
|
234
|
+
rescue Errno::EBUSY
|
235
|
+
retry
|
236
|
+
rescue Exception => e
|
237
|
+
puts e.message
|
238
|
+
puts e.backtrace.inspect
|
239
|
+
retry
|
240
|
+
end
|
118
241
|
|
119
|
-
|
242
|
+
data
|
243
|
+
end
|
120
244
|
|
121
|
-
|
122
|
-
|
123
|
-
|
245
|
+
def read_next_chunk(len, blocking=false)
|
246
|
+
data = nil
|
247
|
+
begin
|
248
|
+
@lock.synchronize do
|
249
|
+
if blocking || is_windows?
|
250
|
+
data = @sp.read(len)
|
251
|
+
else
|
252
|
+
data = @sp.read_nonblock(len)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
rescue Errno::EBUSY
|
256
|
+
retry
|
257
|
+
rescue Exception => e
|
258
|
+
puts e.message
|
259
|
+
puts e.backtrace.inspect
|
260
|
+
return nil
|
124
261
|
end
|
125
|
-
|
262
|
+
data
|
263
|
+
end
|
126
264
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
265
|
+
COLORS = {
|
266
|
+
'aliceblue' => {:r => 240, :g => 248, :b => 255},
|
267
|
+
'antiquewhite' => {:r => 250, :g => 235, :b => 215},
|
268
|
+
'aqua' => {:r => 0, :g => 255, :b => 255},
|
269
|
+
'aquamarine' => {:r => 127, :g => 255, :b => 212},
|
270
|
+
'azure' => {:r => 240, :g => 255, :b => 255},
|
271
|
+
'beige' => {:r => 245, :g => 245, :b => 220},
|
272
|
+
'bisque' => {:r => 255, :g => 228, :b => 196},
|
273
|
+
'black' => {:r => 0, :g => 0, :b => 0},
|
274
|
+
'blanchedalmond' => {:r => 255, :g => 235, :b => 205},
|
275
|
+
'blue' => {:r => 0, :g => 0, :b => 255},
|
276
|
+
'blueviolet' => {:r => 138, :g => 43, :b => 226},
|
277
|
+
'brown' => {:r => 165, :g => 42, :b => 42},
|
278
|
+
'burlywood' => {:r => 222, :g => 184, :b => 135},
|
279
|
+
'cadetblue' => {:r => 95, :g => 158, :b => 160},
|
280
|
+
'chartreuse' => {:r => 127, :g => 255, :b => 0},
|
281
|
+
'chocolate' => {:r => 210, :g => 105, :b => 30},
|
282
|
+
'coral' => {:r => 255, :g => 127, :b => 80},
|
283
|
+
'cornflowerblue' => {:r => 100, :g => 149, :b => 237},
|
284
|
+
'cornsilk' => {:r => 255, :g => 248, :b => 220},
|
285
|
+
'crimson' => {:r => 220, :g => 20, :b => 60},
|
286
|
+
'cyan' => {:r => 0, :g => 255, :b => 255},
|
287
|
+
'darkblue' => {:r => 0, :g => 0, :b => 139},
|
288
|
+
'darkcyan' => {:r => 0, :g => 139, :b => 139},
|
289
|
+
'darkgoldenrod' => {:r => 184, :g => 134, :b => 11},
|
290
|
+
'darkgray' => {:r => 169, :g => 169, :b => 169},
|
291
|
+
'darkgreen' => {:r => 0, :g => 100, :b => 0},
|
292
|
+
'darkkhaki' => {:r => 189, :g => 183, :b => 107},
|
293
|
+
'darkmagenta' => {:r => 139, :g => 0, :b => 139},
|
294
|
+
'darkolivegreen' => {:r => 85, :g => 107, :b => 47},
|
295
|
+
'darkorange' => {:r => 255, :g => 140, :b => 0},
|
296
|
+
'darkorchid' => {:r => 153, :g => 50, :b => 204},
|
297
|
+
'darkred' => {:r => 139, :g => 0, :b => 0},
|
298
|
+
'darksalmon' => {:r => 233, :g => 150, :b => 122},
|
299
|
+
'darkseagreen' => {:r => 143, :g => 188, :b => 143},
|
300
|
+
'darkslateblue' => {:r => 72, :g => 61, :b => 139},
|
301
|
+
'darkslategray' => {:r => 47, :g => 79, :b => 79},
|
302
|
+
'darkturquoise' => {:r => 0, :g => 206, :b => 209},
|
303
|
+
'darkviolet' => {:r => 148, :g => 0, :b => 211},
|
304
|
+
'deeppink' => {:r => 255, :g => 20, :b => 147},
|
305
|
+
'deepskyblue' => {:r => 0, :g => 191, :b => 255},
|
306
|
+
'dimgray' => {:r => 105, :g => 105, :b => 105},
|
307
|
+
'dodgerblue' => {:r => 30, :g => 144, :b => 255},
|
308
|
+
'firebrick' => {:r => 178, :g => 34, :b => 34},
|
309
|
+
'floralwhite' => {:r => 255, :g => 250, :b => 240},
|
310
|
+
'forestgreen' => {:r => 34, :g => 139, :b => 34},
|
311
|
+
'fuchsia' => {:r => 255, :g => 0, :b => 255},
|
312
|
+
'gainsboro' => {:r => 220, :g => 220, :b => 220},
|
313
|
+
'ghostwhite' => {:r => 248, :g => 248, :b => 255},
|
314
|
+
'gold' => {:r => 255, :g => 215, :b => 0},
|
315
|
+
'goldenrod' => {:r => 218, :g => 165, :b => 32},
|
316
|
+
'gray' => {:r => 128, :g => 128, :b => 128},
|
317
|
+
'green' => {:r => 0, :g => 128, :b => 0},
|
318
|
+
'greenyellow' => {:r => 173, :g => 255, :b => 47},
|
319
|
+
'honeydew' => {:r => 240, :g => 255, :b => 240},
|
320
|
+
'hotpink' => {:r => 255, :g => 105, :b => 180},
|
321
|
+
'indianred' => {:r => 205, :g => 92, :b => 92},
|
322
|
+
'indigo' => {:r => 75, :g => 0, :b => 130},
|
323
|
+
'ivory' => {:r => 255, :g => 255, :b => 240},
|
324
|
+
'khaki' => {:r => 240, :g => 230, :b => 140},
|
325
|
+
'lavender' => {:r => 230, :g => 230, :b => 250},
|
326
|
+
'lavenderblush' => {:r => 255, :g => 240, :b => 245},
|
327
|
+
'lawngreen' => {:r => 124, :g => 252, :b => 0},
|
328
|
+
'lemonchiffon' => {:r => 255, :g => 250, :b => 205},
|
329
|
+
'lightblue' => {:r => 173, :g => 216, :b => 230},
|
330
|
+
'lightcoral' => {:r => 240, :g => 128, :b => 128},
|
331
|
+
'lightcyan' => {:r => 224, :g => 255, :b => 255},
|
332
|
+
'lightgoldenrodyellow' => {:r => 250, :g => 250, :b => 210},
|
333
|
+
'lightgreen' => {:r => 144, :g => 238, :b => 144},
|
334
|
+
'lightgrey' => {:r => 211, :g => 211, :b => 211},
|
335
|
+
'lightpink' => {:r => 255, :g => 182, :b => 193},
|
336
|
+
'lightsalmon' => {:r => 255, :g => 160, :b => 122},
|
337
|
+
'lightseagreen' => {:r => 32, :g => 178, :b => 170},
|
338
|
+
'lightskyblue' => {:r => 135, :g => 206, :b => 250},
|
339
|
+
'lightslategray' => {:r => 119, :g => 136, :b => 153},
|
340
|
+
'lightsteelblue' => {:r => 176, :g => 196, :b => 222},
|
341
|
+
'lightyellow' => {:r => 255, :g => 255, :b => 224},
|
342
|
+
'lime' => {:r => 0, :g => 255, :b => 0},
|
343
|
+
'limegreen' => {:r => 50, :g => 205, :b => 50},
|
344
|
+
'linen' => {:r => 250, :g => 240, :b => 230},
|
345
|
+
'magenta' => {:r => 255, :g => 0, :b => 255},
|
346
|
+
'maroon' => {:r => 128, :g => 0, :b => 0},
|
347
|
+
'mediumaquamarine' => {:r => 102, :g => 205, :b => 170},
|
348
|
+
'mediumblue' => {:r => 0, :g => 0, :b => 205},
|
349
|
+
'mediumorchid' => {:r => 186, :g => 85, :b => 211},
|
350
|
+
'mediumpurple' => {:r => 147, :g => 112, :b => 219},
|
351
|
+
'mediumseagreen' => {:r => 60, :g => 179, :b => 113},
|
352
|
+
'mediumslateblue' => {:r => 123, :g => 104, :b => 238},
|
353
|
+
'mediumspringgreen' => {:r => 0, :g => 250, :b => 154},
|
354
|
+
'mediumturquoise' => {:r => 72, :g => 209, :b => 204},
|
355
|
+
'mediumvioletred' => {:r => 199, :g => 21, :b => 133},
|
356
|
+
'midnightblue' => {:r => 25, :g => 25, :b => 112},
|
357
|
+
'mintcream' => {:r => 245, :g => 255, :b => 250},
|
358
|
+
'mistyrose' => {:r => 255, :g => 228, :b => 225},
|
359
|
+
'moccasin' => {:r => 255, :g => 228, :b => 181},
|
360
|
+
'navajowhite' => {:r => 255, :g => 222, :b => 173},
|
361
|
+
'navy' => {:r => 0, :g => 0, :b => 128},
|
362
|
+
'oldlace' => {:r => 253, :g => 245, :b => 230},
|
363
|
+
'olive' => {:r => 128, :g => 128, :b => 0},
|
364
|
+
'olivedrab' => {:r => 107, :g => 142, :b => 35},
|
365
|
+
'orange' => {:r => 255, :g => 165, :b => 0},
|
366
|
+
'orangered' => {:r => 255, :g => 69, :b => 0},
|
367
|
+
'orchid' => {:r => 218, :g => 112, :b => 214},
|
368
|
+
'palegoldenrod' => {:r => 238, :g => 232, :b => 170},
|
369
|
+
'palegreen' => {:r => 152, :g => 251, :b => 152},
|
370
|
+
'paleturquoise' => {:r => 175, :g => 238, :b => 238},
|
371
|
+
'palevioletred' => {:r => 219, :g => 112, :b => 147},
|
372
|
+
'papayawhip' => {:r => 255, :g => 239, :b => 213},
|
373
|
+
'peachpuff' => {:r => 255, :g => 218, :b => 185},
|
374
|
+
'peru' => {:r => 205, :g => 133, :b => 63},
|
375
|
+
'pink' => {:r => 255, :g => 192, :b => 203},
|
376
|
+
'plum' => {:r => 221, :g => 160, :b => 221},
|
377
|
+
'powderblue' => {:r => 176, :g => 224, :b => 230},
|
378
|
+
'purple' => {:r => 128, :g => 0, :b => 128},
|
379
|
+
'red' => {:r => 255, :g => 0, :b => 0},
|
380
|
+
'rosybrown' => {:r => 188, :g => 143, :b => 143},
|
381
|
+
'royalblue' => {:r => 65, :g => 105, :b => 225},
|
382
|
+
'saddlebrown' => {:r => 139, :g => 69, :b => 19},
|
383
|
+
'salmon' => {:r => 250, :g => 128, :b => 114},
|
384
|
+
'sandybrown' => {:r => 244, :g => 164, :b => 96},
|
385
|
+
'seagreen' => {:r => 46, :g => 139, :b => 87},
|
386
|
+
'seashell' => {:r => 255, :g => 245, :b => 238},
|
387
|
+
'sienna' => {:r => 160, :g => 82, :b => 45},
|
388
|
+
'silver' => {:r => 192, :g => 192, :b => 192},
|
389
|
+
'skyblue' => {:r => 135, :g => 206, :b => 235},
|
390
|
+
'slateblue' => {:r => 106, :g => 90, :b => 205},
|
391
|
+
'slategray' => {:r => 112, :g => 128, :b => 144},
|
392
|
+
'snow' => {:r => 255, :g => 250, :b => 250},
|
393
|
+
'springgreen' => {:r => 0, :g => 255, :b => 127},
|
394
|
+
'steelblue' => {:r => 70, :g => 130, :b => 180},
|
395
|
+
'tan' => {:r => 210, :g => 180, :b => 140},
|
396
|
+
'teal' => {:r => 0, :g => 128, :b => 128},
|
397
|
+
'thistle' => {:r => 216, :g => 191, :b => 216},
|
398
|
+
'tomato' => {:r => 255, :g => 99, :b => 71},
|
399
|
+
'turquoise' => {:r => 64, :g => 224, :b => 208},
|
400
|
+
'violet' => {:r => 238, :g => 130, :b => 238},
|
401
|
+
'wheat' => {:r => 245, :g => 222, :b => 179},
|
402
|
+
'white' => {:r => 255, :g => 255, :b => 255},
|
403
|
+
'whitesmoke' => {:r => 245, :g => 245, :b => 245},
|
404
|
+
'yellow' => {:r => 255, :g => 255, :b => 0},
|
405
|
+
'yellowgreen' => {:r => 154, :g => 205, :b => 50}
|
406
|
+
}
|
133
407
|
end
|
data/lib/sphero/request.rb
CHANGED
@@ -3,6 +3,8 @@ class Sphero
|
|
3
3
|
SOP1 = 0xFF
|
4
4
|
SOP2 = 0xFF
|
5
5
|
|
6
|
+
attr_reader :data
|
7
|
+
|
6
8
|
def initialize seq, data = []
|
7
9
|
@seq = seq
|
8
10
|
@data = data
|
@@ -19,7 +21,12 @@ class Sphero
|
|
19
21
|
end
|
20
22
|
|
21
23
|
def response header, body
|
22
|
-
|
24
|
+
name = self.class.name.split('::').last
|
25
|
+
if Response.const_defined?(name)
|
26
|
+
Response.const_get(name).new header, body
|
27
|
+
else
|
28
|
+
Response.new header, body
|
29
|
+
end
|
23
30
|
end
|
24
31
|
|
25
32
|
def packet_header
|
@@ -49,49 +56,26 @@ class Sphero
|
|
49
56
|
end
|
50
57
|
end
|
51
58
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
def packet_body
|
60
|
-
@data.pack 'n'
|
61
|
-
end
|
59
|
+
def self.make_command klass, cid, &block
|
60
|
+
Class.new(klass) {
|
61
|
+
define_method(:initialize) do |seq, *args|
|
62
|
+
super(seq, args)
|
63
|
+
@cid = cid
|
64
|
+
end
|
65
|
+
}
|
62
66
|
end
|
63
67
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
69
|
-
end
|
68
|
+
SetBackLEDOutput = make_command Sphero, 0x21
|
69
|
+
SetRotationRate = make_command Sphero, 0x03
|
70
|
+
SetRGB = make_command Sphero, 0x20
|
71
|
+
GetRGB = make_command Sphero, 0x22
|
70
72
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
class SetRGB < Sphero
|
79
|
-
def initialize seq, r, g, b, persistant
|
80
|
-
super(seq, [r, g, b, persistant])
|
81
|
-
@cid = 0x20
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
class GetRGB < Sphero
|
86
|
-
def initialize seq
|
87
|
-
super(seq, [])
|
88
|
-
@cid = 0x22
|
89
|
-
end
|
90
|
-
|
91
|
-
def response header, body
|
92
|
-
Response::GetRGB.new header, body
|
93
|
-
end
|
94
|
-
end
|
73
|
+
Ping = make_command Request, 0x01
|
74
|
+
GetVersioning = make_command Request, 0x02
|
75
|
+
GetBluetoothInfo = make_command Request, 0x11
|
76
|
+
SetAutoReconnect = make_command Request, 0x12
|
77
|
+
GetAutoReconnect = make_command Request, 0x13
|
78
|
+
GetPowerState = make_command Request, 0x20
|
95
79
|
|
96
80
|
class Roll < Sphero
|
97
81
|
def initialize seq, speed, heading, delay
|
@@ -105,70 +89,96 @@ class Sphero
|
|
105
89
|
end
|
106
90
|
end
|
107
91
|
|
108
|
-
class
|
109
|
-
def initialize seq
|
110
|
-
super(seq, [])
|
111
|
-
@cid
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
class GetVersioning < Request
|
116
|
-
def initialize seq
|
117
|
-
super(seq, [])
|
118
|
-
@cid = 0x02
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
class GetBluetoothInfo < Request
|
123
|
-
def initialize seq
|
124
|
-
super(seq, [])
|
125
|
-
@cid = 0x11
|
92
|
+
class Heading < Request
|
93
|
+
def initialize seq, heading
|
94
|
+
super(seq, [heading])
|
95
|
+
@cid = 0x01
|
126
96
|
end
|
127
97
|
|
128
|
-
|
129
|
-
|
98
|
+
private
|
99
|
+
def packet_body
|
100
|
+
@data.pack 'n'
|
130
101
|
end
|
131
102
|
end
|
132
103
|
|
133
|
-
class
|
134
|
-
def initialize seq,
|
135
|
-
super(seq, [
|
136
|
-
@cid
|
104
|
+
class Sleep < Request
|
105
|
+
def initialize seq, wakeup, macro
|
106
|
+
super(seq, [wakeup, macro])
|
107
|
+
@cid = 0x22
|
137
108
|
end
|
138
|
-
end
|
139
109
|
|
140
|
-
|
141
|
-
def initialize seq
|
142
|
-
super(seq, [])
|
143
|
-
@cid = 0x13
|
144
|
-
end
|
110
|
+
private
|
145
111
|
|
146
|
-
def
|
147
|
-
|
112
|
+
def packet_body
|
113
|
+
@data.pack 'nC'
|
148
114
|
end
|
149
115
|
end
|
150
116
|
|
151
|
-
class
|
152
|
-
def initialize seq
|
153
|
-
super(seq, [])
|
154
|
-
@cid =
|
155
|
-
end
|
156
|
-
|
157
|
-
def response header, body
|
158
|
-
Response::GetPowerState.new header, body
|
117
|
+
class SetPowerNotification < Sphero
|
118
|
+
def initialize seq, enable
|
119
|
+
super(seq, [enable])
|
120
|
+
@cid = 0x21
|
159
121
|
end
|
160
122
|
end
|
161
123
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
124
|
+
GYRO_AXIS_H_FILTERED = 0x0000_0001
|
125
|
+
GYRO_AXIS_M_FILTERED = 0x0000_0002
|
126
|
+
GYRO_AXIS_L_FILTERED = 0x0000_0004
|
127
|
+
LEFT_MOTOR_BACK_EMF_FILTERED = 0x0000_0020
|
128
|
+
RIGHT_MOTOR_BACK_EMF_FILTERED = 0x0000_0040
|
129
|
+
MAGNETOMETER_AXIS_Z_FILTERED = 0x0000_0080
|
130
|
+
MAGNETOMETER_AXIS_Y_FILTERED = 0x0000_0100
|
131
|
+
MAGNETOMETER_AXIS_X_FILTERED = 0x0000_0200
|
132
|
+
GYRO_AXIS_Z_FILTERED = 0x0000_0400
|
133
|
+
GYRO_AXIS_Y_FILTERED = 0x0000_0800
|
134
|
+
GYRO_AXIS_X_FILTERED = 0x0000_1000
|
135
|
+
ACCELEROMETER_AXIS_Z_FILTERED = 0x0000_2000
|
136
|
+
ACCELEROMETER_AXIS_Y_FILTERED = 0x0000_4000
|
137
|
+
ACCELEROMETER_AXIS_X_FILTERED = 0x0000_8000
|
138
|
+
IMU_YAW_ANGLE_FILTERED = 0x0001_0000
|
139
|
+
IMU_ROLL_ANGLE_FILTERED = 0x0002_0000
|
140
|
+
IMU_PITCH_ANGLE_FILTERED = 0x0004_0000
|
141
|
+
LEFT_MOTOR_BACK_EMF_RAW = 0x0020_0000
|
142
|
+
RIGHT_MOTOR_BACK_EMF_RAW = 0x0040_0000
|
143
|
+
MAGNETOMETER_AXIS_Z_RAW = 0x0080_0000
|
144
|
+
MAGNETOMETER_AXIS_Y_RAW = 0x0100_0000
|
145
|
+
MAGNETOMETER_AXIS_X_RAW = 0x0200_0000
|
146
|
+
GYRO_AXIS_Z_RAW = 0x0400_0000
|
147
|
+
GYRO_AXIS_Y_RAW = 0x0800_0000
|
148
|
+
GYRO_AXIS_X_RAW = 0x1000_0000
|
149
|
+
ACCELEROMETER_AXIS_Z_RAW = 0x2000_0000
|
150
|
+
ACCELEROMETER_AXIS_Y_RAW = 0x4000_0000
|
151
|
+
ACCELEROMETER_AXIS_X_RAW = 0x8000_0000
|
152
|
+
|
153
|
+
QUATERNION_Q0 = 0x0000_0001
|
154
|
+
QUATERNION_Q1 = 0x0000_0002
|
155
|
+
QUATERNION_Q2 = 0x0000_0004
|
156
|
+
QUATERNION_Q3 = 0x0000_0008
|
157
|
+
ODOMETER_X = 0x0000_0010
|
158
|
+
ODOMETER_Y = 0x0000_0020
|
159
|
+
ACCELONE = 0x0000_0040
|
160
|
+
VELOCITY_X = 0x0000_0080
|
161
|
+
VELOCITY_Y = 0x0000_0100
|
162
|
+
|
163
|
+
class SetDataStreaming < Sphero
|
164
|
+
def initialize seq, n, m, mask, pcnt, mask2
|
165
|
+
super(seq, [n, m, mask, pcnt, mask2])
|
166
|
+
@cid = 0x12
|
167
|
+
@mask = mask
|
168
|
+
@mask2 = mask2
|
166
169
|
end
|
167
170
|
|
168
171
|
private
|
169
172
|
|
170
173
|
def packet_body
|
171
|
-
@data.pack '
|
174
|
+
@data.pack 'nnNCN'
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
class ConfigureCollisionDetection < Sphero
|
179
|
+
def initialize seq, meth, x_t, y_t, x_spd, y_spd, dead
|
180
|
+
super(seq, [meth, x_t, y_t, x_spd, y_spd, dead])
|
181
|
+
@cid = 0x12
|
172
182
|
end
|
173
183
|
end
|
174
184
|
end
|
data/lib/sphero/response.rb
CHANGED
@@ -7,22 +7,36 @@ class Sphero
|
|
7
7
|
DLEN = 4
|
8
8
|
|
9
9
|
CODE_OK = 0
|
10
|
+
SIMPLE_RESPONSE = 0xFF
|
11
|
+
ASYNC_RESPONSE = 0xFE
|
12
|
+
|
13
|
+
def self.simple?(header)
|
14
|
+
header[SOP2] == SIMPLE_RESPONSE
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.async?(header)
|
18
|
+
header[SOP2] == ASYNC_RESPONSE
|
19
|
+
end
|
10
20
|
|
11
21
|
def initialize header, body
|
12
22
|
@header = header
|
13
23
|
@body = body
|
14
24
|
end
|
15
25
|
|
26
|
+
def valid?
|
27
|
+
@header && @body
|
28
|
+
end
|
29
|
+
|
16
30
|
def empty?
|
17
|
-
@header[DLEN] == 1
|
31
|
+
valid? && @header[DLEN] == 1
|
18
32
|
end
|
19
33
|
|
20
34
|
def success?
|
21
|
-
@header[MRSP] == CODE_OK
|
35
|
+
valid? && @header[MRSP] == CODE_OK
|
22
36
|
end
|
23
37
|
|
24
38
|
def seq
|
25
|
-
@header[SEQ]
|
39
|
+
valid? && @header[SEQ]
|
26
40
|
end
|
27
41
|
|
28
42
|
def body
|
@@ -84,5 +98,106 @@ class Sphero
|
|
84
98
|
def g; body[1]; end
|
85
99
|
def b; body[2]; end
|
86
100
|
end
|
101
|
+
|
102
|
+
class AsyncResponse < Response
|
103
|
+
ID_CODE = 2
|
104
|
+
DLEN_MSB = 3
|
105
|
+
DLEN_LSB = 4
|
106
|
+
|
107
|
+
POWER_NOTIFICATION = 0x01
|
108
|
+
LEVEL_1_DIAGNOSTIC = 0x02
|
109
|
+
SENSOR_DATA = 0x03
|
110
|
+
CONFIG_BLOCK = 0x04
|
111
|
+
PRESLEEP_WARNING = 0x05
|
112
|
+
MACRO_MARKERS = 0x06
|
113
|
+
COLLISION_DETECTED = 0x07
|
114
|
+
|
115
|
+
VALID_REPONSES = {POWER_NOTIFICATION => 'Sphero::Response::PowerNotification',
|
116
|
+
#LEVEL_1_DIAGNOSTIC => 'AsyncResponse',
|
117
|
+
SENSOR_DATA => 'Sphero::Response::SensorData',
|
118
|
+
#CONFIG_BLOCK => 'AsyncResponse',
|
119
|
+
#PRESLEEP_WARNING => 'AsyncResponse',
|
120
|
+
#MACRO_MARKERS => 'AsyncResponse',
|
121
|
+
COLLISION_DETECTED => 'Sphero::Response::CollisionDetected'}
|
122
|
+
|
123
|
+
def self.valid?(header)
|
124
|
+
VALID_REPONSES.keys.include?(header[ID_CODE])
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.response header, body
|
128
|
+
raise "no good" unless self.valid?(header)
|
129
|
+
constantize(VALID_REPONSES[header[ID_CODE]]).new(header, body)
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.constantize(camel_cased_word)
|
133
|
+
names = camel_cased_word.split('::')
|
134
|
+
names.shift if names.empty? || names.first.empty?
|
135
|
+
|
136
|
+
constant = Object
|
137
|
+
names.each do |name|
|
138
|
+
constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
|
139
|
+
end
|
140
|
+
constant
|
141
|
+
end
|
142
|
+
|
143
|
+
def empty?
|
144
|
+
@header[DLEN_LSB] == 1
|
145
|
+
end
|
146
|
+
|
147
|
+
def success?
|
148
|
+
AsyncResponse.valid?(@header)
|
149
|
+
end
|
150
|
+
|
151
|
+
def seq
|
152
|
+
1
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
class PowerNotification < GetPowerState
|
157
|
+
end
|
158
|
+
|
159
|
+
class SensorData < AsyncResponse
|
160
|
+
def body
|
161
|
+
@body.unpack 's*'
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
class CollisionDetected < AsyncResponse
|
166
|
+
def body
|
167
|
+
@body.unpack 'nnnCnnCN'
|
168
|
+
end
|
169
|
+
|
170
|
+
def x
|
171
|
+
body[0]
|
172
|
+
end
|
173
|
+
|
174
|
+
def y
|
175
|
+
body[1]
|
176
|
+
end
|
177
|
+
|
178
|
+
def z
|
179
|
+
body[2]
|
180
|
+
end
|
181
|
+
|
182
|
+
def axis
|
183
|
+
body[3]
|
184
|
+
end
|
185
|
+
|
186
|
+
def x_magnitude
|
187
|
+
body[4]
|
188
|
+
end
|
189
|
+
|
190
|
+
def y_magnitude
|
191
|
+
body[5]
|
192
|
+
end
|
193
|
+
|
194
|
+
def speed
|
195
|
+
body[6]
|
196
|
+
end
|
197
|
+
|
198
|
+
def timestamp
|
199
|
+
body[7]
|
200
|
+
end
|
201
|
+
end
|
87
202
|
end
|
88
203
|
end
|
data/test/test_sphero.rb
CHANGED
@@ -1,14 +1,105 @@
|
|
1
1
|
require 'minitest/autorun'
|
2
2
|
require 'sphero'
|
3
|
+
require 'mocha/setup'
|
3
4
|
|
4
5
|
class TestSphero < MiniTest::Unit::TestCase
|
5
|
-
def
|
6
|
-
|
7
|
-
|
6
|
+
def setup
|
7
|
+
Sphero.any_instance.stubs(:initialize_serialport)
|
8
|
+
Sphero.any_instance.stubs(:initialize_socket)
|
9
|
+
@sphero = Sphero.new 'port123'
|
10
|
+
@seq = 0x00
|
8
11
|
end
|
9
12
|
|
10
|
-
def
|
11
|
-
|
12
|
-
|
13
|
+
def test_start_returns_new_sphero
|
14
|
+
assert_kind_of Sphero, Sphero.start('someport')
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_start_sphero_executes_block
|
18
|
+
Sphero.any_instance.expects(:ping)
|
19
|
+
Sphero.any_instance.expects(:close)
|
20
|
+
Sphero.start('someport') do
|
21
|
+
ping
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_ping
|
26
|
+
Sphero::Request::Ping.expects(:new).with(@seq)
|
27
|
+
@sphero.expects(:write)
|
28
|
+
@sphero.ping
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_version
|
32
|
+
Sphero::Request::GetVersioning.expects(:new).with(@seq)
|
33
|
+
@sphero.expects(:write)
|
34
|
+
@sphero.version
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_bluetooth_info
|
38
|
+
Sphero::Request::GetBluetoothInfo.expects(:new).with(@seq)
|
39
|
+
@sphero.expects(:write)
|
40
|
+
@sphero.bluetooth_info
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_auto_reconnect=
|
44
|
+
@time_s = "10"
|
45
|
+
Sphero::Request::SetAutoReconnect.expects(:new).with(@seq, @time_s)
|
46
|
+
@sphero.expects(:write)
|
47
|
+
@sphero.auto_reconnect = @time_s
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_auto_reconnect
|
51
|
+
@time_s = "10"
|
52
|
+
packet = mock 'packet'
|
53
|
+
packet.stubs(:time).returns(@time_s)
|
54
|
+
|
55
|
+
Sphero::Request::GetAutoReconnect.expects(:new).with(@seq)
|
56
|
+
@sphero.expects(:write).returns(packet)
|
57
|
+
assert_equal @sphero.auto_reconnect, @time_s
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_disable_auto_reconnect
|
61
|
+
Sphero::Request::SetAutoReconnect.expects(:new).with(@seq, 0, 0x00)
|
62
|
+
@sphero.expects(:write)
|
63
|
+
@sphero.disable_auto_reconnect
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_power_state
|
67
|
+
Sphero::Request::GetPowerState.expects(:new).with(@seq)
|
68
|
+
@sphero.expects(:write)
|
69
|
+
@sphero.power_state
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_sphero_sleep
|
73
|
+
wakeup = 1
|
74
|
+
macro = 2
|
75
|
+
Sphero::Request::Sleep.expects(:new).with(@seq, wakeup, macro)
|
76
|
+
@sphero.expects(:write)
|
77
|
+
@sphero.sphero_sleep wakeup, macro
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_roll
|
81
|
+
speed = 1
|
82
|
+
heading = 2
|
83
|
+
state = 1
|
84
|
+
Sphero::Request::Roll.expects(:new).with(@seq, speed, heading, state)
|
85
|
+
@sphero.expects(:write)
|
86
|
+
@sphero.roll speed, heading, true
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_stop
|
90
|
+
@sphero.expects(:roll).with(0, 0)
|
91
|
+
@sphero.stop
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_keepgoing
|
95
|
+
Kernel.expects(:sleep).with(3)
|
96
|
+
@sphero.keep_going 3
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_directions
|
100
|
+
assert_equal 0, Sphero::FORWARD
|
101
|
+
assert_equal 90, Sphero::RIGHT
|
102
|
+
assert_equal 180, Sphero::BACKWARD
|
103
|
+
assert_equal 270, Sphero::LEFT
|
13
104
|
end
|
14
105
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'sphero'
|
3
|
+
|
4
|
+
class TestSpheroRequest < MiniTest::Unit::TestCase
|
5
|
+
def test_ping_checksum
|
6
|
+
ping = Sphero::Request::Ping.new 0
|
7
|
+
expected_bytes = "\xFF\xFF\x00\x01\x00\x01\xFD".force_encoding(Encoding::ASCII_8BIT)
|
8
|
+
assert_equal expected_bytes, ping.to_str
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_sleep_dlen
|
12
|
+
sleep = Sphero::Request::Sleep.new 0, 0, 0
|
13
|
+
assert_equal 0x04, sleep.dlen
|
14
|
+
end
|
15
|
+
end
|
metadata
CHANGED
@@ -1,48 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sphero
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
|
-
-
|
8
|
+
- Hybrid Group
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-07-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
-
- !ruby/object:Gem::Dependency
|
15
|
-
name: serialport
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
|
-
requirements:
|
19
|
-
- - ! '>='
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: '0'
|
22
|
-
type: :runtime
|
23
|
-
prerelease: false
|
24
|
-
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
|
-
requirements:
|
27
|
-
- - ! '>='
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '0'
|
30
|
-
- !ruby/object:Gem::Dependency
|
31
|
-
name: minitest
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
|
-
requirements:
|
35
|
-
- - ~>
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
version: '3.2'
|
38
|
-
type: :development
|
39
|
-
prerelease: false
|
40
|
-
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
|
-
requirements:
|
43
|
-
- - ~>
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
version: '3.2'
|
46
14
|
- !ruby/object:Gem::Dependency
|
47
15
|
name: rdoc
|
48
16
|
requirement: !ruby/object:Gem::Requirement
|
@@ -50,7 +18,7 @@ dependencies:
|
|
50
18
|
requirements:
|
51
19
|
- - ~>
|
52
20
|
- !ruby/object:Gem::Version
|
53
|
-
version: '
|
21
|
+
version: '4.0'
|
54
22
|
type: :development
|
55
23
|
prerelease: false
|
56
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -58,7 +26,7 @@ dependencies:
|
|
58
26
|
requirements:
|
59
27
|
- - ~>
|
60
28
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
29
|
+
version: '4.0'
|
62
30
|
- !ruby/object:Gem::Dependency
|
63
31
|
name: hoe
|
64
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,7 +34,7 @@ dependencies:
|
|
66
34
|
requirements:
|
67
35
|
- - ~>
|
68
36
|
- !ruby/object:Gem::Version
|
69
|
-
version: '3.
|
37
|
+
version: '3.6'
|
70
38
|
type: :development
|
71
39
|
prerelease: false
|
72
40
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -74,13 +42,13 @@ dependencies:
|
|
74
42
|
requirements:
|
75
43
|
- - ~>
|
76
44
|
- !ruby/object:Gem::Version
|
77
|
-
version: '3.
|
45
|
+
version: '3.6'
|
78
46
|
description: ! 'A ruby gem for controlling your Sphero ball. Sends commands over
|
79
47
|
the TTY
|
80
48
|
|
81
49
|
provided by the bluetooth connection.'
|
82
50
|
email:
|
83
|
-
-
|
51
|
+
- sphero@hybridgroup.com
|
84
52
|
executables:
|
85
53
|
- sphero
|
86
54
|
extensions: []
|
@@ -99,8 +67,9 @@ files:
|
|
99
67
|
- lib/sphero/request.rb
|
100
68
|
- lib/sphero/response.rb
|
101
69
|
- test/test_sphero.rb
|
70
|
+
- test/test_sphero_request.rb
|
102
71
|
- .gemtest
|
103
|
-
homepage: http://github.com/
|
72
|
+
homepage: http://github.com/hybridgroup/sphero
|
104
73
|
licenses: []
|
105
74
|
post_install_message:
|
106
75
|
rdoc_options:
|
@@ -113,7 +82,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
113
82
|
requirements:
|
114
83
|
- - ! '>='
|
115
84
|
- !ruby/object:Gem::Version
|
116
|
-
version: 1.9.
|
85
|
+
version: 1.9.2
|
117
86
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
87
|
none: false
|
119
88
|
requirements:
|
@@ -122,9 +91,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
91
|
version: '0'
|
123
92
|
requirements: []
|
124
93
|
rubyforge_project: sphero
|
125
|
-
rubygems_version: 1.8.
|
94
|
+
rubygems_version: 1.8.24
|
126
95
|
signing_key:
|
127
96
|
specification_version: 3
|
128
97
|
summary: A ruby gem for controlling your Sphero ball
|
129
98
|
test_files:
|
130
99
|
- test/test_sphero.rb
|
100
|
+
- test/test_sphero_request.rb
|