Skip to content

Commit

Permalink
Get a websocket frame stream working (base64 encoded)
Browse files Browse the repository at this point in the history
  • Loading branch information
rangerscience committed Aug 3, 2019
1 parent b331fc3 commit 45ce6e2
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 99 deletions.
1 change: 1 addition & 0 deletions server/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ source 'https://rubygems.org'
ruby '2.5.5'

gem 'sinatra'
gem 'sinatra-websocket'
gem 'slim'

gem 'rubyserial'
Expand Down
17 changes: 17 additions & 0 deletions server/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
GEM
remote: https://rubygems.org/
specs:
addressable (2.6.0)
public_suffix (>= 2.0.2, < 4.0)
coderay (1.1.2)
daemons (1.3.1)
diff-lcs (1.3)
em-websocket (0.3.8)
addressable (>= 2.1.1)
eventmachine (>= 0.12.9)
eventmachine (1.2.7)
ffi (1.11.1)
method_source (0.9.2)
mustermann (1.0.3)
pry (0.12.2)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
public_suffix (3.1.1)
rack (2.0.7)
rack-protection (2.0.5)
rack
Expand All @@ -32,10 +40,18 @@ GEM
rack (~> 2.0)
rack-protection (= 2.0.5)
tilt (~> 2.0)
sinatra-websocket (0.3.1)
em-websocket (~> 0.3.6)
eventmachine
thin (>= 1.3.1, < 2.0.0)
slim (4.0.1)
temple (>= 0.7.6, < 0.9)
tilt (>= 2.0.6, < 2.1)
temple (0.8.1)
thin (1.7.2)
daemons (~> 1.0, >= 1.0.9)
eventmachine (~> 1.0, >= 1.0.4)
rack (>= 1, < 3)
tilt (2.0.9)

PLATFORMS
Expand All @@ -46,6 +62,7 @@ DEPENDENCIES
rspec
rubyserial
sinatra
sinatra-websocket
slim

RUBY VERSION
Expand Down
13 changes: 13 additions & 0 deletions server/lib/integer_patches.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module IntegerPatches
def to_hex_s
"0x" + to_s(16).upcase.rjust(6, '0')
end

def to_chr_bytes
((self & 0xFF0000) >> 16).chr +
((self & 0x00FF00) >> 8).chr +
((self & 0x0000FF) ).chr
end
end

Integer.include IntegerPatches
61 changes: 15 additions & 46 deletions server/lib/serial.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
require 'rubyserial'

module Arduino
module PrintHex
def to_hex_s
"0x" + to_s(16).upcase.rjust(6, '0')
end
end
Integer.include PrintHex

module Arduino
class SerialOut
attr_accessor :playing, :frame
attr_reader :ports, :connections, :func, :frame_size, :slice_size

def initialize &func
@func = func
@frame = func.call
attr_reader :ports, :connections, :slice_size

def initialize
# Establish the connections
@connections = if RUBY_PLATFORM =~ /darwin/ # MacOS
@ports = `ls /dev/cu.*`.split("\n").select{|s| s =~ /cu.usbmodem/}
Expand All @@ -21,47 +23,14 @@ def initialize &func
end
end

def play
@playing = true
if @connections.size == 0
@frame = fake_play
else
@frame = real_play
end
@playing = false
@frame
end

private

def fake_play
@frame = func.call
while(@playing) do
# Render the frame, and do nothing with it....
@frame = func.call
sleep(0.1)
end
@frame
end

def real_play
# Get a first frame for sizing
@frame = func.call
@frame_size = frame.size
@slice_size = (@frame_size/@connections.size.to_f).round

while(@playing) do
# Render the frame
@frame = func.call

# Split the frame amongst the connections
@frame.each_slice( @slice_size ).with_index do |slice, index|
@connections[index].write(slice.map(&:chr).join(""))
def write frame
if @connections.any?
slice_size = (frame.size/@connections.size.to_f).round
frame.each_slice( slice_size ).with_index do |slice, index|
byte_string = slice.map(&:to_chr_bytes).join("")
@connections[index].write(byte_string)
end
end

# Return the last frame
@frame
end
end
end
95 changes: 71 additions & 24 deletions server/server.rb
Original file line number Diff line number Diff line change
@@ -1,42 +1,89 @@
require 'sinatra'
require 'sinatra-websocket'

Dir[File.join("./lib", "**/*.rb")].each do |f|
require f
end

module PrintHex
def to_hex_s
"0x" + to_s(16).upcase.rjust(6, '0')
require 'pry'

set :server, 'thin'
set :sockets, []
set :num_leds, 300
set :version, File.read('.version').chomp

class Renderer
attr_accessor :pattern, :num_leds

def initialize pattern, num_leds
@pattern = pattern
@num_leds = num_leds
end

def render
t = Time.now
c = Effects::Context.new(@num_leds, t: t)
(0..@num_leds).collect do |i|
c.position = i
@pattern.apply(c)
c.color
end
end
end
Integer.include PrintHex

NUM_LEDS = 300
$version = File.read('.version').chomp
$active_pattern = Compositions::MASTERAVERBAITER_V1
$s = Arduino::SerialOut.new do
t = Time.now
c = Effects::Context.new(NUM_LEDS, t: t)
(0..NUM_LEDS).collect do |i|
c.position = i
$active_pattern.apply(c)
c.color

set :renderer, Renderer.new(Compositions::MASTERAVERBAITER_V1, settings.num_leds)

set :playing, true

def play
serial_out = Arduino::SerialOut.new

Thread.new do
while(settings.playing)
# Render frame
frame = settings.renderer.render

# Write out to serial ports
serial_out.write frame

# Write out to websockets
settings.sockets.each do |s|
byte_string = frame.map(&:to_chr_bytes).join("")
s.send(Base64.encode64(byte_string))
end

# Give other threads some time
sleep(0.1)
end
end
end

get '/' do
"Butterfly Server #{$version} #{NUM_LEDS} #{$s.playing}"
"Butterfly Server #{settings.version} #{settings.num_leds}"
end

get '/frame' do
$s.frame.map{|c| c.to_hex_s}.join("\n")
#$frame.map{|c| c.to_hex_s}.join("\n")
settings.renderer.render.map{|c| c.to_hex_s}.join("\n")
end

get '/subscribe' do
if request.websocket?
request.websocket do |ws|
ws.onopen do
settings.sockets << ws
end

ws.onclose do
settings.sockets.delete(ws)
end
end
else
"for websockets only"
end
end

# get '/debug' do
# require 'pry'
# binding.pry
# $s.frame.map{|c| c.to_hex_s}.join("\n")
# end
get '/pry' do
binding.pry
end

$t = Thread.new { $s.play }
$t = play
8 changes: 0 additions & 8 deletions server/spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,6 @@
require f
end

module PrintHex
def to_hex_s
"0x" + to_s(16).upcase.rjust(6, '0')
end
end

Integer.include PrintHex

RSpec.configure do |config|

config.expect_with :rspec do |expectations|
Expand Down
42 changes: 21 additions & 21 deletions server/tmp/rspec_state.txt
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
example_id | status | run_time |
----------------------------------------------------- | ------ | --------------- |
./spec/lib/colors_spec.rb[1:1:1] | passed | 0.00008 seconds |
./spec/lib/colors_spec.rb[1:1:2] | passed | 0.00007 seconds |
./spec/lib/colors_spec.rb[1:1:1] | passed | 0.00006 seconds |
./spec/lib/colors_spec.rb[1:1:2] | passed | 0.00005 seconds |
./spec/lib/colors_spec.rb[1:1:3] | passed | 0.00007 seconds |
./spec/lib/colors_spec.rb[1:1:4] | passed | 0.00008 seconds |
./spec/lib/compositions/masteraverbaiter_spec.rb[1:1] | passed | 0.00094 seconds |
./spec/lib/compositions/masteraverbaiter_spec.rb[1:2] | passed | 0.00271 seconds |
./spec/lib/effects/core/pulse_spec.rb[1:1] | passed | 0.00017 seconds |
./spec/lib/effects/core/pulse_spec.rb[1:2] | passed | 0.00016 seconds |
./spec/lib/effects/core/pulse_spec.rb[1:3] | passed | 0.00014 seconds |
./spec/lib/effects/core/pulse_spec.rb[1:4] | passed | 0.00018 seconds |
./spec/lib/effects/core/wheel_spec.rb[1:1] | passed | 0.00012 seconds |
./spec/lib/effects/core/wheel_spec.rb[1:2] | passed | 0.00016 seconds |
./spec/lib/effects/core/wheel_spec.rb[1:3] | passed | 0.00008 seconds |
./spec/lib/compositions/masteraverbaiter_spec.rb[1:1] | passed | 0.00093 seconds |
./spec/lib/compositions/masteraverbaiter_spec.rb[1:2] | passed | 0.00345 seconds |
./spec/lib/effects/core/pulse_spec.rb[1:1] | passed | 0.00016 seconds |
./spec/lib/effects/core/pulse_spec.rb[1:2] | passed | 0.00019 seconds |
./spec/lib/effects/core/pulse_spec.rb[1:3] | passed | 0.00019 seconds |
./spec/lib/effects/core/pulse_spec.rb[1:4] | passed | 0.00016 seconds |
./spec/lib/effects/core/wheel_spec.rb[1:1] | passed | 0.00096 seconds |
./spec/lib/effects/core/wheel_spec.rb[1:2] | passed | 0.00011 seconds |
./spec/lib/effects/core/wheel_spec.rb[1:3] | passed | 0.00009 seconds |
./spec/lib/effects/core/wipe_spec.rb[1:1] | passed | 0.00005 seconds |
./spec/lib/effects/meta/composition_spec.rb[1:1] | passed | 0.00124 seconds |
./spec/lib/effects/meta/composition_spec.rb[1:2:1] | passed | 0.00017 seconds |
./spec/lib/effects/meta/composition_spec.rb[1:2:2] | passed | 0.00012 seconds |
./spec/lib/effects/meta/moving_spec.rb[1:1] | passed | 0.00011 seconds |
./spec/lib/effects/meta/moving_spec.rb[1:2] | passed | 0.00011 seconds |
./spec/lib/effects/meta/composition_spec.rb[1:1] | passed | 0.00028 seconds |
./spec/lib/effects/meta/composition_spec.rb[1:2:1] | passed | 0.00018 seconds |
./spec/lib/effects/meta/composition_spec.rb[1:2:2] | passed | 0.00008 seconds |
./spec/lib/effects/meta/moving_spec.rb[1:1] | passed | 0.00008 seconds |
./spec/lib/effects/meta/moving_spec.rb[1:2] | passed | 0.00007 seconds |
./spec/lib/effects/meta/moving_spec.rb[1:3] | passed | 0.00014 seconds |
./spec/lib/effects/meta/moving_spec.rb[1:4] | passed | 0.00007 seconds |
./spec/lib/effects/meta/moving_spec.rb[1:5] | passed | 0.00008 seconds |
./spec/lib/effects/meta/moving_spec.rb[1:4] | passed | 0.00011 seconds |
./spec/lib/effects/meta/moving_spec.rb[1:5] | passed | 0.00011 seconds |
./spec/lib/effects/meta/moving_spec.rb[1:6] | passed | 0.0001 seconds |
./spec/lib/effects_spec.rb[1:1] | passed | 0.00005 seconds |
./spec/lib/effects_spec.rb[1:2] | passed | 0.00005 seconds |
./spec/lib/effects_spec.rb[1:3] | passed | 0.00007 seconds |
./spec/lib/effects_spec.rb[1:1] | passed | 0.00006 seconds |
./spec/lib/effects_spec.rb[1:2] | passed | 0.00009 seconds |
./spec/lib/effects_spec.rb[1:3] | passed | 0.00005 seconds |

0 comments on commit 45ce6e2

Please sign in to comment.