Author Topic: Read string in UDT  (Read 4801 times)

Phrog30

  • Guest
Read string in UDT
« on: July 05, 2016, 10:12:11 AM »
I can read this:
MainForm_CpLX.Read("Reject_Reasons[1]").ToString

But when I try this:
MainForm_CpLX.Read("Ties_MySql.t_stamp").ToString
it returns garbage.

The difference, one is an array of strings.  The other is part of a UDT, but still a string.  Is this a known issue?

Any work around?

I'm using EIP driver with CpLX v24.

James

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5322
    • View Profile
    • AdvancedHMI
Re: Read string in UDT
« Reply #1 on: July 05, 2016, 10:37:38 AM »
Is it a standard length or custom length string?

Phrog30

  • Guest
Re: Read string in UDT
« Reply #2 on: July 05, 2016, 10:41:34 AM »
Is it a standard length or custom length string?

In the first example I have tried 82 and custom, 20, 30, etc., they all work, regardless.  The second example I have only tried less than 82.  I will add an 82 to a UDT and see what that does.

James

Phrog30

  • Guest
Re: Read string in UDT
« Reply #3 on: July 05, 2016, 10:49:23 AM »
I created a UDT with a "full length" string.  It does work.  Ok, why would this matter?  I can read strings of different lengths successfully, except when they are inside of a UDT.  Is this something with the driver?

James

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5322
    • View Profile
    • AdvancedHMI
Re: Read string in UDT
« Reply #4 on: July 05, 2016, 07:52:49 PM »
I am actually surprised any custom length string returns a meaningful result with .ToString

A custom length string is a UDT and the driver doesn't know how to parse UDTs, so it return an array of bytes encoded in hex as a continuous string. The first 4 bytes of a string is the length. So let's say you read a custom length string that contains "A". It should return 0100000041

Phrog30

  • Guest
Re: Read string in UDT
« Reply #5 on: July 05, 2016, 08:55:47 PM »
Not sure what to tell you, but it works except in a UDT.  It's not really a deal breaker, but it would be nice to have the driver work for strings other than 82.  If I only need 30 characters it's a waste of memory to use more than that.

I just created another UDT with full length strings and use this as my "working file".

James

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5322
    • View Profile
    • AdvancedHMI
Re: Read string in UDT
« Reply #6 on: July 05, 2016, 09:29:11 PM »
I won't have a way to test this until I get back to the office tomorrow, but this is one possible way to make it work:

Code: [Select]
.
.
        Dim s As String = ExtractString(EthernetIPforCLXCom1.Read("Ties_MySql.t_stamp"))
.
.

    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

Phrog30

  • Guest
Re: Read string in UDT
« Reply #7 on: March 08, 2017, 11:37:56 AM »
I tried this code this morning and it worked like a champ.  Thanks.

James

Larry Griffin

  • Newbie
  • *
  • Posts: 11
    • View Profile
Re: Read string in UDT
« Reply #8 on: September 19, 2017, 12:17:12 PM »
This works okay for reading.
Is there a fix for writing?

That is, I can't do a complete .WriteUDT to a UDT that contains multiple custom strings shorter than 82.  The first custom string gets written, but subsequent strings are empty.
And if I try to .WriteUDT to one custom string member of the UDT I get a "Not Enough Data" error.

LarGriff
« Last Edit: September 19, 2017, 12:29:30 PM by Larry Griffin »

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5322
    • View Profile
    • AdvancedHMI
Re: Read string in UDT
« Reply #9 on: September 19, 2017, 12:53:41 PM »
That is, I can't do a complete .WriteUDT to a UDT that contains multiple custom strings shorter than 82.  The first custom string gets written, but subsequent strings are empty.
And if I try to .WriteUDT to one custom string member of the UDT I get a "Not Enough Data" error.
How did you define the structures in VB for writing?

You may have to create a structure for the custom string (since it is technically a UDT), then use that structure in the main UDT structure.
Code: [Select]
Public Structure CustomString
    Dim Length As Integer
    Dim Characters() As Byte
End Structure

Public Structure MyUDT
    Dim s1 As CustomString
    Dim s2 As CustomString
End Structure

Then something like this to
Code: [Select]
        Dim MyString As String = "ABC"
        Dim s1a As CustomString
        s1a.Length = 20 '* the size as defined in RSLogix
        Dim c(s1a.Length-1) As Byte
        System.Text.ASCIIEncoding.ASCII.GetBytes(MyString).CopyTo(c, 0)
        s1a.Characters = c

        MyUDT.s1 = s1a

Larry Griffin

  • Newbie
  • *
  • Posts: 11
    • View Profile
Re: Read string in UDT
« Reply #10 on: September 19, 2017, 05:50:26 PM »
Not VB.  C#.

Code: [Select]
    // Work Order Structure
    public class WO
    {
        public int Sequence { get; set; }
        public string Description { get; set; } = "";  // STRING82
        public string ProductID { get; set; } = "";  // STRING20
        public string CustWO { get; set; } = "";  // STRING20
        public string ThisWO { get; set; } = "";  // STRING20
        public float CasingLen { get; set; }
        public float TubingLen { get; set; }
        public int Qty { get; set; }
        public int Priority { get; set; }
    }

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5322
    • View Profile
    • AdvancedHMI
Re: Read string in UDT
« Reply #11 on: September 19, 2017, 07:10:22 PM »
Treat you custom strings as nested UDTs. Here is an example class for String20 that will make things easier:
Code: [Select]
   class String20
    {
        public int Length;
        public System.SByte[] Characters;

        public String20()
            {
            Characters = new System.SByte[20];
            }

        public String20(string value) : this()
        {
            SetValue(value);
        }


        public void SetValue(string value)
        {
            Length =Math.Min(20, value.Length);
            if (value.Length >20)
                    {
                value = value.Substring(0, 20);
            }
            // WriteUDT does not support byte, so we have to do a little rework here
            byte[] TmpArray= new byte[20];
            System.Text.ASCIIEncoding.ASCII.GetBytes(value).CopyTo(TmpArray, 0);
            Characters = (sbyte[])(Array)TmpArray;
        }

    }

Then in your class, you would change this:
Code: [Select]
public String20 ProductID { get; set; };

Then you can set the value as such:
Code: [Select]
ProductID = new String20("TheValue");

I have not tested this, so it may not work the first try, but should get quite close.

Larry Griffin

  • Newbie
  • *
  • Posts: 11
    • View Profile
Re: Read string in UDT
« Reply #12 on: September 20, 2017, 03:19:54 PM »
It worked perfect, first time.  I also added an override for ToString() so I can easily read values back out of it.

Code: [Select]
    public class String20
    {
        public int Length;
        public System.SByte[] Characters;

        public String20()
        {
            Characters = new System.SByte[20];
        }

        public String20(string value) : this()
        {
            Length = Math.Min(20, value.Length);
            if (value.Length > 20)
            {
                value = value.Substring(0, 20);
            }
            byte[] TmpArray = new byte[20];
            System.Text.ASCIIEncoding.ASCII.GetBytes(value).CopyTo(TmpArray, 0);
            Characters = (sbyte[])(Array)TmpArray;
        }

        public override string ToString()
        {
            return System.Text.Encoding.ASCII.GetString(Array.ConvertAll(Characters, a => (byte)a));
        }
    }

Thank you so much for the help.  Would be nice if custom strings could be automatically handled by .WriteUDT, but this is workable for now.
Looking forward to .ReadUDT too.  Soon?

LarGriff