Introduction
The functionality described below was added by RTE >= 34.24 and RC3E >= 33.6.2.
To use persistent global variables, a retentive memory area must be reserved:
•With RDE version >= 33.5.1 in Configuration/General/Memory/Settings, the parameter "Maximum size of global variables" must be set to 65536
•With RDE version <33.5.1, the following lines need to be added in the RTE.CFG file:
_ifvs 0x22180000 DIM_PV_AREA 65536 _endvs 0x22180000 |
Bookmarks
Access to global variable data types
Global variables are variables (real, int or even structs) that can be accessed from any task in the control (R3 task, rules, OB functions or even RPL tasks).
These variables, in addition to being "Global," can also be declared "Persistent," in which case they will retain their values after the control is turned off.
RTE provides some functions to safely create, read, and write these variables.
To simplify the use of these variables in OB functions, the compiler defines some special data types that encompass and hide RTE function calls.
These data types are: rGlobalInt for integer (int) variables, rGlobalReal for real (double) variables, rGlobalBool for boolean (bool) variables, and rGlobalString for string (char []) variables.
The declaration of these variables must provide the "Global Name" of the variable (a string that must be unique throughout the application and used as the global variable identifier) and (optionally) some flags that are used when the global variable is created (such as the Persistent attribute).
The flags defined are:
•gv :: Persistent (0x000001) The variable is persistent
•gv :: ForceOverwrite (0x000002) Force the writing of the already existing variable
•gv :: NoDataFile (0x000004) If not persistent, the data file is not created
•gv :: WriteValue (0x000008) If the variable already exists, overwrite the value with the one in the cache
An optional const string parameter is also provided to set a password for writing the variable; without providing the correct password set when the variable was created, the variable can only be read.
Example
rGlobalInt gvKEY_MODE ("KEY_MODE", gv::NoDataFile); rGlobalReal gvDesFr ("DES_FR", gv::Persistent); rGlobalReal myPrivateVar ("myvar", gv::Persistent, “1234abc”); |
These variables can be used as any 'int' or 'double' variable
Example
if (gvKEY_MODE > 3) gvKEY_MODE = 1; gvDesFr = i_maximum(gvDesFr - frstep, 0.01); |
You cannot use these variables with functions that carry a pointer to int or double as a parameter; if you need to pass the variables by reference, use a reference to rGlobalInt or rGlobalReal. For the same reason in functions with open arguments, such as printf, you must explicitly pass the variable to the base type.
It is important in any case to remember that these variables are only an interface to "true" global variables, so a new link is created when the variable is created, and the variable has local memory to "store" the value of the global variable.
For these reasons, it is important that:
•To avoid a large memory loss and time, these variables should be declared in "global" (static) space and not declared "locally" in a function
•(Only for global structs) A different variable must be declared for each different task that uses it. It means that if there are two functions in the OB that use the same global variable, and one function is called by a task and the other function is called by the rules (or by an ob service), there must be two different variables declared, one for each task
Using global variables as OB properties
To define a global variable in an externally accessible OB, such as R3 tasks, RDE tools or RTM widgets, the OB interface can declare some virtual properties that will provide access to internal global variables.
There are two ways to do this:
•Define global or persistent properties in the .obs file
Example
; Class properties properties global real gvr global ro int gvi persistent real nvgvr persistent int nvgvi end_properties |
•Use some macros defined in the compiler
Example
In .obs file: ; Class properties properties virtual real gvr virtual ro int gvi virtual real nvgvr virtual int nvgvi end_properties
In .h file: // virtual properties OB_DEFINE_GLOBAL_PROPERTY0(double, gvr) OB_DEFINE_GLOBAL_PROPERTY_RO0(int, gvi) OB_DEFINE_GLOBAL_PROPERTY0(double, nvgvr) OB_DEFINE_GLOBAL_PROPERTY0(int, nvgvi)
In .cpp file: // Constructor obclass::obclass (rObOptions *opts): obclass_base(opts), OB_INIT_GLOBAL_PROPERTY0(gvr, gv::NoDataFile), OB_INIT_GLOBAL_PROPERTY_RO0(gvi, gv::NoDataFile), OB_INIT_GLOBAL_PROPERTY0(nvgvr, gv::Persistent), OB_INIT_GLOBAL_PROPERTY0(nvgvi, gv::Persistent) { } OB_IMPLEMENT_GLOBAL_PROPERTY0(obclass, double, gvr) OB_IMPLEMENT_GLOBAL_PROPERTY_RO0(obclass, int, gvi) OB_IMPLEMENT_GLOBAL_PROPERTY0(obclass, double, nvgvr) OB_IMPLEMENT_GLOBAL_PROPERTY0(obclass, int, nvgvi) |
Using either method, these properties will be accessible from outside the OB (R3 task, RDE tools or RTM widget) as:
•obname.gvr
Inside the OB they will be used as:
•gvr
The 'global name', used to access from other OBs or RPL tasks, will be:
•“obname_gvr”
Global and Persistent Arrays
Global and persistent variables of integer and real types can also be defined as arrays:
•global real my_vect[10]
In this case, the variable defined in another OB must be defined as:
•rGlobalRealVect gvMyVect("obname_my_vect", 10);
and can be used as a vector of 10 doubles:
•gvMyVect[i] = gvMyVect[i-1] + 1;
Remember that it is not a real array, so you cannot pass it to functions that accept a pointer (double *), but you must pass it as a reference (rGlobalRealVect &).
Use of registers as global variables
To also facilitate the use of RTE registers from an OB, the following data types have been defined:
•rIntRegVar varname(index); // like R(index)
•rBitRegVar varname(index, bit); // like R(index).(bit)
•rRealRegVar varname(index); // like RR(index)
•rNvIntRegVar varname(index); // like NVR(index)
•rNvRealRegVar varname(index); // like NVRR(index)
•rStringRegVar varname(index); // like SR(index)
•rNvStringRegVar varname(index); // like NVSR(index)
Reading and writing these variables will be the same as reading and writing the corresponding register.
The idx () method will provide the "indexof" the register.
On integer registers, a single bit can also be accessed by the bit () and setBit () methods.
Example
rIntRegVar RHMI_CMD1(1); // as R(1) rBitRegVar bAutoMan (RHMI_CMD1.idx(), 1); // as R(1).1 rRealRegVar rrAG_FR(37); // as RR(37) rStringRegVar srProgramPath(2); // as SR(2) … if (bAutoMan) { bAutoMan = 0; RHMI_CMD1.setBit(5, true); } rrAG_FR = rrAG_FR + 0.1; srProgramPath = “name of program |