4

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?

1
  • Don't understand what this means: "how create dynamically add addresses variable knx` to this table" Commented Jan 4, 2014 at 6:12

2 Answers 2

1

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' }
}
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks for answer Ryan. What you write should be used for reading all registers.
@RaynStein Thanks for answer Ryan. What you write should be used for reading all registers. But I have specific list of registers which is not in a one by one ... see 3003, 3009. So addresses and type is input from user and based on this I would like create regTable with automatically added addresses from 1/1/1 to count of registers which I read.
So your users would need to do something like allocRegister('float', 3003) where 'float' is the type and 3003 is the address where the new register should go?
youre definitely right. user only call function what you send. or better should be to have table with registers and types and call function with this parameters. if you have 20 registers call 20x function on 20 lines isnt too ok.
I've updated my answer with something that may be more suitable for what you want. Instead of 20 function calls, you could pass a table to one function call.
|
0

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.