lib/sphero.rb in sphero-1.4.1 vs lib/sphero.rb in sphero-1.5.0
- old
+ new
@@ -1,20 +1,20 @@
require 'sphero/request'
require 'sphero/response'
require 'thread'
class Sphero
- VERSION = '1.4.1'
+ VERSION = '1.5.0'
FORWARD = 0
RIGHT = 90
BACKWARD = 180
LEFT = 270
DEFAULT_RETRIES = 3
- attr_accessor :connection_types, :messages
+ attr_accessor :connection_types, :messages, :packets, :response_queue, :responses
class << self
def start(dev, &block)
retries_left = DEFAULT_RETRIES
begin
@@ -45,89 +45,116 @@
@dev = 0x00
@seq = 0x00
@lock = Mutex.new
@messages = Queue.new
+ @packets = Queue.new
+ @response_queue = Queue.new
+ @responses = []
+ Thread.new {
+ loop do
+ write @packets.pop
+ end
+ }
+ Thread.new {
+ loop do
+ @responses << @response_queue.pop
+ end
+ }
end
def close
+ return if @sp.nil? || @sp.closed?
begin
stop
rescue Exception => e
puts e.message
ensure
@sp.close
end
end
def ping
- write Request::Ping.new(@seq)
+ packet = Request::Ping.new(@seq)
+ queue_packet packet
+ return sync_response packet.seq
end
def version
- write Request::GetVersioning.new(@seq)
+ packet = Request::GetVersioning.new(@seq)
+ queue_packet packet
+ return sync_response packet.seq
end
def bluetooth_info
- write Request::GetBluetoothInfo.new(@seq)
+ packet = Request::GetBluetoothInfo.new(@seq)
+ queue_packet packet
+ return sync_response packet.seq
end
+ # This retrieves the "user LED color" which is stored in the config block
+ # (which may or may not be actively driven to the RGB LED).
+ def user_led
+ packet = Request::GetRGB.new(@seq)
+ queue_packet packet
+ return sync_response packet.seq
+ end
+
def auto_reconnect= time_s
- write Request::SetAutoReconnect.new(@seq, time_s)
+ queue_packet Request::SetAutoReconnect.new(@seq, limit1(time_s) )
end
def auto_reconnect
- write(Request::GetAutoReconnect.new(@seq)).time
+ queue_packet(Request::GetAutoReconnect.new(@seq)).time
end
def disable_auto_reconnect
- write Request::SetAutoReconnect.new(@seq, 0, 0x00)
+ queue_packet Request::SetAutoReconnect.new(@seq, 0, flag(false) )
end
def power_state
- write Request::GetPowerState.new(@seq)
+ queue_packet Request::GetPowerState.new(@seq)
end
def sphero_sleep wakeup = 0, macro = 0
- write Request::Sleep.new(@seq, wakeup, macro)
+ queue_packet Request::Sleep.new(@seq, limit2(wakeup), limit1(macro) )
end
def roll speed, heading, state = true
- write Request::Roll.new(@seq, speed, heading, state ? 0x01 : 0x00)
+ queue_packet Request::Roll.new(@seq, limit1(speed), degrees(heading), flag(state) )
end
def stop
roll 0, 0
end
def heading= h
- write Request::Heading.new(@seq, h)
+ queue_packet Request::Heading.new(@seq, degrees(h) )
end
+ def stabilization= on
+ queue_packet Request::Stabilization.new(@seq, on)
+ end
+
def color colorname, persistant = false
color = COLORS[colorname]
rgb color[:r], color[:g], color[:b], persistant
end
def rgb r, g, b, persistant = false
- write Request::SetRGB.new(@seq, r, g, b, persistant ? 0x01 : 0x00)
+ queue_packet Request::SetRGB.new(@seq, limit1(r), limit1(g), limit1(b), flag(persistant) )
end
- # This retrieves the "user LED color" which is stored in the config block
- # (which may or may not be actively driven to the RGB LED).
- def user_led
- write Request::GetRGB.new(@seq)
- end
# Brightness 0x00 - 0xFF
def back_led_output= h
- write Request::SetBackLEDOutput.new(@seq, h)
+ queue_packet Request::SetBackLEDOutput.new(@seq, limit1(h) )
end
# Rotation Rate 0x00 - 0xFF
def rotation_rate= h
- write Request::SetRotationRate.new(@seq, h)
+ queue_packet Request::SetRotationRate.new(@seq, limit1(h))
end
# just a nicer alias for Ruby's own sleep
def keep_going(duration)
Kernel::sleep duration
@@ -135,25 +162,86 @@
## async messages
# configure power notification messages
def set_power_notification enable=true
- write Request::SetPowerNotification.new(@seq, enable ? 0x01 : 0x00)
+ queue_packet Request::SetPowerNotification.new(@seq, flag(enable) )
end
# configure data streaming notification messages
def set_data_streaming n, m, mask, pcnt, mask2
- write Request::SetDataStreaming.new(@seq, n, m, mask, pcnt, mask2)
+ queue_packet Request::SetDataStreaming.new(@seq, limit2(n), limit2(m),
+ limit4(mask), limit1(pcnt), limit4(mask2) )
end
# configure collision detection messages
def configure_collision_detection meth, x_t, y_t, x_spd, y_spd, dead
- write Request::ConfigureCollisionDetection.new(@seq, meth, x_t, y_t, x_spd, y_spd, dead)
+ queue_packet Request::ConfigureCollisionDetection.new(@seq, limit1(meth),
+ limit1(x_t), limit1(y_t),
+ limit1(x_spd), limit1(y_spd),
+ limit1(dead) )
end
-
+
private
-
+
+ def sync_response seq
+ 100.times do
+ @responses.each do |response|
+ if response.seq == seq
+ @responses.delete(response)
+ return response
+ end
+ end
+ sleep 0.001
+ end
+ return nil
+ end
+
+ def limit(value, max)
+ return nil if value.nil?
+
+ value = value.to_i
+ if value < 0
+ 0
+ elsif value > max
+ max
+ else
+ value
+ end
+ end
+
+ def wrap(value, max)
+ value && (value.to_i % max)
+ end
+
+ def degrees(value)
+ wrap value, 360
+ end
+
+ def limit1(value)
+ limit value, 0xFF
+ end
+
+ def limit2(value)
+ limit value, 0xFFFF
+ end
+
+ def limit4(value)
+ limit value, 0xFFFFFFFF
+ end
+
+ def flag(value)
+ case value
+ when true
+ 0x01
+ when false
+ 0x00
+ else
+ value
+ end
+ end
+
def is_windows?
os = RUBY_PLATFORM.split("-")[1]
if (os == 'mswin' or os == 'bccwin' or os == 'mingw' or os == 'mingw32')
true
else
@@ -171,29 +259,30 @@
end
rescue LoadError
puts "Please 'gem install hybridgroup-serialport' for serial port support."
end
+ def queue_packet packet
+ @packets << packet
+ end
+
def write packet
header, body = nil
- IO.select([], [@sp], [], 20)
-
+ IO.select([], [@sp], [], 1)
@lock.synchronize do
@sp.write packet.to_str
@seq += 1
end
-
- IO.select([@sp], [], [], 20)
+ IO.select([@sp], [], [], 1)
header = read_header(true)
body = read_body(header.last, true) if header
-
# pick off asynch packets and store, till we get to the message response
while header && Response.async?(header)
messages << Response::AsyncResponse.response(header, body)
- IO.select([@sp], [], [], 20)
+ IO.select([@sp], [], [], 1)
header = read_header(true)
if header
body = read_body(header.last, true)
else
body = nil
@@ -201,10 +290,10 @@
end
response = packet.response header, body
if response.success?
- response
+ @response_queue << response
else
raise "Unable to write to Sphero!"
end
end