sphero_pwn 0.0.0 → 0.0.1
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.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/bin/sphero_diagnostics.rb +71 -0
- data/bin/sphero_map_flash.rb +82 -0
- data/bin/sphero_save_flash_block.rb +47 -0
- data/bin/sphero_set_flag.rb +38 -0
- data/bin/sphero_soft_reboot.rb +33 -0
- data/bin/sphero_toggle_user_hack.rb +36 -0
- data/lib/sphero_pwn.rb +24 -14
- data/lib/sphero_pwn/asyncs/flash_block.rb +26 -0
- data/lib/sphero_pwn/channel.rb +72 -29
- data/lib/sphero_pwn/commands/boot_main_app.rb +17 -0
- data/lib/sphero_pwn/commands/enter_bootloader.rb +15 -0
- data/lib/sphero_pwn/commands/get_device_mode.rb +35 -0
- data/lib/sphero_pwn/commands/get_flash_block.rb +34 -0
- data/lib/sphero_pwn/commands/get_permanent_flags.rb +44 -0
- data/lib/sphero_pwn/commands/get_versions.rb +12 -10
- data/lib/sphero_pwn/commands/is_page_blank.rb +36 -0
- data/lib/sphero_pwn/commands/l1_diagnostics.rb +0 -1
- data/lib/sphero_pwn/commands/l2_diagnostics.rb +50 -0
- data/lib/sphero_pwn/commands/set_device_mode.rb +25 -0
- data/lib/sphero_pwn/commands/set_permanent_flags.rb +29 -0
- data/lib/sphero_pwn/session.rb +12 -4
- data/sphero_pwn.gemspec +130 -0
- data/test/command_test.rb +10 -0
- data/test/commands/boot_main_app_test.rb +11 -0
- data/test/commands/enter_bootloader_test.rb +33 -0
- data/test/commands/get_device_mode_test.rb +40 -0
- data/test/commands/get_flash_block_test.rb +101 -0
- data/test/commands/get_permanent_flags_test.rb +48 -0
- data/test/commands/get_versions_test.rb +10 -1
- data/test/commands/is_page_blank_test.rb +65 -0
- data/test/commands/l2_diagnostics_test.rb +58 -0
- data/test/commands/set_device_mode_test.rb +56 -0
- data/test/commands/set_permanent_flags_test.rb +55 -0
- data/test/data/enter_bootloader.txt +4 -0
- data/test/data/get_device_mode.txt +2 -0
- data/test/data/get_factory_config.txt +2 -0
- data/test/data/get_permanent_flags.txt +2 -0
- data/test/data/get_soul.txt +2 -0
- data/test/data/get_version.txt +2 -2
- data/test/data/is_page_blank.txt +6 -0
- data/test/data/l2_diagnostics.txt +8 -0
- data/test/data/ping.txt +2 -2
- data/test/data/set_device_mode.txt +12 -0
- data/test/data/set_permanent_flags.txt +8 -0
- metadata +44 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9eac1b907fc6e5963161d6572b72c2d8f2ff241d
|
4
|
+
data.tar.gz: ae48c0c7bb5ca8a3c851bbaf512a7612e5caee5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 33bf8e533323091af250cccdeefbec7abb09ad2d71901ce9c7c61cc2aa4d35eb64b66cde688c28c8a088c7d2624f219e6eac4f89728ecf4da41dcd73c0faa421
|
7
|
+
data.tar.gz: f6357fc7cda85e4c77d25787827e99251f4304f3f9e34cc5b6f7dcfa45746545b037c2b07d01284311123d255b3b89982b42242f26c1bad5d5f5bd254c81cf74
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.1
|
@@ -0,0 +1,71 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative '../lib/sphero_pwn.rb'
|
4
|
+
|
5
|
+
require 'pp'
|
6
|
+
|
7
|
+
unless ARGV.length == 1
|
8
|
+
puts <<END_USAGE
|
9
|
+
Usage: #{$PROGRAM_NAME} /dev/bluetooth-device
|
10
|
+
|
11
|
+
The block name can be soul|factory_config|user_config.
|
12
|
+
END_USAGE
|
13
|
+
exit 1
|
14
|
+
end
|
15
|
+
|
16
|
+
rfconn_path = ARGV[0]
|
17
|
+
channel = SpheroPwn::Channel.new rfconn_path
|
18
|
+
session = SpheroPwn::Session.new channel
|
19
|
+
|
20
|
+
session.send_command SpheroPwn::Commands::L1Diagnostics.new
|
21
|
+
response = nil
|
22
|
+
async = nil
|
23
|
+
while response.nil? || async.nil?
|
24
|
+
message = session.recv_message
|
25
|
+
if message.nil?
|
26
|
+
sleep 0.05
|
27
|
+
next
|
28
|
+
end
|
29
|
+
|
30
|
+
if message.kind_of? SpheroPwn::Response
|
31
|
+
response = message
|
32
|
+
if response.code == :ok
|
33
|
+
puts "Queued command to L1 diagnostics.\n"
|
34
|
+
else
|
35
|
+
puts "Failed to get L1 diagnostics. Code: #{response.code}\n"
|
36
|
+
exit 1
|
37
|
+
end
|
38
|
+
else
|
39
|
+
async = message
|
40
|
+
puts "L1 diagnostics:\n"
|
41
|
+
puts message.text
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
session.send_command SpheroPwn::Commands::L2Diagnostics.new
|
46
|
+
response = nil
|
47
|
+
async = nil
|
48
|
+
while response.nil? || async.nil?
|
49
|
+
message = session.recv_message
|
50
|
+
if message.nil?
|
51
|
+
sleep 0.05
|
52
|
+
next
|
53
|
+
end
|
54
|
+
|
55
|
+
if message.kind_of? SpheroPwn::Response
|
56
|
+
response = message
|
57
|
+
if response.code == :ok
|
58
|
+
puts "Queued command to L2 diagnostics.\n"
|
59
|
+
else
|
60
|
+
puts "Failed to get L2 diagnostics. Code: #{response.code}\n"
|
61
|
+
exit 1
|
62
|
+
end
|
63
|
+
else
|
64
|
+
async = message
|
65
|
+
puts "L2 diagnostics:\n"
|
66
|
+
pp message.counters
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
session.close
|
71
|
+
exit 0
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative '../lib/sphero_pwn.rb'
|
4
|
+
|
5
|
+
unless ARGV.length == 1
|
6
|
+
puts <<END_USAGE
|
7
|
+
Usage: #{$PROGRAM_NAME} /dev/bluetooth-device
|
8
|
+
END_USAGE
|
9
|
+
exit 1
|
10
|
+
end
|
11
|
+
|
12
|
+
rfconn_path = ARGV[0]
|
13
|
+
channel = SpheroPwn::Channel.new rfconn_path
|
14
|
+
session = SpheroPwn::Session.new channel
|
15
|
+
|
16
|
+
session.send_command SpheroPwn::Commands::EnterBootloader.new
|
17
|
+
response = session.recv_until_response
|
18
|
+
unless response.code == :ok
|
19
|
+
puts "Failed to enter bootloader. Code: #{response.code}\n"
|
20
|
+
exit 1
|
21
|
+
end
|
22
|
+
|
23
|
+
page_map = []
|
24
|
+
first_good = 0
|
25
|
+
first_bad = 0
|
26
|
+
|
27
|
+
begin
|
28
|
+
loop do
|
29
|
+
print "Probing page #{first_good}... "
|
30
|
+
session.send_command SpheroPwn::Commands::IsPageBlank.new(first_good)
|
31
|
+
response = session.recv_until_response
|
32
|
+
case response.code
|
33
|
+
when :ok
|
34
|
+
page_map[first_good] = response.is_blank? ? '.' : '*'
|
35
|
+
puts(response.is_blank? ? 'blank' : 'used')
|
36
|
+
break
|
37
|
+
when :bad_page
|
38
|
+
page_map[first_good] = 'X'
|
39
|
+
puts 'bad'
|
40
|
+
first_good += 1
|
41
|
+
next
|
42
|
+
else
|
43
|
+
puts "Failed to get page status. Code: #{response.code}\n"
|
44
|
+
exit 1
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
first_bad = first_good + 1
|
49
|
+
loop do
|
50
|
+
print "Probing page #{first_bad}... "
|
51
|
+
session.send_command SpheroPwn::Commands::IsPageBlank.new(first_bad)
|
52
|
+
response = session.recv_until_response
|
53
|
+
case response.code
|
54
|
+
when :ok
|
55
|
+
page_map[first_bad] = response.is_blank? ? '.' : '*'
|
56
|
+
puts(response.is_blank? ? 'blank' : 'used')
|
57
|
+
first_bad += 1
|
58
|
+
next
|
59
|
+
when :bad_page
|
60
|
+
page_map[first_bad] = 'X'
|
61
|
+
puts 'bad'
|
62
|
+
break
|
63
|
+
else
|
64
|
+
puts "Failed to get page status. Code: #{response.code}\n"
|
65
|
+
exit 1
|
66
|
+
end
|
67
|
+
end
|
68
|
+
ensure
|
69
|
+
puts "First valid page: #{first_good}\n"
|
70
|
+
puts "Last valid page: #{first_bad - 1}\n"
|
71
|
+
puts "Page map:\n#{page_map.join('')}\n"
|
72
|
+
|
73
|
+
session.send_command SpheroPwn::Commands::BootMainApp.new
|
74
|
+
response = session.recv_until_response
|
75
|
+
unless response.code == :ok
|
76
|
+
puts "Failed to boot main application. Code: #{response.code}\n"
|
77
|
+
exit 1
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
session.close
|
82
|
+
exit 0
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative '../lib/sphero_pwn.rb'
|
4
|
+
|
5
|
+
unless ARGV.length == 3
|
6
|
+
puts <<END_USAGE
|
7
|
+
Usage: #{$PROGRAM_NAME} /dev/bluetooth-device block_name flash_file.bin
|
8
|
+
|
9
|
+
The block name can be soul|factory_config|user_config.
|
10
|
+
END_USAGE
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
|
14
|
+
rfconn_path = ARGV[0]
|
15
|
+
channel = SpheroPwn::Channel.new rfconn_path
|
16
|
+
session = SpheroPwn::Session.new channel
|
17
|
+
|
18
|
+
session.send_command SpheroPwn::Commands::GetFlashBlock.new ARGV[1].to_sym
|
19
|
+
|
20
|
+
response = nil
|
21
|
+
async = nil
|
22
|
+
while response.nil? || async.nil?
|
23
|
+
message = session.recv_message
|
24
|
+
if message.nil?
|
25
|
+
sleep 0.05
|
26
|
+
next
|
27
|
+
end
|
28
|
+
|
29
|
+
if message.kind_of? SpheroPwn::Response
|
30
|
+
response = message
|
31
|
+
if response.code == :ok
|
32
|
+
puts "Queued command to get #{ARGV[1]} block.\n"
|
33
|
+
else
|
34
|
+
puts "Failed to get #{ARGV[1]} block. Code: #{response.code}\n"
|
35
|
+
exit 1
|
36
|
+
end
|
37
|
+
else
|
38
|
+
async = message
|
39
|
+
File.open ARGV[2], 'wb' do |f|
|
40
|
+
f.write async.data_bytes.pack('C*')
|
41
|
+
end
|
42
|
+
puts "Wrote #{ARGV[1]} block to #{ARGV[2]}\n"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
session.close
|
47
|
+
exit 0
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative '../lib/sphero_pwn.rb'
|
4
|
+
|
5
|
+
unless ARGV.length == 3
|
6
|
+
puts <<END_USAGE
|
7
|
+
Usage: #{$PROGRAM_NAME} /dev/bluetooth-device flag_name {true|false}
|
8
|
+
|
9
|
+
Known flags: #{SpheroPwn::Commands::SetPermanentFlags::FLAGS.keys.join(' ')}
|
10
|
+
END_USAGE
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
|
14
|
+
rfconn_path = ARGV[0]
|
15
|
+
channel = SpheroPwn::Channel.new rfconn_path
|
16
|
+
session = SpheroPwn::Session.new channel
|
17
|
+
|
18
|
+
session.send_command SpheroPwn::Commands::GetPermanentFlags.new
|
19
|
+
response = session.recv_until_response
|
20
|
+
unless response.code == :ok
|
21
|
+
puts "Failed to retrieve current flags. Code: #{response.code}\n"
|
22
|
+
exit 1
|
23
|
+
end
|
24
|
+
puts "Current flags: #{response.flags.inspect}\n"
|
25
|
+
|
26
|
+
new_flags = response.flags.merge({ ARGV[1].to_sym => (ARGV[2] == 'true') })
|
27
|
+
puts "New flags: #{new_flags}\n"
|
28
|
+
|
29
|
+
session.send_command SpheroPwn::Commands::SetPermanentFlags.new(new_flags)
|
30
|
+
response = session.recv_until_response
|
31
|
+
unless response.code == :ok
|
32
|
+
puts "Failed to set new flags. Code: #{response.code}\n"
|
33
|
+
exit 1
|
34
|
+
end
|
35
|
+
|
36
|
+
puts "New flags set successfully\n"
|
37
|
+
session.close
|
38
|
+
exit 0
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative '../lib/sphero_pwn.rb'
|
4
|
+
|
5
|
+
unless ARGV.length == 1
|
6
|
+
puts <<END_USAGE
|
7
|
+
Usage: #{$PROGRAM_NAME} /dev/bluetooth-device
|
8
|
+
END_USAGE
|
9
|
+
exit 1
|
10
|
+
end
|
11
|
+
|
12
|
+
rfconn_path = ARGV[0]
|
13
|
+
channel = SpheroPwn::Channel.new rfconn_path
|
14
|
+
session = SpheroPwn::Session.new channel
|
15
|
+
|
16
|
+
session.send_command SpheroPwn::Commands::EnterBootloader.new
|
17
|
+
response = session.recv_until_response
|
18
|
+
unless response.code == :ok
|
19
|
+
puts "Failed to enter bootloader. Code: #{response.code}\n"
|
20
|
+
exit 1
|
21
|
+
end
|
22
|
+
puts "Entered bootloader\n"
|
23
|
+
|
24
|
+
session.send_command SpheroPwn::Commands::BootMainApp.new
|
25
|
+
response = session.recv_until_response
|
26
|
+
unless response.code == :ok
|
27
|
+
puts "Failed to boot main application. Code: #{response.code}\n"
|
28
|
+
exit 1
|
29
|
+
end
|
30
|
+
puts "Entered main app\n"
|
31
|
+
|
32
|
+
session.close
|
33
|
+
exit 0
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative '../lib/sphero_pwn.rb'
|
4
|
+
|
5
|
+
unless ARGV.length == 1
|
6
|
+
puts <<END_USAGE
|
7
|
+
Usage: #{$PROGRAM_NAME} /dev/bluetooth-device
|
8
|
+
END_USAGE
|
9
|
+
exit 1
|
10
|
+
end
|
11
|
+
|
12
|
+
rfconn_path = ARGV[0]
|
13
|
+
channel = SpheroPwn::Channel.new rfconn_path
|
14
|
+
session = SpheroPwn::Session.new channel
|
15
|
+
|
16
|
+
session.send_command SpheroPwn::Commands::GetDeviceMode.new
|
17
|
+
response = session.recv_until_response
|
18
|
+
unless response.code == :ok
|
19
|
+
puts "Failed to retrieve device mode. Code: #{response.code}\n"
|
20
|
+
exit 1
|
21
|
+
end
|
22
|
+
puts "Current device mode: #{response.mode}\n"
|
23
|
+
|
24
|
+
new_mode = (response.mode == :normal) ? :user_hack : :normal
|
25
|
+
puts "Switching device to mode: #{new_mode}\n"
|
26
|
+
|
27
|
+
session.send_command SpheroPwn::Commands::SetDeviceMode.new(new_mode)
|
28
|
+
response = session.recv_until_response
|
29
|
+
unless response.code == :ok
|
30
|
+
puts "Failed to set device mode. Code: #{response.code}\n"
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
|
34
|
+
puts "New mode set successfully\n"
|
35
|
+
session.close
|
36
|
+
exit 0
|
data/lib/sphero_pwn.rb
CHANGED
@@ -2,19 +2,29 @@
|
|
2
2
|
module SpheroPwn
|
3
3
|
end
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
require_relative './sphero_pwn/async.rb'
|
6
|
+
require_relative './sphero_pwn/asyncs.rb'
|
7
|
+
require_relative './sphero_pwn/channel.rb'
|
8
|
+
require_relative './sphero_pwn/channel_recorder.rb'
|
9
|
+
require_relative './sphero_pwn/command.rb'
|
10
|
+
require_relative './sphero_pwn/commands.rb'
|
11
|
+
require_relative './sphero_pwn/replay_channel.rb'
|
12
|
+
require_relative './sphero_pwn/response.rb'
|
13
|
+
require_relative './sphero_pwn/session.rb'
|
14
|
+
require_relative './sphero_pwn/test_channel.rb'
|
15
15
|
|
16
|
-
|
16
|
+
require_relative './sphero_pwn/asyncs/flash_block.rb'
|
17
|
+
require_relative './sphero_pwn/asyncs/l1_diagnostics.rb'
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
19
|
+
require_relative './sphero_pwn/commands/boot_main_app.rb'
|
20
|
+
require_relative './sphero_pwn/commands/enter_bootloader.rb'
|
21
|
+
require_relative './sphero_pwn/commands/get_device_mode.rb'
|
22
|
+
require_relative './sphero_pwn/commands/get_flash_block.rb'
|
23
|
+
require_relative './sphero_pwn/commands/get_permanent_flags.rb'
|
24
|
+
require_relative './sphero_pwn/commands/get_versions.rb'
|
25
|
+
require_relative './sphero_pwn/commands/is_page_blank.rb'
|
26
|
+
require_relative './sphero_pwn/commands/l1_diagnostics.rb'
|
27
|
+
require_relative './sphero_pwn/commands/l2_diagnostics.rb'
|
28
|
+
require_relative './sphero_pwn/commands/ping.rb'
|
29
|
+
require_relative './sphero_pwn/commands/set_device_mode.rb'
|
30
|
+
require_relative './sphero_pwn/commands/set_permanent_flags.rb'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# The result of a get flash block request.
|
2
|
+
#
|
3
|
+
# This is an asynchronous message because it's too long to fit into the command
|
4
|
+
# response structure.
|
5
|
+
class SpheroPwn::Asyncs::FlashBlock < SpheroPwn::Async
|
6
|
+
# @return {String} the text form of the diagnostics
|
7
|
+
attr_reader :text
|
8
|
+
|
9
|
+
def initialize(data_bytes)
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class SpheroPwn::Asyncs::FlashBlock::Config < SpheroPwn::Asyncs::FlashBlock
|
15
|
+
def self.id_code
|
16
|
+
0x04
|
17
|
+
end
|
18
|
+
end
|
19
|
+
SpheroPwn::Asyncs.register SpheroPwn::Asyncs::FlashBlock::Config
|
20
|
+
|
21
|
+
class SpheroPwn::Asyncs::FlashBlock::Soul < SpheroPwn::Asyncs::FlashBlock
|
22
|
+
def self.id_code
|
23
|
+
0x0D
|
24
|
+
end
|
25
|
+
end
|
26
|
+
SpheroPwn::Asyncs.register SpheroPwn::Asyncs::FlashBlock::Soul
|
data/lib/sphero_pwn/channel.rb
CHANGED
@@ -10,29 +10,17 @@ class SpheroPwn::Channel
|
|
10
10
|
#
|
11
11
|
# @param {String} rfconn_path the path to the device file connecting to the
|
12
12
|
# robot's Bluetooth RFCONN service
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
raise e unless e.message == 'EBUSY'
|
21
|
-
raise e if Time.now >= give_up_at
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
13
|
+
# @param {Hash} options the options below
|
14
|
+
# @option {Number} connect_timeout retry for this number of seconds when the
|
15
|
+
# connection gets refused with EBUSY
|
16
|
+
def initialize(rfconn_path, options = {})
|
17
|
+
@connect_timeout = options[:connect_timeout] || 15
|
18
|
+
@read_timeout = options[:read_timeout] || 30
|
19
|
+
@read_backoff = options[:read_backoff] || 0.2
|
25
20
|
@send_queue = Queue.new
|
26
|
-
@send_thread = Thread.new @send_queue do
|
27
|
-
send_queue = @send_queue
|
28
21
|
|
29
|
-
|
30
|
-
|
31
|
-
break if bytes == :close
|
32
|
-
|
33
|
-
@port.write bytes
|
34
|
-
end
|
35
|
-
end
|
22
|
+
@port = connect rfconn_path, @connect_timeout
|
23
|
+
@send_thread = spawn_sending_thread @send_queue, @port
|
36
24
|
end
|
37
25
|
|
38
26
|
# @param {String} bytes a binary-encoded string of bytes to be sent to the
|
@@ -43,15 +31,27 @@ class SpheroPwn::Channel
|
|
43
31
|
self
|
44
32
|
end
|
45
33
|
|
46
|
-
# @param {Integer}
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
34
|
+
# @param {Integer} byte_count the number of bytes to be read from the RFCONN
|
35
|
+
# port
|
36
|
+
# @return {String} a binary-encoded string of bytes retrieved from the RFCONN
|
37
|
+
# port; the string may have fewer bytes than requested
|
38
|
+
def recv_bytes(byte_count)
|
39
|
+
buffer = ''.encode Encoding::BINARY
|
40
|
+
|
41
|
+
last_byte_at = Time.now
|
42
|
+
loop do
|
43
|
+
new_bytes = @port.read byte_count - buffer.length
|
44
|
+
buffer.concat new_bytes
|
45
|
+
break if buffer.length == byte_count
|
46
|
+
|
47
|
+
if new_bytes.empty?
|
48
|
+
break if Time.now - last_byte_at >= @read_timeout
|
49
|
+
sleep @read_backoff
|
50
|
+
else
|
51
|
+
last_byte_at = Time.now
|
52
|
+
end
|
53
53
|
end
|
54
|
-
|
54
|
+
buffer
|
55
55
|
end
|
56
56
|
|
57
57
|
# Gracefully shuts down the communication channel with the robot.
|
@@ -62,4 +62,47 @@ class SpheroPwn::Channel
|
|
62
62
|
@port.close
|
63
63
|
self
|
64
64
|
end
|
65
|
+
|
66
|
+
# Connects to an RFCONN serial port.
|
67
|
+
#
|
68
|
+
# @param {String} rfconn_path the path to the device file connecting to the
|
69
|
+
# robot's Bluetooth RFCONN service
|
70
|
+
# @param {Number} timeout the number of seconds to retry connecting when
|
71
|
+
# getting EBUSY
|
72
|
+
# @return {Serial} the connected port
|
73
|
+
def connect(rfconn_path, timeout)
|
74
|
+
give_up_at = Time.now + timeout
|
75
|
+
port = nil
|
76
|
+
while port.nil?
|
77
|
+
begin
|
78
|
+
port = Serial.new rfconn_path, 115200, 8
|
79
|
+
rescue RubySerial::Exception => e
|
80
|
+
raise e unless e.message == 'EBUSY'
|
81
|
+
raise e if Time.now >= give_up_at
|
82
|
+
end
|
83
|
+
end
|
84
|
+
port
|
85
|
+
end
|
86
|
+
private :connect
|
87
|
+
|
88
|
+
# Creates a thread that reads data from a queue and writes it to an IO.
|
89
|
+
#
|
90
|
+
# The thread expects to pop String instances from the queue, and will
|
91
|
+
# write them to the IO. When the thread pops the :close symbol, it stops
|
92
|
+
# executing.
|
93
|
+
#
|
94
|
+
# @param {Queue} send_queue the queue that the tread will read data from
|
95
|
+
# @param {IO} io the IO that the data bytes will be written to
|
96
|
+
# @return {Thread} the newly created thread
|
97
|
+
def spawn_sending_thread(send_queue, io)
|
98
|
+
Thread.new do
|
99
|
+
loop do
|
100
|
+
bytes = send_queue.pop
|
101
|
+
break if bytes == :close
|
102
|
+
|
103
|
+
io.write bytes
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
private :spawn_sending_thread
|
65
108
|
end
|