The attached control is a modified BasicButton control.
It was created to support writing multiple values to multiple addresses with a single click of the button. This could be useful for presets (zeroing or setting identical value to bunch of PLC addresses) or repetitive writes. Multiple buttons can be used to point to the same PLCAddresses but write different values.
The following would be a representation of how the control could be used:
Single Address - Single Value to write to this address
Single Address - Multiple Values to write to the range starting with this address
Multiple Addresses - Single Value to write to each address
Multiple Addresses - Multiple Values to write to each range starting with each address
The button's property
PLCAddressClickItems holds PLCAddresses (it has replaced PLCAddressClick property but provides the same functionality if single address is used). Each item independently allows for ScaleFactor and ScaleOffset values.
The button's property
ValueToWrite holds values (which is array of strings). It represents NumberOfElements that will be written with the driver's BeginWrite function.
There is a new property
ValueToWriteType which defines whether ScaleFactor and ScaleOffset are applied to the value before it is written to the destination address. NumericType writes scaled numeric values and StringType just writes the string as it is. The string doesn't have to be numerical but then its destination has to be able to accept string <-- the example could be AB ST9:x addresses. Writing strings with Modbus is not implemented since it is quite complex to integrate into this control (at the end of this post, there is an example of how to go about writing/reading a string value with Modbus).
<-- Modbus String writing for this button control might work properly in v3.99y+ since Archie implemented that functionality into drivers For this all to work, the button's
OtputType property has to be set to
WriteValue.
Any other setting will still use defined PLCAddresses but will be using True/False values only, as intended.
If you need to use the code to receive values then you might try using this control's ClickItemsDataReturned event. Here is a code example for Modbus, knowing that F40001 and F40011 addresses were subscribed to, with 2 elements each:
Private Sub BasicButtonMulti1_ClickItemsDataReturned(sender As Object, e As AdvancedHMIControls.SubscriptionHandlerEventArgs) Handles BasicButtonMulti1.ClickItemsDataReturned
If e.PLCComEventArgs.PlcAddress.Equals("F40001") Then
Label2.Text = e.PLCComEventArgs.Values(0)
Label3.Text = e.PLCComEventArgs.Values(1)
ElseIf e.PLCComEventArgs.PlcAddress.Equals("F40011") Then
Label4.Text = e.PLCComEventArgs.Values(0)
Label5.Text = e.PLCComEventArgs.Values(1)
End If
End Sub
You could as well try using the drivers DataReceived event.
Try to understand all of the above before attempting to use the control.
The control was tested to a degree with MODRSSim simulator and RSLogix Emulate 500. It might have bugs and is offered AS IS.
----------------- M O D B U S ------------------
Here is a possible way of writing a string (str) with Modbus by using the BeginWrite function of the driver inside some sub (maybe a Click event of a button named btnWrite):
Private str As String = "123abc"
... Some Sub ...
'Format to write is: startAddress As String, numberOfElements As Integer, dataToWrite() As String
ModbusTCPCom1.BeginWrite("40061", str.Length, ConvertStringToStringOfIntegers(str))
... Some Sub ...
Private Function ConvertStringToStringOfIntegers(ByVal str As String) As String()
'* Convert string to an array of bytes
Dim ByteArray(str.Length - 1) As Byte
ByteArray = System.Text.Encoding.Default.GetBytes(str)
'* Convert each byte to integer and then convert this integer to its string representation and store it in the string array
Dim ints(ByteArray.Length - 1) As String
For i = 0 To ByteArray.Length - 1
ints(i) = CStr(CInt(ByteArray(i)))
Next
'* Return the string array
Return ints
End Function
Holding registers, 4xxxx addresses, should be used to store a string as an array of integers.
In order to read the string, this exact array of integers has to be read and converted back to string inside some sub (maybe a Click event of a button named btnRead), and the string could be shown on some standard label:
... Some Sub ...
'For example, we could initiate the read and then use DataReceived event of the driver
'Format to read is: startAddress As String, numberOfElements As Integer
ModbusTCPCom1.BeginRead("40061", str.Length)
... Some Sub ...
Private Sub ModbusTCPCom1_DataReceived(sender As Object, e As Drivers.Common.PlcComEventArgs) Handles ModbusTCPCom1.DataReceived
If e.PlcAddress.Equals("40061") Then
Dim ints(e.Values.Count - 1) As String
For i = 0 To e.Values.Count - 1
ints(i) = e.Values(i)
Next
Label6.Text = ConvertStringOfIntegersToString(ints)
End If
End Sub
Private Function ConvertStringOfIntegersToString(ByVal ints() As String) As String
'* Convert integer values to strings and then to an array of bytes
Dim ByteArray(ints.Length - 1) As Byte
For i = 0 To ints.Length - 1
ByteArray(i) = CByte(CStr(ints(i)))
Next
'* Convert the array of bytes to a string
Dim result As String
result = System.Text.Encoding.UTF8.GetString(ByteArray)
'Return the string
Return result
End Function
Archie already explained some of this here:
https://www.advancedhmi.com/forum/index.php?topic=1301.msg6918#msg6918I slightly modified his code.