class Rbbit::Microbit

Class Library

Constants

TONE
WAIT

Attributes

l[R]
p[R]
r[R]
t[R]
x[R]
y[R]
z[R]

Public Class Methods

new(port = nil, ws_server = nil) click to toggle source
# File lib/rbbit.rb, line 155
def initialize(port = nil, ws_server = nil)
  @agent = Agent.new(self, ws_server) if ws_server
  @q     = Queue.new

  @x                    = nil
  @y                    = nil
  @z                    = nil
  @p                    = nil
  @r                    = nil
  @l                    = nil
  @t                    = nil
  @button_down          = {}
  @button_down_last     = {}
  @button_press         = {}
  @button_release       = {}
  @button_down[:a]      = nil
  @button_down[:b]      = nil
  @button_down_last[:a] = nil
  @button_down_last[:b] = nil
  @button_press[:a]     = nil
  @button_press[:b]     = nil
  @button_release[:a]   = nil
  @button_release[:b]   = nil

  @on_press_a           = nil
  @on_press_b           = nil
  @on_release_a         = nil
  @on_release_b         = nil

  @volume               = 127
  @bpm                  = 120   # ウェイト調整のため、この値で明示的に初期化(initialize末尾)

  @continue_thread      = nil
  @continue_loop        = nil

  @port     = port || ENV['MB_PORT']
  baud_rate = 115200
  data_bits = 8
  stop_bits = 1
  parity    = 0

  raise Rbbit::Error, "serialport 'nil' is not available" unless @port

  begin
    @sp = SerialPort.open(@port, baud_rate, data_bits, stop_bits, parity)
  rescue => e
    #Kernel.puts e
    #exit
    raise Rbbit::Error, "serialport '#{@port}' is not available"
  end
  Kernel.sleep 0.5

  # -- for write
  @thread_w = Thread.new do
    loop do
      Thread.pass   # for other threads
      unless @q.empty?
        cmd = @q.pop
        if cmd.class == Array
          @sp.write cmd[0]; Kernel.sleep cmd[1]
        else
          @sp.write cmd
        end
      end
    end
  end

  # -- for read
  @thread_r = Thread.new do
    # Thread.pass
    @sp.read_timeout = 200
    @continue_thread = true
    loop do
      break unless @continue_thread
      Thread.pass   # for other threads
      begin
        value = @sp.readline.chomp.strip.split(',')
        # Kernel.p value
      rescue EOFError
        Kernel.sleep 0.1
        retry
      rescue ArgumentError
        # 回避:`strip': invalid byte sequence in UTF-8 (ArgumentError)
        #       `split': invalid byte sequence in UTF-8 (ArgumentError)
        Kernel.sleep 0.1
        retry
      end

      @x = value[0].to_i
      @y = value[1].to_i
      @z = value[2].to_i
      @p = value[3].to_i          # pitch
      @r = value[4].to_i          # roll
      @l = value[5].to_i          # light
      @t = value[6].to_i          # temp
      @button_down[:a] = (value[7] == "1" ? true : false)
      @button_down[:b] = (value[8] == "1" ? true : false)
      button_status
      event_proc
      if @agent
        senddata = JSON.generate({x: @x,
                                  y: @y,
                                  z: @z,
                                  p: @p,
                                  r: @r,
                                  l: @l,
                                  t: @t,
                                  a_down:    @button_down[:a],
                                  a_press:   @button_press[:a],
                                  a_release: @button_release[:a],
                                  b_down:    @button_down[:b],
                                  b_press:   @button_press[:b],
                                  b_release: @button_release[:b]})
        @agent.send_to_ws senddata
      end
    end
  end

  # -- init
  self.sound_volume = @volume
  self.sound_tempo  = @bpm
end

Public Instance Methods

break() click to toggle source
# File lib/rbbit.rb, line 304
def break
  Kernel.sleep 0.5         ###
  @continue_loop = false
end
button_down?(k) click to toggle source
# File lib/rbbit.rb, line 352
def button_down?(k)
  @button_down[k]
end
close(delay = 0) click to toggle source
# File lib/rbbit.rb, line 309
def close(delay = 0)
  @continue_thread = false
  Kernel.sleep 1
  until @q.empty?       # wait for until command queue has been empty
    Kernel.sleep 0.5
    # Kernel.puts "sync #{@q.size}"
  end
  Kernel.sleep 0.5 + delay / 1000
  @thread_w.kill
  @thread_r.kill
  @sp.close
end
led_off(x = nil, y = nil) click to toggle source
# File lib/rbbit.rb, line 378
def led_off(x = nil, y = nil)
  if (x == nil and y == nil)
    @q << ["LEDclr\n", WAIT]
  else
    @q << ["LEDoff#{x}#{y}\n", WAIT]
  end
end
Also aliased as: off
led_on(x = nil, y = nil) click to toggle source
Pending...

def button_release?(k)

status = @button_release[k]
@button_release[k] = false if @button_release[k]          # avoid continuous judgment
status

end

# File lib/rbbit.rb, line 370
def led_on(x = nil, y = nil)
  if (x == nil and y == nil)
    @q << ["LEDfil\n", WAIT]
  else
    @q << ["LEDon #{x}#{y}\n", WAIT]
  end
end
Also aliased as: on
led_puts(str) click to toggle source
# File lib/rbbit.rb, line 390
def led_puts(str)
  @q << ["LEDput#{str}\n", WAIT + str.length * 0.5]
end
Also aliased as: puts
led_show(pattern) click to toggle source
# File lib/rbbit.rb, line 394
def led_show(pattern)
  ptn = []
  5.times do |j|
    ptn[j] = 0
    5.times do |i|
      ptn[j] += (2 ** (4 - i)) unless pattern[j][i] == 0   # 5-digits to decimal
    end
  end
  #Kernel.p ptn
  @q << ["LEDshw%02d%02d%02d%02d%02d\n" % ptn, WAIT]
end
Also aliased as: show
led_turn(x, y) click to toggle source
# File lib/rbbit.rb, line 386
def led_turn(x, y)
  @q << ["LEDtrn#{x}#{y}\n", WAIT]
end
Also aliased as: turn
mainloop(&block) click to toggle source
# File lib/rbbit.rb, line 294
def mainloop(&block)
  @b = block           # ブロックを登録
  @continue_loop = true
  loop do
    break unless @continue_loop
    @b.call
    Kernel.sleep WAIT  # ブロック1回処理ごとにウェイト
  end
end
off(x = nil, y = nil)
Alias for: led_off
on(x = nil, y = nil)
Alias for: led_on
on_press_a(&block) click to toggle source
# File lib/rbbit.rb, line 278
def on_press_a(&block)
  @on_press_a = block
end
on_press_b(&block) click to toggle source
# File lib/rbbit.rb, line 286
def on_press_b(&block)
  @on_press_b = block
end
on_release_a(&block) click to toggle source
# File lib/rbbit.rb, line 282
def on_release_a(&block)
  @on_release_a = block
end
on_release_b(&block) click to toggle source
# File lib/rbbit.rb, line 290
def on_release_b(&block)
  @on_release_b = block
end
play(freq, beat)
Alias for: sound_play
port() click to toggle source
# File lib/rbbit.rb, line 330
def port
  @port
end
puts(str)
Alias for: led_puts
reset() click to toggle source
# File lib/rbbit.rb, line 326
def reset
  @q << "RESET \n"
end
rest(beat)
Alias for: sound_rest
show(pattern)
Alias for: led_show
sound_play(freq, beat) click to toggle source
# File lib/rbbit.rb, line 416
def sound_play(freq, beat)
  @q << ["SNDply%04d%s\n" % [TONE[freq], _beat(beat)], WAIT * 0 + 60.0 / @bpm * beat]   ###
end
Also aliased as: play
sound_rest(beat) click to toggle source
# File lib/rbbit.rb, line 420
def sound_rest(beat)
  @q << ["SNDrst%s\n" % [_beat(beat)], WAIT + 60.0 / @bpm * beat]
end
Also aliased as: rest
sound_tempo=(bpm) click to toggle source
# File lib/rbbit.rb, line 411
def sound_tempo=(bpm)
  @q << ["SNDbpm#{bpm}\n", WAIT]
  @bpm = bpm
end
Also aliased as: tempo=
sound_volume=(v) click to toggle source
# File lib/rbbit.rb, line 406
def sound_volume=(v)
  @q << ["SNDvol#{v}\n", WAIT]
  @volume = v
end
Also aliased as: volume=
tempo=(bpm)
Alias for: sound_tempo=
turn(x, y)
Alias for: led_turn
volume=(v)
Alias for: sound_volume=
wait(ms) click to toggle source
# File lib/rbbit.rb, line 322
def wait(ms)
  @q << ["SLEEP %03d\n" % [ms], WAIT + ms / 1000.0]
end

Private Instance Methods

_beat(beat) click to toggle source
# File lib/rbbit.rb, line 424
        def _beat(beat)
  if    beat >= 4.0      # Whole note
    return "4"
  elsif beat >= 2.0      # Half note
    return "2"
  elsif beat >= 1.0      # Quarter note
    return "1"
  elsif beat >= 0.5      # Eighth note
    return "/2"
  elsif beat >= 0.25     # Sixteenth note
    return "/4"
  elsif beat >= 0.125    # Thirty-second note
    return "/8"
  else                   # Sixty-fourth note
    return "/16"
  end
end
button_status() click to toggle source
# File lib/rbbit.rb, line 334
        def button_status
  @button_down.each_key do |k|
    change  = @button_down[k] ^ @button_down_last[k]        # Get change of mouse press status (XOR)
    press   = change &  @button_down[k]                     # Detect change to press from release
    release = change & !@button_down[k]                     # Detect change to release from press
    @button_press[k] = press                                # Set mouse_press status
    @button_release[k] = release                            # Set mouse_release status
    @button_down_last[k] = @button_down[k]
  end
end
event_proc() click to toggle source
# File lib/rbbit.rb, line 345
        def event_proc
  @on_press_a.call   if @on_press_a   and @button_press[:a]
  @on_press_b.call   if @on_press_b   and @button_press[:b]
  @on_release_a.call if @on_release_a and @button_release[:a]
  @on_release_b.call if @on_release_b and @button_release[:b]
end