Lua循环创建表中的变量

4

我遇到了关于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`到这个表中”。 - Oliver
2个回答

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 感谢您的回答,Ryan。您所写的内容应该用于读取所有寄存器。但是我有一个特定的寄存器列表,不是一个接一个地列出来的...请参见3003、3009。因此,地址和类型是从用户输入的,并且基于此,我想创建一个regTable,其中包含从1/1/1到我读取的寄存器数量自动添加的地址。 - user3159120
你说得没错。用户只调用你发送的函数。或者更好的方法是使用具有寄存器和类型的表格,并使用这些参数调用函数。如果你有20个寄存器,那么在20行上调用20次函数并不太好。 - user3159120
我已经更新了我的答案,提供了更适合你所需的内容。你可以通过传递一个表格给一个函数调用来代替20个函数调用。 - Ryan Stein
我该说什么呢... 真是太棒了!我使用了你的代码和脚本的其余部分,完美地运行了。谢谢你。 - user3159120
不用客气。如果这个答案完全解决了你的问题,请在旁边勾选绿色复选标记,将其选择为所选答案。 - Ryan Stein
显示剩余2条评论

0

所以你想动态创建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) 检查地址是否有效。例如,

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接