AdvancedHMI Software
General Category => Support Questions => Topic started by: ianfinlay_aus on September 04, 2015, 04:35:19 AM
-
Hi Support,
I am on my first advancedHMI project - so apologies in adv. for not knowing much about your product
I have an application which is a underwater thruster testing station (units are sealed and modbus ID is not always documented)
so need to poll device each address 1-254 sequentially and function read address 40001
The problem is I don't have access to the timeout, and it takes a REALLY long time to get through all the polls,
whereas in Python code is extremely fast (I am trying to get rid of the Python)
Below is what I have tried:
(Is there anything else I can try? have played with as I imagine I need to adjust the timeout, but this isn't exposed)
Private Sub BtnFindModbusId_Click(sender As Object, e As EventArgs) Handles Button4.Click
Try
'adress 1-254
Dim bFound As Boolean = False
ModbusRTUComFind.PollRateOverride = 100
For id As Byte = 1 To 254
ModbusRTUComFind.StationAddress = id
Try
lblFindStatus.Text = String.Format("Try ID={0}", id)
Dim sVal As String = ModbusRTUComFind.Read("40001")
'if unable to read generates exception here ^^^
bFound = True
tbFoundId.Text = id.ToString()
Exit For
Catch ex As Exception
'not read from device, so try next
End Try
Next
Catch ex As Exception
End Try
End Sub
Any guidance appreciated
-
Try this to see if it works:
- Edit AdvancedHMIDrivers\Modbus\ModbusBase.vb
- Go to line 638
Private MaxTicks As Integer = 300 '* 100 ticks per second
- Change the 300 (which is 3 seconds) to something lower
-
Thanks for getting back so fast
I exposed a function in ModbusBase.vb:
#Region "Public Methods"
Public Sub SetResponseWait(imSec As Integer)
Try
'default = 300 (3sec)
'1 tick = 10msec (i.e. 100 ticks per second)
MaxTicks = Convert.ToInt32(imSec / 10)
Catch ex As Exception
End Try
End Sub
#End Region
Test1:
I only have one device on test at ID 123, if I do read requests on id=123 for 1000 times before I start the discovery method (below) I get valid read responses,
but then inside the discovery method even id=123 does not respond to a read()
Test 2:
restart program
If however I call modbus id 1-122 (non of which exist) and then follow by calling modbus id 123 (exists) , even 123 does not respond and generates an exception from the Read() call (same exception as though it doesn't exist "No Response from the PLC, Ensure driver settings are correct."
Must be something residual, between changing modbus id, and successive reads that needs top be reset
(unfortunately, cant find a similar forum thread dealing with this, as generally modbus id is hard coded, unless in a redundancy situation, when need to fail-over to another modbus plc)
Baud rate is 115200, which gets back pretty fast when talking to the device
My Discovery Code:
Private Sub BtnFindModbusId_Click(sender As Object, e As EventArgs) Handles Button4.Click
Try
'adress 1-254
Dim bFound As Boolean = False
Timer1.Enabled = True
For id As Byte = 1 To 254
ModbusRTUComFind.StationAddress = id
ModbusRTUComFind.SetResponseWait(50) ' 500msec, must set every timeout, as base code sets to 100, after a timeout
Try
sTestingId = String.Format("Try Modbus ID={0}", id)
Application.DoEvents()
Dim sVal() As String = ModbusRTUComFind.Read("40001", 1)
'if unable to read generates exception here ^^^
bFound = True
tbFoundId.Text = id.ToString()
Exit For
Catch ex As Exception
'not read from device, so try next
Thread.Sleep(100)
End Try
Thread.Sleep(50)
Next
Timer1.Enabled = False
ModbusRTUComFind.SetResponseWait(300) 'return to default
Catch ex As Exception
End Try
End Sub
-
Can you run a serial port monitor and post the results of the capture?
-
OK Solved it! after a day of hacking
Had to modify core to achive it:
a) modbusbase.vb:
#Region "Public Methods"
Public Sub SetResponseWait(imSec As Integer)
Try
'default = 300 (3sec)
'1 tick = 10msec (i.e. 100 ticks per second)
MaxTicks = Convert.ToInt32(imSec / 10)
Catch ex As Exception
End Try
End Sub
Public Function GetResponseWait() As Integer
Return MaxTicks
End Function
#End Region
b) ModbusRTUCom.vb Added:
Note: The NEXT execution of SendRequest() will then call CreateDLLInstance() to create a new instance , problem seemed to be recycling teh existing instance of the dll whilst changing the modbus id
Public Sub RemoveAllDLLConnection()
Dim instance As Integer = MyDLLInstance
'* The handle linked to the DataLink Layer has to be removed, otherwise it causes a problem when a form is closed
If DLL.ContainsKey(instance) AndAlso DLL(instance) IsNot Nothing Then
RemoveHandler DLL(instance).DataReceived, AddressOf DataLinkLayerDataReceived
RemoveHandler DLL(instance).ComError, AddressOf DataLinkLayerComError
RemoveHandler DLL(instance).ConnectionEstablished, AddressOf DataLinkLayerConnectionEstablished
EventHandlerDLLInstance = 0
DLL(instance).ConnectionCount -= 1
If DLL(instance).ConnectionCount <= 0 Then
DLL(instance).Dispose()
DLL(instance) = Nothing
Dim x As MfgControl.AdvancedHMI.Drivers.ModbusRTU.ModbusRTUDataLinkLayer = Nothing
DLL.TryRemove(instance, x)
End If
End If
End Sub
c) Winform code:
Private sTestingId As String = ""
Private sRetry As String = ""
Private sTestDuration As String = ""
Private Sub BtnFindModbusId_Click(sender As Object, e As EventArgs) Handles Button4.Click
Try
'adress 1-254
Dim bFound As Boolean = False
Dim iRetry As Integer = 0
'Timer1.Enabled = True
Dim tStart As DateTime = DateTime.MinValue
Dim tEnd As DateTime = DateTime.MinValue
tStart = DateTime.Now
Const RETRY_MAX As Integer = 1
Const SCAN_ID_MIN As Integer = 119
Const SCAN_ID_MAX As Integer = 254
For id As Byte = SCAN_ID_MIN To SCAN_ID_MAX
iRetry = 0
ModbusRTUComFind.PollRateOverride = 100
ModbusRTUComFind.StationAddress = id
Application.DoEvents()
For i As Integer = 0 To (RETRY_MAX - 1)
Try
ModbusRTUComFind.SetResponseWait(100)
sTestingId = String.Format("Read Id={0}, Tag={1}", id.ToString(), "40001")
sRetry = String.Format("Try {0}/{1}", i + 1, RETRY_MAX)
Dim sVal As String = ModbusRTUComFind.Read("40001")
'if unable to read generates timeout exception here ^^^
bFound = True
tbFoundId.Text = id.ToString()
Catch ex As Exception
'not read from device, so try next
Thread.Sleep(100)
End Try
Dim bIdReceived As Byte = ModbusRTUComFind.GetModbusId_ReceivedLast()
If (bIdReceived > 0) Then
ModbusRTUComFind.SetModbusId_ReceivedLast(0)
bFound = True
bMOdbus_FoundId = bIdReceived
Application.DoEvents()
Exit For
End If
ModbusRTUComFind.RemoveAllDLLConnection()
Next
If bFound Then
Exit For
End If
Thread.Sleep(100)
Next
tEnd = DateTime.Now
Dim tDiff As TimeSpan = tEnd - tStart
sTestDuration = String.Format("Duration = {0} sec", tDiff.TotalSeconds)
If bFound Then
sTestingId = String.Format("End Test: Found @ {0}", bMOdbus_FoundId)
Else
sTestingId = String.Format("End Test: Not Found in range [{0}-{1}]", SCAN_ID_MIN, SCAN_ID_MAX)
End If
'Timer1.Enabled = False
Application.DoEvents()
ModbusRTUComFind.SetResponseWait(300) 'return to default
Catch ex As Exception
End Try
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Try
lblFindStatus.Text = sTestingId
lblRetry.Text = sRetry
tbFoundId.Text = bMOdbus_FoundId.ToString()
lblDuration.Text = sTestDuration
Catch ex As Exception
End Try
End Sub
-
I'm still not quite sure why this made it work. I checked the StationAddress and the only place it is used is in the SendRequest function for creating a new RTU frame. The value is pushed to the DLL, but it is not used at all.
On another note, the line where you set the PollRateOverride may not apply for your code unless you are using subscriptions some where else in your code. That value is used to determined the delay in between requests of the subscriptions.
-
Hi Archie,
design time:
modbus rtu control property 'Disable Subscription' = false
I found that without the previous call, I would only get a response from the device (@address 123) being processed when I was already queueing read requests for device 129 or device 130, some latency added in queue
but haven't access to this code
I wanted to add a trace of protocol on code, but the dll doesnt have source code (MfgControl.AdvancedHMI.drivers.dll)
Is it possible to get it?
-
I think I know what is happening. When you delete the DLL instance, it clears the Que and closed the port. Otherwise each packet will attempt to be sent 2 times with a delay in between, so when you send the next request the first probably still has not cleared the que.
-
design time:
modbus rtu control property 'Disable Subscription' = false
I found that without the previous call, I would only get a response from the device (@address 123) being processed when I was already queueing read requests for device 129 or device 130, some latency added in queue
Are you using visual controls that are linked to the driver? If so, these are creating the subscriptions.
I will create a new project for the Modbus drivers and publish the complete code.
-
I sincerely appreciate your efforts
-
You can download the complete source for the ModbusRTU driver from here:
https://sourceforge.net/projects/modbusrtu
I think the area you are interested in is ModbusRTUDataLinkLayer.vb in the SendQueProcessor subroutine. In this code:
While i < WaitCycles And (Not ResponseReceived And Not ChecksumFailed)
'* Wait for 2xInterpacketDelay (7 characters of time)
System.Threading.Thread.Sleep(SleepTime)
'* Once the data stream started coming, change our wait
If WaitCycles = 1500 AndAlso ReceivedDataPacket.Count > 0 Then
i = 0
WaitCycles = 600
End If
i += 1
End While
-
Hi Archie,
I am a little confused, how does the above ModbusRTU project fits into the AdvancedHMI 3.5 solution (v398t or v399)?
I can only see the following DLL's that don't have source code for in project AdvancedHMI:
a) ..\AdvancedHMIControls\Support\MfgControl.AdvancedHMI.Controls.dll
b) ..\AdvancedHMIDrivers\Support\MfgControl.AdvancedHMI.Drivers.dll
something is different as the new project uses .NET framework 4.5.2 and not 3.5
Thanks for your support
Ian
-
That project does not go back into AdvancedHMI. It is the Modbus driver from the AdvancedHMI project, but as a stand alone driver. I thought maybe you wanted to run your code against the driver and dig deeper into it to understand the problems you were seeing.
The full source code to the base DLLs are no longer published.
-
HI Archie,
Is there a way to purchase source for the Dll's, for maintenance purposes, much of my work requires me to enter into long term maintenance and support agreements,
and without full source I wouldn't be able to rebuild dll's in a new Visual Studio IDE's, .NET frameworks or O/S's (if and when they are released)
I Hope you understand
Sincerely
Ian
-
Is there a way to purchase source for the Dll's, for maintenance purposes, much of my work requires me to enter into long term maintenance and support agreements,
and without full source I wouldn't be able to rebuild dll's in a new Visual Studio IDE's, .NET frameworks or O/S's (if and when they are released)
I Hope you understand
Sincerely
Ian
Ian
I am sorry, but we just don't release the source to those DLLs. We maintain all updates to those underlying classes. There are a number of reasons for that including financial reasons to our company.
-
Hey Archie,
Thanks a lot for this standalone Modbus RTU drivers but if I'm not asking too much can we also get the ModbusTCP drivers the same way you released ModbusRTU drivers It makes for a very light weight Application and easy to tweak little things as per the project requirements.