DMX on the Logic Machine

To get the DMX control of the Logic Machine one needs to get two scripts running. The first is a “handler” that needs to be added as a resident script:

Logic Machine - DMX handler resident script



-- This software may be used and distributed according to the terms of the
-- GNU General Public License version 3, incorporated herein by reference.

if not d then
  d = DMX:init({
    channels = 16,
    transition = 1,
  })
  log('DMX initialized')

-- reset custom DMX RGB color settings to "off" (0), comment out if not needed
  storage.set('DMXrgbred', 0)
  storage.set('DMXrgbgreen', 0)
  storage.set('DMXrgbblue', 0)
  log('Reset RGB colors')
end

d:run()

and the second are the common functions, that you can just add to the end of the current common functions.



-- This code is copyright of openrb.com
-- Open Source but != free 

DMX = {
  -- default params
  defaults = {
    -- storage key
    skey = 'dmx_chan_',
    -- RS-485 port
    port = '/dev/ttyAPP2',
    -- number of calls per second
    resolution = 20,
    -- total number of channels to use
    channels = 16,
    -- transition time in seconds, does not include DMX transfer time
    transition = 2,
  },
  -- value setter
  set = function(i, v)
    -- validate channel number
    if type(i) == 'number' and i >= 1 and i < = 512 then
      -- validate channel value
      if type(v) == 'number' and v >= 0 and v < = 255 then
        storage.set(DMX.defaults.skey .. i, v)
      end
    end
  end
}

-- DMX init, returns new DMX object
function DMX:init(params)
  log('starting DMX')
  require('luadmx')

  local n = setmetatable({}, { __index = DMX })
  local k, v

  -- set user parameters
  n.params = params

  -- copy parameters that are set by user
  for k, v in pairs(DMX.defaults) do
    if n.params&#91; k &#93; == nil then
      n.params&#91; k &#93; = v
    end
  end

  n:reset()

  return n
end

function DMX:reset()
  local err, chan
  log('resetting DMX')
  self.dm, err = luadmx.open(self.params.port)

    -- error while opening
  if err then
    os.sleep(1)
    error(err)
  end

  -- set channel count
  self.dm:setcount(self.params.channels)

  -- number of transaction ticks
  self.ticks = math.max(1, self.params.transition * self.params.resolution)

  -- calculate sleep time
  self.sleep = 1 / self.params.resolution

  -- reset channel map
  self.channels = {}

  -- fill channel map
  for chan = 1, self.params.channels do
    self.channels&#91; chan &#93; = { current = 0, target = 0, ticks = 0 }

    -- turn off by default
    storage.set(self.params.skey .. chan, 0)
    self.dm:setchannel(chan, 0)
  end
end

-- get new values
function DMX:getvalues()
  local chan, val
  --log('getting DMX values')
      
  -- check for new values for each channel
  for chan = 1, self.params.channels do
    val = storage.get(self.params.skey .. chan)

    -- target value differs, set transcation
    if val ~= self.channels&#91; chan &#93;.target then
      self.channels&#91; chan &#93;.target = val
      self.channels&#91; chan &#93;.delta = (self.channels&#91; chan &#93;.target - self.channels&#91; chan &#93;.current) / self.ticks
      self.channels&#91; chan &#93;.ticks = self.ticks
    end
  end
end

-- main loop handler
function DMX:run()
  local i, bs, bm, as, am, delta
  local res = self.params.resolution

  if not self.calibrated then
    bs, bm = os.microtime()
  end
    
  self:getvalues()

  -- transition loop
  for i = 1, res do
    self:step()
    self.dm:send()

    -- wait until next step
    os.sleep(self.sleep)
  end

  -- calibrate delay loop to match 1 second
  if not self.calibrated then
    as, am = os.microtime()
    delta = (as - bs) + (am - bm) / 1000000

    if delta > 1.05 then
      self.sleep = self.sleep - math.max(10, self.sleep / res)
    else
      self.calibrated = true
    end
  end
end

-- single transition step
function DMX:step()
  local chan, t

  -- transition for each channel
  for chan = 1, self.params.channels do
    t = self.channels[ chan ].ticks

    -- transition is active
    if t > 0 then
      t = t - 1

      self.channels[ chan ].current = self.channels[ chan ].target - self.channels[ chan ].delta * t
      self.channels[ chan ].ticks = t

      self.dm:setchannel(chan, self.channels[ chan ].current)
    end
  end
end

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.