Author Topic: ModbusTCP and Tag Database  (Read 2500 times)

rbelknap

  • Jr. Member
  • **
  • Posts: 68
    • View Profile
ModbusTCP and Tag Database
« on: November 09, 2015, 08:21:38 AM »
I'm working on my first AHMI app.  I'm going to use the ModbusTCP driver to talk to an AutomationDirect PAC3000.  The PAC sofware automatically creates a CSV tag file when you save the program.  I want to use this as my Tag database for the HMI program.

I have a bunch of tags that I use in code, so I'm going to read the CSV file and put anything that has a modbus address in a dictionary object.  Then I can use the full tag name in my program, which will make it a lot more readable, and use the dictionary object to translate it to the modbus address.

Now I'm wondering if I could do something similar for all of the onscreen controls.  I would pre-populate the controls with the tag names and then when the form gets created translate them with the dictionary and start the subscription.  I assume I can do this by using the DisableSubscriptions property?

Hopefully this makes sense.  I have a bunch of the code already worked out, just need to finish the details.

Rich

rbelknap

  • Jr. Member
  • **
  • Posts: 68
    • View Profile
Re: ModbusTCP and Tag Database
« Reply #1 on: November 09, 2015, 10:29:08 AM »
Here is what I've come up with for the onscreen controls

Code: [Select]
'in the Form Load
  Dim cControl As Control
        For Each cControl In Me.Controls
            If (TypeOf cControl Is AdvancedHMIControls.PilotLightEx) Then
                Dim myPilotEx As AdvancedHMIControls.PilotLightEx = cControl
                myPilotEx.PLCAddressClick = LookupModbusAddr(myPilotEx.PLCAddressClick)
                myPilotEx.PLCAddressText = LookupModbusAddr(myPilotEx.PLCAddressText)
                myPilotEx.PLCAddressValue = LookupModbusAddr(myPilotEx.PLCAddressValue)
                myPilotEx.PLCAddressVisible = LookupModbusAddr(myPilotEx.PLCAddressVisible)
            End If
            'Would need to add the same if then block for each Control Type
        Next cControl

        'Subscribe
        Me.ModbusTCPCom1.DisableSubscriptions = False


This seems like it could be a lot of code if I use many different controls.  Not sure if there is a better way to do this or not.

Code: [Select]
  Private Function LookupModbusAddr(TagName As String) As String
        'Translate the Tagname to the modbus address.
        Dim value As String = ""
        If (ModbusAddressLookup.TryGetValue(TagName, value)) Then
            'ModbusAddressLookup("key") = value + 1
            Return value
        End If
        Return TagName
    End Function

I have a simple screen with 2 pilot lights on it and it does work.

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5322
    • View Profile
    • AdvancedHMI
Re: ModbusTCP and Tag Database
« Reply #2 on: November 09, 2015, 06:44:53 PM »
You can use reflection to do this with less code, but reflection can be quite advanced and confusing.
Code: [Select]
   For i = 0 To Me.Controls.Count - 1
       Dim p() As Reflection.PropertyInfo = Me.Controls(i).GetType().GetProperties
       For propertyIndex = 0 To p.Length - 1
           If (p(propertyIndex) IsNot Nothing) AndAlso (Not String.IsNullOrEmpty(p(propertyIndex).Name)) AndAlso ((p(propertyIndex).PropertyType) Is GetType(String)) Then
               '* Does this property start with "PLCAddress"?
               If p(propertyIndex).Name.IndexOf("PLCAddress", StringComparison.CurrentCultureIgnoreCase) = 0 Then
                   Dim value As String = LookupModbusAddr(Me.Controls(i).Name & "." & p(propertyIndex).Name)
                   p(propertyIndex).SetValue(Me.Controls(i), value, Nothing)
               End If
           End If
       Next
   Next

rbelknap

  • Jr. Member
  • **
  • Posts: 68
    • View Profile
Re: ModbusTCP and Tag Database
« Reply #3 on: November 10, 2015, 08:35:56 AM »
Archie,

I knew you'd come up with something, which is why I posted this.
I've seen some reflection code before, and as much as it's more difficult to read, there should be little code maintenance going forward.
I modified it a little, and put it in a function.


Here's the functions
Code: [Select]
Private Sub FixPLCAddresses(ByVal ctrlParent As Control)


        For i = 0 To ctrlParent.Controls.Count - 1
            Dim p() As Reflection.PropertyInfo = ctrlParent.Controls(i).GetType().GetProperties
            For propertyIndex = 0 To p.Length - 1
                If (p(propertyIndex) IsNot Nothing) AndAlso (Not String.IsNullOrEmpty(p(propertyIndex).Name)) AndAlso ((p(propertyIndex).PropertyType) Is GetType(String)) Then
                    '* Does this property start with "PLCAddress"?
                    If p(propertyIndex).Name.IndexOf("PLCAddress", StringComparison.CurrentCultureIgnoreCase) = 0 Then
                        'Dim value As String = LookupModbusAddr(Me.Controls(i).Name & "." & p(propertyIndex).Name)
                        Dim value As String = LookupModbusAddr(p(propertyIndex).GetValue(ctrlParent.Controls(i), Nothing))
                        p(propertyIndex).SetValue(ctrlParent.Controls(i), value, Nothing)
                    End If
                End If
            Next
            'Fix anything in a container control, such as a panel or groupbox
            If ctrlParent.Controls(i).HasChildren Then
                FixPLCAddresses(ctrlParent.Controls(i))
            End If
        Next

    End Sub
    Private Function LookupModbusAddr(TagName As String) As String
        'Translate the Tagname to the modbus address.
        Dim value As String = ""
        If (ModbusAddressLookup.TryGetValue(TagName, value)) Then
            Return value
        End If
        Return TagName
    End Function

You call the FixPLCAddresses from the form_Load like this:
Code: [Select]
Call FixPLCAddresses(Me)

The piece I added near the end will cause it to look in container controls.
This has come together nicely.

As always, Your help is much appreciated.