AdvancedHMI Software
General Category => Support Questions => Topic started by: rolandgpainter on October 11, 2016, 11:34:16 PM
-
Hello,
I am attempting to read and write tags to a Control Logix PLC, using the EthernetIPforCLX driver.
We have various numeric and standard string tags, and it works fine for these.
However for SHORT STRING and LONG STRING data types, attempting to write results in an error message "Not Enough Data".
The following exception data is generated:
ClxDriver.Common.PLCDriverException
ErrorCode=19
HResult=-2146233088
Message=Not Enough Data
Source=ClxDriver
StackTrace:
at ClxDriver.EthernetIPforCLX.Write(String startAddress, Int32 numberOfElements, String[] dataToWrite)
at ClxDriver.EthernetIPforCLX.Write(String startAddress, String dataToWrite)
at VBDemo.Form1.SynchronousWriteButton_Click(Object sender, EventArgs e)
Attempting to read SHORT and LONG string tags executes without exceptions, however the data is not decoded into the actual strings. Instead they are some sort of raw format containing a length value and a string of hexadecimal values corresponding to the ASCII bytes. e.g. "06000000526f6c616e6400000000000000000000".
I have tried writing the same data back to the tag however even this still fails with the same "Not Enough Data" error.
The results are the same using either the Standalone Driver VBdemo or the AdvancedHMI free version.
Does anyone know how to solve this issue?
Thanks,
Roland
-
String tags that are not the default length are considered UDTs. The driver is only capable of reading/writing primitive types (INT, DINT, etc.) with the exception of pre-defined UDTs (Timers, Counters, default strings). When reading a UDT by it's root element, a string of concatenated bytes in hex will be returned. Since the driver does not know the structure of UDTs, it is not possible to write to using it's root element.
To access these UDTs/custom length strings, it is necessary to access them by their primative elements, which is a DINT for the string length and an array of SINT for each character.
In your example of reading the custom string:
06000000526f6c616e6400000000000000000000
The breaks down to :
00000006 = string length as a DINT
52 6f 6c 61 6e 64 = *oland (array of SINT representing each character)
To write to this string, you can do something like this:
'* Write ABC to a custom string
Dim ByteValues() as string={"65",66","67"}
ClxDriver1.BeginWrite("MyString.LEN",ByteValues.length}
clxDriver1.BegineWrite("MyString.Data",ByteValues)
-
Here is a subroutine you can use to extract the string from the string of hex values returned when reading a custom length string:
Private Function ExtractString(ByVal s As String) As String
Dim bytes((s.Length / 2) - 1) As Byte
For i = 0 To (s.Length / 2) - 1
bytes(i) = Byte.Parse(s.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber)
Next
Dim StringLength As Integer = BitConverter.ToInt32(bytes, 0)
Dim StringResult As String = System.Text.Encoding.Default.GetString(bytes, 4, bytes.Length - 4)
Return StringResult
End Function
-
The problem there is that when using custom strings, those are seen as UDTs and when the drivers read them it reads some extra data, so when you try to write the data back it show the error of "Not Enough Data".
It is recommended to keep track of the size of the custom strings being used. So as suggested as Archie
To write to this string, you can do something like this:
'* Write ABC to a custom string
Dim ByteValues() as string={"65",66","67"}
ClxDriver1.BeginWrite("MyString.LEN",ByteValues.length}
clxDriver1.BegineWrite("MyString.Data",ByteValues)
I have done it this way:
Dim MyString As String = "My Data"
Dim lLen As Integer = 0
'Checks if the string length exceeds the custom string length
If MyString.Length > lLen Then
'Sets the maximum length. It will trunc the string we are trying to write to the tag
lLen = 13
Else
lLen = MyString.Length
End If
For i = 0 To lLen - 1
EthernetIPforCLXCom1.Write("MyString.Data[" & i & "]", Mid(MyString, i + 1, 1))
Next
EthernetIPforCLXCom1.Write("MyString.Len", MyString.Length)
I prefer to write the byte array first and then the lenght
-
It's actually a coincidence this topic came back up because just this past week the driver had been given functionality to write complete UDTs and custom length strings. If testing goes well this coming week, it should be part of the next release.
-
Those are excellent news. I just started using AdvancedHMI to improve an application we made with an older version of ASABTCP.
We need to read an UDT with +270 elements. For now we are going to work with the current release.
We will be looking forward for the next release.
After been working a while and usig the ExtractString function, it returns the content of the data array as string, so we added some lines to check the length, and only assign to the variable the number of characters the tag says it have.
Private Function ExtractString(ByVal s As String) As String
Dim bytes((s.Length / 2) - 1) As Byte
For i = 0 To (s.Length / 2) - 1
bytes(i) = Byte.Parse(s.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber)
Next
Dim StringLength As Integer = BitConverter.ToInt32(bytes, 0)
Dim StringResult As String = ""
If StringLength > 0 Then
StringResult = System.Text.Encoding.Default.GetString(bytes, 4, bytes.Length - 4)
StringResult = Mid(StringResult, 1, StringLength)
End If
Return StringResult
End Function