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