I'm working with a system that represents their alarms as a 32-bit integer with an alarm assigned to each bit of the integer.
While I can read the contents of the integer as a boolean array, I cannot write to them. I can write to the integer itself, but I can't write to any of the array points. This has been covered in some prior posts, but I'm unable to write to the array using any of the strategies referenced before (ex. write to the opc tag plus (.bit), like opcIntVar.bit.
Per tag data types, there are certain OPC servers that don't allow individual bit writes. Is this common and could be causing me an issue?
Alternatively, is writing the binary array equivalent the integer itself straightforward? I could imagine a putting a script on a button or potentially using a derived tag to do some of the work.
Cheers.
I think you'll have to figure out how to use derived tags to manipulate it, being cognizant of the inherit race conditions involved, and making sure to put the tag into a Tag Group that has Optimistic Writes enabled.
FWIW I think writing to a tag that is an integer value being cast to a boolean array by forcing the tag datatype is just broken or unsupported right now, nothing to do with OPC.
2 Likes
Great. Thanks Kevin, I'll dip into it a bit further and make it work.
Thinking about this further, this would / should never work. If the server is modeling this tag as an integer instead of a boolean array then the index range parameter you probably found reference to in other threads doesn't apply. You must write an integer to it. Using derived tags pointing at the integer is definitely the move here.
Ideally whoever built this server would have made better modelling choices, especially if the intent is that clients will also be writing to the bits in this integer.
I ended up using a script running off the button. I found python a bit easier than working with the expression library for derived tags. The script reads the int32 'bool array', changes the index/bit that needs changing, recompiles the number as a binary string, and converts it. Maybe a little dodgy, but it works just fine.
def toggleDefeat(bit):
#read boolean array
bitState = system.tag.readBlocking(["[default]Well 1/Alarms/Alarm Defeat"])[0].value
#toggle bitstate
bitState[bit] = not bitState[bit]
#cycle thorugh bool array, interpret as 0 or 1 and create a binary string.
bitString = ""
for tempBit in bitState:
bitString = str(int(tempBit))+bitString
#convert binary string to int
newInt = int(bitString,2)
#write the new int to an int tag
system.tag.writeBlocking(["[default]Well 1/Alarms/Alarm Defeat Write"], [newInt])
There is a race condition there, which should trigger a risk analysis - especially in process control.
- Is is possible to have two bits changed by different processes at the same time?
- If so, what are the consequences if that happens (auto-heal on the next scan vs. creation of a black hole that swallows the planet)?
No need to answer here...
1 Like
Great point. I did test the failure of it just by writing a handful at once. Sure enough, things got wonky from the blocking between reads and writes.
If the user is going slow, it's fine. If they press 3 at once, chances are one of them isn't getting written. From a risk standpoint, my one or two users grumble and press the button again. It works. Life goes on. The application is a 'disabling alarm' screen, it isn't mission critical to fix.
But to fix this, I think I would need to have a number of memory tags representing the bit. On a timer script, I would bulk read all the bit tags, assemble a solid int, and do the write. The trade-off is that I use a bunch of resources and it's a little more dense to pick through later on.
Thanks for the point, I appreciate it.
Good.
I would also consider what if something other than Ignition changes the value - e.g., the PLC is setting individual bits. If you are changing /0 and the PLC is changing /3 then you could revert the change to /3. This might be as innocuous as the screen flashing to a previous value or it might change the position of a value.
A robust solution that doesn't deadlock could certainly get complicated... probably more complicated than a decree "don't use bit fields in writable interface variables for devices that don't allow bit writes".
I think that last solution might be the best one, haha. Some cleverness that was handy 20 yrs ago isn't t always as scalable nowadays.
Appreciate the tips.
I remember when we could see the bits on the memory board, and hear the bits (quadbits?) on the modem...
We can afford to use memory and bandwidth a bit differently now.