lib/sphero.rb in sphero-1.0.0 vs lib/sphero.rb in sphero-1.4.1

- old
+ new

@@ -1,19 +1,65 @@ -require 'serialport' require 'sphero/request' require 'sphero/response' require 'thread' class Sphero - VERSION = '1.0.0' + VERSION = '1.4.1' + FORWARD = 0 + RIGHT = 90 + BACKWARD = 180 + LEFT = 270 + + DEFAULT_RETRIES = 3 + + attr_accessor :connection_types, :messages + + class << self + def start(dev, &block) + retries_left = DEFAULT_RETRIES + begin + sphero = self.new dev + if (block_given?) + begin + sphero.instance_eval(&block) + ensure + sphero.close + end + return nil + end + return sphero + rescue Errno::EBUSY + puts retries_left + retries_left = retries_left - 1 + retry unless retries_left < 0 + end + end + end + def initialize dev - @sp = SerialPort.new dev, 115200, 8, 1, SerialPort::NONE + if dev.is_a?(String) + initialize_serialport dev + else + @sp = dev + end + @dev = 0x00 @seq = 0x00 @lock = Mutex.new + @messages = Queue.new end + + def close + begin + stop + rescue Exception => e + puts e.message + ensure + @sp.close + end + end def ping write Request::Ping.new(@seq) end @@ -39,11 +85,11 @@ def power_state write Request::GetPowerState.new(@seq) end - def sleep wakeup = 0, macro = 0 + def sphero_sleep wakeup = 0, macro = 0 write Request::Sleep.new(@seq, wakeup, macro) end def roll speed, heading, state = true write Request::Roll.new(@seq, speed, heading, state ? 0x01 : 0x00) @@ -55,10 +101,15 @@ def heading= h write Request::Heading.new(@seq, h) 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) end # This retrieves the "user LED color" which is stored in the config block @@ -75,59 +126,282 @@ # Rotation Rate 0x00 - 0xFF def rotation_rate= h write Request::SetRotationRate.new(@seq, h) end + # just a nicer alias for Ruby's own sleep + def keep_going(duration) + Kernel::sleep duration + end + + ## async messages + + # configure power notification messages + def set_power_notification enable=true + write Request::SetPowerNotification.new(@seq, enable ? 0x01 : 0x00) + 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) + 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) + end + private + + def is_windows? + os = RUBY_PLATFORM.split("-")[1] + if (os == 'mswin' or os == 'bccwin' or os == 'mingw' or os == 'mingw32') + true + else + false + end + end + def initialize_serialport dev + require 'serialport' + @sp = SerialPort.new dev, 115200, 8, 1, SerialPort::NONE + if is_windows? + @sp.read_timeout=1000 + @sp.write_timeout=0 + @sp.initial_byte_offset=5 + end + rescue LoadError + puts "Please 'gem install hybridgroup-serialport' for serial port support." + end + def write packet - header = nil - body = nil + header, body = nil + IO.select([], [@sp], [], 20) + @lock.synchronize do @sp.write packet.to_str @seq += 1 + end - header = @sp.read(5).unpack 'C5' - body = @sp.read header.last + IO.select([@sp], [], [], 20) + 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) + header = read_header(true) + if header + body = read_body(header.last, true) + else + body = nil + end end response = packet.response header, body if response.success? response else - raise response + raise "Unable to write to Sphero!" end end -end -if $0 == __FILE__ - begin - s = Sphero.new "/dev/tty.Sphero-BRR-RN-SPP" - rescue Errno::EBUSY - retry + def read_header(blocking=false) + header = nil + begin + data = read_next_chunk(5, blocking) + return nil unless data + header = data.unpack 'C5' + rescue Errno::EBUSY + retry + rescue Exception => e + puts e.message + puts e.backtrace.inspect + retry + end + + header end - 10.times { - p s.ping - } + def read_body(len, blocking=false) + data = nil + begin + data = read_next_chunk(len, blocking) + return nil unless data && data.length == len + rescue Errno::EBUSY + retry + rescue Exception => e + puts e.message + puts e.backtrace.inspect + retry + end - trap(:INT) { - s.stop - } + data + end - s.roll 100, 0 - - loop do - [0, 180].each do |dir| - s.heading = dir + def read_next_chunk(len, blocking=false) + data = nil + begin + @lock.synchronize do + if blocking || is_windows? + data = @sp.read(len) + else + data = @sp.read_nonblock(len) + end + end + rescue Errno::EBUSY + retry + rescue Exception => e + puts e.message + puts e.backtrace.inspect + return nil end - end + data + end - #36.times { - # i = 10 - # p :step => i - # s.heading = i - # sleep 0.5 - #} + COLORS = { + 'aliceblue' => {:r => 240, :g => 248, :b => 255}, + 'antiquewhite' => {:r => 250, :g => 235, :b => 215}, + 'aqua' => {:r => 0, :g => 255, :b => 255}, + 'aquamarine' => {:r => 127, :g => 255, :b => 212}, + 'azure' => {:r => 240, :g => 255, :b => 255}, + 'beige' => {:r => 245, :g => 245, :b => 220}, + 'bisque' => {:r => 255, :g => 228, :b => 196}, + 'black' => {:r => 0, :g => 0, :b => 0}, + 'blanchedalmond' => {:r => 255, :g => 235, :b => 205}, + 'blue' => {:r => 0, :g => 0, :b => 255}, + 'blueviolet' => {:r => 138, :g => 43, :b => 226}, + 'brown' => {:r => 165, :g => 42, :b => 42}, + 'burlywood' => {:r => 222, :g => 184, :b => 135}, + 'cadetblue' => {:r => 95, :g => 158, :b => 160}, + 'chartreuse' => {:r => 127, :g => 255, :b => 0}, + 'chocolate' => {:r => 210, :g => 105, :b => 30}, + 'coral' => {:r => 255, :g => 127, :b => 80}, + 'cornflowerblue' => {:r => 100, :g => 149, :b => 237}, + 'cornsilk' => {:r => 255, :g => 248, :b => 220}, + 'crimson' => {:r => 220, :g => 20, :b => 60}, + 'cyan' => {:r => 0, :g => 255, :b => 255}, + 'darkblue' => {:r => 0, :g => 0, :b => 139}, + 'darkcyan' => {:r => 0, :g => 139, :b => 139}, + 'darkgoldenrod' => {:r => 184, :g => 134, :b => 11}, + 'darkgray' => {:r => 169, :g => 169, :b => 169}, + 'darkgreen' => {:r => 0, :g => 100, :b => 0}, + 'darkkhaki' => {:r => 189, :g => 183, :b => 107}, + 'darkmagenta' => {:r => 139, :g => 0, :b => 139}, + 'darkolivegreen' => {:r => 85, :g => 107, :b => 47}, + 'darkorange' => {:r => 255, :g => 140, :b => 0}, + 'darkorchid' => {:r => 153, :g => 50, :b => 204}, + 'darkred' => {:r => 139, :g => 0, :b => 0}, + 'darksalmon' => {:r => 233, :g => 150, :b => 122}, + 'darkseagreen' => {:r => 143, :g => 188, :b => 143}, + 'darkslateblue' => {:r => 72, :g => 61, :b => 139}, + 'darkslategray' => {:r => 47, :g => 79, :b => 79}, + 'darkturquoise' => {:r => 0, :g => 206, :b => 209}, + 'darkviolet' => {:r => 148, :g => 0, :b => 211}, + 'deeppink' => {:r => 255, :g => 20, :b => 147}, + 'deepskyblue' => {:r => 0, :g => 191, :b => 255}, + 'dimgray' => {:r => 105, :g => 105, :b => 105}, + 'dodgerblue' => {:r => 30, :g => 144, :b => 255}, + 'firebrick' => {:r => 178, :g => 34, :b => 34}, + 'floralwhite' => {:r => 255, :g => 250, :b => 240}, + 'forestgreen' => {:r => 34, :g => 139, :b => 34}, + 'fuchsia' => {:r => 255, :g => 0, :b => 255}, + 'gainsboro' => {:r => 220, :g => 220, :b => 220}, + 'ghostwhite' => {:r => 248, :g => 248, :b => 255}, + 'gold' => {:r => 255, :g => 215, :b => 0}, + 'goldenrod' => {:r => 218, :g => 165, :b => 32}, + 'gray' => {:r => 128, :g => 128, :b => 128}, + 'green' => {:r => 0, :g => 128, :b => 0}, + 'greenyellow' => {:r => 173, :g => 255, :b => 47}, + 'honeydew' => {:r => 240, :g => 255, :b => 240}, + 'hotpink' => {:r => 255, :g => 105, :b => 180}, + 'indianred' => {:r => 205, :g => 92, :b => 92}, + 'indigo' => {:r => 75, :g => 0, :b => 130}, + 'ivory' => {:r => 255, :g => 255, :b => 240}, + 'khaki' => {:r => 240, :g => 230, :b => 140}, + 'lavender' => {:r => 230, :g => 230, :b => 250}, + 'lavenderblush' => {:r => 255, :g => 240, :b => 245}, + 'lawngreen' => {:r => 124, :g => 252, :b => 0}, + 'lemonchiffon' => {:r => 255, :g => 250, :b => 205}, + 'lightblue' => {:r => 173, :g => 216, :b => 230}, + 'lightcoral' => {:r => 240, :g => 128, :b => 128}, + 'lightcyan' => {:r => 224, :g => 255, :b => 255}, + 'lightgoldenrodyellow' => {:r => 250, :g => 250, :b => 210}, + 'lightgreen' => {:r => 144, :g => 238, :b => 144}, + 'lightgrey' => {:r => 211, :g => 211, :b => 211}, + 'lightpink' => {:r => 255, :g => 182, :b => 193}, + 'lightsalmon' => {:r => 255, :g => 160, :b => 122}, + 'lightseagreen' => {:r => 32, :g => 178, :b => 170}, + 'lightskyblue' => {:r => 135, :g => 206, :b => 250}, + 'lightslategray' => {:r => 119, :g => 136, :b => 153}, + 'lightsteelblue' => {:r => 176, :g => 196, :b => 222}, + 'lightyellow' => {:r => 255, :g => 255, :b => 224}, + 'lime' => {:r => 0, :g => 255, :b => 0}, + 'limegreen' => {:r => 50, :g => 205, :b => 50}, + 'linen' => {:r => 250, :g => 240, :b => 230}, + 'magenta' => {:r => 255, :g => 0, :b => 255}, + 'maroon' => {:r => 128, :g => 0, :b => 0}, + 'mediumaquamarine' => {:r => 102, :g => 205, :b => 170}, + 'mediumblue' => {:r => 0, :g => 0, :b => 205}, + 'mediumorchid' => {:r => 186, :g => 85, :b => 211}, + 'mediumpurple' => {:r => 147, :g => 112, :b => 219}, + 'mediumseagreen' => {:r => 60, :g => 179, :b => 113}, + 'mediumslateblue' => {:r => 123, :g => 104, :b => 238}, + 'mediumspringgreen' => {:r => 0, :g => 250, :b => 154}, + 'mediumturquoise' => {:r => 72, :g => 209, :b => 204}, + 'mediumvioletred' => {:r => 199, :g => 21, :b => 133}, + 'midnightblue' => {:r => 25, :g => 25, :b => 112}, + 'mintcream' => {:r => 245, :g => 255, :b => 250}, + 'mistyrose' => {:r => 255, :g => 228, :b => 225}, + 'moccasin' => {:r => 255, :g => 228, :b => 181}, + 'navajowhite' => {:r => 255, :g => 222, :b => 173}, + 'navy' => {:r => 0, :g => 0, :b => 128}, + 'oldlace' => {:r => 253, :g => 245, :b => 230}, + 'olive' => {:r => 128, :g => 128, :b => 0}, + 'olivedrab' => {:r => 107, :g => 142, :b => 35}, + 'orange' => {:r => 255, :g => 165, :b => 0}, + 'orangered' => {:r => 255, :g => 69, :b => 0}, + 'orchid' => {:r => 218, :g => 112, :b => 214}, + 'palegoldenrod' => {:r => 238, :g => 232, :b => 170}, + 'palegreen' => {:r => 152, :g => 251, :b => 152}, + 'paleturquoise' => {:r => 175, :g => 238, :b => 238}, + 'palevioletred' => {:r => 219, :g => 112, :b => 147}, + 'papayawhip' => {:r => 255, :g => 239, :b => 213}, + 'peachpuff' => {:r => 255, :g => 218, :b => 185}, + 'peru' => {:r => 205, :g => 133, :b => 63}, + 'pink' => {:r => 255, :g => 192, :b => 203}, + 'plum' => {:r => 221, :g => 160, :b => 221}, + 'powderblue' => {:r => 176, :g => 224, :b => 230}, + 'purple' => {:r => 128, :g => 0, :b => 128}, + 'red' => {:r => 255, :g => 0, :b => 0}, + 'rosybrown' => {:r => 188, :g => 143, :b => 143}, + 'royalblue' => {:r => 65, :g => 105, :b => 225}, + 'saddlebrown' => {:r => 139, :g => 69, :b => 19}, + 'salmon' => {:r => 250, :g => 128, :b => 114}, + 'sandybrown' => {:r => 244, :g => 164, :b => 96}, + 'seagreen' => {:r => 46, :g => 139, :b => 87}, + 'seashell' => {:r => 255, :g => 245, :b => 238}, + 'sienna' => {:r => 160, :g => 82, :b => 45}, + 'silver' => {:r => 192, :g => 192, :b => 192}, + 'skyblue' => {:r => 135, :g => 206, :b => 235}, + 'slateblue' => {:r => 106, :g => 90, :b => 205}, + 'slategray' => {:r => 112, :g => 128, :b => 144}, + 'snow' => {:r => 255, :g => 250, :b => 250}, + 'springgreen' => {:r => 0, :g => 255, :b => 127}, + 'steelblue' => {:r => 70, :g => 130, :b => 180}, + 'tan' => {:r => 210, :g => 180, :b => 140}, + 'teal' => {:r => 0, :g => 128, :b => 128}, + 'thistle' => {:r => 216, :g => 191, :b => 216}, + 'tomato' => {:r => 255, :g => 99, :b => 71}, + 'turquoise' => {:r => 64, :g => 224, :b => 208}, + 'violet' => {:r => 238, :g => 130, :b => 238}, + 'wheat' => {:r => 245, :g => 222, :b => 179}, + 'white' => {:r => 255, :g => 255, :b => 255}, + 'whitesmoke' => {:r => 245, :g => 245, :b => 245}, + 'yellow' => {:r => 255, :g => 255, :b => 0}, + 'yellowgreen' => {:r => 154, :g => 205, :b => 50} + } end