Author Topic: Not Enough Data  (Read 2993 times)

rolandgpainter

  • Newbie
  • *
  • Posts: 1
    • View Profile
Not Enough Data
« 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

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5322
    • View Profile
    • AdvancedHMI
Re: Not Enough Data
« Reply #1 on: October 11, 2016, 11:50:32 PM »
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)

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5322
    • View Profile
    • AdvancedHMI
Re: Not Enough Data
« Reply #2 on: October 11, 2016, 11:55:36 PM »
Here is a subroutine you can use to extract the string from the string of hex values returned when reading a custom length string:
Code: [Select]
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

mondacag

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: Not Enough Data
« Reply #3 on: June 11, 2017, 07:49:01 PM »
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:

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

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5322
    • View Profile
    • AdvancedHMI
Re: Not Enough Data
« Reply #4 on: June 11, 2017, 11:49:51 PM »
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.

mondacag

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: Not Enough Data
« Reply #5 on: June 12, 2017, 02:57:29 PM »
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.
Code: [Select]
    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
« Last Edit: June 12, 2017, 05:25:19 PM by mondacag »