Skip to content
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

Batch Expectations of writeTagGroup? #52

Closed
ericvicenti opened this issue Apr 26, 2019 · 5 comments
Closed

Batch Expectations of writeTagGroup? #52

ericvicenti opened this issue Apr 26, 2019 · 5 comments

Comments

@ericvicenti
Copy link
Contributor

We have some code to send a group of tag values:

// fooTag and barTag have been previously defined
fooTag.value = 123;
barTag.value = 456;
const outputGroup = new TagGroup();
outputGroup.add(fooTag);
outputGroup.add(barTag);
await plc.writeTagGroup(outputGroup);

In our PLC, we expect that foo and bar have both been changed for the same scan. But occasionally it seems that one tag is applied in one scan, and the other is applied later.

Again, this issue is flaky.. it seems that both tags usually get applied on the same scan, but every once in a while, it seems they don't.

Is this the expected behavior of Ethernet IP? Or are tag write groups supposed to be batched properly? Is there any way to write several tags to the PLC that will be picked up on the same scan?

@jhenson29
Copy link
Collaborator

I/O updates are asynchronous in Control/CompactLogix, so I would assume that is the issue you are seeing, but @cmseaton42 might be able to answer better.

@kyle-github
Copy link

Not only are different tags within groups not read/written all together, but tags with multiple elements can be partially written. We've seen this a lot with some of our networking PLC code. This is how the AB code works, nothing to do with the node-ethernet-ip library!

I've never seen anything written out of order, but definitely it is all written async to the execution of the PLC program.

@Penlane
Copy link

Penlane commented Apr 26, 2019

I see in your code that you use writeTagGroup. I haven't used it in my applications, but it probably uses the Multiple-Service-Packet like readTagGroup in order to pack your individual requests into one batch.

According to CIP-Vol1. Appendix A - Multiple Service Packet
A-4.10.1 Service Requirements
The following list details requirements associated with the Multiple_Service_Packet service:
1. Performs services as an autonomous sequence of services.
2. Performs services in the sequence supplied.
3. Performs all services, reporting individual responses for each one.
4. Packs responses into the response buffer in the sequence in which they were executed.
5. A response timeout must be implemented for those service requests that do not guarantee a
response.
6. Each embedded service may return a success or failure, as indicted in the response
structure. If one or more service requests result in an error this service shall return an error.
The error code returned shall be 1Ehex (Embedded service error).
This service allows clients to submit a sequence of ‘embedded’ services in a single message
packet. The object processing the Multiple_Service_Packet shall not perform any other service
until the entire sequence of embedded services has been attempted.

so it looks like it depends on whether the cpu was able to process all of your write-services in one cycle. It would be interesting to see, if they get changed in the correct order in your case? Because according to spec, the CPU should be definitely handling them at least in the correct sequence.

@ericvicenti
Copy link
Contributor Author

Thanks for the responses!

@Penlane, looking at the implementation of this library, it seems that writeTagGroup does in fact write a Multiple Service Packet. The API does not clearly allow you to define an order, but it does seem possible.

The order of tag writes is defined by Object.keys(tags) within the tag group. So the order will be the same order of the tags as you first added to them to the group.

const outputGroup = new TagGroup();
outputGroup.add(fooTag); // fooTag will be the first tag written
outputGroup.add(barTag); // barTag will be the last tag written
outputGroup.add(fooTag); // this duplicate tag is ignored.. the order will not be affected
await plc.writeTagGroup(outputGroup); // will write fooTag, barTag in order

The trick now, is to program the PLC such that it can handle race conditions on batched tag writes.

Closing the issue for now because it seems that aside from some improved documentation about the order of grouped tag writes, this is not very actionable.

@kyle-github
Copy link

We have found that lots of tag write or multi-word write can be split across scans. As I mentioned above, we have always seen the writes take place in exact operation order.

The way we worked around this was to write a single word first, called the header. Usually a DINT. Then we write all our data. Then we write another word, called the footer, usually a DINT. If we are writing to the PLC code, we first set the header value to X, set our data, then set the footer value to X. In the PLC we check. If header = footer, then we likely got "unsplit" data (we call the problem tearing). On the next update, we use X=X+1.

We do the same for data we read from the PLC. The ladder writes the header value, then the data part, then the footer value. In our client code we check whether the header and footer are equal. Only then do we process the data.

It is not perfect but it is vastly better than what we were seeing before.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants