Class: OpenLighting::DmxController

Inherits:
Object
  • Object
show all
Defined in:
lib/open_lighting/dmx_controller.rb

Overview

The DmxController class is responsible for sending control messages across the DMX bus.

Due to idiosynchricies of the underlying open_lighting subsytem, all devices must receive a control signal each time anything on the bus receives a control signal. The DmxController class is responsible for aggregating this information from the DmxDevice instances and sending it down the bus.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ DmxController

Returns a new instance of DmxController.



13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/open_lighting/dmx_controller.rb', line 13

def initialize(options = {})
  @devices = []
  (options[:devices] || []).each {|dev| @devices << dev}
  self.fps = options[:fps] || 40
  self.universe = options[:universe] || 1
  self.cmd = options[:cmd] || "ola_streaming_client -u #{universe}"

  if options[:test]
    self.do_not_sleep = true
    self.connect_test_pipe
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args, &block) ⇒ Object



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/open_lighting/dmx_controller.rb', line 137

def method_missing(meth, *args, &block)
  meth_without_bang = meth.to_s.gsub(/!\Z/, "").to_sym

  if points.include? meth
    buffer :point => meth
  elsif points.include? meth_without_bang
    # causes controller.center! to convert to controller.instant!(:point => :center)
    instant! :point => meth_without_bang
  elsif capabilities.include? meth
    buffer meth => args.first
  elsif capabilities.include? meth_without_bang
    instant! meth_without_bang => args.first
  else
    super # You *must* call super if you don't handle the
          # method, otherwise you'll mess up Ruby's method
          # lookup.
  end
end

Instance Attribute Details

#cmdObject

Returns the value of attribute cmd.



12
13
14
# File 'lib/open_lighting/dmx_controller.rb', line 12

def cmd
  @cmd
end

#devicesObject

Returns the value of attribute devices.



12
13
14
# File 'lib/open_lighting/dmx_controller.rb', line 12

def devices
  @devices
end

#do_not_sleepObject

Returns the value of attribute do_not_sleep.



12
13
14
# File 'lib/open_lighting/dmx_controller.rb', line 12

def do_not_sleep
  @do_not_sleep
end

#fpsObject

Returns the value of attribute fps.



12
13
14
# File 'lib/open_lighting/dmx_controller.rb', line 12

def fps
  @fps
end

#read_pipeObject

Returns the value of attribute read_pipe.



12
13
14
# File 'lib/open_lighting/dmx_controller.rb', line 12

def read_pipe
  @read_pipe
end

#universeObject

Returns the value of attribute universe.



12
13
14
# File 'lib/open_lighting/dmx_controller.rb', line 12

def universe
  @universe
end

#write_pipeObject

Returns the value of attribute write_pipe.



12
13
14
# File 'lib/open_lighting/dmx_controller.rb', line 12

def write_pipe
  @write_pipe
end

Instance Method Details

#<<(val) ⇒ Object



42
43
44
45
46
# File 'lib/open_lighting/dmx_controller.rb', line 42

def <<(val)
  val.start_address ||= current_values.count + 1
  val.controller = self
  @devices << val
end

#[](key) ⇒ Object



34
35
36
# File 'lib/open_lighting/dmx_controller.rb', line 34

def [](key)
  @devices[key]
end

#[]=(key, val) ⇒ Object



38
39
40
# File 'lib/open_lighting/dmx_controller.rb', line 38

def []=(key, val)
  @devices[key] = val
end

#animate!(options = {}, &block) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/open_lighting/dmx_controller.rb', line 103

def animate!(options = {}, &block)
  previous = current_values
  buffer(options)

  block.call(self) if block

  count = ticks(options[:seconds])
  count.times do |i|
    # interpolate previous to current
    write! interpolate(previous, current_values, count, i+1)
    sleep(wait_time) unless self.do_not_sleep
  end
end

#begin_animation!(options = {}, &block) ⇒ Object



117
118
119
# File 'lib/open_lighting/dmx_controller.rb', line 117

def begin_animation!(options = {}, &block)
  animate!(options, &block)
end

#buffer(options = {}) ⇒ Object



52
53
54
# File 'lib/open_lighting/dmx_controller.rb', line 52

def buffer(options = {})
  @devices.each {|device| device.buffer(options)}
end

#capabilitiesObject



129
130
131
# File 'lib/open_lighting/dmx_controller.rb', line 129

def capabilities
  @devices.map{|device| device.capabilities}.flatten.uniq
end

#close!Object



67
68
69
70
# File 'lib/open_lighting/dmx_controller.rb', line 67

def close!
  self.write_pipe.close if self.write_pipe
  self.read_pipe.close  if self.read_pipe
end

#connect_test_pipeObject



26
27
28
# File 'lib/open_lighting/dmx_controller.rb', line 26

def connect_test_pipe
  self.read_pipe, self.write_pipe = IO.pipe
end

#current_valuesObject



82
83
84
85
86
87
88
89
# File 'lib/open_lighting/dmx_controller.rb', line 82

def current_values
  results = []
  @devices.each do |d|
    results[d.start_address, d.start_address+d.capabilities.count] = d.current_values
  end
  # backfill unknown values with zero, in case of gaps due to starting_address errors
  results.map{|i| i.nil? ? 0 : i}.drop(1)
end

#instant!(options = {}) ⇒ Object



72
73
74
75
# File 'lib/open_lighting/dmx_controller.rb', line 72

def instant!(options = {})
  buffer(options)
  write!
end

#interpolate(first, last, total, i) ⇒ Object



121
122
123
124
125
126
127
# File 'lib/open_lighting/dmx_controller.rb', line 121

def interpolate(first, last, total, i)
  results = []
  first.count.times do |j|
    results[j] = (last[j] - first[j])*i.to_f/total + first[j]
  end
  results
end

#pointsObject



133
134
135
# File 'lib/open_lighting/dmx_controller.rb', line 133

def points
  @devices.map{|device| device.points.keys}.flatten.uniq
end

#set(options = {}) ⇒ Object



48
49
50
# File 'lib/open_lighting/dmx_controller.rb', line 48

def set(options = {})
  warn "[DEPRECATION] `set` is deprecated. Use `buffer` instead."
end

#ticks(seconds) ⇒ Object



91
92
93
# File 'lib/open_lighting/dmx_controller.rb', line 91

def ticks(seconds)
  [1, (seconds.to_f * self.fps.to_f).to_i].max
end

#to_dmxObject



77
78
79
80
# File 'lib/open_lighting/dmx_controller.rb', line 77

def to_dmx
  # dmx addresses start at 1, ruby arrays start at zero
  current_values.join ","
end

#transition!(options = {}, &block) ⇒ Object



99
100
101
# File 'lib/open_lighting/dmx_controller.rb', line 99

def transition!(options = {}, &block)
  warn "[DEPRECATION] `transition!` is deprecated. Use `begin_animation!` instead."
end

#wait_timeObject



95
96
97
# File 'lib/open_lighting/dmx_controller.rb', line 95

def wait_time
  1.0 / self.fps.to_f
end

#write!(values = current_values) ⇒ Object



56
57
58
59
60
61
62
63
64
65
# File 'lib/open_lighting/dmx_controller.rb', line 56

def write!(values=current_values)
  self.write_pipe ||= IO.popen(self.cmd, "w")
  self.write_pipe.sync = true

  # DMX only wants integer inputs
  values.map!{|i| i.to_i}

  self.write_pipe.write "#{values.join ","}\n"
  self.write_pipe.flush
end