1 with_system_controller = true
5 -- try loading the various logging plugins
6 m:try_load_plugin('systemd')
7 m:try_load_plugin('dlog')
9 -- load the console plugin
10 m:try_load_plugin('console')
12 m:try_load_plugin('console.disabled', 'webconsole', {
13 address = 'wsck:127.0.0.1:3000/murphy',
14 httpdir = '/usr/share/murphy/webconsole' });
16 -- load the dbus plugin
17 if m:plugin_exists('dbus') then
21 -- load the native resource plugin
22 if m:plugin_exists('resource-native') then
23 m:load_plugin('resource-native')
24 m:info("native resource plugin loaded")
26 m:info("No native resource plugin found...")
29 -- load the dbus resource plugin
30 m:try_load_plugin('resource-dbus', {
32 dbus_service = "org.Murphy",
34 default_zone = "driver",
35 default_class = "implicit"
38 -- load the domain control plugin
39 if m:plugin_exists('domain-control') then
40 m:load_plugin('domain-control')
42 m:info("No domain-control plugin found...")
45 -- load the AMB plugin
46 if m:plugin_exists('amb') then
49 m:info("No amb plugin found...")
52 -- load the ASM resource plugin
53 if m:plugin_exists('resource-asm') then
54 m:load_plugin('resource-asm', {
56 share_mmplayer = "player:AVP,mandatory,exclusive,strict",
57 ignored_argv0 = "WebProcess"
60 m:info("No audio session manager plugin found...")
63 if m:plugin_exists('ivi-resource-manager') then
64 m:load_plugin('ivi-resource-manager')
65 with_system_controller = false
68 -- define application classes
115 application_class { name="event" , priority=4 , modal=false, share=true , order="fifo" }
116 application_class { name="game" , priority=3 , modal=false, share=false, order="lifo" }
117 --# doesn't need to be created here, ivi-resource-manager creates it if loaded
118 --#application_class { name="basic" , priority=2 , modal=false, share=false, order="lifo" }
119 application_class { name="player" , priority=1 , modal=false, share=true , order="lifo" }
120 application_class { name="implicit" , priority=0 , modal=false, share=false, order="lifo" }
122 -- define zone attributes
124 type = {mdb.string, "common", "rw"},
125 location = {mdb.string, "anywhere", "rw"}
133 location = "front-left"
141 location = "front-right"
149 location = "back-left"
157 location = "back-right"
165 location = "back-left"
170 -- define resource classes
171 if not m:plugin_exists('ivi-resource-manager') then
173 name = "audio_playback",
176 role = { mdb.string, "music", "rw" },
177 pid = { mdb.string, "<unknown>", "rw" },
178 policy = { mdb.string, "relaxed", "rw" }
184 name = "audio_recording",
187 role = { mdb.string, "music" , "rw" },
188 pid = { mdb.string, "<unknown>", "rw" },
189 policy = { mdb.string, "relaxed" , "rw" }
194 name = "video_playback",
199 name = "video_recording",
203 if not m:plugin_exists('ivi-resource-manager') then
204 resource.method.veto = {
205 function(zone, rset, grant, owners)
206 rset_priority = application_class[rset.application_class].priority
208 owner_id = owners.audio_playback.resource_set
211 if (rset_priority >= 50 and owner_id ~= rset_id) then
212 print("*** resource-set "..rset_id.." - veto")
221 -- test for creating selections
223 name = "audio_owner",
224 table = "audio_playback_owner",
225 columns = {"application_class"},
226 condition = "zone_name = 'driver'"
230 name = "vehicle_speed",
231 table = "amb_vehicle_speed",
233 condition = "key = 'VehicleSpeed'"
237 name = "speed2volume",
238 inputs = { speed = mdb.select.vehicle_speed, param = 9 },
239 outputs = { mdb.table { name = "speedvol",
240 index = {"zone", "device"},
241 columns = {{"zone", mdb.string, 16},
242 {"device", mdb.string, 16},
243 {"value", mdb.floating}},
248 update = function(self)
249 speed = self.inputs.speed.single_value
251 volume = (speed - 144.0) / 7.0
255 diff = volume - self.oldvolume
256 if (diff*diff > self.inputs.param) then
257 print("*** element "..self.name.." update "..volume)
258 self.oldvolume = volume
259 mdb.table.speedvol:replace({zone = "driver", device = "speakers", value = volume})
264 -- Night mode processing chain
267 name = "exterior_brightness",
268 table = "amb_exterior_brightness",
269 columns = { "value" },
270 condition = "key = 'ExteriorBrightness'"
275 inputs = { brightness = mdb.select.exterior_brightness },
279 name = "amb_nightmode",
283 { "id", mdb.unsigned },
284 { "night_mode", mdb.unsigned }
288 update = function(self)
289 -- This is a trivial function to calculate night mode. Later, we will
290 -- need a better threshold value and hysteresis to prevent oscillation.
292 brightness = self.inputs.brightness.single_value
294 if not brightness then
298 print("*** element "..self.name.." update brightness: "..brightness)
300 if brightness > 300 then
306 print("*** resulting mode: ".. mode)
308 if not (mode == self.oldmode) then
309 mdb.table.amb_nightmode:replace({ id = 0, night_mode = mode })
317 name = "select_night_mode",
318 table = "amb_nightmode",
319 columns = { "night_mode" },
325 inputs = { owner = mdb.select.select_night_mode },
326 property = "NightMode",
328 initiate = builtin.method.amb_initiate,
329 update = builtin.method.amb_update
333 -- Driving mode processing chain
337 name = "drivingmode",
338 inputs = { speed = mdb.select.vehicle_speed },
342 name = "amb_drivingmode",
346 { "id", mdb.unsigned },
347 { "driving_mode", mdb.unsigned }
351 update = function(self)
353 speed = self.inputs.speed.single_value
365 if not (mode == self.oldmode) then
366 mdb.table.amb_drivingmode:replace({ id = 0, driving_mode = mode })
374 name = "select_driving_mode",
375 table = "amb_drivingmode",
376 columns = { "driving_mode" },
381 name = "driving_mode",
382 inputs = { owner = mdb.select.select_driving_mode },
383 property = "DrivingMode",
385 initiate = builtin.method.amb_initiate,
386 update = builtin.method.amb_update
389 -- turn signals (left, right)
393 table = "amb_turn_signal",
394 columns = { "value" },
395 condition = "key = 'TurnSignal'"
398 -- regulation (on), use "select_driving_mode"
400 -- shift position (parking, reverse, other)
403 name = "gear_position",
404 table = "amb_gear_position",
405 columns = { "value" },
406 condition = "key = 'GearPosition'"
409 -- cameras (back, front, left, right)
412 name = "camera_state",
413 inputs = { winker = mdb.select.winker, gear = mdb.select.gear_position },
417 name = "target_camera_state",
421 { "id", mdb.unsigned },
422 { "front_camera", mdb.unsigned },
423 { "back_camera", mdb.unsigned },
424 { "right_camera", mdb.unsigned },
425 { "left_camera", mdb.unsigned }
429 update = function(self)
436 if self.inputs.gear == 128 then
438 elseif self.inputs.winker == 1 then
440 elseif self.inputs.winker == 2 then
444 mdb.table.target_camera_state:replace({ id = 0, front_camera = front_camera, back_camera = back_camera, right_camera = right_camera, left_camera = left_camera })
449 -- load the telephony plugin
450 m:try_load_plugin('telephony')
453 -- system controller test setup
455 if not with_system_controller or
456 not m:plugin_exists('system-controller') then
460 m:load_plugin('system-controller')
462 window_operation_names = {
471 function window_operation_name(oper)
472 local name = window_operation_names[oper]
473 if name then return name end
474 return "<unknown " .. tostring(oper) .. ">"
478 [0x00001] = "send_appid",
479 [0x10001] = "create",
480 [0x10002] = "destroy",
484 [0x10006] = "change_active",
485 [0x10007] = "change_layer",
486 [0x10008] = "change_attr",
488 [0x10011] = "map_thumb",
489 [0x10012] = "unmap_thumb",
490 [0x10020] = "show layer",
491 [0x10021] = "hide_layer",
492 [0x10022] = "change_layer_attr",
493 [0x20001] = "add_input",
494 [0x20002] = "del_input",
495 [0x20003] = "send_input"
498 function command_name(command)
499 local name = command_names[command]
500 if name then return name end
501 return "<unknown " .. tostring(command) .. ">"
504 wmgr = window_manager({
505 geometry = function(self, w,h, v)
506 if type(v) == "function" then
512 outputs = { { name = "Center",
518 width = function(w,h) return w end,
525 width = function(w,h) return w end,
526 height = function(w,h) return h-64-128 end
532 width = function(w,h) return w end,
533 height = function(w,h) return (h-64-128)/2 end
538 pos_y = function(w,h) return (h-64-128)/2+64 end,
539 width = function(w,h) return w end,
540 height = function(w,h) return (h-64-128)/2 end
546 width = function(w,h) return w/2 end,
547 height = function(w,h) return (h-64-128)/2 end
551 pos_x = function(w,h) return w/2 end,
553 width = function(w,h) return w/2 end,
554 height = function(w,h) return (h-64-128)/2 end
559 pos_y = function(w,h) return (h-64-128/2)+64 end,
560 width = function(w,h) return w/2 end,
561 height = function(w,h) return (h-64-128)/2 end
565 pos_x = function(w,h) return w/2 end,
566 pos_y = function(w,h) return (h-64-128/2)+64 end,
567 width = function(w,h) return w/2 end,
568 height = function(w,h) return (h-64-128)/2 end
574 width = function(w,h) return w end,
575 height = function(w,h) return h-64-128 end
581 width = function(w,h) return w/2-181 end,
582 height = function(w,h) return h-64-128 end
586 pos_x = function(w,h) return w/2+181 end,
588 width = function(w,h) return w/2-181 end,
589 height = function(w,h) return h-64-128 end
598 layers = { { 0, "Background" , 1 },
599 { 1, "Application" , 2 },
600 { 2, "Softkeyboard" , 4 },
601 { 3, "HomeScreen" , 2 },
602 { 4, "ControlBar" , 2 },
603 { 5, "InterruptApp" , 2 },
604 { 6, "OnScreen" , 2 },
605 { 101, "Input" , 3 },
606 { 102, "Touch" , 4 },
607 { 103, "Cursor" , 5 },
608 { 0x1000, "Background" , 1 },
609 { 0x2000, "Normal" , 2 },
610 { 0x3000, "Fullscreen" , 2 },
611 { 0x4000, "InputPanel" , 3 },
612 { 0xA000, "Touch" , 4 },
613 { 0xB000, "Cursor" , 5 },
614 { 0xC000, "Startup" , 6 }
618 window_update = function(self, oper, win, mask)
620 print("*** WINDOW UPDATE oper:"..window_operation_name(oper).." mask: "..tostring(mask))
624 local arg = m:JSON({ surface = win.surface,
629 if oper == 1 then -- create
630 if win.layertype and win.layertype == 3 then
631 print("ignoring input panel window creation")
635 elseif oper == 2 then -- destroy
637 elseif oper == 3 then -- namechange
639 elseif oper == 4 or oper == 5 then --visible or configure
643 arg.layer = win.layer
644 arg.pos_x = win.pos_x
645 arg.pos_y = win.pos_y
646 arg.width = win.width
647 arg.height = win.height
648 arg.raise = win.raise
649 arg.visible = win.visible
650 arg.active = win.active
651 elseif oper == 6 then -- active
652 if false and win.active ~= 0 then
653 print("### already active")
658 print("### nothing to do")
662 local msg = m:JSON({ command = command,
667 print("### sending window message: " .. command_name(msg.command))
669 sc:send_message(msg.appid, msg)
671 if (oper == 1) then -- create
672 local a = animation({})
673 local r = m:JSON({surface = win.surface,
676 self:window_request(r,a,0)
680 layer_update = function(self, oper, j, mask)
682 print("*** LAYER UPDATE oper:"..oper.." mask: "..tostring(mask))
686 output_update = function(self, oper, out, mask)
687 local idx = out.index
689 print("*** OUTPUT UPDATE oper:"..oper.." mask: "..tostring(mask))
692 if (oper == 1) then -- create
693 local outdef = self.outputs[idx+1]
695 self:output_request(m:JSON({index = idx,
700 elseif (oper == 5) then -- done
701 local ads = self.outputs[idx+1].areas
703 for name,area in pairs(ads) do
704 local a = m:JSON({name=name,output=out.index})
705 for fld,val in pairs(area) do
706 a[fld] = self:geometry(out.width,out.height,val)
716 sc = m:get_system_controller()
723 -- these shoud be before wmgr:connect() is called
724 print("====== creating applications")
727 area = "Center.Full",
728 privileges = { screen = "none", audio = "none" }
732 appid = "org.tizen.ico.homescreen",
733 area = "Center.Full",
734 privileges = { screen = "system", audio = "system" }
738 appid = "org.tizen.ico.statusbar",
739 area = "Center.Status",
740 privileges = { screen = "system", audio = "none" }
745 sc.client_handler = function (self, cid, msg)
746 print('*** client handler: ' .. tostring(msg))
747 if not connected then
748 print('Trying to connect to wayland...')
749 connected = wmgr:connect()
751 print('Window manager already connected...')
755 sc.generic_handler = function (self, cid, msg)
756 print('*** generic handler: ' .. tostring(msg))
759 sc.window_handler = function (self, cid, msg)
760 print('*** window handler: ' .. command_name(msg.command) .. ' ' .. tostring(msg))
762 local a = animation({})
763 if msg.command == 0x10003 then -- ico SHOW command
764 local raise_mask = 0x01000000
765 local lower_mask = 0x02000000
767 if msg.arg and msg.arg.anim_name then
768 local time = msg.arg.time
769 time = m:AND(time, m:NEG(m:OR(raise_mask, lower_mask)))
771 if m:AND(msg.arg.anim_time, raise_mask) then
773 elseif m:AND(msg.arg.anim_time, lower_mask) then
776 a.show = { msg.arg.anim_name, time }
777 print('time: ' .. tostring(a.show[2]))
780 print(tostring(msg.arg))
781 wmgr:window_request(msg.arg, a, 0)
782 elseif msg.command == 0x10004 then -- ico HIDE command
783 local raise_mask = 0x01000000
784 local lower_mask = 0x02000000
786 if msg.arg and msg.arg.anim_name then
787 local time = msg.arg.time
788 time = m:AND(time, m:NEG(m:OR(raise_mask, lower_mask)))
790 if m:AND(msg.arg.anim_time, raise_mask) then
793 if m:AND(msg.arg.anim_time, lower_mask) then
796 a.hide = { msg.arg.anim_name, time }
797 print('hide animation time: ' .. tostring(a.hide[2]))
800 print(tostring(msg.arg))
801 wmgr:window_request(msg.arg, a, 0)
802 elseif msg.command == 0x10005 then -- ico MOVE
804 print(tostring(msg.arg))
805 wmgr:window_request(msg.arg, a, 0)
806 elseif msg.command == 0x10006 then -- ico ACTIVE
807 print('##### ACTIVE')
808 if not msg.arg.active then
811 print(tostring(msg.arg))
812 wmgr:window_request(msg.arg, a, 0)
813 elseif msg.command == 0x10007 then -- ico CHANGE_LAYER
814 print('##### CHANGE_LAYER')
815 print(tostring(msg.arg))
817 if msg.arg.layer ~= 4 or msg.arg.layer ~= 5 then
818 print("do not change layer for other than cursor or touch")
822 wmgr:window_request(msg.arg, a, 0)
823 elseif msg.command == 0x10011 then -- ico MAP_THUMB
824 local framerate = msg.arg.framerate
825 print('##### MAP_THUMB')
827 if not framerate or framerate < 0 then
830 wmgr:window_request(msg.arg, a, framerate)
831 elseif msg.command == 0x10012 then -- ico UNMAP_THUMB
832 print('##### UNMAP_THUMB')
834 wmgr:window_request(msg.arg, a, 0)
835 elseif msg.command == 0x10020 then -- ico SHOW_LAYER command
837 print('##### SHOW_LAYER')
838 wmgr:layer_request(msg.arg)
841 sc.input_handler = function (self, cid, msg)
842 print('*** input handler: ' .. tostring(msg))
844 sc.user_handler = function (self, cid, msg)
845 print('*** user handler: ' .. tostring(msg))
847 sc.resource_handler = function (self, cid, msg)
848 print('*** resource handler: ' .. tostring(msg))
850 createResourceSet = function (ctl, client, msg)
851 cb = function(rset, data)
852 print("> resource callback")
854 -- type is either basic (0) or interrupt (1)
857 requestType = msg.res.type
860 if rset.acquired then
861 cmd = 0x00040001 -- acquire
863 cmd = 0x00040002 -- release
874 if rset.resources.audio_playback then
883 if rset.resources.display then
891 if rset.resources.input then
897 print("sending message to client: " .. data.client)
899 if sc:send_message(data.client, reply) then
900 print('*** reply OK')
902 print('*** reply FAILED')
906 rset = m:ResourceSet({
907 application_class = "player",
908 zone = "driver", -- msg.zone ("full")
917 if msg.res.sound then
919 resource_name = "audio_playback"
921 rset.resources.audio_playback.attributes.pid = tostring(msg.pid)
922 rset.resources.audio_playback.attributes.appid = msg.appid
923 print("sound name: " .. msg.res.sound.name)
924 print("sound zone:" .. msg.res.sound.zone)
925 print("sound adjust: " .. tostring(msg.res.sound.adjust))
926 if msg.res.sound.id then
927 print("sound id: " .. msg.res.sound.id)
931 if msg.res.input then
933 resource_name = "input"
935 rset.resources.input.attributes.pid = tostring(msg.pid)
936 rset.resources.input.attributes.appid = msg.appid
937 print("input name: " .. msg.res.sound.name)
938 print("input event:" .. tostring(msg.res.input.event))
941 if msg.res.window then
943 resource_name = "display"
945 rset.resources.display.attributes.pid = tostring(msg.pid)
946 rset.resources.display.attributes.appid = msg.appid
947 print("display name: " .. msg.res.display.name)
948 print("display zone:" .. msg.res.display.zone)
949 if msg.res.display.id then
950 print("display id: " .. msg.res.display.id)
959 -- fields common to all messages:
964 if msg.command == 0x00040011 then -- MSG_CMD_CREATE_RES
965 print("command CREATE")
968 sets.cid = createResourceSet(self, cid, msg)
971 elseif msg.command == 0x00040012 then -- MSG_CMD_DESTORY_RES
972 print("command DESTROY")
978 sets.cid = nil -- garbage collecting
980 elseif msg.command == 0x00040001 then -- MSG_CMD_ACQUIRE_RES
981 print("command ACQUIRE")
984 sets.cid = createResourceSet(self, cid, msg)
989 elseif msg.command == 0x00040002 then -- MSG_CMD_RELEASE_RES
990 print("command RELEASE")
996 elseif msg.command == 0x00040003 then -- MSG_CMD_DEPRIVE_RES
997 print("command DEPRIVE")
999 elseif msg.command == 0x00040004 then -- MSG_CMD_WAITING_RES
1000 print("command WAITING")
1002 elseif msg.command == 0x00040005 then -- MSG_CMD_REVERT_RES
1003 print("command REVERT")
1006 sc.inputdev_handler = function (self, cid, msg)
1007 print('*** inputdev handler: ' .. tostring(msg))