Author Topic: Problem with ModbusTCPCom and DataSubscriber2  (Read 3525 times)

robkwan

  • Newbie
  • *
  • Posts: 44
    • View Profile
Problem with ModbusTCPCom and DataSubscriber2
« 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?

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5317
    • View Profile
    • AdvancedHMI
Re: Problem with ModbusTCPCom and DataSubscriber2
« Reply #1 on: June 26, 2019, 07:20:51 PM »
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.

robkwan

  • Newbie
  • *
  • Posts: 44
    • View Profile
Re: Problem with ModbusTCPCom and DataSubscriber2
« Reply #2 on: September 16, 2019, 05:46:05 PM »
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?

Godra

  • Hero Member
  • *****
  • Posts: 1446
    • View Profile
Re: Problem with ModbusTCPCom and DataSubscriber2
« Reply #3 on: September 16, 2019, 06:34:57 PM »
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
« Last Edit: September 17, 2019, 01:39:28 AM by Godra »

robkwan

  • Newbie
  • *
  • Posts: 44
    • View Profile
Re: Problem with ModbusTCPCom and DataSubscriber2
« Reply #4 on: September 17, 2019, 04:50:20 PM »
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)?


Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5317
    • View Profile
    • AdvancedHMI
Re: Problem with ModbusTCPCom and DataSubscriber2
« Reply #5 on: September 17, 2019, 09:33:48 PM »
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:
Code: [Select]
    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

Godra

  • Hero Member
  • *****
  • Posts: 1446
    • View Profile
Re: Problem with ModbusTCPCom and DataSubscriber2
« Reply #6 on: September 18, 2019, 12:16:40 AM »
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?

Godra

  • Hero Member
  • *****
  • Posts: 1446
    • View Profile
Re: Problem with ModbusTCPCom and DataSubscriber2
« Reply #7 on: September 18, 2019, 01:25:03 AM »
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.

robkwan

  • Newbie
  • *
  • Posts: 44
    • View Profile
Re: Problem with ModbusTCPCom and DataSubscriber2
« Reply #8 on: September 18, 2019, 11:18:10 AM »
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).

Godra

  • Hero Member
  • *****
  • Posts: 1446
    • View Profile
Re: Problem with ModbusTCPCom and DataSubscriber2
« Reply #9 on: September 18, 2019, 01:54:13 PM »
Can you share the code you initially had in the DataChanged sub?

robkwan

  • Newbie
  • *
  • Posts: 44
    • View Profile
Re: Problem with ModbusTCPCom and DataSubscriber2
« Reply #10 on: September 18, 2019, 03:01:37 PM »
        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)


Godra

  • Hero Member
  • *****
  • Posts: 1446
    • View Profile
Re: Problem with ModbusTCPCom and DataSubscriber2
« Reply #11 on: September 18, 2019, 10:50:42 PM »
What addresses do these tags point to:

TagAI.TAG_ActiveCS.nTag
TagAI.TAG_FwdLight.nTag
TagAI.TAG_FwdIR.nTag

robkwan

  • Newbie
  • *
  • Posts: 44
    • View Profile
Re: Problem with ModbusTCPCom and DataSubscriber2
« Reply #12 on: September 19, 2019, 10:22:03 AM »
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.

Godra

  • Hero Member
  • *****
  • Posts: 1446
    • View Profile
Re: Problem with ModbusTCPCom and DataSubscriber2
« Reply #13 on: September 19, 2019, 03:05:00 PM »
Your answer kind of suggests that you are subscribing to each address individually.

Have you tried grouping them, similar to the attached picture?

Godra

  • Hero Member
  • *****
  • Posts: 1446
    • View Profile
Re: Problem with ModbusTCPCom and DataSubscriber2
« Reply #14 on: September 19, 2019, 04:50:33 PM »
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:

Code: [Select]
    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:

Code: [Select]
    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:

Code: [Select]
    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

« Last Edit: September 19, 2019, 07:47:02 PM by Godra »