AdvancedHMI Software
General Category => Support Questions => Topic started by: robkwan on June 26, 2019, 06:36:44 PM
-
Using AdvancedHMIv399xR1, DataSubscriber2 linked to ModbusTCPCom. I added a bunch of registers to DataSubscriber2, process the register value changes in DataSubscriber2_DataChanged. There are situation (random?) that a register value changed but the change does not pickup by DataSubscriber2_DataChanged; when this happens, DataSubscriber2_DataChanged does not report any more changes on that register but still does for other subscribed registers.
When the problem occurs, I switch to an error screen that displays some debug counters in DataSubscriber2_DataChanged and also manually read that register using modbusTCPCom.Read. The manual read reports the register value is changing but does not trigger DataSubscriber2_DataChanged because all debug counters did not change.
Any workaround?
-
Since 3.99x is a frozen version, I recommend trying 3.99y beta to see if the problem still exists. In that version it is possible to fix.
-
I am running AdvancedHMIv399yBeta33. Still the same problem. What would cause the DataSubscriber2 not to fire the DataChanged event. I confirmed that using a timer based read of the problem register had the value changed, but no callback from DataChanged event.
I am stuck. What can I try to debug this?
-
Maybe add another DataSubscriber2 and split the addresses 50:50 or just add the problematic register(s) to that second DataSubscriber2 component.
Or try changing the MaxReadGroupSize property of the driver, see here:
https://www.advancedhmi.com/forum/index.php?topic=393.msg12356#msg12356
-
It seems the problem is caused by having both discrete input registers (10000) and analog registers (30000) in the DataSubscriber2 subscription. I now separate the two register types into two DataSubscriber2 and the problem is not showing up. I will do more testing to ensure it is fixed.
Archie, can you confirm my finding (cannot mix register types in DataSubscriber2)?
-
I tested this with Beta 34 and not able to replicate it. I am using ModRSim2 with value animation and I get continuous updates.
What is the PollRateOverride value of the driver and how fast do the values change?
This is my test code in DataChanged:
Private Sub DataSubscriber21_DataChanged(sender As Object, e As Drivers.Common.PlcComEventArgs) Handles DataSubscriber21.DataChanged
If e.PlcAddress = "10001" Then
Label9.Text = Now() & " : 10001=" & e.Values(0)
End If
If e.PlcAddress = "30001" Then
Label10.Text = Now() & " : 30001=" & e.Values(0)
End If
End Sub
-
Could it be the total number of mixed registers that might be causing this issue?
robkwan, what is the exact number for each type that you initially had in the DataSubscriber2?
-
Probably the best option would be if you could provide all your driver settings (besides for the IP) and the list of all PLC addresses you had in the DataSubscriber2.
-
These were the mixed registers in DataSubscriber2
10039 - 10048, 10052, 30001- 30003, 30008, 30011 - 30014, 30041 - 30064, 30075
The problem register is 30001. I would get callback initially, but some random period later, no callback even thought the value had changed (confirmed by separate read).
The modbusTCPCom PollRateOverride is 500. The inputs are slow changing values. I did more testing this morning, could not reproduce the problem (with separate DataSubscriber2 for 10000 and 30000 registers).
-
Can you share the code you initially had in the DataChanged sub?
-
private void dataSubscriber2Std_DataChanged(object sender, MfgControl.AdvancedHMI.Drivers.Common.PlcComEventArgs e)
{
int nPLCAddress;
int iData;
if (!int.TryParse(e.PlcAddress, out nPLCAddress))
return;
if (nPLCAddress == TagAI.TAG_ActiveCS.nTag)
{
iData = int.Parse(e.Values[0]);
TagAI.TAG_ActiveCS.Value = iData;
labelActiveCSValue.Text = (iData == 1) ? ShareVar.TextUnit2 : ShareVar.TextUnit6;
ShareVar.ActiveCS = (ShareVar.bConsoleLocal) ? (iData == 1) : (iData == 2);
ledButtonLocal.LEDState = (iData == 1);
ledButtonRemote.LEDState = (iData == 2);
}
else if (nPLCAddress == TagAI.TAG_FwdLight.nTag)
{
iData = int.Parse(e.Values[0]);
TagAI.TAG_FwdLight.Value = iData;
gTrackBarHMIFwdLight.Value = iData;
gTrackBarHMIFwdLight.Label = ((int)BarValueToPercent[iData]).ToString() + "%";
if (TagAO.TAG_FwdLightNew.Value != iData)
{
TagAO.TAG_FwdLightNew.Value = iData;
modbusTCPComStd.Write(TagAO.TAG_FwdLightNew.sTag, e.Values[0]);
}
}
else if (nPLCAddress == TagAI.TAG_FwdIR.nTag)
-
What addresses do these tags point to:
TagAI.TAG_ActiveCS.nTag
TagAI.TAG_FwdLight.nTag
TagAI.TAG_FwdIR.nTag
-
TagAI is analog input type, 30000 series, specifically 30001, 30041, 30042.
That is just part of the code, the else if continues for each subscribed register.
The actual register number is irrelevant.
-
Your answer kind of suggests that you are subscribing to each address individually.
Have you tried grouping them, similar to the attached picture?
-
You already have a working solution, 2 instances of DataSubscriber2, so all this is just an attempt to find out what was causing the issue you had.
Your code will not work properly with subscriptions as I suggested in the previous post.
When these subscriptions are grouped then only the first address is reported back.
Here is an example of VB code to find out what value changed when subscribed within DataSubscriber2 to address 30001 with 3 elements:
Private previousValue As System.Collections.ObjectModel.Collection(Of String)
Private previousValueSet As Boolean
Private Sub DataSubscriber21_DataChanged(sender As Object, e As Drivers.Common.PlcComEventArgs) Handles DataSubscriber21.DataChanged
If e.ErrorId = 0 Then
'Values returned for addresses: 30001, 30002, 30003
If e.PlcAddress = "30001" Then
If previousValueSet Then
For i As Integer = 0 To e.Values.Count - 1
If previousValue(i) <> e.Values(i) Then
If i = 0 Then 'Address: 30001
MessageBox.Show("Value of address 30001 has changed from " & previousValue(i) & " to " & e.Values(i))
'Do something that this change triggers
ElseIf i = 1 Then 'Address: 30002
MessageBox.Show("Value of address 30002 has changed from " & previousValue(i) & " to " & e.Values(i))
'Do something that this change triggers
Else 'Address: 30003
MessageBox.Show("Value of address 30003 has changed from " & previousValue(i) & " to " & e.Values(i))
'Do something that this change triggers
End If
previousValue(i) = e.Values(i)
End If
Next
Else
'Initial read
previousValue = e.Values
previousValueSet = True
End If
End If
End If
End Sub
Or maybe slightly different:
Private Sub DataSubscriber21_DataChanged(sender As Object, e As Drivers.Common.PlcComEventArgs) Handles DataSubscriber21.DataChanged
If e.ErrorId = 0 Then
'Values returned for addresses: 30001, 30002, 30003
If e.PlcAddress = "30001" Then
If previousValueSet Then
For i As Integer = 0 To e.Values.Count - 1
If previousValue(i) <> e.Values(i) Then
MessageBox.Show("Value of address " & (CInt(e.PlcAddress) + i) & " has changed from " & previousValue(i) & " to " & e.Values(i))
'Do something that this change triggers by using 'CInt(e.PlcAddress) + i' as a condition in your code
previousValue(i) = e.Values(i)
End If
Next
Else
'Initial read
previousValue = e.Values
previousValueSet = True
End If
End If
End If
End Sub
In case if 00000 registers are added, one might consider padding the address in the message:
Private previousValues00001 As System.Collections.ObjectModel.Collection(Of String)
Private previousValues30001 As System.Collections.ObjectModel.Collection(Of String)
Private previousValues00001Set As Boolean
Private previousValues30001Set As Boolean
Private Sub DataSubscriber21_DataChanged(sender As Object, e As Drivers.Common.PlcComEventArgs) Handles DataSubscriber21.DataChanged
If e.ErrorId = 0 Then
'Values returned for addresses: 00001 to 00010
If e.PlcAddress = "00001" Then
If previousValues00001Set Then
For i As Integer = 0 To e.Values.Count - 1
If previousValues00001(i) <> e.Values(i) Then
MessageBox.Show("Value of address " & (CInt(e.PlcAddress) + i).ToString.PadLeft(5, "0"c) & " has changed from " & previousValues00001(i) & " to " & e.Values(i))
'Do something that this change triggers by using 'CInt(e.PlcAddress) + i' as a condition in your code
previousValues00001(i) = e.Values(i)
End If
Next
Else
'Initial read
previousValues00001 = e.Values
previousValues00001Set = True
End If
ElseIf e.PlcAddress = "30001" Then
'Values returned for addresses: 30001 to 30003
If previousValues30001Set Then
For i As Integer = 0 To e.Values.Count - 1
If previousValues30001(i) <> e.Values(i) Then
MessageBox.Show("Value of address " & (CInt(e.PlcAddress) + i) & " has changed from " & previousValues30001(i) & " to " & e.Values(i))
'Do something that this change triggers by using 'CInt(e.PlcAddress) + i' as a condition in your code
previousValues30001(i) = e.Values(i)
End If
Next
Else
'Initial read
previousValues30001 = e.Values
previousValues30001Set = True
End If
End If
End If
End Sub
-
The register numbers provided in the earlier post contain single and group. The group is just me too lazy to type them all. I subscribe programmatically rather than using the collector at design. And all registers are subscribed individually, hence I have "else if" for each one in the change event. I have Excel spreadsheet to track all the registers, then I column copy & paste to the tag cs file. It is easier for me to manage register number update with the single register method.
-
I have no other suggestions for you.
If you check Archie's reply in this topic:
https://www.advancedhmi.com/forum/index.php?topic=2505.0
it might suggest that too many subscriptions could have something misbehave or misfire.