Example: LM as Modbus TCP Slave, interconnection with PLC

Task

Interconnect LogicMachine with PLC and HMI panel over Modbus TCP.

Resident script

Sleep time = 0. It only supports binary objects as coils and 1-byte / 2-byte integer objects as registers. Number of coils and registers is not limited, object mapping can be set by filling coils, registers and regdt tables.

Source code    
  1. if not mb then
  2.   require('genohm-scada.eibdgm')
  3.   require('luamodbus')
  4.  
  5.   -- list of coil mapping, starting from 0
  6.   coils = { '1/1/1', '1/1/2' }
  7.  
  8.   -- list of register mapping, starting from 0
  9.   registers = { '2/2/2', '3/3/3' }
  10.  
  11.   -- list of register data types, element count must match registers table
  12.   regdt = { dt.int8, dt.uint16 }
  13.  
  14.   -- knx group write callback
  15.   function knxgroupwrite(event)
  16.     local value
  17.  
  18.     -- try to find matching coil
  19.     for id, addr in ipairs(coils) do
  20.       if event.dst == addr then
  21.         value = knxdatatype.decode(event.datahex, dt.bool)
  22.         mb:setcoils(id - 1, value)
  23.       end
  24.     end
  25.  
  26.     -- try to find matching register
  27.     for id, addr in ipairs(registers) do
  28.       if event.dst == addr then
  29.         value = knxdatatype.decode(event.datahex, regdt[ id ])
  30.         mb:setregisters(id - 1, value)
  31.       end
  32.     end
  33.   end
  34.  
  35.   -- coil write callback
  36.   function mbwritecoils(coil, value)
  37.     local addr = coils[ coil + 1 ]
  38.     if addr then
  39.       grp.write(addr, value, dt.bool)
  40.     end
  41.   end
  42.  
  43.   -- register write callback
  44.   function mbwriteregisters(register, value)
  45.     local addr = registers[ register + 1 ]
  46.     if addr then
  47.       grp.write(addr, value, regdt[ register + 1])
  48.     end
  49.   end
  50.  
  51.   -- knx group monitor, handles group writes
  52.   knxclient = eibdgm:new({ timeout = 0.1 })
  53.   knxclient:sethandler('groupwrite', knxgroupwrite)
  54.  
  55.   -- modbus slave, listen on all interfaces and default port 502
  56.   mb = luamodbus.tcp()
  57.   mb:open('0.0.0.0', 502)
  58.  
  59.   -- setting slave id is optional
  60.   -- mb:setslave(1)
  61.  
  62.   mb:setreceivetimeout(0.1)
  63.   mb:setmapping(#coils, 0, #registers, 0)
  64.  
  65.   -- init coils
  66.   for id, addr in ipairs(coils) do
  67.     value = grp.getvalue(addr)
  68.     mb:setcoils(id - 1, value)
  69.   end
  70.  
  71.   -- init registers
  72.   for id, addr in ipairs(registers) do
  73.     value = grp.getvalue(addr)
  74.     mb:setregisters(id - 1, value)
  75.   end
  76.  
  77.   -- set callbacks for coil and register write
  78.   mb:setwritecoilcb(mbwritecoils)
  79.   mb:setwriteregistercb(mbwriteregisters)
  80. end
  81.  
  82. -- handle modbus and knx
  83. mb:handleslave()
  84. knxclient:loop(0.1)