Applies To:
  • CitectSCADA 5.x, 6.x, 7.x
  • VijeoCitect 5.x, 6.x, 7.x
  • PowerScada 5.x, 6.x, 7.x 

Summary:
How to correctly use Errset() and IsError() functions

Solution:

 

When a Cicode hardware alarm is triggered, a fatal error is caused and the task will be terminated. This can cause significant issues, particularly in critical code that needs to be runnning in an infinite loop. Manual error-checking mode, Errset(1), can be used for parts of Cicode when task termination is undesirable, working around the underlying issue in the Cicode. After executing ErrSet(1), CitectSCADA will not automatically check for errors, and the user can manually check for errors using the Cicode function IsError() after a line of code is executed.

This should only be used if the intent of the Cicode is to check for errors and handle them (such as displaying a message, or shutting down the function gracefully). The default action of terminating the task is to prevent unintended actions if your code is not checking for problems (such as trying to log to a database that could not be opened). Many Cicode functions, like DevOpen(), will return an error code and IsError() is not required, but Errset(1) is still required to prevent task termination (see Q1686). Refer to the individual help on each Cicode function for further details. 

Note that ErrSet(1) is NOT global, and when used it will only affect all functions within the particular thread in which it has been called. It is recommended that you apply ErrSet() around specific small segments of Cicode that are problematic (i.e. single Cicode statements), and not around large sections of code. An example of the use of this code is below, where we want to display an error message to the user if we fail to write to a device.

ErrSet(1);                           ! Disable error checking
DevWrite(nonexistingdevicehandle, "data to write");
nError = IsError();                  ! Sets nError to 269 (bad handle specified)
ErrSet(0);                           ! Re-enable error checking
IF nError <> 0 THEN
    Message("Error", "Failed to write to device. Error:" + IntToStr(nError), 16);
    RETURN -1;
END

Not all errors are fatal, and the user should reset the error code using IsError() prior to the line of Cicode that you are trying to check, otherwise an error code from a previous line of code will propagate into the next line, as a successful statement does not reset any error code that has been triggered from a previous statement. The following code demonstrates where this is an issue:

ErrSet(1);
rTest = nVar / 0;                    ! Causes divide by 0 error (273)
DevWrite(hDevice, "data to write");  ! Line of code we want to check for errors
nError = IsError();

The nError variable will be set to 273 (Divide by 0 Error) if DevWrite is successful, as the internal error variable has not been reset. If DevWrite fails, then the error code will correctly be set to a Cicode error such as 269 (bad handle specified). The user should reset the internal error code: 

ErrSet(1);
Test = nVar / 0;                     ! Causes divide by 0 error (273)
IsError();                           ! Reset the internal error variable
DevWrite(hDevice, "data to write");  ! Line of code we want to check for errors
nError = IsError();

The error will be reset and the error code from nVar / 0 will not propagate through. So if DevWrite succeeeds, IsError will return 0, and if DevWrite fails, it will return 269. Note that DevWrite also returns its error code, so instead of calling IsError() before and after DevWrite, you can just use: 

nError = DevWrite(hDevice, "data to write"); 


Keywords:
 IsError, Errset, Manual, trap, errors, hardware alarms

Attachments