summaryrefslogtreecommitdiffstats
path: root/docs/controllerConfig.md
blob: d260db74df6db95bd9a77ef543fc2d1a4b5f757d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
# Controller binding configuration

By default the controller searches for a config filename with the same 'middlename' as the daemon process. As an example if your process name is afb-daemon then middle name is 'daemon'. In addition, if your process name is afb-daemon-audio the middle name is also 'daemon'. Moreover the prefix is chosen when you call the [CtlConfigSearch](<#4)_Do_controller_config_parsing_at_binding_pre-init>) function, see below:

```bash
CtlConfigSearch(AFB_ApiT apiHandle, const char *dirList, const char *prefix)
```

```bash
# Middlename is taken from process middlename.
(prefix-)middlename*.json
```

You may overload the config search path with environment variables

* **CONTROL_CONFIG_PATH**: change default reserch path for configuration. You may provide multiple directories separated by ':'.
* **CONTROL_LUA_PATH**: same as CONTROL_CONFIG_PATH but for Lua script files.

Example: to load a config named '(prefix-)myconfig-test.json' do

```bash
afb-daemon --name myconfig --verbose ...'
```

The configuration is loaded dynamically during startup time. The controller scans **CONTROL_CONFIG_PATH** for a file corresponding to the pattern
"(prefix-)bindermiddlename*.json". The first file found in the path is loaded,
any other file corresponding to the same path is ignored and only generates a warning.

Each block in the configuration file is defined with

* **uid**: mandatory, it is used either for debugging or as input for the action
 (eg: signal name, control name, ...)
* **info**:  optional, it is used for documentation purpose only

> **Note**: by default the controller config search path is defined at
> compilation time, but the path might be overloaded with the
> **CONTROL_CONFIG_PATH** environment variable.

## Configuration is organised in sections

* **metadata**: describes the configuration
* **plugins or resources**: defines the plugins to be loaded as additionnal
  resources (compiled C or lua).
* **onload**: a collection of actions meant to be executed at startup time
* **control**: sets the controls with a collection of actions, in dynamic api it
 could also specify the verbs of the api
* **event**: a collection of actions meant to be executed when receiving a given
 signal
* **personnal sections**: personnal section

Callbacks to parse sections are documented in [Declare your controller config section in your binding](<#3_Declare_your_controller_config_section_in_your_binding>)
section. You can use the callback defined in controller or define your own
callback.

## Metadata

As today metadata is only used for documentation purpose.

* **uid**: mandatory
* **version**: mandatory
* **api**: mandatory, string which named the API to be created
* **info**: optional
* **require**: optional, string or array of strings of dependants API's names.
* **author**: optional
* **date**: optional

## OnLoad section

Onload section defines startup time configuration. Onload may provide multiple
initialisation profiles, each with a different uid.

You can define the following keys or arrays of the following keys:

* **uid**: mandatory.
* **info**: optional
* **action**: mandatory, an object or array of object describing an action and
 explained in the later [Action Elements](<#Action Elements>) chapter.
* **args**: optionnal, action's arguments.

## Control section

Control section defines a list of controls that are accessible.

You can define the following keys or arrays of the following keys, moreover
this section could be verb api:

* **uid**: mandatory, used as the verb's name.
* **info**: optional
* **action**: mandatory, an object or array of object describing an action and
 explained in the later [Action Elements](<#Action Elements>) chapter.
* **args**: optionnal, action's arguments.

## Events section

Events section defines a list of actions to be executed on event reception.
Event can do anything a controller can (change state, send back signal, ...)
eg: if a controller subscribes to vehicle speed, then speed-event may adjust
master-volume to speed.

You can define the following keys or arrays of the following keys, moreover you
can define an event from an another API with the following syntax "API/event".

* **uid**: mandatory must match an event name with format **api/event_name**,
 i.e: **low-can/messages.engine.speed**
* **info**: optional
* **action**: mandatory, an object or array of object describing an action and
 explained in the later [Action Elements](<#Action Elements>) chapter.
* **args**: optionnal, action's arguments.

## Plugin section

Plugin section defines plugins used with this controller. A plugin is a C/C++
program meant to execute some tasks after an event or on demand. This easily
extends intrinsec binding logic for ad-hoc needs.

You can define the following keys or arrays of the following keys:

* **uid**: mandatory
* **info**: optionnal
* **spath**: optionnal, semicolon separated paths where to find the plugin. This
 could be a compiled shared library or LUA scripts. Could be specified using
 **CONTROL_PLUGIN_PATH** environment variable also.
* **libs**: mandatory, Plugin file or LUA scripts to load
* **lua**: optionnal, a JSON object listing C functions that could be called
 from a LUA script and could prefixed.
  * **function**: string or array of string of C functions
  * **prefix**: a prefix to be used with the listed C functions

## Personnal sections

* **uid**: mandatory
* **info**: optionnal
* **action**: mandatory, an object or array of object describing an action and
 explained in the later [Action Elements](<#Action Elements>) chapter.
* **args**: optionnal, action's arguments.
* **any keys wanted**: optionnal

You can define your own sections and add your own callbacks into the CtlSectionT
structure, see [Declare your controller config section in your binding](<#3_Declare_your_controller_config_section_in_your_binding>)
section.

## Action Elements

Controller supports three categories of actions. Each action returns a status
where 0=success and 1=failure.

* **AppFw API** provides a generic model to request other bindings. Requested
 bindings can be local (eg: ALSA/UCM) or external (eg: vehicle signalling).
  * `"action": "api://API_NAME#verb_name"`
* C-API, when defined in the onload section, the plugin may provide C native API
 with `CTLP-CAPI(apiname, uid, args, query, context)`. Plugin may also create
 Lua command with `CTLP-LUA2C(LuaFuncName, uid, args, query, context)`. Where
 `args`+`query` are JSON-C object and context is the returned value from
 `CTLP_ONLOAD` function. Any missing value is set to NULL.
  * `"action": "plugin://plugin_name#function_name"`
* Lua-API, when compiled with Lua option, the controller supports action defined
 directly in Lua script. During "*onload*" phase, the controller searches in
 `CONTROL_LUA_PATH` file with pattern "(prefix-)bindermiddlename*.lua". Any file
 corresponding to this pattern is automatically loaded. Any function defined in
 those Lua scripts can be called through a controller action. Lua functions
 receive three parameters (uid, args, query).
  * `"action": "lua://plugin_name#function_name"`

You also can add the **privileges** property that handles AGL permission
needed to be able to call this action.

> **Note**: Lua added functions are systematically prefixed. AGL standard AppFw
functions are prefixed with AGL: (eg: AFB:notice(), AFB:success(), ...).
> User Lua functions added through the plugin and CTLP_LUA2C are prefixed with
the plugin uid or the one you defined in your config (eg: MyPlug:HelloWorld1).

## Available Application Framework Commands

Each LUA AppFw commands should be prefixed by AFB:

* `AFB:notice ("format", arg1,... argn)` directly printed LUA tables as json
   string with '%s'. `AFB:error`, `AFB:warning`, `AFB:info`, `AFB:debug` work on
   the same model. Printed messages are limited to 512 characters.

* `AFB:service ('API', 'VERB', {query}, "Lua_Callback_Name", {context})` is an
  asynchronous call to another binding. When empty, query/context should be set
  to '{}' and not to 'nil'. When 'nil', Lua does not send 'NULL' value but
  removes arguments to calling stack. WARNING:"Callback" is the name of the
  callback as a string and not a pointer to the callback. (If someone as a
  solution to fix this, please let me known). Callback is call as LUA
  "function Alsa_Get_Hal_CB (error, result, context)" where:
  * error is a Boolean
  * result is the full answer from AppFw (do not forget to extract the response)
  * context is a copy of the Lua table pass as an argument (warning it's a copy
   not a pointer to original table)

* `error,result=AFB:servsync('API', 'VERB', {query})` is saved as previous but
   for synchronous call. Note that Lua accepts multiple returns. AFB:servsync
   returns both the error message and the response as a Lua table. Like for
   AFB:service, the user should not forget to extract response from result.

* `AFB:success(request, response)` is the success request. request is the opaque
  handle passes when Lua is called from (api="control", verb="docall"). Response
  is a Lua table that will be returned to the client.

* `AFB:fail(request, response)` is the same as for success. Note that LUA
  generates automatically the error code from Lua function name. The response
  is transformed into a json string before being returned to the client.

* `EventHandle=AFB:evtmake("MyEventName")` creates an event and returns the
  handle as an opaque handle. Note that due to a limitation of json_object, this
  opaque handle cannot be passed as an argument in a callback context.

* `AFB:subscribe(request, MyEventHandle)` subscribes a given client to a
  previously created event.

* `AFB:evtpush (MyEventHandle, MyEventData)` pushes an event to every subscribed
  client. MyEventData is a Lua table that will be sent as a json object to the
  corresponding clients.

* `timerHandle=AFB:timerset (MyTimer, "Timer_Test_CB", context)` initialises a
  timer from MyTimer Lua table. This table should contains 3 elements:
  MyTimer={[l"abel"]="MyTimerName", ["delay"]=timeoutInMs, ["count"]=nBOfCycles}
  Note that if count==0 then timer is cycled infinitely. Context is a standard
  Lua table. This function returns an opaque handle to be used to further
  control the timer.

* `AFB:timerclear(timerHandle)` kills an existing timer. Returns an error when
  timer does not exit.

* `MyTimer=AFB:timerget(timerHandle)` returns uid, delay and count of an active
  timer. Returns an error when timerHandle does not point on an active timer.

* `AFB:GetEventLoop()` retrieves the common systemd's event loop of AFB.

* `AFB:RootDirGetFD()` gets the root directory file descriptor. This file
  descriptor can be used with functions 'openat', 'fstatat', ...

> **Note**: Except for functions call during binding initialisation period. Lua
> calls are protected and should returned clean messages even when they are
> improperly used. If you find bug please report.

## Adding Lua command from User Plugin

User Plugin is optional and may provide either native C-action accessible
directly from controller actions as defined in JSON config file, or
alternatively may provide a set of Lua commands usable inside any script (onload
, control,event). A simple plugin that provides both notice C API and Lua
commands is provided as example (see ctl-plugin-sample.c). Technically a plugin
is a simple sharelibrary and any code fitting in sharelib might be used as a
plugin. Developer should nevertheless forget that except when no-concurrency
flag was at binding construction time, any binding should to be thread safe.

A plugin must be declared with `CTLP_REGISTER("MyCtlSamplePlugin")`. This
entry point defines a special structure that is checked at plugin load time by
the controller. Then you have an optional init routine declare with
`CTLP_ONLOAD(plugin, handle)`. The init routine may create a plugin context that
is later presented to every plugin API, this for both LUA and native C ones.
Then each:

* C API declare with `CTLP_CAPI(MyCFunction, source, argsJ, queryJ) {your code}`.
  Where:
  * **MyFunction** is your function
  * **source** is the structure config
  * **argsJ** a json_object containing the argument attaches to this control in
    JSON config file
  * **queryJ** a json_object

* Lua API declare with `CTLP_LUA2C(MyLuaCFunction, source, argsJ, responseJ) {your code}`.
  Where:
  * **MyLuaCFunction** is both the name of your C function and Lua command
  * **source** is the structure config
  * **argsJ** the arguments passed this time from Lua script and not from JSON
    config file.
  * **responseJ** if success the argument is passed into the request.

> **Warning**: Lua samples use with controller enforce strict mode. As a result
> every variable should be declared either as local or as global. Unfortunately
> "luac" is not smart enough to handle strict mode at build time and errors only
> appear at run time. Because of this strict mode every global variables (which
> include functions) should be prefixed by '_'. Note that LUA requires an
> initialisation value for every variables and declaring something like
> "local myvar" will not allocate "myvar".

## Debugging Facilities

Controller Lua scripts are checked for syntax from CMAKE template with Luac.
When needed to go further, a developer API should be allowed to execute directly
Lua commands within the controller context from Rest/Ws (api=control,
verb=lua_doscript). DoScript API takes two other optional arguments func=xxxx
where xxxx is the function to execute within Lua script and args, a JSON object
to provide input parameters. When funcname is not given by default, the
controller tries to execute middle filename doscript-xxxx-????.lua.

When executed from the controller, Lua script may use any AppFw Apis as well as
any L2C user defines commands in plugin.

## Running as Standalone Controller

The controller is a standard binding. It can be started with the following
command:

```bash
afb-daemon --name=yourname --port=1234 --workdir=. --roothttp=./htdocs --tracereq=common --token= --verbose --binding=pathtoyourbinding.so --monitoring
```

afb-daemon only loads controller bindings without searching for the other
binding. In this case, the controller binding will search for a configuration
file name '(prefix-)bindermiddlename*.json'. This model can be used to implement
for testing purpose or simply to act as the glue between a UI and other
binder/services.