【问题标题】:Lua loop for creating variables in table用于在表中创建变量的 Lua 循环
【发布时间】:2014-01-05 23:03:32
【问题描述】:

我有循环问题,Lua 中的表格 这是带有变量knx 的表(现在它是静态的)

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

从另一个脚本我调用函数readRegisters() 所以我有地址列表,但我不知道用户需要多少地址。如果是 10 或 100。这就是为什么拥有地址列表而不是 +1 步的动态列表不是最佳的原因

1/1/1
1/1/2
...
1/1/255

可以帮我如何创建动态添加地址变量knx到这个表吗?

【问题讨论】:

  • 不明白这是什么意思:“如何创建动态添加地址变量knx`到这个表”

标签: loops lua lua-table


【解决方案1】:

您需要一个考虑最后一个寄存器的地址和大小的寄存器分配器函数。此分配器将根据您的请求动态创建新寄存器。

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

您也可以在循环中使用此函数。以下循环将创建一个与您问题中的非常相似的注册表。

for i=1, 9 do allocRegister'float' end
allocRegister'int64'

编辑:以下代码应该足以说明如何解决您的问题。

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

【讨论】:

  • 感谢瑞恩的回答。你写的应该用于读取所有寄存器。
  • @RaynStein 感谢瑞恩的回答。您所写的内容应用于读取所有寄存器。但是我有特定的寄存器列表,它们不是一一对应的……请参阅 3003、3009。所以地址和类型是用户输入的,基于此我想创建 regTable 并从 1/1/1 自动添加地址计算我读过的寄存器。
  • 所以您的用户需要执行类似allocRegister('float', 3003) 的操作,其中'float' 是类型,3003 是新寄存器的地址?
  • 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 太好了。
  • 我已经用一些可能更适合你想要的东西更新了我的答案。您可以将一个表传递给一个函数调用,而不是 20 个函数调用。
【解决方案2】:

因此,您希望动态创建 regTable,knx 动态生成为“1/1/n”,其中 n 是创建顺序。大概您还希望根据寄存器类型自动计算计数。看起来好像可以按任何顺序分配地址,但它们必须与寄存器类型大小一致。那么这个怎么样:

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

checkAddrVsCount(addr, count) 检查 addr 是否有效。对于示例

  • 如果 regTable 包含具有RegEddr=addr 的条目,则错误(地址已在表中)
  • else 查找与 addr 最接近的较小 RegEddr 的条目,并检查间隙是否至少为找到的条目类型(不是新条目的类型)的 counts[type]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多