aboutsummaryrefslogtreecommitdiffstats
path: root/conf.d/project
diff options
context:
space:
mode:
Diffstat (limited to 'conf.d/project')
-rw-r--r--conf.d/project/alsa.d/README.md175
-rw-r--r--conf.d/project/alsa.d/asoundrc.sample8
-rw-r--r--conf.d/project/json.d/CMakeLists.txt32
-rw-r--r--conf.d/project/json.d/README.md22
-rw-r--r--conf.d/project/json.d/onload-aaaa-sample.json103
-rw-r--r--conf.d/project/lua.d/CMakeLists.txt34
-rw-r--r--conf.d/project/lua.d/onload-aaaa-00-utils.lua86
-rw-r--r--conf.d/project/lua.d/onload-aaaa-01-init.lua48
-rw-r--r--conf.d/project/lua.d/onload-aaaa-03-controls.lua118
-rw-r--r--conf.d/project/lua.d/onload-aaaa-10-event.lua74
10 files changed, 693 insertions, 7 deletions
diff --git a/conf.d/project/alsa.d/README.md b/conf.d/project/alsa.d/README.md
new file mode 100644
index 0000000..aa2a54e
--- /dev/null
+++ b/conf.d/project/alsa.d/README.md
@@ -0,0 +1,175 @@
+
+Alsa Configuration is not complex, but it's heavy and every except intuitive.
+
+In order to set your configuration move step by step. And verify at each new step that you did not introduce a regression.
+
+### Make sure your board is not taken by PulseAudio
+
+* Pavucontrol is your friend. Go in device configuration and switch to off the device you want to make available to ALSA.
+* Check for your device list with 'play -l'. Note that just after card number your get an alias for your sound card.
+ it is simpler to use this alias, card number will change depending on plug/unplug of device when this alias name
+ is more stable (except for few stupid driver who use 'USB' as sound card name.
+* When your know your sound alias (eg:v1340 in mu case) you can test it with 'speaker-test -D v1340 -c2 -twav'. You may also
+ use sound card number with 'speaker-test -D hw:0 -c2 -twav'. Nevertheless as said previously this number is not stable.
+* you are now ready to write your $HOME/.asoundrc config
+
+Note that $HOME/.asoundrc is loaded within libasound client and not by Alsa kernel, this is the reason why you do not need
+to activate any control or restart a daemon for modifications to be taken in account.
+
+To use ALSA with AAAA and the controller you need to write 1 section in your ALSA config
+
+* Sound Card Mixer: Allows multiple audio stream to be played on the same sound card. If hardware support mixer, Alsa will use it. If
+ not it will provide mixing by software.
+* Audio Role Volume: They provide independent volume for each audio role. For reference, we use Alsa softvolume, depending on
+ your hardware you may have this directly avaliable from your sound card.
+* Authorised Audio PCM: those channel are designed for applications we do not trust and then enforce AAAA control check
+ before granting the access to a given channel.
+
+### Sound Card Mixer
+
+```
+pcm.SoundCardMixer {
+ type dmix
+ ipc_key 1024
+ ipc_key_add_uid false
+ ipc_perm 0666 # mixing for all users
+
+ # Define target effective sound card (cannot be a plugin)
+ slave { pcm "hw:v1340" } #Jabra Solmate
+
+ # DMIX can only map two channels
+ bindings {
+ 0 0
+ 1 1
+ }
+}
+```
+
+Warning: if you have more than one Mixer each of them should have a unique ipc_key. You sound card alias move in the slave section.
+When this is done you may try your mixer with:
+
+```
+ speaker-test -D MyMixerPCM -c2 -twav
+```
+
+
+### Audio Role
+
+```
+pcm.NavigationRole {
+ type softvol
+
+ # Point Slave on HOOK for policies control
+ slave.pcm "SoundCardMixer"
+
+ # name should match with HAL but do not set card=xx
+ control.name "Playback Navigation"
+
+}
+
+```
+
+The slave you point to your SoundCardMixer, and the control.name should be EXACTLY the same as the one defined in your HAL.
+
+
+WARNING: The control here "Playback Navigation" is a user defined kernel control. It means that this kernel is created in
+kernel space, but that its action happen in user space. When create those control remains visible until you reset your
+sound card (eg: unplug USB), but they are save each time you reboot. It is recommended to start AAAA binder before testing
+your softvol audio role channel. If you do the opposite the control will be create by Alsa Plugin and this will not inherit
+of the default value you have in your HAL.
+
+When in place you should test it with:
+```
+ speaker-test -D NavigationRole -c2 -twav
+```
+
+IMPORTANT: control volume are attache to your physical hardware and not to intermediary level (Softvol or Mixer). To see the
+newly created channel you should use
+```
+ amixer -Dhw:v1340 controls | grep -i playback
+```
+
+## Authorised Audio PCM
+
+This PCM is supervised with the AAAA audio hook plugin. The pluging and will any application request on this PCM and will
+1st request an autorisation from AAAA controller to grant access for the client application. To do so, two things:
+* the plugin should be declared (only once)
+* you should declare as many authorized PCM as you need.
+
+### Plugin declaration
+
+```
+pcm_hook_type.MyHookPlugin {
+ install "AlsaInstallHook"
+ lib "/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build/Alsa-Plugin/Alsa-Policy-Hook/policy_hook_cb.so"
+}
+
+```
+
+Lib is the path where to find AAAA Alsa hook plugin, install is the name of the init function it should not be changed.
+
+
+When your plugin is defined you may declare your authorised PCM. Those PCM like softvol will take a slave, typically a lower
+level of the audio role, or directly a mixer if your goal is to protect directly the Mixer. The AAAA Plugin hook take as
+
+```
+pcm.AuthorisedToNavigationOnly {
+ type hooks
+ slave.pcm "NavigationRole"
+ # Defined used hook sharelib and provide arguments/config to install func
+ hooks.0 {
+ type "MyHookPlugin"
+ hook_args {
+ verbose true # print few log messages (default false);
+
+ # Every Call should return OK in order PCM to open (default timeout 100ms)
+ uri "ws://localhost:1234/api?token=audio-agent-token&uuid=audio-agent-session"
+ request {
+ # Request autorisation to write on navigation
+ RequestNavigation {
+ api "control"
+ verb "dispatch"
+ query "{'target':'navigation', 'args':{'device':'Jabra SOLEMATE v1.34.0'}}"
+ }
+ }
+ # map event reception to self generated signal
+ event {
+ pause 30
+ resume 31
+ stop 3
+ }
+ }
+ }
+}
+
+```
+
+ * The slave is the PCM that application will be transfer to if access to control is granted.
+ * Request is a suite à control action that respond to AGL standard application framework API
+ * Event is the mapping of signal an appplication will receive in case AAAA controller push event to the audio application.
+
+When using AAAA controller, most action should be transfert to the controller that will take action to authorise/deny the access.
+Nevertheless it is also possible to directly access a lower level (e.g. call alsa Use Case Manager). People may also have their
+own audio policy engine and request it directly from here.
+
+To test this last part your need to have a controller ready to respond to your request. Otherwise control will systematically
+be denied. When your AAAA controller is ready to serve your request you may check this with
+```
+ amixer -Dhw:AuthorisedToMusicOnly controls | grep -i playback
+ amixer -Dhw:AuthorisedToNavigationOnly controls | grep -i playback
+```
+
+IMPORTANT: you need at least to audio role to really test this part. While you may assert with one channel that your flow
+to accept/deny application works. You need two simultaneous audio stream to really play with the control. Typically when playing
+music if you send a navigation message then the audio will be lower during the rendering of the navigation message.
+
+The action on how you lower an audio role when an other one with a higger level of priority come in place not defined at the
+plugin level, but in the AAAA controller, where the API control/dispatch?target=xxxxx will execute a set of actions corresponding
+the set/unset accept/deny of requested control.
+
+Remark: to understand what is happening it is a good idea to have an alxamixer option on the your soundcard
+```
+ amixer -Dhw:v1340
+```
+
+(!) Do not forget to replace 'hw:v1340' by what ever is the alias of your sound card. \ No newline at end of file
diff --git a/conf.d/project/alsa.d/asoundrc.sample b/conf.d/project/alsa.d/asoundrc.sample
index 8976077..0716b11 100644
--- a/conf.d/project/alsa.d/asoundrc.sample
+++ b/conf.d/project/alsa.d/asoundrc.sample
@@ -27,13 +27,7 @@ pcm.MyMixerPCM {
ipc_perm 0666 # mixing for all users
# Define target effective sound card (cannot be a plugin)
- slave {
- pcm "hw:v1340" #Jabra Solmate
- period_time 0
- period_size 1024
- buffer_size 8192
- rate 44100
- }
+ slave { pcm "hw:v1340" } #Jabra Solmate
# DMIX can only map two channels
bindings {
diff --git a/conf.d/project/json.d/CMakeLists.txt b/conf.d/project/json.d/CMakeLists.txt
new file mode 100644
index 0000000..8070997
--- /dev/null
+++ b/conf.d/project/json.d/CMakeLists.txt
@@ -0,0 +1,32 @@
+###########################################################################
+# Copyright 2017 IoT.bzh
+#
+# author: Fulup Ar Foll <fulup@iot.bzh>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###########################################################################
+
+
+##################################################
+# Control Policy Config file
+##################################################
+PROJECT_TARGET_ADD(ctl-config.d)
+
+ file(GLOB XML_FILES "*.json")
+
+ add_input_files("${XML_FILES}")
+
+ SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES
+ LABELS "DATA"
+ OUTPUT_NAME ${TARGET_NAME}
+ )
diff --git a/conf.d/project/json.d/README.md b/conf.d/project/json.d/README.md
new file mode 100644
index 0000000..0f4967d
--- /dev/null
+++ b/conf.d/project/json.d/README.md
@@ -0,0 +1,22 @@
+By default controller searches for a config filename with the same 'middlename' as daemon process. As an example if your process name is afb-daemon then middle name is 'daemon'.
+
+```
+ onload-middlename-xxxxx.json
+
+ # Middlename is taken from process middlename.
+```
+
+You may overload config search path with environement variables
+ * AFB_BINDER_NAME: change patern config search path. 'export AFB_BINDER_NAME=sample' will make controller to search for a configfile name 'onload-sample-xxx.json'.
+ * 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 name 'onload-myconfig-test.json' do
+```
+ AFB_BINDER_NAME='myconfig' afb-daemon --verbose ...'
+```
+
+Note: you may change search pattern for Lua script by adding 'ctlname=afb-middlename-xxx' in the metadata section of your config 'onload-*.json'
+
+WARNING: Audio Control are the one from the HAL and not from Alsa LowLevel
+
diff --git a/conf.d/project/json.d/onload-aaaa-sample.json b/conf.d/project/json.d/onload-aaaa-sample.json
new file mode 100644
index 0000000..c95a62f
--- /dev/null
+++ b/conf.d/project/json.d/onload-aaaa-sample.json
@@ -0,0 +1,103 @@
+{
+ "$schema": "ToBeDone",
+ "metadata": {
+ "label": "sample-aaaa-control",
+ "info": "Sample of Video AAAA controls",
+ "name": "afb-sample-controller",
+ "version": "1.0"
+ },
+ "onload": [{
+ "label": "onload-default",
+ "info": "onload initialisation config",
+ "require": ["alsacore","jabra-usb","intel-hda","hal-most-unicens"],
+ "actions":
+ {
+ "label": "control-init",
+ "lua": "_Audio_Controller_Init",
+ "args": {
+ "evtname": "agl-audio"
+ }
+ }
+ }],
+ "controls":
+ [
+ {
+ "label": "Multimedia",
+ "permissions": "urn:AGL:permission:audio:public:multimedia",
+ "actions": {
+ "label": "authorize-multimedia",
+ "lua": "_Temporarily_Control"
+ }
+ }, {
+ "label": "Navigation",
+ "permissions": "urn:AGL:permission:audio:public:navigation",
+ "actions": {
+ "label": "authorize-navigation",
+ "lua": "_Temporarily_Control",
+ "args": {
+ "ctl" : "Multimedia_Playback_Volume",
+ "val": 40
+ }
+ }
+ }, {
+ "label": "Telephony",
+ "permissions": "urn:AGL:permission:audio:public:telephony",
+ "actions": {
+ "label": "authorize-multimedia",
+ "lua": "_Temporarily_Control",
+ "args": {
+ "ctl" : "Multimedia_Playback_Volume",
+ "val": 20
+ }
+ }
+ }, {
+ "label": "Emergency",
+ "permissions": "urn:AGL:permission:audio:public:emergency",
+ "actions": {
+ "label": "authorize-multimedia",
+ "lua": "_Temporarily_Control",
+ "args": {
+ "ctl" : "Multimedia_Playback_Switch",
+ "val": 0
+ },
+ "label": "authorize-multimedia",
+ "lua": "_Temporarily_Control",
+ "args": {
+ "ctl" : "Navigation_Playback_Switch",
+ "val": 0
+ }
+ }
+ }
+ ],
+ "events":
+ [
+ {
+ "label": "ReverseEngage",
+ "actions": [{
+ "label": "adjust_volume-reverse",
+ "lua": "_Temporarily_Control",
+ "args": {
+ "ctl": "Multimedia_Playback_Volume",
+ "val": 20
+ }
+ },
+ {
+ "label": "prevent-telephony",
+ "lua": "_Temporarily_Control",
+ "args": {
+ "ctl": "Telephony_Playback_Switch",
+ "val": 0
+ }
+ }
+ ]
+ },
+ {
+ "label": "SpeedChanged",
+ "actions": {
+ "label": "adjust_volume",
+ "lua": "_Adjust_Volume"
+ }
+ }
+ ]
+}
+
diff --git a/conf.d/project/lua.d/CMakeLists.txt b/conf.d/project/lua.d/CMakeLists.txt
new file mode 100644
index 0000000..71b3371
--- /dev/null
+++ b/conf.d/project/lua.d/CMakeLists.txt
@@ -0,0 +1,34 @@
+###########################################################################
+# Copyright 2017 IoT.bzh
+#
+# author: Fulup Ar Foll <fulup@iot.bzh>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###########################################################################
+
+
+##################################################
+# Control Policy Config file
+##################################################
+PROJECT_TARGET_ADD(ctl-lua.d)
+ file(GLOB LUA_FILES "*.lua")
+
+ # Romain work around to activate lua compilation
+ set(LUA_LIST "${LUA_FILES}" CACHE STRING "")
+
+ add_input_files("${LUA_FILES}")
+
+ SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES
+ LABELS "DATA"
+ OUTPUT_NAME ${TARGET_NAME}
+ ) \ No newline at end of file
diff --git a/conf.d/project/lua.d/onload-aaaa-00-utils.lua b/conf.d/project/lua.d/onload-aaaa-00-utils.lua
new file mode 100644
index 0000000..29d2c70
--- /dev/null
+++ b/conf.d/project/lua.d/onload-aaaa-00-utils.lua
@@ -0,0 +1,86 @@
+--[[
+ Copyright (C) 2016 "IoT.bzh"
+ Author Fulup Ar Foll <fulup@iot.bzh>
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Note: this file should be called before any other to assert declare function
+ is loaded before anything else.
+
+ References:
+ http://lua-users.org/wiki/DetectingUndefinedVariables
+
+--]]
+
+
+--===================================================
+--= Niklas Frykholm
+-- basically if user tries to create global variable
+-- the system will not let them!!
+-- call GLOBAL_lock(_G)
+--
+--===================================================
+function GLOBAL_lock(t)
+ local mt = getmetatable(t) or {}
+ mt.__newindex = lock_new_index
+ setmetatable(t, mt)
+end
+
+--===================================================
+-- call GLOBAL_unlock(_G)
+-- to change things back to normal.
+--===================================================
+function GLOBAL_unlock(t)
+ local mt = getmetatable(t) or {}
+ mt.__newindex = unlock_new_index
+ setmetatable(t, mt)
+end
+
+function lock_new_index(t, k, v)
+ if (string.sub(k,1,1) ~= "_") then
+ GLOBAL_unlock(_G)
+ error("GLOBALS are locked -- " .. k ..
+ " must be declared local or prefix with '_' for globals.", 2)
+ else
+ rawset(t, k, v)
+ end
+end
+
+function unlock_new_index(t, k, v)
+ rawset(t, k, v)
+end
+
+-- return serialised version of printable table
+function Dump_Table(o)
+ if type(o) == 'table' then
+ local s = '{ '
+ for k,v in pairs(o) do
+ if type(k) ~= 'number' then k = '"'..k..'"' end
+ s = s .. '['..k..'] = ' .. Dump_Table(v) .. ','
+ end
+ return s .. '} '
+ else
+ return tostring(o)
+ end
+end
+
+
+-- simulate C prinf function
+printf = function(s,...)
+ io.write(s:format(...))
+ io.write("\n")
+ return
+end
+
+-- lock global variable
+GLOBAL_lock(_G)
diff --git a/conf.d/project/lua.d/onload-aaaa-01-init.lua b/conf.d/project/lua.d/onload-aaaa-01-init.lua
new file mode 100644
index 0000000..8de0c24
--- /dev/null
+++ b/conf.d/project/lua.d/onload-aaaa-01-init.lua
@@ -0,0 +1,48 @@
+--[[
+ Copyright (C) 2016 "IoT.bzh"
+ Author Fulup Ar Foll <fulup@iot.bzh>
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+--]]
+
+-- Global variable SHOULD start with _
+_Global_Context={}
+
+--[[
+ This function is call during controller init phase as describe in onload-daemon-sample.json
+ It receives two argument 1st one is the source (here on load) second one is the arguments
+ as expose in config file.
+
+ In this sample we create an event that take the name of args["zzzz"], the resulting handle
+ is save into _Global_Context for further use.
+
+ Note: init functions are not call from a client and thus do not receive query
+
+--]]
+function _Audio_Controller_Init(source, control)
+
+ printf ("[--> Audio_Controller_Init -->] source=%d control=%s", source, Dump_Table(control))
+
+ -- create an event from configuration name
+ _Global_Context["event"]=AFB:evtmake(control["evtname"])
+
+ -- query HAL to retrieve sound card.
+ local err,result= AFB:servsync ("alsacore", "hallist", {})
+
+ if (err) then
+ AFB_ERROR("Fail to retrieve Audio HAL")
+ else
+ _Global_Context["registry"]=result["response"]
+ printf("[<-- Audio_Controller_Init <--] Active HAL=%s", Dump_Table(result["response"]))
+ end
+end
diff --git a/conf.d/project/lua.d/onload-aaaa-03-controls.lua b/conf.d/project/lua.d/onload-aaaa-03-controls.lua
new file mode 100644
index 0000000..6c7c8a5
--- /dev/null
+++ b/conf.d/project/lua.d/onload-aaaa-03-controls.lua
@@ -0,0 +1,118 @@
+--[[
+ Copyright (C) 2016 "IoT.bzh"
+ Author Fulup Ar Foll <fulup@iot.bzh>
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Following function are called when a control activate a label with
+ labeller api -> APi=label VERB=dispatch
+ arguments are
+ - source (0) when requesting the label (-1) when releasing
+ - label comme from config given with 'control' in onload-middlename-xxxxx.json
+ - control is the argument part of the query as providing by control requesting the label.
+
+--]]
+
+_CurrentHalVolume={}
+
+
+local function Apply_Hal_Control(source, label, adjustment)
+ local HAL = _Global_Context["registry"]
+
+ -- check we really got some data
+ if (adjustment == nil) then
+ AFB:error ("--* (Hoops) Control should provide volume adjustment")
+ return 1
+ end
+
+ -- loop on each HAL save current volume and push adjustment
+ for key,hal in pairs(_Global_Context["registry"]) do
+ printf ("--- HAL=%s", Dump_Table(hal))
+
+ -- action set loop on active HAL and get current volume
+ -- if label respond then do volume adjustment
+ if (source == 0) then
+
+ -- get current volume for each HAL
+ local err,result= AFB:servsync(hal["api"],"ctlget", {["label"]=label})
+
+ -- if no error save current volume and set adjustment
+ if (err ~= nil) then
+ local response= result["response"]
+ printf ("--- Response %s=%s", hal["api"], Dump_Table(response))
+
+ if (response == nil) then
+ printf ("--- Fail to Activate '%s'='%s' result=%s", hal["api"], label, Dump_Table(result))
+ return 1 -- unhappy
+ end
+
+ -- save response in global space
+ _CurrentHalVolume [hal["api"]] = response
+
+ -- finally set the new value
+ local query= {
+ ["tag"]= response["tag"],
+ ["val"]= adjustment
+ }
+
+ -- best effort to set adjustment value
+ AFB:servsync(hal["api"],"ctlset",query)
+ end
+
+ else -- when label is release reverse action at preempt time
+
+ if (_CurrentHalVolume [hal["api"]] ~= nil) then
+
+ printf("--- Restoring initial volume HAL=%s Control=%s", hal["api"], _CurrentHalVolume [hal["api"]])
+
+ AFB:servsync(hal["api"],"ctlset", _CurrentHalVolume [hal["api"]])
+ end
+ end
+
+ end
+ return 0 -- happy end
+end
+
+
+-- Simple Happy(granted) Control
+function _Temporarily_Control(source, control, client)
+
+ printf ("[--> _Temporarily_Control -->] source=%d control=%s client=%s", source, Dump_Table(control), Dump_Table(client))
+
+ -- Init should have been properly done
+ if (_Global_Context["registry"] == nil) then
+ AFB:error ("--* (Hoops) No Hal in _Global_Context=%s", Dump_Table(_Global_Context))
+ return 1
+ end
+
+ -- make sure label as valid
+ if (control["ctl"] == nil or control["val"] == nil) then
+ AFB:error ("--* Action Ignore no/invalid control=%s", Dump_Table(control))
+ return 1 -- unhappy
+ end
+
+ if (source == 0) then
+ AFB:info("-- Adjust %s=%d", control["ctl"], control["val"])
+ local error=Apply_Hal_Control(source, control["ctl"], control["val"])
+ if (error == nil) then
+ return 1 -- unhappy
+ end
+ AFB:notice ("[<-- _Temporarily_Control Granted<--]")
+ else
+ Apply_Hal_Control(source, control["ctl"],0)
+ AFB:notice ("[<-- _Temporarily_Control Restore--]")
+ end
+
+ return 0 -- happy return
+end
+
diff --git a/conf.d/project/lua.d/onload-aaaa-10-event.lua b/conf.d/project/lua.d/onload-aaaa-10-event.lua
new file mode 100644
index 0000000..474ebe0
--- /dev/null
+++ b/conf.d/project/lua.d/onload-aaaa-10-event.lua
@@ -0,0 +1,74 @@
+--[[
+ Copyright (C) 2016 "IoT.bzh"
+ Author Fulup Ar Foll <fulup@iot.bzh>
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+ Provide Sample Timer Handing to push event from LUA
+--]]
+
+-- Create event on Lua script load
+_MyContext={}
+
+-- WARNING: call back are global and should start with '_'
+function _Timer_Test_CB (timer, context)
+
+ local evtinfo= AFB:timerget(timer)
+ printf ("[-- _Timer_Test_C --] evtInfo=%s", Dump_Table(evtinfo))
+
+ --send an event an event with count as value
+ AFB:evtpush (_MyContext["event"], {["label"]= evtinfo["label"], ["count"]=evtinfo["count"], ["info"]=context["info"]})
+
+ -- note when timerCB return!=0 timer is kill
+ return 0
+
+end
+
+-- sendback event depending on count and delay
+function _Simple_Timer_Test (request, client)
+
+ local context = {
+ ["info"]="My 1st private Event",
+ }
+
+ -- if event does not exit create it now.
+ if (_MyContext["event"] == nil) then
+ _MyContext["event"]= AFB:evtmake(client["label"])
+ end
+
+ -- if delay not defined default is 5s
+ if (client["delay"]==nil) then client["delay"]=5000 end
+
+ -- if count is not defined default is 10
+ if (client["count"]==nil) then client["count"]=10 end
+
+ -- we could use directly client but it is a sample
+ local myTimer = {
+ ["label"]=client["label"],
+ ["delay"]=client["delay"],
+ ["count"]=client["count"],
+ }
+ AFB:notice ("Test_Timer myTimer=%s", myTimer)
+
+ -- subscribe to event
+ AFB:subscribe (request, _MyContext["event"])
+
+ -- settimer take a table with delay+count as input (count==0 means infinite)
+ AFB:timerset (myTimer, "_Timer_Test_CB", context)
+
+ -- nothing special to return send back
+ AFB:success (request, myTimer)
+
+ return 0
+end