Gateway event tag script

Hi everyone

I am performing a tag change event on a gateway, where if these 26 tags change, and if the change is equal to bit 14 or 12, then it disables them. The script works, but sometimes the tag change event does not trigger, especially when all tags change simultaneously.

Is it possible that it fails due to latency between the gateway and the designer?

regards.

Can you show the code of the bit_variable_deactivate function ?

def bit_variable_deactivate(bit_position, original_variable_tag_path):
    bit_value = 1 << bit_position  
    transformer_value = system.tag.readBlocking([original_variable_tag_path])[0].value
    
    transformer_value &= ~bit_value  
    
    system.tag.writeBlocking([original_variable_tag_path], [transformer_value])
    
    return transformer_value

I have implemented this script in many mouseClicked and it works correctly.

I kinda feel like there's a better way to do this...

What kind of tags is this used on ? Where do they get their values ?

1 Like

It is a bit decoded tag, where each bit has a specific meaning. When I send a series of changes to "rearm a container", the end result I want is that when I receive a bit 14 or 15 in the BSW tag (which is the feedback from the PLC), then I turn off bits 14 and 12.

What you are doing is extremely racy. That is, unreliable. Doing read-modify-write operations on an integer that can also be changed by something else will have changes overwritten by one side or the other.

Make tags at the bit level for bits you need to write, and let the driver use an appropriate function to write the bit in a race-free way. If the driver cannot do that (like some modbus devices not supporting masked writes), then you simply cannot safely use an integer register bidirectionally.

1 Like

can you be a little more specific Phil? :sweat_smile: Let's say I create a boolean memoryTag that is triggered when the bit corresponding to that tag is set. So when that bit is set, I will set the memoryTag to indicate that I have received the bit?

If you are using actual boolean tags, they cannot race with other tags. They don't have any side effects with other tags. (Your algorithms using them could have races, but they don't add any races.)

If you try to use an integer's bits, where you read, then use bitwise & or |, then write back, your script can run in parallel with other script that try to do the same thing at the same time. One or more of the bit modifications will be lost by overwrite from a parallel thread. This is made worse if an OPC tag, where the PLC can change bits at the same time your Ignition code tries to change them. One modification or the other will be stomped on.

Basically, if you use any read-modify-write operation in your code, it is only race-free if the variable is locked with a mutex. And there's no such thing for Ignition tags nor for OPC items.

1 Like

If you have a complex sequence of events that need to update shared state, don't use tag events. Use a timer event instead, coded similar to a periodic PLC task. It would repetitively:

  • Use a single readBlocking() call to grab all relevant tag values, including the current state memory tag,

  • Examine all of those values to determine the new state,

  • Then use a single writeBlocking() call to record the new state and update any handshake OPC tags.

Since a timer event cannot run in parallel with itself, this provides a naturally race-free way to handle complex state machines.

1 Like

Thank you for the detailed explanation Phil

As things currently stand, we are not in a position to make alterations to the behavior of the tags. As a developer, I am limited as the project is in production, and making changes of that magnitude carries considerable risk that we must avoid. However, I really appreciate the suggestion and will definitely take your recommendations into account for improvement in future projects, thanks for your understanding and continued support

Then you may be stuck with unfixable bugs. :man_shrugging: