Logic Machine Forum
DMX.set with more options - Printable Version

+- Logic Machine Forum (https://forum.logicmachine.net)
+-- Forum: LogicMachine eco-system (https://forum.logicmachine.net/forumdisplay.php?fid=1)
+--- Forum: Scripting (https://forum.logicmachine.net/forumdisplay.php?fid=8)
+--- Thread: DMX.set with more options (/showthread.php?tid=2786)



DMX.set with more options - Christian_EWW - 11.08.2020

I'm trying to modify the DMX sample my goal would be to create a set method where I have a parameter for the transition time.
I could use dmxhandler.channels in the resident script and manipulate the target and ticks value, but I don't like this idea.
I would be nicer to have a function within the user.dmx.
What I don't understand is how the data from storage.exec('lset', key, chan - 1, val) gets processed to land in the self.channels, so that I can modify it to pass not only the target value but also a transition time?


Thank's
Christian


RE: DMX.set with more options - admin - 11.08.2020

Try this, untested so might not work Smile
Use DMX.settransition to set value and transition time for a given channel.
Code:
local luadmx = require('luadmx')
module('DMX', package.seeall)

local DMX = {}

-- default params
local defaults = {
  -- storage key
  skey = 'dmx_line_1',
  -- RS-485 port
  port = '/dev/RS485',
  -- number of calls per second
  resolution = 20,
  -- total number of channels to use
  channels = 3,
  -- default transition time in seconds, does not include DMX transfer time
  transition = 2,
}

local tsuffix = '_transition'

-- match range
local function range(val, min, max)
  return min <= val and val <= max
end

-- value setter
function set(chan, val, skey)
  skey = skey or defaults.skey
  chan = tonumber(chan) or 0
  val = tonumber(val) or -1

  -- validate channel number and value
  if range(chan, 1, 512) and range(val, 0, 255) then
    storage.exec('lset', skey, chan - 1, val)
  end
end

-- value setter
function settransition(chan, val, tr, skey)
  local tkey
  skey = skey or defaults.skey
  chan = tonumber(chan) or 0
  val = tonumber(val) or -1
  tr = tonumber(val) or -1

  -- validate channel number and value
  if range(chan, 1, 512) and range(val, 0, 255) and range(tr, 0, 255) then
    tkey = skey .. tsuffix
    storage.exec('lset', skey, chan - 1, val)
    storage.exec('lset', tkey, chan - 1, tr)
  end
end

-- value getter
function get(chan, skey)
  local res, val
  skey = skey or defaults.skey
  chan = tonumber(chan) or 0

  -- validate channel number and value
  if chan >= 1 and chan <= 512 then
    res = storage.exec('lrange', skey, chan - 1, chan - 1)
    if type(res) == 'table' then
      val = tonumber(res[ 1 ])
    end
  end

  return val
end

-- DMX init, returns new DMX object
function init(params)
  local n, k, v, _

  -- create metatable and set user parameters
  n = setmetatable({}, { __index = DMX })
  n.params = params or {}

  _, n.conn = pcall(require('redis').connect)

  -- merge parameters that are set by user
  for k, v in pairs(defaults) do
    if n.params[ k ] == nil then
      n.params[ k ] = v
    end
  end

  n:reset()

  return n
end

function DMX:reset()
  local params, skey, tkey, transition, err

  params = self.params
  skey = params.skey
  tkey = skey .. tsuffix
  transition = params.transition

  self.dm, err = luadmx.open(params.port)

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

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

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

  -- reset channel map
  self.channels = {}

  -- empty channel value map
  self.conn:ltrim(skey, 1, 0)
  self.conn:ltrim(tkey, 1, 0)

  -- fill channel map
  for chan = 1, params.channels do
    self.channels[ chan ] = { current = 0, target = 0, ticks = 0 }

    -- turn off by default, set default transition
    self.conn:lpush(skey, 0)
    self.conn:lpush(tkey, transition)
    self.dm:setchannel(chan, 0)
  end
end

-- get new values
function DMX:getvalues()
  local skey, tkey, max, channels, values, transition, val, tr, ticks

  skey = self.params.skey
  tkey = skey .. tsuffix

  max = self.params.channels
  channels = self.channels
  values = self.conn:lrange(skey, 0, max - 1) or {}
  transitions = self.conn:lrange(tkey, 0, max - 1) or {}

  -- check for new values for each channel
  for chan = 1, max do
    val = tonumber(values[ chan ]) or 0
    tr = tonumber(transitions[ chan ]) or 0
    ticks = math.max(1, tr * self.params.resolution)

    -- target value differs, set transcation
    if val ~= channels[ chan ].target then
      channels[ chan ].target = val
      channels[ chan ].delta = (channels[ chan ].target - channels[ chan ].current) / ticks
      channels[ chan ].ticks = ticks
    end
  end
end

-- main loop handler
function DMX:run()
  self:getvalues()

  -- transition loop
  for i = 1, self.params.resolution do
    self:step()
    self.dm:send()
    os.sleep(self.sleep)
  end
end

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

  channels = self.channels

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

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

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

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



RE: DMX.set with more options - Christian_EWW - 11.08.2020

Thanks a lot, sems to work.
Line 150 should be: ticks = math.max(1, tr * self.params.resolution)