Question

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?

Was it helpful?

Solution

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' }
}

OTHER TIPS

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,

  • if regTable contains an entry that has RegEddr=addr, error (addr already in table)
  • else find entry that is closest smaller RegEddr to addr, and check that the gap is at least counts[type] for found entry's type (not the new entry's type)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top