LLExec Web Server

From Axel Public Wiki
Jump to: navigation, search

Server API

This section describes the internal API that LLExec integrated Web Server offers to access PLC variables and parameters.

Please note that this API is wrapped by the LLWebServer library, that should be used instead.

Variables access

To access variables (also called symbols), the web server offes two http methods: GET to read simple variables and PUT to write simple variables.
The symbols that can be accessed are global variables of simple types (numeric, boolean, string).
The symbols can also be structured query of the type my_arr[123].my_field, with the constraint that the value of the expression must be of simple type.

GET symbols method syntax

The syntax of the url to do the GET method:

http://1.2.3.4/api/sym?sym_name1&sym_name2&sym_name3

The content value of any symbol will be written on a single line.

PUT symbols method syntax

The syntax of the url to do the PUT method:

http://1.2.3.4/api/sym?sym_name1=value1&sym_name2=value2&sym_name3=value3

Where the valueN is the value of the variable N. String values doesn't need limiters, and spaces must be coded in the URL with the string %20 . For example:

PUT http://1.2.3.4/api/sym?var_bool=true&var_int=123&var_string=hello%20world

Parameters access

To access parameters web server offes two http methods: GET to read parameters and PUT to write parameters.
To access parameters their index must be known, eventually with subindex (this indexes are called IPA): IPA examples are 10000.12 or 60000 .

GET symbols method syntax

The syntax of the url to do the GET method:

http://1.2.3.4/api/par?ipa1&ipa2&ipa3

The content value of any parameter will be written on a single line.

PUT symbols method syntax

The syntax of the url to do the PUT method:

http://1.2.3.4/api/par?ipa1=value1&ipa2=value2&ipa3=value3

Where the valueN is the value of the variable N. String values doesn't need limiters, and spaces must be coded in the URL with the string %20 . For example:

PUT http://1.2.3.4/api/par?10000=true&10010=123&10021=Hello%20world

Browsing variables

The Web Server offers a method to obtain information about variables on the system.
The url for browsing symbols have to be called with http GET method and is as follows:

http://1.2.3.4/api/symlist?name=pattern

The pattern can be a variable name, the jolly * character, or a name with the jolly character prefixed or suffixed.
Examples are

http://1.2.3.4/api/symlist?name=*
http://1.2.3.4/api/symlist?name=my_variable_name
http://1.2.3.4/api/symlist?name=count*
http://1.2.3.4/api/symlist?name=*substr*

The output of the query is a JSON containing the list of the symbols that matches the pattern, with attributes like name, type and description.
For example, if in my system i do the query

http://127.0.0.1/api/symlist?name=*

I obtain the following output:

[
	{ "name":"$$STKLIMIT$$", "type":"LWORD", "descr":""},
	{ "name":"$$STKPOINTER$$", "type":"LWORD", "descr":""},
	{ "name":"$$DEBUGID$$", "type":"DWORD", "descr":""},
	{ "name":"CNT", "type":"INT", "descr":""},
	{ "name":"SYSPLCSTATUS", "type":"PLC_STATUS", "descr":"Internal PLC Status"},
	{ "name":"SYSTIMER", "type":"UDINT", "descr":"System timer [ms]"},
	{ "name":"SYSPLUGINSDATARO", "type":"BYTE", "descr":"RO allocation area for plugins"},
	{ "name":"SYSPLUGINSDATARW", "type":"BYTE", "descr":"RW allocation area for plugins"},
	{ "name":"SYSUSERDATABLOCK", "type":"BYTE", "descr":"Data block available for user data mapping"},
	{ "name":"SYSUSERDATABLOCKRETAIN", "type":"BYTE", "descr":"Data block available for user data mapping - Retain DB"},
	{ "name":"SYSHOURS", "type":"USINT", "descr":"Values 0-23"},
	{ "name":"SYSMINUTES", "type":"USINT", "descr":"Values 0-59"},
	{ "name":"SYSSECONDS", "type":"USINT", "descr":"Values 0-59"},
	{ "name":"SYSDAY", "type":"USINT", "descr":"Values 1-31"},
	{ "name":"SYSDAYOFWEEK", "type":"USINT", "descr":"Values 0-6 where 0 is Sunday "},
	{ "name":"SYSMONTH", "type":"USINT", "descr":"Values 1-12"},
	{ "name":"SYSYEAR", "type":"UINT", "descr":"Values 4 digit"},
	{ "name":"SYSCOPMSDOFAILEVENT", "type":"COPMSDOFAIL", "descr":"This struct is filled just before an occurred parametrization SDO fail is signaled to PLC task"},
	{ "name":"SYSCOPMNODESTATUSCHANGEDEVENT", "type":"COPMNODESTATUSCHANGED", "descr":"This struct is filled just before a node status change is signaled to PLC task"},
	{ "name":"SYSCOPMEMERGENCYEVENT", "type":"COPMEMERGENCY", "descr":"This struct is filled just before an occurred emergency event is signaled to PLC task"},
	{ "name":"SYSCOPMPDOERREVENT", "type":"COPMPDOERR", "descr":"This struct is filled just before a malformed PDO RX event is signaled to PLC task"},
	{ "name":"SYSCOPMEVENTID", "type":"DINT", "descr":"This value is set with the event ID value. The struct corresponding to the ID set can be used in the notify event task when it is executed"},
	{ "name":"SYSCOPMRESYNCINFO", "type":"COPMRESYNC", "descr":"This struct is filled just before a master/slave resync event"},
	{ "name":"SYSCOPMMASTERSTATUS", "type":"COPMMASTERSTATUS", "descr":"See structure definition COPMMASTERSTATUS"},
	{ "name":"SYSCOPMNODESTATUS", "type":"COPMNODESTATUS", "descr":"See structure definition COPMNODESTATUS"},
	{ "name":"SYSCOPMSDOSCHEDULINGDIAGNO", "type":"COPMSDOSCHEDULINGDIAGNO_SLAVE", "descr":"This structure show for each node the last SDO scheduled succeded and failed"},
	{ "name":"SYSMBMRTUNODESTATUS", "type":"MBMNODESTATUS", "descr":"System Modbus Master RTU communication status for network with id MB_RTU_NETWORK_0. ..."},
	{ "name":"SYSMBMRTUNODESTATUS_1", "type":"MBMNODESTATUS", "descr":"System Modbus Master RTU communication status for network with id MB_RTU_NETWORK_1. ..."},
	{ "name":"SYSMBMRTUNODESTATUS_2", "type":"MBMNODESTATUS", "descr":"System Modbus Master RTU communication status for network with id MB_RTU_NETWORK_2. ..."},
	{ "name":"SYSMBMRTUNODESTATUS_3", "type":"MBMNODESTATUS", "descr":"System Modbus Master RTU communication status for network with id MB_RTU_NETWORK_3. ..."},
	{ "name":"SYSMBMTCPNODESTATUS", "type":"MBMTCPNODESTATUS", "descr":"System Modbus Master TCP communication status. It is a structure of type MBMTCPNODESTATUS composed ..."},
	{ "name":"SYSALARMCFGOK", "type":"BOOL", "descr":"Alarm manager properly configured"},
	{ "name":"SYSALARMACTIVE", "type":"BOOL", "descr":"At least one alarm is active (associated condition holds true)"},
	{ "name":"SYSALARMWAITACK", "type":"BOOL", "descr":"No alarm is active but at least one alarm is waiting for acknowledgement"},
	{ "name":"SYSALARMCOUNT", "type":"UINT", "descr":"Number of active alarms"},
	{ "name":"SYSPLCCONNECTMASTERSTATUS", "type":"PLCCONNECTMASTERSTATUS", "descr":""},
	{ "name":"SYSPLCCONNECTENDPOINTSSTATUS", "type":"PLCCONNECTENDPOINTSTATUS", "descr":""},
	{ "name":"$$CODEBASE$$", "type":"UDINT", "descr":""},
	{ "name":"$$CODESTART$$", "type":"UDINT", "descr":""},
	{ "name":"$$CODESIZE$$", "type":"UDINT", "descr":""},
	{ "name":"$$CODEEND$$", "type":"UDINT", "descr":""},
	{ "name":"$$DATASIZE$$", "type":"UDINT", "descr":""},
	{ "name":"$$AUXDATASIZE$$", "type":"UDINT", "descr":""},
	{ "name":"$$BITDATASIZE$$", "type":"UDINT", "descr":""},
	{ "name":"$$RITDATASIZE$$", "type":"UDINT", "descr":""}
]

Browsing parameters and menus

LogicLab allows to define application parameters and status variables, with an IPA a type and some others attributes.
From the perspective of the web server, parameters and status variables are the same type of objects, so we simply refer as parameters.
In LogicLab you can also define menus in wich some parameters can be contained: every menu is identified by an unique id.
Menus can be nested.
An user can define also custom web pages, that can be nested also in mixed mode with menus, they have theirs own unique id.
The web server offer two API to browse menus, custom pages and parameters, both can be called with the GET http method. The two urls are:

http://1.2.3.4/api/parlist?id=unique_id_of_a_menu
http://1.2.3.4/api/menulist?id=unique_id_of_a_menu&recursive=[TRUE | FALSE]

Parlist API

With this API an user can query the list of parameters contained in a menu, specified with its id
If the id is set to 0, all the application parameters are listed.
The output is a JSON containing the list of parameters with teirs attributes.
For example if I query the url

http://127.0.0.1/api/parlist?id=0

to my server I obtain the following output:

[
	{ "ipa": 1, "name": "Par 1", "typepar": "short", "readonly": false, "defval": 0, "descr": "", "form": "", "um": ""},
	{ "ipa": 10001, "name": "Par 2", "typepar": "short", "readonly": true, "defval": 0, "descr": "", "form": "", "um": ""}
]

The attributes that can be found for every parametes are:

  • ipa: the IPA of the parameter
  • subindex: if presemt, the subindex of the parameter. Note that the subindex presence depends on how LogicLab manage the address of parameters.
  • name: the name of the parameter.
  • typepar: the type of the parameter.
  • readonly: the attribute read-only of the parameter.
  • defval: the parameter's default value.
  • descr: the description of the parameter.
  • form: the printf-style desired format.
  • um: the measure unit for the parameter value.

Menulist API

With this API an user can query the menus and custom pages structure,
the id specifies the starting node, if zero it shows all the root menus.
If the recursive parameters is TRUE, nested menus and custom pages are shown.
For example if on my system I query the url

http://127.0.0.1/api/menulist?id=0&recursive=TRUE

I obtain the foolowing JSON output:

[
  { "type": 0, "id": 30000, "caption": "MyMenu", "children": 
    [
      { "type": 0, "id": 30001, "caption": "Nested Menu" },
      { "type": 1, "id": 30002, "caption": "Nested Custom Page", "link": "custom.html", "icon": "custom.ico" }
    ]
  }
]

the attributes are:

  • type: 0 is a menu, 1 is a custom page
  • id: the menu or custom page unique id
  • caption: the menu or custom page title
  • link: only for custom pages, its URL
  • icon: only for custom pages, its icon
  • children: when recursive=TRUE, this is a list of nested elements

System API

With the System API is possible to stop, start and get the status of LLExec runtime
It's also possible to read the LLExec Logs.
The API is composed of the following commands, all retrieving JSON responses:

  • /api/sys/start
  • /api/sys/stop
  • /api/sys/restart
  • /api/sys/status
  • /api/sys/log

start command

With the command /api/sys/start, without parameters is it possible to start the PLC.
Example:

http://127.0.0.1/api/sys/start

produces the following output:

{
 "plcCommand":"start",
 "result":"success"
}

stop command

With the command /api/sys/stop, without parameters is it possible to stop the PLC.
Example:

http://127.0.0.1/api/sys/stop

produces the following output:

{
 "plcCommand":"stop",
 "result":"success"
}

restart command

With the command /api/sys/restart, without parameters is it possible to restart the PLC.
Example:

http://127.0.0.1/api/sys/restart

produces the following output:

{
 "plcCommand":"restart",
 "result":"success"
}

status command

With the command /api/sys/status, without parameters is it possible to get some information about PLC runtime.
Example:

http://127.0.0.1/api/sys/status

produces the following output:

{
 "plcCommand":"status",
 "result":"success",
 "status":"sysStatusStarted",
 "arch" : "ARM32_VFP2",
 "runtime_version" : "1.33.0",
 "system_info" : "LLExec 2.17.15",
 "runtimes" : 
 [{
   "rtid":"0",
   "targetid":"LLExec_x86_2p0",
   "numtask":"5",
   "numdatablocks":"33",
   "numfunctions":"221",
   "datasize":"262144",
   "retsize":"4096",
   "bitsize":"0", 
   "codesize":"1048576",
   "debugsize":"0",
   "tracesize":"0",
   "srcsize":"0",
   "plcok":"true",
   "plcalarm":"false",
   "plcerrcode":"0",
   "appname":"LLSDO     ",
   "vermajor":"0",
   "verminor":"0",
   "appid":"1818769352"
 }]
}

log command

With the command /api/sys/log is it possible to get the actually buffered logs of LLExec.
It has three optional parameters:

  • mask - the exadecimal log print mask
  • startLine - the line where logging starts (default = 0)
  • numLines - Number of lines to print (default till the end of the log buffer)

Example:

http://127.0.0.1/api/sys/log?mask=FF&numLines=10

produces the following output:

{
 "plcCommand":"log", 
 "result":"success", 
 "lines":
  [ 
   { 
    "time":"00000000",
    "code":"00000001",
    "callId":"794EF2CA",
    "line":"LLEXEC 2.15.11 (Build: Apr 20 2020 15:15:20 32bit)"
   }
   ,{ 
    "time":"00000001",
    "code":"00000001",
    "callId":"794EF2CA",
    "line":"LLEXEC Starting up..."
   }
   ,{ 
    "time":"00000002",
    "code":"00000002",
    "callId":"794ECB94",
    "line":"Tracing: Configuration level"
   }
   ,{ 
    "time":"00000003",
    "code":"00000004",
    "callId":"794ECBA3",
    "line":"Tracing: Scheduler level"
   }
   ,{ 
    "time":"00000004",
    "code":"00000008",
    "callId":"794ECBB2",
    "line":"Tracing: Basic communication level"
   }
   ,{ 
    "time":"00000005",
    "code":"00000010",
    "callId":"794ECBC1",
    "line":"Tracing: XML configuration file level"
   }
   ,{ 
    "time":"00000006",
    "code":"00000020",
    "callId":"794ECBD0",
    "line":"Tracing: Fault and PLC debug informations"
   }
   ,{ 
    "time":"00000007",
    "code":"00000040",
    "callId":"794ECBDF",
    "line":"Tracing: General purpose message of advenced level"
   }
   ,{ 
    "time":"00000008",
    "code":"00000001",
    "callId":"794EF2CA",
    "line":"** Loading configuration"
   }
   ,{ 
    "time":"00000009",
    "code":"00000010",
    "callId":"794EF2CA",
    "line":"XML: overtime check : 0"
   }	
  ]
}

productlist command

With the command /api/sys/productlist, without parameters is it possible retrieve the list of products implemented in the runtime.
Example:

http://127.0.0.1/api/sys/productlist

produces the following output:

[
 {
  "name":"LLExec",
  "default":"yes"
 }
 ,
 {
  "name":"EtherCAT",
  "default":"no"
 }
]

This indicates two products implemented: LLExec and EtherCAT.
The product with the attribute default:true is the one implementing the PLC runtime.

licensestatus command

With the command /api/sys/licensestatus, get the status of the license for the product specified by the optional parameter product.
Also the HardwareID of the machine is returned. Example:

http://127.0.0.1/api/sys/licensestatus?product=EtherCAT

produces the following output:

{
 "product":"EtherCAT",
 "status":"licstatOk",
 "hwid":"0828c0dc45c4440c5f"
}

The status field can assume the values: licstatNotOk, licstatOk, licstatOkExternal or licstatDemo.

licenseregister command

With the command /api/sys/licenseregister , one can give the license for a product.
In this example I give the license for the EtherCAT product. Example:

http://127.0.0.1/api/sys/licenseregister?product=EtherCAT&license=925f7f84246441bad11d504978ac0b25

The result is returned.

admlogin command

With the command /api/sys/admlogin, an user can log in for administrative functions.
That includes all operations that can write variables and modify the state of the system.
All the session api are active only if SSL/TLS is enabled. Example:

https://127.0.0.1/api/sys/admlogin?username=poldo&password=pluto

admlogout command

With the command /api/sys/admlogout, close an administrative session Example:

https://127.0.0.1/api/sys/admlogout

admstate command

With the command /api/sys/admlogout, close an administrative session Example:

https://127.0.0.1/api/sys/admstate

returns

{"result":"ok"}   when this browser is in administrative state
{"result":"ko"}   when this browser is not in administrative state

Reference Table

List of commands
Command Output type HTTP method Parameters Description
/api/sym list of values GET list of symbol names Get the values of the specified symbols
/api/sym list of values PUT list of symbol=value pairs Set the values of the specified symbols
/api/par list of values GET list of IPAs Get the values of the specified parameters
/api/par list of values PUT list of ipa=value pairs Set the values of the specified parameters
/api/symlist JSON GET name=pattern Get the symbols list
/api/menulist JSON GET id (unique id), recursive (TRUE FALSE) Get the list of child menus from a menu with a specified menu id
/api/parlist JSON GET id (unique id) Get the list of the parameters in the menu entry
/api/sys/start JSON PUT NA Starts the runtime
/api/sys/stop JSON PUT NA Stops the runtime
/api/sys/restart JSON PUT NA Restarts the runtime
/api/sys/status JSON GET NA Get the runtime status
/api/sys/log JSON GET mask (print mask), startLine (first line to get), numLines (number of lines to get) Get the runtime logs
/api/sys/productlist JSON GET NA Get the runtime products
/api/sys/licensestatus JSON GET product: the optional product name Get the product license status and the HardwareID of the machine
/api/sys/licenseregister JSON PUT product, license Register a license into runtime
/api/sys/admlogin JSON PUT username, password Start an administrative session
/api/sys/admlogout JSON PUT NA Stop the current administrative session
/api/sys/admstate JSON GET NA Get the current administrative session state

Client library

This section describes the LLWebServer.js library and its features.

In order to use the library, you have to create HTML Elements with some specific data attributes; LLWebServer will find them in the web page and will take care of managing their data and their values.

The accepted data attributes are:

  • data-llweb-sym: used to link a PLC symbol on server the to the HTML Element
  • data-llweb-par: used to link a PLC parameter on server to the HTML Element
  • data-llweb-img: associated to a symbol or a parameter, with an img HTML Element, allows to display an user-defined image that corresponds to a value read from the server
  • data-llweb-refresh: flag used to set the automatic refresh on an HTML Element
  • data-llweb-format: sprintf format to format values

An explanation for each one is provided in the following sections.

Creating controls

Symbol input field

Here's an example how to create a simple input text field using the data-llweb-sym attribute.

<input type="text" data-llweb-sym="cnt">

cnt is the symbol name and it's used to link the PLC symbol on the Web Server to the HTML Element, so that you can read and write it.


Parameter input field

Here's an example how to create a simple input text field using the data-llweb-par attribute.

<input type="text" data-llweb-par="10001">

10001 is the parameter IPA and it's used to link the PLC symbol on the Web Server the to the HTML Element, so that you can read and write it.


Image control

Here's an example how to create an image control using data-llweb-sym combined with the data-llweb-img attribute.

<img data-llweb-sym="myEnum" data-llweb-img="2:error.gif, 1:true.png, 0:false.jpg" alt="missing image">

The LLWebServer library will get from the data-llweb-img attribute a list of items separated by comma. Each item has a value and an image; before the colon there's the symbol value and after the associated image, like this: Value:ImageName.jpeg.

When the value of myEnum symbol is read from the server, if myEnum == 2 the image source will be error.gif, if myEnum == 1 will be true.png and if myEnum == 0, false.jpg.

In the following example, the read value is 1 and the src attribute img/true.png is set from the LLWebServer library.

<img data-llweb-sym="myEnum" data-llweb-img="2:error.gif, 1:true.png, 0:false.jpg" alt="missing image" src="img/true.png">

As you can see, you can specify whatever image format you want.

Note: the image file must be in a img folder in the same path of the HTML page.

Writing control values

LLWebServer will write the Element value on server when "Enter" is pressed in a input field or the value of radio button or a select is changed.

Also images support writing values: if you click on an image, the next value listed in the data-llweb-img attribute is written (considering the example from the previous paragraph, if the current value is 1, then 0 is written on server).

Of course you can make an image read-only adding data-readonly="true" attribute, since images are natively read-only in HTML and do not suppor standard "disabled" or "readonly" attributes.

Updating controls

You can manually update the values in HTML controls calling the JavaScript function UpdateControls, for instance when a button is pressed.

LLWebServer.UpdateControls();

The UpdateControls function will update once all the controls in the page having data-llweb-par or data-llweb-sym attributes.


Otherwise the LLWebServer library supports an autorefresh feature that automalically refreshes all the values with the data-llweb-autorefresh attribute.
For example, in the image control example above, you can add data-llweb-autorefresh="true" to enable autorefresh.

<img data-llweb-sym="myEnum" data-llweb-img="2:error.gif, 1:true.png, 0:false.jpg" alt="missing image" data-llweb-refresh="true" >

Once you defined HTML Elements with the data-llweb-autorefresh attribute, you have to call the JavaScript function AutoRefreshStart specifying the refresh timeout in milliseconds after each request.

In the following example, the autorefresh is started with a timeout of 500 milliseconds:

const TIMEOUT_MS = 500;
LLWebServer.AutoRefreshStart(TIMEOUT_MS);

To stop the autorefresh, use the function AutoRefreshStop:

LLWebServer.AutoRefreshStop();

Of course you can use the data-llweb-autorefresh attribute on image, input, select, radio and checkbox HTML controls.

Note: when you focus an input Element while autorefresh is enabled, LLWebServer will stop updating that specific control until its value is written or the focus is left.

Formatting values

It is possible to format the values in HTML inputs trough the data-llweb-format attribute which uses the C sprintf syntax.

<input type="text" data-llweb-sym="real1" data-llweb-refresh="true" data-llweb-format="%.2f">
<input type="text" data-llweb-sym="cnt" data-llweb-refresh="true" data-llweb-format="%x">

In the first example it's used %.2f to get two decimals of precision while in the second %x to get an hex value.

More examples

Select control example

<select data-llweb-sym="myBool" data-llweb-refresh="true">
	<option value="0">false</option>
	<option value="1">true</option>
</select>

Checkbox control example

<input type="checkbox" data-llweb-sym="myBool" data-llweb-refresh="false" disabled>

Radio button control example

<input type="radio" data-llweb-sym="myEnum" name="rad-myEnum" value="1" id="rad-ctrl-myEnum-1" data-llweb-refresh="true">
<label for="rad-ctrl-myEnum-1">one</label>
<input type="radio" data-llweb-sym="myEnum" name="rad-myEnum" value="2" id="rad-ctrl-myEnum-2" data-llweb-refresh="true">
<label for="rad-ctrl-myEnum-2">two</label>
<input type="radio" data-llweb-sym="myEnum" name="rad-myEnum" value="3" id="rad-ctrl-myEnum-3" data-llweb-refresh="true">
<label for="rad-ctrl-myEnum-3">three</label>
<input type="radio" data-llweb-sym="myEnum" name="rad-myEnum" value="4" id="rad-ctrl-myEnum-4" data-llweb-refresh="true">
<label for="rad-ctrl-en2var-4">four</label>

Button control example

You can also use buttons to directly write a value on the web server:

<button data-llweb-sym="myEnum" value="1">one</button>
<button data-llweb-sym="myEnum" value="2">two</button>
<button data-llweb-sym="myEnum" value="3">three</button>
<button data-llweb-sym="myEnum" value="4">four</button>