Using CitectSCADA > Communicating with I/O Devices > Advanced Driver Information > Write delay effects

Write delay effects

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.

TestFunc(INT nValue)
PLC_VAR = nValue;

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");

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).