-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to read/write strings #359
Comments
Hello, did you get this solved? Looks like I am having the same issue |
I have the same problem, I half solved it, the way I used to solve it was that instead of using StringPlcMapper I am using a SintPlcMapper expecting an array of type sbyte[]. Actually I can Read any String but I can not Write a String that is longer than the one written in the PLC, that is if I write a word of 10 letters I can write a word between 1 to 10 letters, but if I write a word of 8 now I am limited again to write a word of 8 or less, with the ErrorOutOfBounds error. I sincerely believe that the main problem is a Bug in the library to read this type of Strings since it is not really a String, the Micro820 handles it as an Int8 Array where the first position is the length of the stored word, that is if I have a word of 4 letters I will get an array of 5 where in the first position is stored the length of the String and in the other 4 the encoding of the String in ASCII. |
IIRC, Micro8x0 uses a different string format from Control/CompactLogix. Some PLCs send the entire string buffer from the PLC. Some only send the "used" bytes. It looks like the Micro8x0 only sends the used bytes. You will need to increase the size of the tag to write a longer string. The underlying C library makes sure that the local buffer (in the PC) has enough space for the data returned from the PLC. If you read a string with 4 characters, that will be 5 bytes for a Micro8x0. If you want to write a longer string, you will need to resize the local tag's buffer. In the underlying C library, you can call specific functions to do this. I am not sure what the .Net methods are but they are probably roughly the same names and hopefully the auto-complete feature of your IDE will figure it out. |
Hi Kyle. Yes, the method to create a tag in the wrapper has a parameter called ArrayDimensions that you can predefine it or it autocalculates if you send a null, but the autocalculation or change the dimension in this case that is the String in this controller does not work, in any other type of variable works correctly, only when manipulating strings in the Micro820 is not possible, it may be more a matter of the wrapper than the native library. Do you have an example of how to read a string from the native function in a Micro820 PLC? I have been trying to read it but I get an error when creating the tag, I think I am not understanding how to use the native library from C# for the Micro820. |
The way types are encoded in C#/.NET memory is (often) different to how they are encoded in PLC memory. There is an example here of using the NativeImport library from C# and more examples of using the String APIs in C When libplctag first initializes a tag, it performs a read from the PLC, which allows libplctag to create a buffer in memory to store the data. When you want to write a string that is larger than its first value, you'll first need to resize that buffer using This is not there in the built-in StringMapper, but you could develop your own where you do actually resize the buffer before calling SetString - e.g. MyStringMapper : PlcMapperBase<string>
{
....
...
override public void Encode(Tag tag, int offset, string value)
{
tag.SetSize(offset, value.Length + 2?);
tag.SetString(offset, value);
}
} I don't know if this is the logic that is needed - I don't know how strings are encoded in the Micro820. ArrayDimensions is used for an array of strings (or DINT/SINT/TIMER/etc), |
I am looking through the C code and I thought I had broken out the Micro8x0 separately from the Logix PLCs. But it looks like I did not. Can you set the following (these are the C tag string attributes, so you'll need to translate them for .Net)? str_is_counted = 1 str_is_fixed_length = 0 str_is_byte_swapped = 0 (? this might be true or 1, need to test) str_count_word_bytes = 1 str_max_capacity = 255 str_total_length = 0 str_pad_bytes = 0 These attributes are set when you create a Tag object. This might allow strings to work out-of-the-box. |
Okidoke - unfortunately the Mapper based tag type does not yet have the ability to configure a tag prior to initialization (#212) - so will need to use the That would look something like this: var myString = Tag()
{
Gateway = "127.0.0.1",
Name = "MyString",
... other parameters ...
StringIsCounted = true,
StringIsFixedLength = false,
StringIsByteSwapped = false, // this might be true, need to test
StringCountWordBytes = 1,
StringMaxCapacity = 255,
StringTotalLength = 0,
StringPadBytes = 0,
};
await myString.InitializeAsync();
// myString.SetSize(???);
myString.SetString(0, "Hello World");
await myString.WriteAsync(); |
Thank you very much @timyhac and @kyle-github for your time and information shared. I will keep testing to see if I find a stable solution on how to read it and I will share here the progress whether it is good or bad. Best regards. |
Based on the code, I think you will need to set the size of the tag. There is a check that looks to see what the maximum size is and what the index of the last character in the string is. The last index is compared to the size of the existing tag buffer not the maximum possible size of the string. |
How are you doing, today I was testing my work using your recommended information, from the SetSize and SetString function I could never write the Tag, it returned an error with an answer of the current string length, although they did not work that way after some tests I solved it using the SetBuffer in the following way:
Thank you very much for your help @kyle-github @timyhac . |
Can I use the myString Initialized by the StringMapper or i need to perform
I will test it to omron PLC |
num = -7 (BadConfig) (This when i run WriteStringDirectAsync func, but in sync )
|
I overrided StringPlcMapper by inserting Omron's maximum size (256) into ElementSize, while in the encode I added the solution that seemed to work for @ElegantCatterpillar but not for me.
First of all I don't understand why After setting the size, if you read the size it appears that it has been set, but in reality it is not, and this is demonstrated by the exception, and also by the tag_rw command
If I initialize the tag as ElegantCaterpillar, but modifying StringMaxCapacity and StringCountWordBytes, adapted to Omron, it still gives me an error:
|
I've made some progress.Since the size doesn't seem to be set in the tag with SetSize or SetBuffer, I tried writing to a variable that already had data, 10 to be exact. "I can write to the variable, but only once, the other times it doesn't give any exceptions, if I do a read afterwards I see the value old, so he doesn't write anything."While, if I try it from tag_rw it doesn't write anything in both as it doesn't set the buffer size
|
In the output log from tag_rw2, I see the following warning:
This is preventing tag_rw2 from getting very far in the process of connecting to the PLC. You need to have a path element and for Omron it should be "18,". In your case that would be:
I do not know why, but Omron seems to require the use of a bridge-type path. To see if you can write with tag_rw2, try writing a string that is the same length but with a different value. I.e. if you have the value "test1" in the tag, try writing "test2". If I remember correctly, tag_rw2 will not try to extend the tag buffer for longer strings. |
Sorry, you're right, in path I always put 1.0 and it always went for all other types of Read/Write variables, even for reading strings 1.0 is fine.
I tried to enter 18, for string write but the error is still the same
In my opinion we should focus on my last comment, by setting Size and Buffer correctly I can write, but only the first time, the other times everything seems to go well without exceptions but if a read is done the value has not changed. maybe we can mention some user who works on the c part to understand if there is something wrong there? |
I recommend using the base tag because it is designed to work with almost no default settings so I used it that way. I really don't know how the String will work on the Omron PLC, I run pure Allen Bradley PLC's so I wouldn't know the configuration but on the Micro820 which is where I did it I got this error, so instead of treating it as a String that if it worked in the higher end PLCs of the brand I used it as a byte array through the ASCII codes of what I wanted to write in addition to adding in position 0 the new length of the ASCII Array, so always the array that had to write bytes should be 1 position more than normal. What model of Omron PLC are you using? You may see natively from the PLC programming software how the String is built to help you to transfer it to use the library, are you using C#? |
@kyle-github However, I don't quite understand why I should put path=18,IP. I've always worked with path=1,0 with Micrologix, Allen Bradley, I remember reading somewhere that 1,0 was generic for everyone. The PLC is an Omron NX1P2, from your writing example, I didn't follow the initialization of the tag as it gave me a configuration error (-7), I managed to write a string, as you can see from the comment above, only that this works only once, the other times the writing no longer works but no error is generated, it is as if it were fine for the library, but not for the PLC, only the first write is fine. Yes, I use C#, I initialize the tags via mapper
|
I found a library written in python (https://github.com/aphyt/aphytcomm) that might help with Omron. It also has tag discover, as well as read/write (works on strings) |
Any news on this? I am having the same issue. I tried using the suggested python library, it works. Trying the same with libplctag gives a different wireshark output. |
Can you capture the Wireshark output of writing a string, @MountainKing91? I don't have an Omron PLC so it is hard to debug this. I have seen aphyt before but without an Omron, I cannot capture its packets to make sure I understand what it is doing. If the PLC returns strings with only the valid characters, then the tag buffer will not be as long as the maximum length. You should be able to set the size of the tag to the length needed by the string. Looking at the docs, it appears that Omron strings have a 2-byte count word followed by the character data. So something like this (this is in C, you'll have to translate for the C# version):
|
Full wireshark captures with libplctag and aphyt |
I'm trying to understand what I am seeing here while looking at the Aphyt code. This is using UCMM, unconnected messaging. Here's the packet:
Above is the Ethernet header I think. Now the IP header. 20 bytes.
Now we start the TCP header (usually 20-24 bytes)
Then the EIP header
We start the CPF (common packet format) section. This looks like a UCMM message.
Now comes the actual request payload.
And finally this is the data we are going to write. There are 256 bytes of it.
OK. So I think I see the problem. When you are writing a string, you need to write the entire thing. And strings are up to 256 bytes long. And the count word is omitted. So... Maybe this will work? const char *my_str = "MyStringInitialValue";
int tag_size = 256;
rc = plc_tag_set_size(tag, tag_size);
...
/* copy the string in manually without a count word */
/* get the string length */
len = strlen(my_str);
/* we are going to set _all_ the data in the tag buffer, some of
which will be the string data.
*/
for(i=0; i < tag_size; i++) {
if(i < len) {
plc_tag_set_uint8(tag, i, my_str[i]);
} else {
plc_tag_set_uint8(tag, i, 0);
}
}
/* now try to write. */
rc = plc_tag_write(tag, 5000); |
I am going to try as soon as I can get back to the plc, tonight or tomorrow morning. In general, in omron world strings are from STRING[1] to STRING[1986]. Default is STRING[256]. |
Hi @MountainKing91, thanks for the support, Please also take a look at my comments above, they might be very helpful, from the .net library it is not possible to change the buffer size, it throws the error with code: the size. In this comment, I even managed to write to it once in the created string, but then nothing more. Here you will find the Mapper with ElementiSize 256. Come on, let's fix this Bug!!!! |
I tried, with no success. @zN3utr4l this throws exception 22
I can build the 256 bytes buffer for "MyStringInitialValue", but because of the SetSize error i guess I cannot actually write it?
Is it really the With this encode method I create the buffer above
wireshark dump for write command:
wireshark dump for write response "Not enough data":
|
I don't think that is correctly constructed. But I am not an Omron person so I am not sure. It does not look right to me though:
I think you need 00 01 in the XX XX bytes above. |
Hmm, this makes some sense if the plc is interpreting the first two bytes of the data as a byte count. It would see 0x794d as the byte count. |
…ibplctag.NET wrapper code. Previously it was enforcing the result of set_size to be 0, but the core API says that it is only an error on a negative result and a positive result indicates the previous size.
There is a bug in the wrapper causing SetSize to throw an exception - a fix will be released with libplctag.NET 1.3.1 |
@kyle-github shifting the buffer of 2 bytes and setting the first two elements to 0x0 and 0x1 gives me this wireshark dump and ErrorTooSmall, I had already tried. Something is still off.
@timyhac ok good to know, can we try to override in some way to at least make it work for some tests with the omron cpu? |
@MountainKing91 - I'm not sure what you want to override but you can always download both libplctag and the wrapper and tweak to your heart's content. Including your own libplctag core binary is straightforward - https://github.com/libplctag/libplctag.NET/blob/master/docs/Using-a-non-packaged-version-of-the-native-libplctag-library.md |
@timyhac Sorry, I didn't notice you already released 1.4, my bad. I updated to 1.4 and the exception is gone. Same error "too small" though. |
All good thanks for testing |
Maybe try a raw tag and copy the working CIP command into the raw tag directly? The total packet lengths are going to be somewhat different as it looks like Aphyt is using UCMM (unconnected message) and libplctag uses connected messaging where possible (less overhead). If you want to turn off connected messaging, use the |
Maybe I got it working (looks like yes): code:
wireshark:
full capture: @kyle-github this is not sending a 256 bytes payload, right? Not sure if it is ok, it looked like we needed to send the full 256 all the time.. |
I'm not very familiar with Wireshark, like you, I think, I'm a developer who ran into this problem and tried to understand something about it, but I don't know anything about this CIP or UCMM protocol. Your Encode function looks very similar to mine (#359 (comment)), they differ only by the As @kyle-github says, try UseConnectedMessaging to false, he's the expert on this. |
It works in both ways, with UseConnectedMessaging set to true or false. |
Perfect I would say, then we just wait for this behavior to be merged into the Native string Mapper. Or just override like you did. Thank you @MountainKing91 for your support in resolving this issue. |
I will give it a try with STRING[1986] and see how it goes. |
This works for me, thank you so much. Anyone managed to read array of Strings? |
I did not try yet @Ashpatell1. |
@MountainKing91 / @Ashpatell1 - if either of you try working with string arrays on the Omron I would be interested to know what data structure they return and how that changes with the content of the string. |
I would to - I am a bit overwhelmed with work lately, I couldn't find time to dedicate :/ |
Here we go. I created an array of two STRING[256] Let's see what I tried to read the values:
Result with
Result with
It appears that the behaviour is the same as a standalone STRING[256] tag - only the non 00 values are returned and the first two bytes hold the length in bytes of the actual string value. This could be because I am simply reading element 0 of the array though. If I pass
I get |
Thanks @MountainKing91 - I have quickly glanced at the logs and although this is currently outside of my range of expertise, I believe the error response is coming from the PLC so I guess the problem is that either libplctag core isn't creating the correct request structure, or Omron PLCs are just not capable of returning String array tags and you would need to request each element individually. |
You cannot ask for two elements when you use the bare name for the string
array. Omron pulls back the whole tag when you do that. So the number of
elements is 1 (one).
…On Sun, Jul 21, 2024 at 4:49 PM timyhac ***@***.***> wrote:
Thanks @MountainKing91 <https://github.com/MountainKing91> - I have
quickly glanced at the logs and although this is currently outside of my
range of expertise, I believe the error response is coming from the PLC so
I guess the problem is that either libplctag core isn't creating the
correct request structure, or Omron PLCs are just not capable of returning
String array tags and you would need to request each element individually.
—
Reply to this email directly, view it on GitHub
<#359 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAN4LCY374LZRHUKO4KLNNDZNRCH3AVCNFSM6AAAAABAYYSVR6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENBRHAYTSMZXHA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Yep my bad, I keep doing this error over and over again! @timyhac requesting each element of the array individually is something I am already doing in case of arrays of large data structure, where you can easily hit the 199x bytes limit. I imagine this might be an ok solution for string arrays too. I am looking at Omron documentation to see if I can find some hints. |
Hi,
I am trying to retrieve a string from my micro800 Allen bradley PLC. I am getting this fault.
I am not using string[] on the definition, so why do i get this error. Is it becouse the library dosent support this??
Bool,int work!
Thanks for the help. I will keep trying, but please let me know if it is not supported.
here is what i have on the micro 800. The string is on the global variables.
The text was updated successfully, but these errors were encountered: