This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

Modbus TCP Writes Fail after Reads
#1
Hi 

I am having some frustrating issues in determining what is happening with regards to writes failing after a previous read has occurred when using Lua Modbus. 

A Description of what is occuring. 

Using Lua a connection is opened and maintained to the modbus tcp slave. 

Values are first read from the device to determine its current state.  All read results are working fine with correct values returned from the device. 
Depending on values read a new value is written to the unit. and then the previous values are read again to verify the change has occurred.  

When run in this format - after the write registers occurs,  the logged result is 

arg: 1
nil
arg: 2
string: Operation timed out


and then the following reads  of values also return a Nil.  where they previously returned a values prior to write. 

The interesting result is if closing the connection and re-opening it, the value that was attempted to be written was successful.  as reading again on a new connection works just fine.

note i have tried using delays (sleep(1)) as example between each item it has made no impact. 

Code:
require('luamodbus')

mb = luamodbus.tcp()
mb:open('192.168.1.175', 1501)
res, err = mb:connect()
if res then
  log("connected!")
  mb:setslave(1)
local r6 = mb:readregistervalue(0xE004, "uint16", "n")
log('Mode = '.. tostring(r6))
    r6 = mb:readregistervalue(0xE008, "float32", "n")
log('Backup= '.. tostring(r6))
r6 = mb:readregistervalue(0xE00A, "uint16", "n")
log('Default = '.. tostring(r6))
  if (r6 == 1) then
res,err = mb:writeregisters(0xE00A, 7)
log(res,err)
      end
r6 = mb:readregistervalue(0xE004, "uint16", "n")
log('Mode = '.. tostring(r6))
r6 = mb:readregistervalue(0xE008, "float32", "n")
log('Backup = '.. tostring(r6))
  

else
  log('connect failed', err)
end

mb:close()


 
I have also Verified, that if  the only action is to do a connection and write it works correctly.

Code:
mb = luamodbus.tcp()
mb:open('192.168.1.175', 1501)
res, err = mb:connect()
if res then
res,err = mb:writeregisters(0xE00A, 7)
log(res,err)
else
  log('connect failed', err)
end



returns 
arg: 1
  number: 1
  arg: 2
  nil


Can anyone provide some assistance as to why this issue is occurring after a write event only when inside a single connection.  

I have thought that it might be just some form of time out,  but currently i can not find any documentation on luamodbus to increase timeout for write and read
Reply
#2
Seems like an issue in the Modbus device. If you say that creating new connection works fine then you can simply do reading first, then close the connection and open new one for writing when needed. But there might be another issue as some Modbus devices do not handle multiple connections well and do not correctly detect closed connections. So if you open one connection right after the first one is closed it might refuse it.
Reply
#3
(12.09.2022, 09:03)admin Wrote: Seems like an issue in the Modbus device. If you say that creating new connection works fine then you can simply do reading first, then close the connection and open new one for writing when needed. But there might be another issue as some Modbus devices do not handle multiple connections well and do not correctly detect closed connections. So if you open one connection right after the first one is closed it might refuse it.

That is the path i have chosen / forced  to implement,  at this time until I have more time to look and see what may be causing it, 

The device is permitting only single connection at a time, and correct a small delay between Open, Close , Open is more reliable.  

Why this is confusing is that using a Profile,  with a persistent connection, appears to work find for reading and writing hence i left wondering what's different using script.

I did not want to use a profile, as there is a sequence of steps to be taken when writing changes to the device including a read to validate successful execution of the changes,  thus i feel its too easy to screw up using a profile,  as there is no control over manual modification when in configurator.

Are there any debug commands for modbus,  or is it required to insert Wireshark on the port mirror to observer the packet transactions between Master and slave?
Reply
#4
You can use mb:setdebug() like in this example: https://forum.logicmachine.net/showthrea...0#pid27310
But if you get a timeout error I doubt that debug will give any useful information.
Reply
#5
I have implemented a Separate write and read function now,  

For the most part it is working well however I do get an issue occurring a few times a day where i fail to get a read back from some random register,  almost never the same regitser. 

When this occurs it was generally forcing my script to fail as i would attempt to do a calculation on a vil value as res from  res,err mb:readregistervalue(_address, _type, _mbOrder).  will return a nil for res,  

TO try and resolve this i wrote some extra code to retry see below

Code:
function tryReadRegister(_Address, _Type, _Oder)
local _Count = 0
local _Result
repeat
   _Count = _Count + 1 
  _Result, err = mb:readregistervalue(_Address, _Type, _Oder)
      if err then
       alert("Modbus Read Error of Type "..tostring(err).."For readregistervalue at Adress "..tostring(_Address).."For Data Type "..tostring(_Type)" and Order"..tostring(_Oder).." Attempt "..tostring(_Count).." Of 3")
         sleep(0.3)
      end
until ((_Count ==3) or _Result)
if not _Result then
            alert("Modbus Read Returned no Result Forced to 0")
      return 0
   else
      return _Result
   end
end

I chose for now to return a 0 to stop the script from failing and to try ID the cause. 

I also tried to improve the situation by delaying the read attempts in between by 300ms (i assumed it possible to put delays inside functions ?

Anyway turns out when the error occurs it is not improved by trying the same again with with a delay.

But the error returned on fail is  "method called on invalid context"  I have looked this up on the forum to find this may have something to do with float32 where the solution was for a profile.  to add "Value send delta"

The script above has been modified with the message to confirm that the failure is on random register address yes, but always on a float32.   I will run it again an wait to get a result. 


But in mean time any support on what could be the issue here would be helpful.
Reply
#6
"method called on invalid context" means that the connection is not open or already closed.
Both examples will produce this error:
Code:
mb = require('luamodbus').tcp()
mb:open(IP, PORT)
mb:connect()
mb:close()

res, err = mb:readregisters(0)

Code:
mb = require('luamodbus').tcp()
res, err = mb:readregisters(0)
Reply


Forum Jump: