Skip to content

Instantly share code, notes, and snippets.

@jsopenrb
Last active Aug 26, 2016
Embed
What would you like to do?
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,
-- transition time in seconds, does not include DMX transfer time
transition = 2,
}
-- value setter
function set(chan, val, key)
key = key or defaults.skey
chan = tonumber(chan) or 0
val = tonumber(val) or -1
-- validate channel number and value
if chan >= 1 and chan <= 512 and val >= 0 and val <= 255 then
storage.exec('lset', key, chan - 1, val)
end
end
-- value getter
function get(chan, key)
local res, val
key = key or defaults.skey
chan = tonumber(chan) or 0
-- validate channel number and value
if chan >= 1 and chan <= 512 then
res = storage.exec('lrange', key, 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 err, chan, params
params = self.params
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)
-- number of transaction ticks
self.ticks = math.max(1, params.transition * params.resolution)
-- calculate sleep time
self.sleep = 1 / params.resolution
-- reset channel map
self.channels = {}
-- empty channel value map
self.conn:ltrim(params.skey, 1, 0)
-- fill channel map
for chan = 1, params.channels do
self.channels[ chan ] = { current = 0, target = 0, ticks = 0 }
-- turn off by default
self.conn:lpush(params.skey, 0)
self.dm:setchannel(chan, 0)
end
end
-- get new values
function DMX:getvalues()
local max, channels, ticks, values, val
max = self.params.channels
channels = self.channels
ticks = self.ticks
values = self.conn:lrange(self.params.skey, 0, max - 1) or {}
-- check for new values for each channel
for chan = 1, max do
val = tonumber(values[ chan ]) or 0
-- 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment