Reputation: 75
I have problem with loops, table in Lua
here is table with variable knx
(now it's static)
regTable = {
{ RegEddr=3027, count=2, regType="float", knx="1/1/1"},
{ RegEddr=3029, count=2, regType="float", knx="1/1/2"},
{ RegEddr=3031, count=2, regType="float", knx="1/1/3"},
{ RegEddr=2999, count=2, regType="float", knx="1/1/4"},
{ RegEddr=3001, count=2, regType="float", knx="1/1/5"},
{ RegEddr=3003, count=2, regType="float", knx="1/1/6"},
{ RegEddr=3109, count=2, regType="float", knx="1/1/7"},
{ RegEddr=3083, count=2, regType="float", knx="1/1/8"},
{ RegEddr=3059, count=2, regType="float", knx="1/1/9"},
{ RegEddr=3203, count=4, regType="int64", knx="1/1/10"},
}
function readRegisters()
for idx, register in pairs(regTable) do
if register.regType=="int" then
valueInt = mb:readregisters(register.RegEddr)
grp.write(register.knx, valueInt)
elseif register.regType=="float" then
value1, value2 = mb:readregisters(register.RegEddr,register.count)
if value1 then
valueFloat = bit.lshift(value1, 16) + value2
valueFloat = lmcore.inttohex(valueFloat, 4)
valueFloat = knxdatatype.decode(valueFloat, dt.float32)
grp.write(register.knx, valueFloat)
end
elseif register.regType=="int64" then
valueInt1, valueInt2, valueInt3, valueInt4 = mb:readregisters(register.RegEddr,register.count)
if valueInt4 then
valueInt64 = valueInt4
log(valueInt64)
grp.write(register.knx, valueInt64)
end
end
end --end for
end --end function
from another script I call function readRegisters()
so I have list of addresses, but I don't know how many addresses user will need. if 10 or 100. That's the reason why it's not optimal to have list of addresses but dynamic list with +1 step
1/1/1
1/1/2
...
1/1/255
It's possible to help me how create dynamically add addresses variable knx
to this table?
Upvotes: 4
Views: 1287
Reputation: 8000
You need a register allocator function that takes into account the address and size of the last register. This allocator will dynamically create new registers as you request them.
local startAddr = 3000
local sizes = {float = 2, int = 2, int64 = 4}
local registers = {}
local function allocRegister(type)
if sizes[type] == nil then
error'invalid register type'
end
local n = #registers
local addr
if n == 0 then -- If this is the first register, use the starting address.
addr = startAddr
else -- Determine the next starting address based on the last register's address & size.
addr = registers[n].addr + registers[n].count
end
table.insert(registers, { addr = addr, count = sizes[type], type = type, knx = '1/1/' .. n + 1 })
end
-- Example usage:
allocRegister'float'
allocRegister'int64'
allocRegister'int'
-- Resulting table:
{
{ addr = 3000, count = 2, knx = "1/1/1", type = "float" },
{ addr = 3002, count = 4, knx = "1/1/2", type = "int64" },
{ addr = 3006, count = 2, knx = "1/1/3", type = "int" }
}
You could use this function in a loop just as well, too. The following loop would create a register table very similar to the one in your question.
for i=1, 9 do allocRegister'float' end
allocRegister'int64'
Edit: The following code should be illustrative enough to show you how to solve your problem.
local sizes = {float = 2, int = 2, int64 = 4}
local registers = {}
local usedSpace = {}
local function allocRegisters(t)
for i=1, #t do
local addr, size = t[i].addr, sizes[t[i].type]
if size == nil then
error('invalid register type: ' .. t[i].type)
end
-- Check if there's free space for this register.
for j=addr, addr+size-1 do
if usedSpace[j] then
error('address already in use: ' .. addr)
end
end
-- Mark the space for this register as used.
for j=addr, addr+size-1 do
usedSpace[j] = true
end
-- Copy the register into the registers table, setting knx by using the length of the table.
table.insert(registers, { addr = addr, count = size, type = t[i].type, knx = '1/1/' .. #registers + 1})
end
end
-- Example usage:
allocRegisters {
{ addr = 3000, type = 'float' },
{ addr = 3003, type = 'int' },
{ addr = 3009, type = 'int64' }
}
Upvotes: 1
Reputation: 29601
So you want to dynamically create the regTable, with the knx being dynamically generated as '1/1/n' where n is creation order. Presumably you also want count to be automatically computed based on register type. It looks as though the addresses can be assigned in any order, but they do have to be consistent with register type size. So how about this:
local counts = {float = 2, int = 2, int64 = 4}
local regTable = {}
local function newRegister(addr, regType)
local count = counts[regType]
if count == nil then
error 'invalid register type'
end
checkAddrVsCount(addr, count) -- verify that addr is ok
local tableSize = #regTable
knx = '1/1/' .. (tableSize+1)
regTable.insert {RegEddr=addr, count=count, regType=regType, knx=knx}
end
The checkAddrVsCount(addr, count)
checks whether addr is valid. For example,
RegEddr=addr
, error (addr already in table)Upvotes: 0