Logic Machine Forum
LM as a Modbus slave : number of slaves - Printable Version

+- Logic Machine Forum (https://forum.logicmachine.net)
+-- Forum: LogicMachine eco-system (https://forum.logicmachine.net/forumdisplay.php?fid=1)
+--- Forum: Gateway (https://forum.logicmachine.net/forumdisplay.php?fid=10)
+--- Thread: LM as a Modbus slave : number of slaves (/showthread.php?tid=4182)



LM as a Modbus slave : number of slaves - SigmaTec - 08.08.2022

Hi,

dear Admin, did you confirm than it is possible to create only one slave at the save time on the same LM ?
No way to increase it ?

Have a good day.


RE: LM as a Modbus slave : number of slaves - admin - 08.08.2022

In TCP mode you can have multiple slave scripts but they must use different ports (e.g. 502, 503 etc). In RTU mode only one slave is supported at the moment.


RE: LM as a Modbus slave : number of slaves - SigmaTec - 08.08.2022

Thank's !


RE: LM as a Modbus slave : number of slaves - SigmaTec - 09.08.2022

(08.08.2022, 13:08)admin Wrote: In TCP mode you can have multiple slave scripts but they must use different ports (e.g. 502, 503 etc). In RTU mode only one slave is supported at the moment.

Hi Admin,

Ok, I understood the principle. But how to decompose the cyclic script which sets the port (eg. 502) and the slave id (eg. 2) into several slave scripts with different ports?

How will the mbConfusedetregisters() function find its way?

Code:
-- modbus init cyclic script

if not mb then


require('luamodbus')

-->>>>>>>>>Modbus slave setting<<<<<<<<<<<<<<<<<<<<<<<<
 
------------------------------------------------------
-- Pour Modbus RTU
------------------------------------------------------
--mb = luamodbus.rtu()
--mb:open('/dev/RS485', 19200, 'E', 8, 1, 'H')
--mb:connect()
------------------------------------------------------
-- Pour Modbus TCP
------------------------------------------------------
mb = luamodbus.tcp()
mb:open('0.0.0.0', 502)
------------------------------------------------------ 

-->>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 
 
-- slave id
mb:setslave(2)
 
-- init slave storage for coils, discrete inputs, holding registers and input registers
mb:setmapping(1, 1, 3300, 1)

  --*****************************************************
-- >>>>>>>>>>>Coil write callback<<<<<<<<<<<<<<<<<<<<<<
mb:setwritecoilcb(function(coil, value)
if coil == 0 then
grp.write('0/0/12', value, dt.bool)
else
alert('coil: %d = %s', coil, tostring(value))
end
end)
--*****************************************************
-->>>>>>>>>>>Register write callback<<<<<<<<<<<<<<<<<<<
mb:setwriteregistercb(function(register, value)
if register == 0 then
-- send value limited to 0..100
grp.write('0/0/13', math.min(100, value), dt.scale)
else
alert('register: %d = %d', register, value)
end
end)
--*****************************************************
end
-- server part init
if not server then
log("Modbus slave handler (cyclic) : IN...server init")
require('rpc')
-- incoming data handler
local handler = function(request)
local fn, res
fn = tostring(request.fn)
if not mb[ fn ] then
return { nil, 'unknown function ' .. fn }
end
if type(request.params) == 'table' then
table.insert(request.params, 1, mb)
res = { mb[ fn ](unpack(request.params)) }
else
res = { mb[ fn ](mb) }
end
return res
end
server = rpc.server('127.0.0.1', 28002, 'mbproxy', handler, 0.01)
log("Modbus slave handler (cyclic) : OUT...handleslave = ")
end
res, err = mb:handleslave()
res, err = server:step()

Thank's for your time....


RE: LM as a Modbus slave : number of slaves - admin - 09.08.2022

If you only need read-only values on the modbus side you can simply periodically update the register values in the resident script itself. Modify register mapping in updateregisters() as needed. Each script must use a unique port (502, 503 etc).
Code:
if not mb then
  require('luamodbus')
  mb = luamodbus.tcp()

  mb:open('0.0.0.0', 502)
  mb:setslave(2)

  function setint64(grpaddr, regaddr)
    local value = grp.getvalue(grpaddr) or 0
    local raw = knxdatatype.encode(value, dt.int64).dataraw
    local r1 = raw:byte(2) * 0x100 + raw:byte(1)
    local r2 = raw:byte(4) * 0x100 + raw:byte(3)
    local r3 = raw:byte(6) * 0x100 + raw:byte(5)
    local r4 = raw:byte(8) * 0x100 + raw:byte(7)

    mb:setregisters(regaddr, r4, r3, r2, r1)
  end

  function updateregisters()
    setint64('32/1/1', 3204)
  end

  mb:setmapping(0, 0, 3300, 0)
  updateregisters()

  prev = os.time()
end

mb:handleslave()

curr = os.time()
if curr ~= prev then
  updateregisters()
  prev = curr
end



RE: LM as a Modbus slave : number of slaves - SigmaTec - 09.08.2022

(09.08.2022, 06:27)admin Wrote: If you only need read-only values on the modbus side you can simply periodically update the register values in the resident script itself. Modify register mapping in updateregisters() as needed. Each script must use a unique port (502, 503 etc).
Code:
if not mb then
  require('luamodbus')
  mb = luamodbus.tcp()

  mb:open('0.0.0.0', 502)
  mb:setslave(2)

  function setint64(grpaddr, regaddr)
    local value = grp.getvalue(grpaddr) or 0
    local raw = knxdatatype.encode(value, dt.int64).dataraw
    local r1 = raw:byte(2) * 0x100 + raw:byte(1)
    local r2 = raw:byte(4) * 0x100 + raw:byte(3)
    local r3 = raw:byte(6) * 0x100 + raw:byte(5)
    local r4 = raw:byte(8) * 0x100 + raw:byte(7)

    mb:setregisters(regaddr, r4, r3, r2, r1)
  end

  function updateregisters()
    setint64('32/1/1', 3204)
  end

  mb:setmapping(0, 0, 3300, 0)
  updateregisters()

  prev = os.time()
end

mb:handleslave()

curr = os.time()
if curr ~= prev then
  updateregisters()
  prev = curr
end

Sorry Admin, using your script (without modify it, except '32/1/1') no communication with Modbus master is possible.
Note : I suspended cyclic "Modbus handler" script and preserved "mbproxy" script in common functions.

Perhaps interesting for you 'timeout ?' > founded by monotoring in log : 

res, err = mb:handleslave()
log("mb:handleslave :",res,err)
* arg: 1
  * string: mb:handleslave :
* arg: 2
  * nil
* arg: 3
  * string: timeout


RE: LM as a Modbus slave : number of slaves - admin - 09.08.2022

First, check the Error log for any errors.
You can use this test script for reading from local TCP slave with port 502 (check Logs tab for the read result or any errors):
Code:
require('luamodbus')

mb = luamodbus.tcp()
mb:open('127.0.0.1', 502)
res, err = mb:connect()

if res then
  val, err = mb:readregistervalue(3204, 'int64', 'b')
  
  if val then
    log('read ok', val)
  else
    log('read failed', err)
  end
else
  log('connect failed', err)
end

mb:close()



RE: LM as a Modbus slave : number of slaves - SigmaTec - 09.08.2022

(09.08.2022, 10:11)admin Wrote: First, check the Error log for any errors.
You can use this test script for reading from local TCP slave with port 502 (check Logs tab for the read result or any errors):
Code:
require('luamodbus')

mb = luamodbus.tcp()
mb:open('127.0.0.1', 502)
res, err = mb:connect()

if res then
  val, err = mb:readregistervalue(3204, 'int64', 'b')
 
  if val then
    log('read ok', val)
  else
    log('read failed', err)
  end
else
  log('connect failed', err)
end

mb:close()

Result : 
* arg: 1
  * string: connect failed
* arg: 2
  * string: Connection refused

But to be sure we are on the same subject :
my deal is to use LM as Modbus slave in order to write in it some registers which will be read by a master.


RE: LM as a Modbus slave : number of slaves - admin - 09.08.2022

"Connection refused" means that either your slave script is not running or it's not using port 502. The test script is a master that checks if a local slave is running or not.


RE: LM as a Modbus slave : number of slaves - SigmaTec - 09.08.2022

(09.08.2022, 11:30)admin Wrote: "Connection refused" means that either your slave script is not running or it's not using port 502. The test script is a master that checks if a local slave is running or not.

I use your previous script, that I run. Then I run your test script.
Did I make a mistake ?

Code:
if not mb then
  require('luamodbus')
  mb = luamodbus.tcp()

  mb:open('0.0.0.0', 502)
  mb:setslave(2)

  function setint64(grpaddr, regaddr)
    local value = grp.getvalue(grpaddr) or 0
    local raw = knxdatatype.encode(value, dt.int64).dataraw
    local r1 = raw:byte(2) * 0x100 + raw:byte(1)
    local r2 = raw:byte(4) * 0x100 + raw:byte(3)
    local r3 = raw:byte(6) * 0x100 + raw:byte(5)
    local r4 = raw:byte(8) * 0x100 + raw:byte(7)

    mb:setregisters(regaddr, r4, r3, r2, r1)
  end

  function updateregisters()
    setint64('32/1/1', 3204)
  end



RE: LM as a Modbus slave : number of slaves - admin - 09.08.2022

You're missing a part of the slave script. It should have at least 35 lines, you've posted only 21.


RE: LM as a Modbus slave : number of slaves - SigmaTec - 09.08.2022

(09.08.2022, 11:35)admin Wrote: You're missing a part of the slave script. It should have at least 35 lines, you've posted only 21.

yes, it was only the first lines...
Here is full !
Code:
if not mb then
  require('luamodbus')
  mb = luamodbus.tcp()
 
  res, err = mb:open('0.0.0.0', 502)
  log("mb:open :",res,err)
  res, err = mb:setslave(2)
  log("mb:setslave :",res,err)
 
  log("Modbus slave IN : 502/2")
  function setint64(grpaddr, regaddr)
    local value = grp.getvalue(grpaddr) or 0
    local raw = knxdatatype.encode(value, dt.int64).dataraw
    local r1 = raw:byte(2) * 0x100 + raw:byte(1)
    local r2 = raw:byte(4) * 0x100 + raw:byte(3)
    local r3 = raw:byte(6) * 0x100 + raw:byte(5)
    local r4 = raw:byte(8) * 0x100 + raw:byte(7)

    res, err = mb:setregisters(regaddr, r4, r3, r2, r1)
    log("mb:setregisters :",res,err)
  end

  function updateregisters()
    setint64('0/0/14', 3204)
  end

  mb:setmapping(0, 0, 3300, 0)
  updateregisters()
 
  prev = os.time()
end

mb:handleslave()

curr = os.time()
if curr ~= prev then
  updateregisters()
  prev = curr
end
log("Modbus slave OUT : 502/2")



RE: LM as a Modbus slave : number of slaves - admin - 09.08.2022

Works for me.


RE: LM as a Modbus slave : number of slaves - SigmaTec - 09.08.2022

(09.08.2022, 12:25)admin Wrote: Works for me.

Congratulations ;-)

For me :
mbproxy = {} is in common fuctions
no cyclic script as in my first post
your script for one objet/port

And nothing...


RE: LM as a Modbus slave : number of slaves - admin - 09.08.2022

What do you mean by "no cyclic script"? Each TCP slave runs in a separate resident script with 0 sleep time.


RE: LM as a Modbus slave : number of slaves - SigmaTec - 09.08.2022

(09.08.2022, 12:46)admin Wrote: What do you mean by "no cyclic script"? Each TCP slave runs in a separate resident script with 0 sleep time.
Yes, Admin, that's what I understood from analyzing the scripts. 

I discover your answer after everything works in resident script ! 
Sorry for the response time: I had no Internet for 3 hours (fiber optic installation in progress)


Question : Is there a limit in number of resident scripts with sleep time 0?


Thank you once again for your precious help and your patience...


RE: LM as a Modbus slave : number of slaves - admin - 09.08.2022

There's no exact limit on how many scripts can run no matter what the sleep time is set to. All scripts consume some amount of RAM but it's quite hard to hit this limit in normal use cases.

Modbus script is in sleeping state most of time anyway when it's waiting for a client to connect. 0 sleep time should avoided for busy loops which consume all CPU resources.


RE: LM as a Modbus slave : number of slaves - SigmaTec - 09.08.2022

Perfect Admin !
Have a good evening.