AdvancedHMI Software
General Category => Support Questions => Topic started by: Phrog30 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
-
Is it a standard length or custom length string?
-
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
-
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
-
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
-
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
-
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:
.
.
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
-
I tried this code this morning and it worked like a champ. Thanks.
James
-
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
-
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.
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
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
-
Not VB. C#.
// 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; }
}
-
Treat you custom strings as nested UDTs. Here is an example class for String20 that will make things easier:
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:
public String20 ProductID { get; set; };
Then you can set the value as such:
ProductID = new String20("TheValue");
I have not tested this, so it may not work the first try, but should get quite close.
-
It worked perfect, first time. I also added an override for ToString() so I can easily read values back out of it.
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