Module | Name | Version | License | Source | Languages | Platforms | Type | Author | Description |
---|---|---|---|---|---|---|---|---|---|
JavaLikeCalc | Calculator on the Java-like language | 5.6 | GPL2 | daq_JavaLikeCalc.so | en,uk,ru,de | x86,x86_64,ARM | DAQ | Roman Savochenko Maxim Lysenko (2009-2010) — the page initial translation |
Provides a calculator and libraries engine on the Java-like language. The user can create and modify functions and their libraries. |
The data source module provides OpenSCADA for a mechanism of creating functions and their libraries on Java-like language. The writing of the function in the Java-like language is reduced to the binding of the parameters of the function by an algorithm.
Direct computations are provided by the creation of controller object and linking it with the function of this module. For linked function it is created the frame of values (context), with which the periodically calculating is carried out.
The module implements the functions of the horizontal redundancy, that is working in conjunction with the remote station of the same level. In addition to the synchronization of the archives of values and archives of attributes of parameters, the module implements synchronization of computational function, in order to shockless holding of the algorithms.
Parameters of functions can be freely created, deleted or modified. The current version of the module supports up to 65535 parameters of the function, in the sum with the internal variables. The view of editing functions in the OpenSCADA configurator is shown in Figure 1. The parameter name's rows after the first one treat as help.
After any change in the program text or parameter configuration, the program is recompiled by notifying the values objects TValCfg associated with the function. The language compiler is built using the well-known grammar generator "Bison", which is compatible with the no less well-known "Yacc" utility.
The language uses the implicit definition of local variables, which is to define a new variable in the case of assigning a value to it. This type of local variable is set according to the type of the assigning value. For example, the expression Qr=Q0*Pi+0.01; will define Qr variable with the type of variable Q0.
In working with various types of data the language uses the mechanism of casting the types in the places where such casting is appropriate.
To comment the sections of code in the language it is provided "//" and "/* ... */" characters. Everything that comes after "//" up to the end of the line and between "/* ... */", is ignored by the compiler.
During the code generation, the language compiler produces an optimization of constants and casting the types of the constants to the required type. The optimization of the constants means the calculation of two constants and the insertion of the result into the code in the process of constructing a byte-code. For example, the expression y=pi*10; reduces to a simple assignment y=31.4159;. Casting the types of constants to the required type means formation of the constant in the code which excludes the cast in the execution process. For example, the expression y=x*"10";, in the case of the real type of the variable x, is transformed into y=x*10;.
Assignment expressions can be recorded through symbol ',', for example:
var1 = 1, var2 = 3, var4 = var1+var2;
for(var1 = 0, var2 = 0, var3 = -1; var1 < 10; var1++, var2++) var3++;
The language supports calls of the external and internal functions. Name of any function in general is perceived as a character, which is tested to belong a particular category in the following order:
Calling an external function, like the global attribute of the DAQ parameter, is written as an address to the node of the object model OpenSCADA: "DAQ.JavaLikeCalc.lib_techApp.klapNotLin". For static functions you are allowed to the dynamic linking also in the following way:
function klapNotLin = "DAQ.JavaLikeCalc.lib_techApp.klapNotLin";
rez = klapNotLin(prm1, prm2, ..., prmN);
To provide the writing of custom control procedures for various components of OpenSCADA, this module provides the implementation of the precompiling API of custom procedures for individual components of OpenSCADA in the Java-like language. These components for example are: templates of the parameters of the subsystem "Data acquisition" and the visual control area (VCA).
Keywords: if, else, while, for, in, break, continue, return, function, using.
Constants:
Types of variables:
Built-in constants: pi = 3.14159265..., e = 2.71828182..., EVAL_BOOL(2), EVAL_INT(-9223372036854775807), null,EVAL,EVAL_REAL(-1.79E308), EVAL_STR("<EVAL>")
Global attributes of the DAQ parameter (starting from the subsystem "DAQ", as follows {Type of DAQ module}.{Controller}.{Parameter}.{Attribute}).
The functions and parameters of the object model of OpenSCADA.
The EVAL (Error VALue) variants and null are processed specially in conversion one to one depending on used the base type, that is you are free in use only null or EVAL for any cases.
The operations supported by the language are presented in the table below. Priority of the operations is reduced from top to bottom. Operations with the same priority are in the same color group.
Symbol | Description |
() | Call of function. |
{} | Program blocks. |
++ | Increment (post and pre). |
-- | Decrement (post and pre). |
- | Unary minus. |
! | Logical negation. |
~ | Bitwise negation. |
* | Multiplication. |
/ | Division. |
% | Remainder of integer division. |
+ | Addition |
- | Subtraction |
<< | Bitwise shift left |
>> | Bitwise shift right |
> | Greater |
>= | Greater than or equal to |
< | Less |
<= | Less than or equal to |
== | Equals |
!= | Unequal |
| | Bitwise "OR" |
& | Bitwise "AND" |
^ | Bitwise "Exclusive OR" |
&& | Boolean "AND" |
|| | Boolean "OR" |
?: | Conditional operation "i=(i<0)?0:i;" |
= | Assignment. |
+= | Assignment with addition. |
-= | Assignment with subtraction. |
*= | Assignment with multiplication. |
/= | Assignment with division. |
The virtual machine of the language provides the following set of built-in functions general-purpose:
To provide high speed work in mathematical calculations, the module provides built-in mathematical functions that are called at the level of the commands of the virtual machine:
The total list of the operators of the language:
The language supports two types of conditions. First — this is the operation of condition for use within the expression, second — a global, based on the conditional operators.
The condition inside an expression is based on the operations '?' and ':'. As an example we'll write the following practical expression:
st_open = (pos >= 100) ? true : false;
Which reads as — if the variable pos greater than or equal to 100, the variable st_open is set to true, otherwise — to false.
The global condition is based on the conditional operators "if" and "else". As an example, we can show the same expression, but recorded in another way:
if(pos > 100) st_open = true; else st_open = false;
Two types of the loops are supported: while, for and for-in. The syntax of the loops corresponds to the programming languages: C++, Java and JavaScript.
Loop while is written generally as follows: while({condition}) {body of the loop};
Loop for is written as follows: for({pre-initialization};{condition};{post-calculation}) {body of the loop};
Loop for-in is written as follows: for({variable} in {object}) {body of the loop};
Where:
The language supports definition and call of internal functions. To determine the internal function, the keyword "function" is used and in general, the definition has a syntax: function {fName} ({var1}, {var2}, ... {varN}) { {the function body} }. Defining an internal function inside another is not allowed but it is allowed to call a previously defined one.
Calling an internal function is done in a typical way as a procedure {fName}({var1}, {var2}, ... {varN}); or as a function {vRez} = {fName}({var1}, {var2}, ... {varN});. The call of internal functions is valid only after their declaration is higher!
All defined variables into the main body inaccessible into the internal function and can be pass in as two way arguments of the internal function call or as the main function arguments. All defined variables into the internal function have itself namespace and inaccessible from the main body or any other internal function and can be pass out to the main body as two way arguments, return of the internal function call or the main function arguments. The internal function variables are registered for saving/restoring their context after second and more entry to the function, so they completely support the recursive calls!
Operator "return" into the internal function makes controllable finishing of the function execution and places a pointed variable or an expression result as the internal function call result.
An example of the internal function declaration and using in typical way shown next:
function sum(a, b, c, d) { return a + ((b==null)?0:b) + ((c==null)?0:c) + ((d==null)?0:d); }
rez = sum(1, 2);
The language supports the following special characters of the string variables:
JavaLikeCalc provides support of the data type "Object". The data type "Object" is an associated container of properties and functions. The properties can support data of fourth basic types and other objects. Access to object properties can be done through the record of property names to the object obj.prop, through a dot, and also through the inclusion of the property name in square brackets obj["prop"]. It is obvious that the first mechanism is static, while the second lets you to specify the name of the property through a variable. The name of the property through the dot must not start with a digit and contain operations symbols; otherwise, for the first digit, the object prefix should be used — SYS.BD.SQLite.db_1s, or write in square brackets — SYS.BD.SQLite["1+s"], for operations symbols in the name. Object's properties removing you can perform by the operator "delete". Reading of an undefined property will return null-EVAL. Creating an object is carried by the keyword new: varO = new Object(). The basic definition of the object does not contain functions. Copying of an object is actually makes the reference to the original object. When you delete an object is carried out the reducing of the reference count, and when the count is set to zero then the object is removed physically.
Different components of OpenSCADA can define the basic object with special properties and functions. The standard extension of the object is an array "Array", which is created by the command varO = new Array(prm1,prm2,prm3,...,prmN). Comma-separated parameters are placed in the array in the original order. If the parameter is the only one the array is initiated by the specified number of empty elements. Peculiarity of the array is that it works with the properties as the indexes and the main mechanism of addressing is placing the index into square brackets arr[1] is accessible. Array stores the properties in its own container of the one-dimensional array. Digital properties of the array are used to access directly to the array, and the characters work as the object properties. For more details about the properties and functions of the array can be read here.
The object of regular expression "RegExp" is created by command varO = new RegExp(pat, flg), where pat — pattern of the regular expression, and flg — match flags. The object for work with regular expressions, based on the library "PCRE". In the global search set object attribute "lastIndex", which allows you to continue searching for the next function call. In the case of an unsuccessful search for the attribute "lastIndex" reset to zero. For more details about the properties and functions of the regular expression object can be read here.
For random access to the function arguments provided the arguments object, which you can refer to by the symbol "arguments". This object contains the property "length" with a number of arguments in the function and allows you to access to a value of the argument by its number or ID. Consider the enumeration of the arguments on the cycle:
args = new Array();
for(var i = 0; i < arguments.length; i++)
args[i] = arguments[i];
The basic types have the partial properties of the object. Properties and functions of the basic types are listed below:
var rez = "Java123Script".search("script","i"); // rez = 7
var rez = "Java123Script".search(new RegExp("script","i")); // rez = 7
var rez = "1 plus 2 plus 3".match("\\d+","g"); // rez = [1], [2], [3]
var rez = "1 plus 2 plus 3".match(new RegExp("\\d+","g")); // rez = [1], [2], [3]
rez = "1,2, 3 , 4 ,5".split(new RegExp("\\s*,\\s*")); // rez = [1], [2], [3], [4], [5]
rez = "Javascript".replace(4,3,"67"); // rez = "Java67ipt"
rez = "123 321".replace("3","55"); // rez = "1255 5521"
rez = "value = \"123\"".replace(new RegExp("\"([^\"]*)\"","g"),"``$1''")); // rez = "value = ``123''"
For access to the system objects(nodes) of OpenSCADA the corresponding object is provided which is created simply by specifying the enter point "SYS" of the root object OpenSCADA, and then with the point separator the sub-objects in accordance with the hierarchy are specified. For example, the call of the request function over the output transport is carried out as follows: SYS.Transport.Sockets.out_testModBus.messIO(Special.FLibSYS.strEnc2Bin("15 01 00 00 00 06 01 03 00 00 00 05"));.
Here are some examples of programs on the Java-like language:
//Model of the course of the executive machinery of ball valve
if(!(st_close && !com) && !(st_open && com))
{
tmp_up = (pos>0&&pos<100) ? 0 : (tmp_up>0&&lst_com==com) ? tmp_up-1/frq : t_up;
pos += (tmp_up>0) ? 0 : (100*(com?1:-1))/(t_full*frq);
pos = (pos>100) ? 100 : (pos<0) ? 0 : pos;
st_open = (pos>=100) ? true : false;
st_close = (pos<=0) ? true : false;
lst_com = com;
}
//Valve model
Qr = Q0 + Q0*Kpr*(Pi-1) + 0.01;
Sr = (S_kl1*l_kl1+S_kl2*l_kl2)/100;
Ftmp = (Pi>2*Po) ? Pi*pow(Q0*0.75/Ti,0.5) : (Po>2*Pi) ? Po*pow(Q0*0.75/To,0.5) : pow(abs(Q0*(pow(Pi,2)-pow(Po,2))/Ti),0.5);
Fi -= (Fi-7260*Sr*sign(Pi-Po)*Ftmp)/(0.01*lo*frq);
Po += 0.27*(Fi-Fo)/(So*lo*Q0*frq);
Po = (Po<0) ? 0 : (Po>100) ? 100 : Po;
To += (abs(Fi)*(Ti*pow(Po/Pi,0.02)-To)+(Fwind+1)*(Twind-To)/Riz)/(Ct*So*lo*Qr*frq);
The controller object of the module, to provide immediate calculations, connects with the functions of libraries, built with his help, or with the data acquisition template. In the case of a data acquisition template, the possibility of external linking with other parameters and attributes of the subsystem "Data Collection" is added. In order to provide calculated data in OpenSCADA, parameters can be created in the controller object. Example of the configuration tab of the controller object of the given type shown in Figure 2.
From this tab you can set:
Tab "Calculation" of the controller object (Fig. 3) contains parameters and a text of the program, are directly performed by the controller. Also, for monitoring of the execution, the time of calculating of the program is shown. The module provides processing a number of special options available in the controller program:
The module provides only one the "Standard (std)" type of the parameters with the parameters table name "JavaLikePrm_{CntrId}".
Parameter of the controller object of the module performs the function of providing the access to the results of computation of the controller to OpenSCADA by attributes if the parameters. From the specific fields, the configuration tab of the parameter of the controller object contains only the field for listing the parameters of the computational function that must be reflected.
The module provides a mechanism to create libraries of user's functions on the Java-like language. Example of the configuration tab of the library is shown in Figure 4. The tab contains the basic fields: accessing, address of the DB table (with tracking the availability of the data in different storages and providing the sequentially removing duplicates), date and time of modification, identifier, name and description.
Function, as well as the library, contains the basic configuration tab, the tab of the formation of the program and the parameters of the function (Fig. 1), as well as the performance tab of the created function.
Some objects of the module provides functions for user's programming.
The object "Functions library" (SYS.DAQ.JavaLikeCalc["lib_Lfunc"])
The object "User function" ( SYS.DAQ.JavaLikeCalc["lib_Lfunc"]["func"] )
Service functions are an interface for accessing OpenSCADA from external systems through the Control Interface. This mechanism is the basis of all exchange within OpenSCADA, implemented through weak links and OpenSCADA's own exchange protocol.
Getting for values of the function IO of the controller object
REQ: <get path="/DAQ/JavaLikeCalc/{CNTR}/%2fserv%2ffncAttr" />
RESP: <get path="/DAQ/JavaLikeCalc/{CNTR}/%2fserv%2ffncAttr" rez="0">{IOs}</get>
<get path="/DAQ/JavaLikeCalc/testCalc/%2fserv%2ffncAttr" rez="0" user="roman">
<a id="f_frq">0.1</a>
<a id="f_start">0</a>
<a id="f_stop">0</a>
<a id="this"><TCntrNodeObj path="/sub_DAQ/mod_JavaLikeCalc/cntr_testCalc/"/></a>
<a id="offset">100</a>
<a id="out">50</a>
<a id="test">1</a>
<a id="rez" />
<a id="inFarg">3</a>
</get>
Setting for values of the function IO of the controller object
REQ[root-DAQ]: <set path="/DAQ/JavaLikeCalc/{CNTR}/%2fserv%2ffncAttr">{IOs}</set>
<set path="/DAQ/JavaLikeCalc/testCalc/%2fserv%2ffncAttr">
<a id="out">50</a>
<a id="test">1</a>
</set>
Source text of the procedures on the language is compiled into a bytecode, which is then computed by the virtual machine. The bytecode is not native machine code and achieving to productivity of the hardware platform into the virtual machine that executing is theoretical unreal, sure if the virtual machine code is not executed directly by the CPU. That is, the productivity of the bytecode execution approximately low by ten to the hardware productivity due to the overhead of the virtual machine commands, the distribution of multithreaded data access, the transparent casting of types and the lack of strict typing, as well as the dynamic nature of the language and the presence of complex types "String" and "Object ".
28.01.2006:
Description: Initial estimation of the productivity of the OpenSCADA virtual machine in example of the expression y=x1+x2, where all the variables are global and in the float-point type.
Stage | Action | K7_1G-0, us |
---|---|---|
1 | The registers list initialization | 2.3 |
2 | Entry to the function exec() | 3 |
3 | The commands coming | 4.4 |
4 | Reading | 9 |
5 | Full time | 10.2 |
17.07.2013:
Description: Justification of the current performance evaluation and optimization. The measurements were made by sampling the minimum time from five calls to 1000 executions of the formula a -= b*(a-c) and its abbreviations in each call. All the variables are global and in the float-point type.
Formula | Time on AMDGeode-500 (the operation time), us | Notes |
---|---|---|
a -= b*(a-c) | 4.52 (0.74) | |
a -= b*c | 3.78 (0.72) | |
a -= b | 3.06 (0.56)
|
|
a = b | 2.5 (1.21)
|
Writing to the function IO is longer then reading from the local register for other context call and additional checking for NAN and real modification. |
Empty | 1.29 | the infrastructure and measurement method utilization time. |
24.04.2016:
Reason: Estimate performance of accessing to the low level IO lines on Raspberry Pi GPIO in different ways of the JavaLikeCalc language of OpenSCADA.
Conditions: Raspberry Pi 3, GPIO40, DAQ.GPIO (based on the library bcm2835)
Operation | Result, us |
---|---|
Sleep. Lag on sleep in 1ms measuring, which mostly limited by the realtime reaction about 100us. | |
SYS.sleep(); | +110 |
Special.FLibSYS.fnc_tmSleep(); | +70 |
Sleep. Lag on sleep in 100us measuring, which performs in the measuring cycle. | |
SYS.sleep(); | +17 |
Special.FLibSYS.fnc_tmSleep(); | +2 |
Get a level of the GPIO pin | |
From an attribute res = GPIO.io.pi.gpio17; | 5.4 |
By the static accessing function res = DAQ.GPIO.io.pi.fnc_get(17); | 1.6 |
By the static accessing function with the link preparation function get = "DAQ.GPIO.io.pi.fnc_get"; for(i = 0; i < 10000; i++) res = get(17); | 1.7 |
By the dynamic accessing function res = SYS.DAQ.GPIO.io.pi.fnc_get.call(17); | 80 |
By the dynamic accessing function with the end object preparation tO = SYS.DAQ.GPIO.io.pi.fnc_get; for(i = 0; i < 1000; i++) res = tO.call(17); | 14.3 |
Put a level to the GPIO pin | |
To an attribute GPIO.io.pi.gpio18 = true; | 2.1 |
By the static accessing function DAQ.GPIO.io.pi.fnc_put(18, true); | 1.4 |
By the static accessing function with the link preparation function put = "DAQ.GPIO.io.pi.fnc_put"; for(i = 0; i < 10000; i++) put(17, false); | 1.5 |
By the dynamic accessing function SYS.DAQ.GPIO.io.pi.fnc_put.call(18, true); | 79 |
By the dynamic accessing function with the end object preparation tO = SYS.DAQ.GPIO.io.pi.fnc_put; for(i = 0; i < 1000; i++) tO.call(18, true); | 14.3 |
Modules/JavaLikeCalc/en - GFDL | March 2024 | OpenSCADA 0.9.7 |