CitectSCADA performs writes to the I/O Device asynchronously (that is, when you write to the I/O Device, the write takes time to get to the I/O Device, during which CitectSCADA continues to perform other operations). If the other Cicode assumes that the write has completed immediately, you might encounter some side effects such as inconsistencies in the value of a variable tag across two Cicode threads.
If you have the following Cicode:
PLC_VAR = 1234;
Prompt("Variable is " + PLC_VAR : ####);
the first line is a write to the PLC.
When CitectSCADA executes the first line, it
generates a request to the I/O Server to write the value 1234 into
the PLC variable PLC_VAR
.
CitectSCADA then executes
the next line of Cicode before the PLC write is completed.
CitectSCADA does this so
that the Cicode is not stopped while waiting for a slow I/O Device.
As the write to the PLC has not completed, you might think that the
next line of Cicode will display the last value of PLC_VAR
and not the value 1234. However, this
Cicode will display the correct value (1234) because whenever
CitectSCADA writes to the
PLC, it first updates its local copy of the variable: any following
Cicode will get the correct value.
Sometimes this solution will not work as
CitectSCADA might keep
multiple copies of an I/O Device variable, and only update the one
associated with the current Cicode. The other variables will
contain the old value of the I/O Device variable until they are
refreshed (with a read from the I/O Device). There is a separate
data area for each display page, Cicode file, for alarms, trends
and reports. If you write to an I/O Device variable from a page
keyboard command, the copy of the I/O Device variable associated
with that page will be updated; however, the copy associated with
other pages and the Cicode functions is not updated until the next
read (as determined by the [Page]ScanTime
parameter). If you call a Cicode
function that assumes the write has completed, it will get the last
value.
The workaround is to write to the I/O Device variable in the Cicode function. Every Cicode function shares the same I/O Device variables, so the writes will operate as expected.
FUNCTION
TestFunc(INT nValue)
PLC_VAR = nValue;
END
Another side effect of the delays inherent in
asynchronous writes to I/O devices is that you might assume that
CitectSCADA has
successfully written to the I/O Device, when in fact the write
operation might not yet have been completed or even attempted. In
such cases, it is still possible that a hardware- or
configuration-based error will prevent the success of the write
operation. While such an unsuccessful write operation will generate
an error, your Cicode cannot be notified or use the IsError()
function because the Cicode has
continued to execute past the initial I/O device write command.
Therefore, when it is important to check the success of a write
operation before allowing code execution to continue, you might
insert the function TagRead()
after
the write and then verify the value of the variable. TagRead()
forces Cicode to re-read the I/O
Device variable so that you can check the new value. TagRead()
is a blocking function. It blocks the
calling Cicode task until the operation is complete.
PLC_VAR = 1234;
sTestStr = TagRead("PLC_VAR");
IF sTestStr <> 1234 THEN
Prompt("Write not completed");
END
Here the data will be read from the physical PLC,
not from the I/O Server cache, as the I/O Server will invalidate
any cached data associated with a PLC write. This will allow you to
test for a completed write. Please be aware that other Cicode tasks
running at the same time will not be waiting on the TagRead, so
they might see the old or new value, depending on if they are using
the same copy of the PLC variable. You can also stop CitectSCADA from writing to the local
copy of the variable by using the function CodeSetMode(0, 0)
.