From 1faf63f8a7a557450bac238ddc1fb95593eadd08 Mon Sep 17 00:00:00 2001 From: Holger Behrens Date: Fri, 13 Feb 2015 12:13:58 +0100 Subject: genivi-demo-platform-hmi: uprev to version 0.3 Signed-off-by: Holger Behrens --- configure.ac | 20 +- genivi-demo-platform-hmi.bb | 27 +- include/gdp-dbus-service.h | 42 +++ include/gdp-dbus-systemd.h | 53 +++ include/gdp-hmi-apps.h | 60 +++ include/gdp-hmi-surfaces.h | 90 +++++ protocol/Makefile.am | 3 + protocol/dbus/Makefile.am | 19 + protocol/dbus/gdp-hmi-introspect.xml | 29 ++ protocol/dbus/systemd-login1.xml | 272 ++++++++++++++ protocol/dbus/systemd-systemd1.xml | 437 ++++++++++++++++++++++ src/Makefile.am | 35 +- src/gdp-dbus-service.cpp | 83 +++++ src/gdp-dbus-systemd.cpp | 39 ++ src/gdp-hmi-controller.c | 471 ----------------------- src/gdp-hmi-controller.cpp | 705 +++++++++++++++++++++++++++++++++++ 16 files changed, 1884 insertions(+), 501 deletions(-) create mode 100644 include/gdp-dbus-service.h create mode 100644 include/gdp-dbus-systemd.h create mode 100644 include/gdp-hmi-apps.h create mode 100644 include/gdp-hmi-surfaces.h create mode 100644 protocol/dbus/Makefile.am create mode 100644 protocol/dbus/gdp-hmi-introspect.xml create mode 100644 protocol/dbus/systemd-login1.xml create mode 100644 protocol/dbus/systemd-systemd1.xml create mode 100644 src/gdp-dbus-service.cpp create mode 100644 src/gdp-dbus-systemd.cpp delete mode 100644 src/gdp-hmi-controller.c create mode 100644 src/gdp-hmi-controller.cpp diff --git a/configure.ac b/configure.ac index a88da25..17e2faf 100644 --- a/configure.ac +++ b/configure.ac @@ -13,6 +13,9 @@ # List of changes: # 23.Jan.2015, Holger Behrens, written # 05.Feb.2015, Holger Behrens, added support for 'doc' making +# 06.Feb.2015, Holger Behrens, added support for C++ source +# updated CONTROL flag +# 09.Feb.2015, Holger Behrens, add support for dbus/dbus-c++/glib AC_PREREQ([2.69]) AC_INIT([genivi-demo-platform-hmi], [0.2], @@ -25,6 +28,7 @@ AM_SILENT_RULES([yes]) # Check for programs AC_PROG_CC +AC_PROG_CXX # Initialize libtool LT_PREREQ([2.4]) @@ -32,9 +36,16 @@ LT_INIT([disable-static]) PKG_PROG_PKG_CONFIG() +PKG_CHECK_MODULES([DBUS], [ + dbus-1 + dbus-c++-1 + dbus-c++-glib-1 + ]) PKG_CHECK_MODULES([CONTROL], [ + wayland-client >= 1.5.0 weston >= 1.5.0 - libsystemd]) + libsystemd + glib-2.0]) PKG_CHECK_MODULES([PLUGIN], [weston >= 1.5.0 cairo xkbcommon]) PKG_CHECK_MODULES([CLIENT], [ wayland-client >= 1.5.0 @@ -60,6 +71,10 @@ WAYLAND_PREFIX=`$PKG_CONFIG --variable=prefix wayland-client` AC_PATH_PROG([WAYLAND_SCANNER], [wayland-scanner],, [${WAYLAND_PREFIX}/bin$PATH_SEPARATOR$PATH]) +# check for dbusxx-xml2cpp +AC_PATH_PROG([XML2CPP], [dbusxx-xml2cpp]) + +# handle arguments AM_CONDITIONAL(BUILD_DOCS, [test x$enable_documentation = xyes]) if test "x$enable_documentation" = "xyes"; then AC_PATH_PROG(DOXYGEN, doxygen) @@ -75,9 +90,10 @@ AC_CONFIG_FILES([Makefile]) AC_CONFIG_FILES([doc/Makefile]) AC_CONFIG_FILES([doc/doxygen/Makefile]) AC_CONFIG_FILES([protocol/Makefile]) +AC_CONFIG_FILES([protocol/dbus/Makefile]) AC_CONFIG_FILES([src/Makefile]) AC_CONFIG_HEADERS([config.h]) -AC_CONFIG_SRCDIR(src/gdp-hmi-controller.c) +AC_CONFIG_SRCDIR(src/gdp-hmi-controller.cpp) # enable C standard as published in 2011 as ISO/IEC 9899:2011 (known as C11) CFLAGS="$CFLAGS -std=c11" diff --git a/genivi-demo-platform-hmi.bb b/genivi-demo-platform-hmi.bb index 979e2bc..d5d05e3 100644 --- a/genivi-demo-platform-hmi.bb +++ b/genivi-demo-platform-hmi.bb @@ -1,12 +1,12 @@ # Copyright (C) 2015 GENIVI Alliance # Released under the MIT license (see COPYING.MIT for the terms) -SUMMARY = "Simple HMI for the GENIVI Demo Platform (GDP)" +SUMMARY = "Simple HMI for the GENIVI Demo Platform (GDP)" HOMEPAGE = "http://projects.genivi.org/genivi-demo-platform/" -LICENSE = "MPL-2.0" +LICENSE = "MPL-2.0" LIC_FILES_CHKSUM = "file://LICENSE;md5=815ca599c9df247a0c7f619bab123dad" -DEPENDS = "wayland-ivi-extension weston" +DEPENDS = "wayland-ivi-extension weston dbus-c++ dbus-c++-native systemd" # SRC_URI = "git://git.projects.genivi.org/genivi-demo-platform-hmi.git" # SRCREV = "" @@ -17,23 +17,4 @@ inherit externalsrc EXTERNALSRC = "/home/holger/Projects/GDP/stash.wrs.com/genivi-demo-platform-hmi" # make sure this matches the version given in configure.ac -PV = "0.2" - -# by default the plugin should end up as: -# /usr/lib/weston/genivi-demo-platform-hmi.so -# to load this plugin you need to add this (.so) to your weston.ini ivi-module -FILES_${PN} += "\ - ${datadir}/weston/* \ - ${libdir}/weston/genivi-demo-platform-hmi.so \ - " -FILES_${PN}-dev += "\ - ${libdir}/weston/genivi-demo-platform-hmi.la \ - " -FILES_${PN}-dbg += "\ - ${libdir}/weston/.debug/* \ - " - -do_install_append() { - install -d ${D}${datadir}/weston - install -m 0444 ${S}/assets/GDP_Panel.png ${D}${datadir}/weston/GDP_Panel.png -} +PV = "0.3" diff --git a/include/gdp-dbus-service.h b/include/gdp-dbus-service.h new file mode 100644 index 0000000..ccb7fe2 --- /dev/null +++ b/include/gdp-dbus-service.h @@ -0,0 +1,42 @@ +/** + * SPDX license identifier: MPL-2.0 + * + * Copyright (C) 2015, GENIVI Alliance + * + * This file is part of GENIVI Demo Platform HMI. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License (MPL), v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * For further information see http://www.genivi.org/. + * + * List of changes: + * 10.Feb.2014, Holger Behrens, written + */ + +#ifndef GDP_HMI_SERVICE_H +#define GDP_HMI_SERVICE_H + +#include +#include +#include + +#include "gdp-hmi-server-glue.h" + +static const char *GDP_DBUS_SERVICE_NAME = "org.genivi.gdp.hmi.controller"; +static const char *GDP_DBUS_SERVICE_PATH = "/org/genivi/gdp/hmi/controller"; + +class HmiService : public org::genivi::gdp::HMI_Controller_adaptor, + public DBus::IntrospectableAdaptor, + public DBus::ObjectAdaptor +{ +public: + HmiService(DBus::Connection &connection); + + int64_t GetId(); + + std::string Show(const std::string &name); +}; + +#endif // GDP_HMI_SERVICE_H \ No newline at end of file diff --git a/include/gdp-dbus-systemd.h b/include/gdp-dbus-systemd.h new file mode 100644 index 0000000..9ae835e --- /dev/null +++ b/include/gdp-dbus-systemd.h @@ -0,0 +1,53 @@ +/** + * SPDX license identifier: MPL-2.0 + * + * Copyright (C) 2015, GENIVI Alliance + * + * This file is part of GENIVI Demo Platform HMI. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License (MPL), v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * For further information see http://www.genivi.org/. + * + * List of changes: + * 11.Feb.2014, Holger Behrens, written + */ + +#ifndef GDP_SYSTEMD_SERVICE_H +#define GDP_SYSTEMD_SERVICE_H + +#include +#include +#include + +#include "systemd1-client-glue.h" + +static const char *SYSTEMD_DBUS_SERVICE_NAME = "org.freedesktop.systemd1"; +static const char *SYSTEMD_DBUS_SERVICE_PATH = "/org/freedesktop/systemd1"; + +class SystemdService : public org::freedesktop::systemd1::Manager_proxy, + public DBus::IntrospectableProxy, + public DBus::ObjectProxy +{ +public: + SystemdService(DBus::Connection &connection, + const char *path, const char *service); + +private: + // make virtual functions dirty no-op's + void UnitNew(const std::string& argin0, const ::DBus::Path& argin1){} + void UnitRemoved(const std::string& argin0, const ::DBus::Path& argin1) {} + void JobNew(const uint32_t& argin0, const ::DBus::Path& argin1, + const std::string& argin2) {} + void JobRemoved(const uint32_t& argin0, const ::DBus::Path& argin1, + const std::string& argin2, const std::string& argin3) {} + void StartupFinished(const uint64_t& argin0, const uint64_t& argin1, + const uint64_t& argin2, const uint64_t& argin3, + const uint64_t& argin4, const uint64_t& argin5) {} + void UnitFilesChanged() {} + void Reloading(const bool& argin0) {} +}; + +#endif // GDP_SYSTEMD_SERVICE_H \ No newline at end of file diff --git a/include/gdp-hmi-apps.h b/include/gdp-hmi-apps.h new file mode 100644 index 0000000..1618650 --- /dev/null +++ b/include/gdp-hmi-apps.h @@ -0,0 +1,60 @@ +/** + * SPDX license identifier: MPL-2.0 + * + * Copyright (C) 2015, GENIVI Alliance + * + * This file is part of GENIVI Demo Platform HMI. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License (MPL), v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * For further information see http://www.genivi.org/. + * + * List of changes: + * 11.Feb.2014, Holger Behrens, written + */ + +#ifndef GDP_HMI_APP_H +#define GDP_HMI_APP_H + +#define GDP_PANEL_SURFACE_ID 0 +#define GDP_PANEL_LAYER_ID 0 +#define GDP_PANEL_UNIT "gdp-hmi-panel.service" + +#define GDP_LAUNCHER_SURFACE_ID 1 +#define GDP_LAUNCHER_LAYER_ID 100 +#define GDP_LAUNCHER_UNIT "gdp-hmi-launcher.service" + +#define GDP_BACKGROUND_SURFACE_ID 2 +#define GDP_BACKGROUND_LAYER_ID 200 +#define GDP_BACKGROUND_UNIT "gdp-hmi-background.service" + +#define QML_EXAMPLE_SURFACE_ID 3 +#define QML_EXAMPLE_LAYER_ID 300 +#define QML_EXAMPLE_UNIT "qml-example.service" + +#define AM_DEMO_SURFACE_ID 20 +#define AM_DEMO_LAYER_ID 300 +#define AM_DEMO_UNIT "AudioManager_PoC.service" + +#define BROWSER_POC_SURFACE_ID 30 +#define BROWSER_POC_LAYER_ID 400 +#define BROWSER_POC_UNIT "browser.service" + +#define FSA_SURFACE_ID 40 +#define FSA_LAYER_ID 500 +#define FSA_UNIT "fsa.service" + +#define MOCK_NAVIGATION_SURFACE_ID 10 +#define MOCK_NAVIGATION_LAYER_ID 600 +#define MOCK_NAVIGATION_UNIT "EGLWLMockNavigation.service" + +#define INPUT_EVENT_EXAMPLE_SURFACE_ID 5100 +#define INPUT_EVENT_EXAMPLE_LAYER_ID 700 +#define INPUT_EVENT_EXAMPLE_UNIT "EGLWLInputEventExample.service" + +#define GDP_MAX_LAYER_ID 800 +#define GDP_LAYER_ID_INCR 100 + +#endif // GDP_HMI_APP_H \ No newline at end of file diff --git a/include/gdp-hmi-surfaces.h b/include/gdp-hmi-surfaces.h new file mode 100644 index 0000000..11f3e50 --- /dev/null +++ b/include/gdp-hmi-surfaces.h @@ -0,0 +1,90 @@ +/** + * SPDX license identifier: MPL-2.0 + * + * Copyright (C) 2015, GENIVI Alliance + * + * This file is part of GENIVI Demo Platform HMI. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License (MPL), v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * For further information see http://www.genivi.org/. + * + * List of changes: + * 11.Feb.2014, Holger Behrens, written + */ + +#ifndef GDP_HMI_SURFACES_H +#define GDP_HMI_SURFACES_H + +#include +#include + +#include "gdp-hmi-apps.h" + +struct gdp_surface_context { + t_ilm_bool created; + const t_ilm_uint id_surface; + const t_ilm_uint id_layer; + const std::string unit; +}; + +static struct gdp_surface_context gdp_surfaces[] = { + { + ILM_FALSE, + GDP_PANEL_SURFACE_ID, + GDP_PANEL_LAYER_ID, + GDP_PANEL_UNIT + }, + { + ILM_FALSE, + GDP_LAUNCHER_SURFACE_ID, + GDP_LAUNCHER_LAYER_ID, + GDP_LAUNCHER_UNIT + }, + { + ILM_FALSE, + GDP_BACKGROUND_SURFACE_ID, + GDP_BACKGROUND_LAYER_ID, + GDP_BACKGROUND_UNIT + }, + { + ILM_FALSE, + QML_EXAMPLE_SURFACE_ID, + QML_EXAMPLE_LAYER_ID, + QML_EXAMPLE_UNIT + }, + { + ILM_FALSE, + AM_DEMO_SURFACE_ID, + AM_DEMO_LAYER_ID, + AM_DEMO_UNIT + }, + { + ILM_FALSE, + BROWSER_POC_SURFACE_ID, + BROWSER_POC_LAYER_ID, + BROWSER_POC_UNIT + }, + { + ILM_FALSE, + FSA_SURFACE_ID, + FSA_LAYER_ID, + FSA_UNIT + }, + { + ILM_FALSE, + MOCK_NAVIGATION_SURFACE_ID, + MOCK_NAVIGATION_LAYER_ID, + MOCK_NAVIGATION_UNIT + }, + { + ILM_FALSE, + INPUT_EVENT_EXAMPLE_SURFACE_ID, + INPUT_EVENT_EXAMPLE_LAYER_ID, + INPUT_EVENT_EXAMPLE_UNIT + }, +}; + +#endif // GDP_HMI_SURFACES_H \ No newline at end of file diff --git a/protocol/Makefile.am b/protocol/Makefile.am index c0ee80d..a444b80 100644 --- a/protocol/Makefile.am +++ b/protocol/Makefile.am @@ -12,6 +12,9 @@ # # List of changes: # 23.Jan.2015, Holger Behrens, written +# 10.Feb.2015, Holger Behrens, defined SUBDIRS + +SUBDIRS = dbus EXTRA_DIST = \ ivi-application.xml \ diff --git a/protocol/dbus/Makefile.am b/protocol/dbus/Makefile.am new file mode 100644 index 0000000..bdc8c06 --- /dev/null +++ b/protocol/dbus/Makefile.am @@ -0,0 +1,19 @@ +# SPDX license identifier: MPL-2.0 +# +# Copyright (C) 2015, GENIVI Alliance +# +# This file is part of the GENIVI Demo Platform HMI. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License (MPL), v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# For further information see http://www.genivi.org/. +# +# List of changes: +# 10.Feb.2015, Holger Behrens, written + +EXTRA_DIST = \ + gdp-hmi-introspect.xml \ + systemd-systemd1.xml \ + systemd-login1.xml diff --git a/protocol/dbus/gdp-hmi-introspect.xml b/protocol/dbus/gdp-hmi-introspect.xml new file mode 100644 index 0000000..3bb57c1 --- /dev/null +++ b/protocol/dbus/gdp-hmi-introspect.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/protocol/dbus/systemd-login1.xml b/protocol/dbus/systemd-login1.xml new file mode 100644 index 0000000..49dfcce --- /dev/null +++ b/protocol/dbus/systemd-login1.xml @@ -0,0 +1,272 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/protocol/dbus/systemd-systemd1.xml b/protocol/dbus/systemd-systemd1.xml new file mode 100644 index 0000000..3cdc990 --- /dev/null +++ b/protocol/dbus/systemd-systemd1.xml @@ -0,0 +1,437 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Makefile.am b/src/Makefile.am index 1085479..ac95fb4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,15 +12,28 @@ # # List of changes: # 23.Jan.2015, Holger Behrens, written +# 06.Feb.2015, Holger Behrens, define include directory location +# 09.Feb.2015, Holger Behrens, add support for dbus/dbus-c++/glib +# 10.Feb.2015, Hogler Behrens, add support for systemd1/login1 dbus-c++ client +# -BUILT_SOURCES = ivi-controller-client-protocol.h +AM_CPPFLAGS = -I$(top_srcdir)/include +BUILT_SOURCES = ivi-controller-client-protocol.h \ + gdp-hmi-server-glue.h \ + gdp-hmi-client-glue.h \ + systemd1-client-glue.h \ + login1-client-glue.h bin_PROGRAMS = gdp-hmi-controller -gdp_hmi_controller_CPPFLAGS = $(CONTROL_FLAGS) $(AM_CPPFLAGS) -gdp_hmi_controller_LDADD = $(ILM_LIBS) $(CONTROL_LIBS) +gdp_hmi_controller_CPPFLAGS = $(CONTROL_CFLAGS) $(DBUS_CFLAGS) $(AM_CPPFLAGS) +gdp_hmi_controller_LDADD = $(ILM_LIBS) $(CONTROL_LIBS) $(DBUS_LIBS) gdp_hmi_controller_SOURCES = \ - ivi-controller-client-protocol.h \ - gdp-hmi-controller.c + gdp-dbus-systemd.cpp \ + systemd1-client-glue.h \ + gdp-dbus-service.cpp \ + gdp-hmi-server-glue.h \ + ivi-controller-client-protocol.h \ + gdp-hmi-controller.cpp %-protocol.c : ../protocol/%.xml $(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@ @@ -30,3 +43,15 @@ gdp_hmi_controller_SOURCES = \ %-client-protocol.h : ../protocol/%.xml $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ + +gdp-hmi-client-glue.h: $(top_srcdir)/protocol/dbus/gdp-hmi-introspect.xml + $(XML2CPP) $< --proxy=$@ + +gdp-hmi-server-glue.h: $(top_srcdir)/protocol/dbus/gdp-hmi-introspect.xml + $(XML2CPP) $< --adaptor=$@ + +systemd1-client-glue.h: $(top_srcdir)/protocol/dbus/systemd-systemd1.xml + $(XML2CPP) $< --proxy=$@ + +login1-client-glue.h: $(top_srcdir)/protocol/dbus/systemd-login1.xml + $(XML2CPP) $< --proxy=$@ diff --git a/src/gdp-dbus-service.cpp b/src/gdp-dbus-service.cpp new file mode 100644 index 0000000..89222ba --- /dev/null +++ b/src/gdp-dbus-service.cpp @@ -0,0 +1,83 @@ +/** + * SPDX license identifier: MPL-2.0 + * + * Copyright (C) 2015, GENIVI Alliance + * + * This file is part of GENIVI Demo Platform HMI. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License (MPL), v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * For further information see http://www.genivi.org/. + * + * List of changes: + * 10.Feb.2014, Holger Behrens, written + */ + +/*! \file gdp-dbus-service.cpp + * \brief HMI controller service API on D-Bus for the GENIVI Demo Platform + * + * This component implements the HMI controller service API and makes it + * available on the D-Bus session bus. + */ + +#include +#include +#include +#include + +#include "gdp-hmi-surfaces.h" +#include "gdp-dbus-service.h" +#include "gdp-dbus-systemd.h" + +extern SystemdService *gSystemdSession; // systemd on session bus (d-bus) +extern SystemdService *gSystemd; // systemd on system bus (d-bus) + +HmiService::HmiService(DBus::Connection &connection) + : DBus::ObjectAdaptor(connection, GDP_DBUS_SERVICE_PATH) +{ + sd_journal_print(LOG_INFO, "HmiService - constructor (path= %s)\n", + GDP_DBUS_SERVICE_PATH); +} + +int64_t HmiService::GetId() +{ + sd_journal_print(LOG_DEBUG, "HmiService::GetId() - %d\n", getpid()); + return getpid(); +} + +std::string HmiService::Show(const std::string &unit) +{ + if (0 == unit.compare(0, 15, "poweroff.target")) { + sd_journal_print(LOG_DEBUG, "HmiService::Show() - %s (match)\n", + unit.c_str()); + std::string path = gSystemd->StartUnit(unit, "replace"); + } else { + sd_journal_print(LOG_DEBUG, "HmiService::Show() - %s\n", + unit.c_str()); + for (int count = 0; + count < sizeof gdp_surfaces / sizeof gdp_surfaces[0]; count++) { + if (0 == unit.compare(gdp_surfaces[count].unit)) { + if (ILM_TRUE == gdp_surfaces[count].created) { + // FIXME + // bring gdp_surfaces[count].id_surface to front + sd_journal_print(LOG_DEBUG, + "HmiService::Show() - %s surface (%d) exists.\n", + unit.c_str(), gdp_surfaces[count].id_surface); + } else { + // request systemd to start the unit + std::string path = gSystemdSession->StartUnit(unit, "replace"); + sd_journal_print(LOG_DEBUG, + "systemd(session)::StartUnit() - %s\n", path.c_str()); + } + break; // for-loop + } + else { + sd_journal_print(LOG_DEBUG, "DEBUG: compare \"%s\" with \"%s\"", + unit.c_str(), gdp_surfaces[count].unit.c_str()); + } + } // for-loop + } + return "Show unit \"" + unit + "\"!"; +} diff --git a/src/gdp-dbus-systemd.cpp b/src/gdp-dbus-systemd.cpp new file mode 100644 index 0000000..2f971c7 --- /dev/null +++ b/src/gdp-dbus-systemd.cpp @@ -0,0 +1,39 @@ +/** + * SPDX license identifier: MPL-2.0 + * + * Copyright (C) 2015, GENIVI Alliance + * + * This file is part of GENIVI Demo Platform HMI. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License (MPL), v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * For further information see http://www.genivi.org/. + * + * List of changes: + * 11.Feb.2014, Holger Behrens, written + */ + +/*! \file gdp-dbus-systemd.cpp + * \brief HMI controller interface with systemd via D-Bus + * + * This component implements the HMI controller interface with systemd via + * D-Bus. Using the session bus to query application status and using the + * system bus for calling the systemd 'PowerOff' method. + */ + +#include +#include +#include +#include + +#include "gdp-dbus-systemd.h" + +SystemdService::SystemdService(DBus::Connection &connection, + const char *path, const char *service) + : DBus::ObjectProxy(connection, path, service) +{ + sd_journal_print(LOG_INFO, "SystemdService - constructor (path= %s)\n", + path); +} diff --git a/src/gdp-hmi-controller.c b/src/gdp-hmi-controller.c deleted file mode 100644 index 6c4e579..0000000 --- a/src/gdp-hmi-controller.c +++ /dev/null @@ -1,471 +0,0 @@ -/* SPDXLicenseID: MPL-2.0 - * - * Copyright (C) 2015, GENIVI Alliance - * - * This file is part of the GENIVI Demo Platform HMI. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License (MPL), v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * For further information see http://www.genivi.org/. - * - * List of changes: - * 23.Jan.2015, Holger Behrens, written - * 05.Feb.2015, Holger Behrens, added surface ID '3' handling - */ - -/*! \file gdp-hmi-controller.c - * \brief HMI controller for the GENIVI Demo Platform - * - * This component implements the HMI controller of the GENIVI Demo Platform - * using the GENIVI Alliance wayland-ivi-extension. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "wayland-util.h" -#include "ivi-controller-client-protocol.h" - - -// definitions - -#define DEFAULT_SCREEN_WIDTH 1024 -#define DEFAULT_SCREEN_HEIGHT 768 - -struct gdp_surface_context { - t_ilm_bool created; - t_ilm_uint id_surface; - t_ilm_uint id_layer; -}; - -// initialize global variables - -static int verbose = 0; -static int gRunLoop = 0; -static t_ilm_uint screenID = 0; -static t_ilm_uint screenWidth = DEFAULT_SCREEN_WIDTH; -static t_ilm_uint screenHeight = DEFAULT_SCREEN_HEIGHT; -static int surfacesArrayCount = 0; -static unsigned int* surfacesArray = NULL; - -static struct gdp_surface_context gdp_surfaces[] = { - {ILM_FALSE, 1 /* Background / Logo */, 100}, - {ILM_FALSE, 2 /* GDP HMI */, 200}, - {ILM_FALSE, 3 /* QML Example */, 300}, - {ILM_FALSE, 20 /* AudioManager PoC */, 300}, - {ILM_FALSE, 30 /* Browser PoC */, 400}, - {ILM_FALSE, 40 /* FSA PoC */, 500}, - {ILM_FALSE, 10 /* EGL Mock Navigation */, 600}, - {ILM_FALSE, 5100 /* EGL Input Example */, 700}, -}; - -/** - * \brief signal handler - * - * This function shall handle all signals of type 'SIGINT'. - * - */ -static void sig_handler(int signo) -{ - signo = signo; - printf(" signal caught\n"); - gRunLoop = 0; -} - -/** - * \brief creates IVI layer - * - * This function creates the following layers with the the given ID: - * - * Layer Assignment | Layer ID - * -----------------: | :------: - * background w/ logo | 100 - * launcher | 200 - * AM PoC | 300 - * Browser PoC | 400 - * FSA PoC | 500 - * MockNavigation | 600 - * InputEventExample | 700 - * - */ -static void layer_create(void) -{ - ilmErrorTypes callResult = ILM_FAILED; - struct ilmScreenProperties screenProperties; - t_ilm_layer layerid = 0; - t_ilm_uint* pIDs = NULL; - t_ilm_uint numberOfIDs = 0; - - if (!ilm_isInitialized()) - return; - - callResult = ilm_getScreenIDs(&numberOfIDs, &pIDs); - if (ILM_SUCCESS != callResult) { - sd_journal_print(LOG_ERR, - "Error: layer_create() ilm_getScreenIDs - %s. Exiting.\n", - ILM_ERROR_STRING(callResult)); - exit(EXIT_FAILURE); - } else { - screenID = pIDs[0]; - sd_journal_print(LOG_DEBUG, - "Debug: ilm_getScreenIDs - %s. number of screens = %u\n", - ILM_ERROR_STRING(callResult), numberOfIDs); - } - sd_journal_print(LOG_INFO, - "Info: layer_create - in screen with ID = %u\n", - screenID); - - - callResult = ilm_getPropertiesOfScreen(screenID, &screenProperties); - if (ILM_SUCCESS != callResult) { - sd_journal_print(LOG_ERR, - "Error: layer_create() ilm_getPropertiesOfScreen - %s. Exiting.\n", - ILM_ERROR_STRING(callResult)); - exit(EXIT_FAILURE); - } - screenWidth = screenProperties.screenWidth; - screenHeight = screenProperties.screenHeight; - sd_journal_print(LOG_INFO, - "Info: layer_create - screen size = %u x %u\n", - screenWidth, screenHeight); - if (0 == screenWidth) - screenWidth = DEFAULT_SCREEN_WIDTH; - if (0 == screenHeight) - screenHeight = DEFAULT_SCREEN_HEIGHT; - - for(layerid = 100; layerid < 800; layerid += 100) { - callResult = ilm_layerCreateWithDimension(&layerid, - screenWidth, screenHeight); - if (ILM_SUCCESS != callResult) { - sd_journal_print(LOG_ERR, - "Error: layer_create (id = %u) - %s\n", - layerid, ILM_ERROR_STRING(callResult)); - break; - } else { - sd_journal_print(LOG_DEBUG, - "Debug: layer_create (id = %u) - %s (%u x %u)\n", - layerid, ILM_ERROR_STRING(callResult), - screenWidth, screenHeight); - } - } // for-loop - - callResult = ilm_commitChanges(); - if (ILM_SUCCESS != callResult) { - sd_journal_print(LOG_ERR, - "Error: layer_create() ilm_commitChanges - %s. Exiting.\n", - ILM_ERROR_STRING(callResult)); - exit(EXIT_FAILURE); - } -} - -/** - * \brief print help message to stderr - * - * This function does print a help message to stderr explaining the usage - * of the executable \p name. - * - * \param name The name of this executable. - */ -static void help(const char *name) -{ - fprintf(stderr, "Usage: %s [args...]\n", name); - fprintf(stderr, " -s, --surface Use surface with specified ID\n"); - fprintf(stderr, " -v, --verbose Be verbose\n"); - fprintf(stderr, " -h, --help Display this help message\n"); -} - -/** - * \brief control the IVI surface - * - * This function does control the surface \p gdp_surface. - * Currently the surface is added to its assigned layer, - * the layer brought into view on the screen and assigned input focus. - * - * \param gdp_surfaces The name of this executable. - */ -static void surface_control(struct gdp_surface_context gdp_surface) -{ - ilmErrorTypes callResult = ILM_FAILED; - t_ilm_surface surfaceIdArray[] = {1, 2, 3}; - t_ilm_layer layerIdArray[] = {100, 200, 300}; - - sd_journal_print(LOG_DEBUG, "surface_control" - "(surface = %u, layer = %u)\n", - gdp_surface.id_surface, gdp_surface.id_layer); - - surfaceIdArray[2] = gdp_surface.id_surface; - layerIdArray[2] = gdp_surface.id_layer; - - switch(gdp_surface.id_surface) { - case 1: // Background / Logo - break; - case 2: // GDP HMI - break; - case 3: // QML Example - // fall-through - case 20: // AudioManager PoC - callResult = ilm_surfaceSetDestinationRectangle( - gdp_surface.id_surface, 0, 0, screenWidth, screenHeight); - callResult = ilm_surfaceSetVisibility( - gdp_surface.id_surface, ILM_TRUE); - callResult = ilm_surfaceSetOpacity( - gdp_surface.id_surface, 1.0f); - callResult = ilm_commitChanges(); - sd_journal_print(LOG_DEBUG, "surface_control - input focus on\n"); - callResult = ilm_UpdateInputEventAcceptanceOn( - gdp_surface.id_surface, - ILM_INPUT_DEVICE_POINTER | - ILM_INPUT_DEVICE_TOUCH | - ILM_INPUT_DEVICE_KEYBOARD, - ILM_TRUE); - callResult = ilm_SetKeyboardFocusOn(gdp_surface.id_surface); - callResult = ilm_commitChanges(); - - sd_journal_print(LOG_DEBUG, "surface_control - render order - layer\n"); - callResult = ilm_layerSetRenderOrder(gdp_surface.id_layer, - surfaceIdArray, 3); - callResult = ilm_layerSetVisibility(gdp_surface.id_layer, - ILM_TRUE); - callResult = ilm_commitChanges(); - - sd_journal_print(LOG_DEBUG, "surface_control - render order - screen\n"); - callResult = ilm_displaySetRenderOrder((t_ilm_display)screenID, - layerIdArray, 3); - - callResult = ilm_commitChanges(); - break; - case 30: // Browser PoC - break; - case 40: // FSA PoC - break; - case 10: // EGL Mock Navigation - break; - case 5100: // EGL Input Example - break; - default: - sd_journal_print(LOG_DEBUG, - "surface_control - unknown surface.\n"); - break; - } // switch -} - -/** - * \brief retrieve surface ID(s) that appeared - * - * This function will check if, from the list of expected surfaces, any new - * surface has appeared. - * - * \param length The length of the array - * \param pArray Pointer to array of surface IDs - */ -static void surfaces_appear_check(t_ilm_int length, t_ilm_surface* pArray) -{ - if ((length <= 0) && (pArray == NULL)) - return; - - // check for appearance - for (int i = 0; i < length; i++) { - // check out list of expected surface IDs 'gdp_surfaces' - for (int count = 0; - count < sizeof gdp_surfaces / sizeof gdp_surfaces[0]; count++) { - if (pArray[i] == gdp_surfaces[count].id_surface) { - // check if surface is already known - if (ILM_TRUE == gdp_surfaces[count].created) - continue; // inner for-loop - // get to know *new* surface - gdp_surfaces[count].created = ILM_TRUE; - sd_journal_print(LOG_DEBUG, - "Debug: new surface id: %i (for layer: %i)\n", - gdp_surfaces[count].id_surface, - gdp_surfaces[count].id_layer); - surface_control(gdp_surfaces[count]); - } - } // inner for-loop - } // outer for-loop -} - -/** - * \brief retrieve surface ID(s) that disappeared - * - * This function will check if, from the list of expected surfaces, any - * surface has disappeared. - * - * \param length The length of the array - * \param pArray Pointer to array of surface IDs - */ -static void surfaces_disappear_check(t_ilm_int length, t_ilm_surface* pArray) -{ - if ((length <= 0) && (pArray == NULL)) - return; - - // check for disappearance - for (int count = 0; - count < sizeof gdp_surfaces / sizeof gdp_surfaces[0]; count++) { - t_ilm_bool found = ILM_FALSE; - - for (int i = 0; i < length; i++) { - if (pArray[i] == gdp_surfaces[count].id_surface) { - found = ILM_TRUE; - break; // inner for-loop - } - } // inner for-loop - - if ((ILM_FALSE == found) && (ILM_TRUE == gdp_surfaces[count].created)) { - gdp_surfaces[count].created = ILM_FALSE; - sd_journal_print(LOG_DEBUG, - "Debug: surface id: %i disappeared (from layer: %i)\n", - gdp_surfaces[count].id_surface, - gdp_surfaces[count].id_layer); - } - } // outer for-loop -} - -/** - * \brief poll for surface appearance - * - * This function gets all surface IDs and compares them with a previous - * copy to find out if a new surface did appear or an existing vanished. - */ -static void surface_create_poll(void) -{ - int count = 0; - unsigned int* array = NULL; - ilmErrorTypes callResult = ILM_FAILED; - - // retrieve all surface ID(s) - callResult = ilm_getSurfaceIDs(&count, &array); - if (ILM_SUCCESS != callResult) { - sd_journal_print(LOG_ERR, - "Error: surface_create_poll ilm_getSurfaceIDs - %s.\n", - ILM_ERROR_STRING(callResult)); - } else if (count != surfacesArrayCount) { - unsigned int* oldArray = surfacesArray; - - // new previously unknown surface(s) appeared - - if (surfacesArrayCount < count) { - sd_journal_print(LOG_DEBUG, - "Debug: surface_create_poll surfaces = %i (++)\n", count); - surfaces_appear_check(count, array); - } else if (surfacesArrayCount > count) { - sd_journal_print(LOG_DEBUG, - "Debug: surface_create_poll surfaces = %i (--)\n", count); - surfaces_disappear_check(count, array); - } - - surfacesArray = array; - surfacesArrayCount = count; - array = oldArray; - } - - // free 'array' that had been allocated by ilm_getSurfaceIDs() - if (NULL != array) - free(array); -} - -/** - * \brief main thread - * - * This function is the main entry point of this executable. - * It reads and interprets command line options given by user, - * creates some layers, waits for surfaces to appear and once - * it did, assign the surface to a layer and have it rendered. - */ -int main(int argc, char * const* argv) -{ - t_ilm_surface surfaceId = 210; - ilmErrorTypes callResult = ILM_FAILED; - - // read and interpret command line options - while (1){ - struct option opts[] = { - { "surface", required_argument, NULL, 's' }, - { "verbose", no_argument, NULL, 'v' }, - { "help", no_argument, NULL, 'h' }, - { 0, 0, NULL, 0 } - }; - - int c = getopt_long(argc, argv, "s:vh", opts, NULL); - if (-1 == c) // no more options - break; - - switch(c){ - default: - sd_journal_print(LOG_ERR, - "Error: Unrecognized option '%s'\n", optarg); - break; - case 's': - surfaceId = strtol(optarg, NULL, 0); - break; - case 'v': - verbose = 1; - break; - case 'h': - help("gdp-hmi-controller"); - exit(EXIT_FAILURE); - break; - } - } - - // initializes the IVI LayerManagement Client - callResult = ilm_init(); - if (ILM_SUCCESS != callResult) { - sd_journal_print(LOG_ERR, - "Error: ilm_init - %s. Exiting.\n", - ILM_ERROR_STRING(callResult)); - exit(EXIT_FAILURE); - } - - // create all the layers needed - layer_create(); - - gRunLoop = 1; - - // establish signal handling - if ((void *)-1 == signal(SIGINT, sig_handler)) { - sd_journal_print(LOG_ERR, "Error: signal()\n"); - exit(EXIT_FAILURE); - } - - // fill 'surfacesArray' global with already existing surfaces - callResult = ilm_getSurfaceIDs(&surfacesArrayCount, &surfacesArray); - if (ILM_SUCCESS != callResult) { - sd_journal_print(LOG_ERR, "Error: ilm_getSurfaceIDs - %s.\n", - ILM_ERROR_STRING(callResult)); - } else { - sd_journal_print(LOG_DEBUG, - "Debug: main surfaces = %i\n", surfacesArrayCount); - } - - // wait for SIGINT to happen - while (gRunLoop) { - /* - * poll for added surfaces as ilm_surfaceAddNotification() - * only work for already existing surfaces - */ - surface_create_poll(); - sleep(1); // was usleep(50) - } - - // destroy the IVI LayerManagement Client - callResult = ilm_destroy(); - if (ILM_SUCCESS != callResult) { - sd_journal_print(LOG_ERR, - "Error: ilm_destroy - %s. Exiting.\n", - ILM_ERROR_STRING(callResult)); - exit(EXIT_FAILURE); - } - - return EXIT_SUCCESS; -} diff --git a/src/gdp-hmi-controller.cpp b/src/gdp-hmi-controller.cpp new file mode 100644 index 0000000..b9597c9 --- /dev/null +++ b/src/gdp-hmi-controller.cpp @@ -0,0 +1,705 @@ +/* SPDXLicenseID: MPL-2.0 + * + * Copyright (C) 2015, GENIVI Alliance + * + * This file is part of the GENIVI Demo Platform HMI. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License (MPL), v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * For further information see http://www.genivi.org/. + * + * List of changes: + * 23.Jan.2015, Holger Behrens, written + * 05.Feb.2015, Holger Behrens, added surface ID '3' handling + * 06.Feb.2015, Holger Behrens, added default surfaces (panel, background) + * introduced SIGUSR signal handling, pidfile + * 09.Feb.2015, Holger Behrens, convert main loop into a glib main loop + * 10.Feb.2015, Holger Behrens, added interface to systemd (via dbus-c++) + */ + +/*! \file gdp-hmi-controller.cpp + * \brief HMI controller for the GENIVI Demo Platform + * + * This component implements the HMI controller of the GENIVI Demo Platform + * using the GENIVI Alliance wayland-ivi-extension. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "wayland-util.h" +#include "ivi-controller-client-protocol.h" +#include "gdp-hmi-surfaces.h" +#include "gdp-dbus-service.h" +#include "gdp-dbus-systemd.h" + +// definitions + +#define DEFAULT_SCREEN_WIDTH 1024 +#define DEFAULT_SCREEN_HEIGHT 768 +#define DEFAULT_PANEL_HEIGHT_LR 68 // low-res (default) +#define DEFAULT_PANEL_HEIGHT_HR 80 // high-res + +// initialize global variables + +static int verbose = 0; +static int gRunLoop = 0; +static GMainLoop* gMainLoop = NULL; +static t_ilm_uint screenID = 0; +static t_ilm_uint screenWidth = DEFAULT_SCREEN_WIDTH; +static t_ilm_uint screenHeight = DEFAULT_SCREEN_HEIGHT; +static t_ilm_uint panelHeight = DEFAULT_PANEL_HEIGHT_LR; +static int surfacesArrayCount = 0; +static unsigned int* surfacesArray = NULL; +static const char *GDP_HMI_PID_FILENAME = "/var/run/gdp-hmi-controller.pid"; + +DBus::Glib::BusDispatcher dispatcher; // dbus-c++ bus dispatcher (glib) +SystemdService *gSystemdSession; // systemd on session bus (d-bus) +SystemdService *gSystemd; // systemd on system bus (d-bus) + + +/** + * \brief creates a PID file + * + * This function creates a file and write this process' ID into it. + * + * \param[IN] progName name of the calling program (i.e., argv[0] or similar) + * \param[IN] pidFile name of file to be created (fully qualified) + * \return file descriptor referring the file created + */ +int create_pid_file(const char *progName, const char *pidFile) +{ + int fd; + char stringBuffer[256]; + + fd = open(pidFile, O_RDWR | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR); + if (-1 == fd) { + strerror_r(errno, stringBuffer, 256); + sd_journal_print(LOG_ERR, + "Error: create_pid_file (open) - %s. Exiting.\n", stringBuffer); + exit(EXIT_FAILURE); + } + + if (-1 == ftruncate(fd, 0)) { + strerror_r(errno, stringBuffer, 256); + sd_journal_print(LOG_ERR, + "Error: create_pid_file (trunc) - %s. Exiting.\n", stringBuffer); + exit(EXIT_FAILURE); + } + + snprintf(stringBuffer, 256, "%ld\n", (long) getpid()); + if (write(fd, stringBuffer, strlen(stringBuffer)) != strlen(stringBuffer)) { + sd_journal_print(LOG_ERR, + "Error: Writing to PID file failed. Exiting.\n"); + exit(EXIT_FAILURE); + } + + return fd; +} + +/** + * \brief creates IVI layer + * + * This function creates the following layers with the given ID: + * + * Layer Assignment | Layer ID + * ------------------: | :------: + * panel | 0 + * launcher | 100 + * background | 200 + * AM PoC | 300 + * Browser PoC | 400 + * FSA PoC | 500 + * MockNavigation | 600 + * InputEventExample | 700 + * + */ +static void layer_create(void) +{ + ilmErrorTypes callResult = ILM_FAILED; + struct ilmScreenProperties screenProperties; + t_ilm_layer layerid = 0; + t_ilm_uint* pIDs = NULL; + t_ilm_uint numberOfIDs = 0; + + if (!ilm_isInitialized()) + return; + + callResult = ilm_getScreenIDs(&numberOfIDs, &pIDs); + if (ILM_SUCCESS != callResult) { + sd_journal_print(LOG_ERR, + "Error: layer_create() ilm_getScreenIDs - %s. Exiting.\n", + ILM_ERROR_STRING(callResult)); + exit(EXIT_FAILURE); + } else { + sd_journal_print(LOG_DEBUG, + "Debug: ilm_getScreenIDs - %s. number of screens = %u\n", + ILM_ERROR_STRING(callResult), numberOfIDs); + for (int i = 0; i < numberOfIDs; i++) { + sd_journal_print(LOG_DEBUG, "Debug: Screen ID[%u] = %d\n", + i, pIDs[i]); + } + screenID = 0; // always use screen with the ID 0 + // (limitation of ivi-shell at time of this writing) + } + sd_journal_print(LOG_INFO, + "Info: layer_create - in screen with ID = %u\n", screenID); + + callResult = ilm_getPropertiesOfScreen(screenID, &screenProperties); + if (ILM_SUCCESS != callResult) { + sd_journal_print(LOG_ERR, + "Error: layer_create() ilm_getPropertiesOfScreen - %s. Exiting.\n", + ILM_ERROR_STRING(callResult)); + exit(EXIT_FAILURE); + } + screenWidth = screenProperties.screenWidth; + screenHeight = screenProperties.screenHeight; + sd_journal_print(LOG_INFO, + "Info: layer_create - screen size = %u x %u\n", + screenWidth, screenHeight); + if (0 == screenWidth) + screenWidth = DEFAULT_SCREEN_WIDTH; + if (0 == screenHeight) + screenHeight = DEFAULT_SCREEN_HEIGHT; + if (1200 < screenWidth) + panelHeight = DEFAULT_PANEL_HEIGHT_HR; + + // create panel layer - layer id '0' + callResult = ilm_layerCreateWithDimension(&layerid, + screenWidth, panelHeight); + if (ILM_SUCCESS != callResult) { + sd_journal_print(LOG_ERR, + "Error: layer_create (id = %u) - %s\n", + layerid, ILM_ERROR_STRING(callResult)); + } else { + sd_journal_print(LOG_DEBUG, + "Debug: layer_create (id = %u) - %s (%u x %u)\n", + layerid, ILM_ERROR_STRING(callResult), + screenWidth, panelHeight); + } + + // create all other layers - layer id's '100..700' + for(layerid = GDP_LAUNCHER_LAYER_ID; layerid < GDP_MAX_LAYER_ID; + layerid += GDP_LAYER_ID_INCR) { + callResult = ilm_layerCreateWithDimension(&layerid, screenWidth, + (GDP_LAUNCHER_LAYER_ID == layerid) ? + screenHeight : (screenHeight - panelHeight)); + if (ILM_SUCCESS != callResult) { + sd_journal_print(LOG_ERR, + "Error: layer_create (id = %u) - %s\n", + layerid, ILM_ERROR_STRING(callResult)); + break; + } else { + sd_journal_print(LOG_DEBUG, + "Debug: layer_create (id = %u) - %s (%u x %u)\n", + layerid, ILM_ERROR_STRING(callResult), screenWidth, + (100 == layerid)?screenHeight:(screenHeight - panelHeight)); + } + } // for-loop + + callResult = ilm_commitChanges(); + if (ILM_SUCCESS != callResult) { + sd_journal_print(LOG_ERR, + "Error: layer_create() ilm_commitChanges - %s. Exiting.\n", + ILM_ERROR_STRING(callResult)); + exit(EXIT_FAILURE); + } +} + +/** + * \brief show the launcher surface + * + * This function does control the launcher surface given by \p gdp_surface. + * Currently the surface is added to its assigned layer with the ID '1'. + * + * \param gdp_surfaces The GDP surface/layer context used for launcher. + */ +static void launcher_show(const struct gdp_surface_context gdp_surface) +{ + ilmErrorTypes callResult = ILM_FAILED; + t_ilm_surface surfaceIdArray[] = {GDP_LAUNCHER_SURFACE_ID}; + t_ilm_layer layerIdArray[] = {GDP_LAUNCHER_LAYER_ID}; + + sd_journal_print(LOG_DEBUG, "launcher_show" + "(surface = %u, layer = %u)\n", + gdp_surface.id_surface, gdp_surface.id_layer); + + surfaceIdArray[0] = gdp_surface.id_surface; + layerIdArray[0] = gdp_surface.id_layer; + callResult = ilm_surfaceSetDestinationRectangle( + gdp_surface.id_surface, 0, 0, screenWidth, screenHeight); + callResult = ilm_surfaceSetVisibility( + gdp_surface.id_surface, ILM_TRUE); + callResult = ilm_surfaceSetOpacity( + gdp_surface.id_surface, 1.0f); + callResult = ilm_commitChanges(); + sd_journal_print(LOG_DEBUG, "launcher_show - input focus on\n"); + callResult = ilm_UpdateInputEventAcceptanceOn( + gdp_surface.id_surface, + ILM_INPUT_DEVICE_POINTER | + ILM_INPUT_DEVICE_TOUCH | + ILM_INPUT_DEVICE_KEYBOARD, + ILM_TRUE); + callResult = ilm_SetKeyboardFocusOn(gdp_surface.id_surface); + callResult = ilm_commitChanges(); + + sd_journal_print(LOG_DEBUG, "launcher_show - render order - layer\n"); + callResult = ilm_layerSetRenderOrder(gdp_surface.id_layer, + surfaceIdArray, 1); + callResult = ilm_layerSetVisibility(gdp_surface.id_layer, + ILM_TRUE); + callResult = ilm_commitChanges(); + + sd_journal_print(LOG_DEBUG, "launcher_show - render order - screen\n"); + callResult = ilm_displaySetRenderOrder((t_ilm_display)screenID, + layerIdArray, 1); + + callResult = ilm_commitChanges(); +} + +/** + * \brief control the IVI surface + * + * This function does control the surface \p gdp_surface. + * Currently the surface is added to its assigned layer, + * the layer together with the layer holding the 'panel' + * are brought into view on the screen and assigned input focus. + * + * ID | Surface + * :--: | :------ + * 0 | Panel + * 1 | GDP HMI + * 2 | Background + * 3 | QML Example + * 20 | AudioManager PoC + * 30 | Browser PoC + * 40 | FSA PoC + * 10 | EGL Mock Navigation + * 5100 | EGL Input Example + * + * \param gdp_surfaces The GDP surface/layer context to be controlled. + */ +static void surface_control(struct gdp_surface_context gdp_surface) +{ + ilmErrorTypes callResult = ILM_FAILED; + t_ilm_surface surfaceIdArray[] = {GDP_BACKGROUND_SURFACE_ID}; + t_ilm_layer layerIdArray[] = {GDP_BACKGROUND_LAYER_ID, + GDP_PANEL_LAYER_ID}; + + sd_journal_print(LOG_DEBUG, "surface_control" + "(surface = %u, layer = %u)\n", + gdp_surface.id_surface, gdp_surface.id_layer); + + surfaceIdArray[0] = gdp_surface.id_surface; + layerIdArray[0] = gdp_surface.id_layer; + + switch(gdp_surface.id_surface) { + case GDP_PANEL_SURFACE_ID: // Panel + callResult = ilm_surfaceSetDestinationRectangle( + gdp_surface.id_surface, 0, 0, screenWidth, panelHeight); + callResult = ilm_surfaceSetVisibility( + gdp_surface.id_surface, ILM_TRUE); + callResult = ilm_surfaceSetOpacity( + gdp_surface.id_surface, 1.0f); + callResult = ilm_commitChanges(); + sd_journal_print(LOG_DEBUG, "surface_control (0) - input focus on\n"); + callResult = ilm_UpdateInputEventAcceptanceOn( + gdp_surface.id_surface, + ILM_INPUT_DEVICE_POINTER | + ILM_INPUT_DEVICE_TOUCH | + ILM_INPUT_DEVICE_KEYBOARD, + ILM_TRUE); + callResult = ilm_SetKeyboardFocusOn(gdp_surface.id_surface); + callResult = ilm_commitChanges(); + sd_journal_print(LOG_DEBUG, "surface_control - render order - layer\n"); + callResult = ilm_layerSetDestinationRectangle(gdp_surface.id_layer, + 0, screenHeight - panelHeight, screenWidth, panelHeight); + callResult = ilm_layerSetRenderOrder(gdp_surface.id_layer, + surfaceIdArray, 1); + callResult = ilm_layerSetVisibility(gdp_surface.id_layer, + ILM_TRUE); + callResult = ilm_commitChanges(); + break; + case GDP_LAUNCHER_SURFACE_ID: // GDP HMI / Launcher + launcher_show(gdp_surface); + break; + case GDP_BACKGROUND_SURFACE_ID: // Background / Logo + // fall-through + case QML_EXAMPLE_SURFACE_ID: // QML Example + // fall-through + case AM_DEMO_SURFACE_ID: // AudioManager PoC/Demo + // fall-through + case BROWSER_POC_SURFACE_ID: // Browser PoC + // fall-through + case FSA_SURFACE_ID: // FSA PoC + // fall-through + case MOCK_NAVIGATION_SURFACE_ID: // EGL Mock Navigation + // fall-through + case INPUT_EVENT_EXAMPLE_SURFACE_ID: // EGL Input Example + callResult = ilm_surfaceSetDestinationRectangle( + gdp_surface.id_surface, 0, 0, screenWidth, screenHeight - panelHeight); + callResult = ilm_surfaceSetVisibility( + gdp_surface.id_surface, ILM_TRUE); + callResult = ilm_surfaceSetOpacity( + gdp_surface.id_surface, 1.0f); + callResult = ilm_commitChanges(); + sd_journal_print(LOG_DEBUG, "surface_control - input focus on\n"); + callResult = ilm_UpdateInputEventAcceptanceOn( + gdp_surface.id_surface, + ILM_INPUT_DEVICE_POINTER | + ILM_INPUT_DEVICE_TOUCH | + ILM_INPUT_DEVICE_KEYBOARD, + ILM_TRUE); + callResult = ilm_SetKeyboardFocusOn(gdp_surface.id_surface); + callResult = ilm_commitChanges(); + + sd_journal_print(LOG_DEBUG, "surface_control - render order - layer\n"); + callResult = ilm_layerSetRenderOrder(gdp_surface.id_layer, + surfaceIdArray, 1); + callResult = ilm_layerSetVisibility(gdp_surface.id_layer, + ILM_TRUE); + callResult = ilm_commitChanges(); + + sd_journal_print(LOG_DEBUG, "surface_control - render order - screen\n"); + callResult = ilm_displaySetRenderOrder((t_ilm_display)screenID, + layerIdArray, 2); + + callResult = ilm_commitChanges(); + break; + default: + sd_journal_print(LOG_DEBUG, + "surface_control - unknown surface.\n"); + return; + break; + } // switch +} + +/** + * \brief retrieve surface ID(s) that appeared + * + * This function will check if, from the list of expected surfaces, any new + * surface has appeared. + * + * \param length The length of the array + * \param pArray Pointer to array of surface IDs + */ +static void surfaces_appear_check(t_ilm_int length, t_ilm_surface* pArray) +{ + if ((length <= 0) && (pArray == NULL)) + return; + + // check for appearance + for (int i = 0; i < length; i++) { + // check out list of expected surface IDs 'gdp_surfaces' + for (int count = 0; + count < sizeof gdp_surfaces / sizeof gdp_surfaces[0]; count++) { + if (pArray[i] == gdp_surfaces[count].id_surface) { + // check if surface is already known + if (ILM_TRUE == gdp_surfaces[count].created) + continue; // inner for-loop + // get to know *new* surface + gdp_surfaces[count].created = ILM_TRUE; + sd_journal_print(LOG_DEBUG, + "Debug: new surface id: %i (for layer: %i)\n", + gdp_surfaces[count].id_surface, + gdp_surfaces[count].id_layer); + surface_control(gdp_surfaces[count]); + } + } // inner for-loop + } // outer for-loop +} + +/** + * \brief retrieve surface ID(s) that disappeared + * + * This function will check if, from the list of expected surfaces, any + * surface has disappeared. + * + * \param length The length of the array + * \param pArray Pointer to array of surface IDs + */ +static void surfaces_disappear_check(t_ilm_int length, t_ilm_surface* pArray) +{ + if ((length <= 0) && (pArray == NULL)) + return; + + // check for disappearance + for (int count = 0; + count < sizeof gdp_surfaces / sizeof gdp_surfaces[0]; count++) { + t_ilm_bool found = ILM_FALSE; + + for (int i = 0; i < length; i++) { + if (pArray[i] == gdp_surfaces[count].id_surface) { + found = ILM_TRUE; + break; // inner for-loop + } + } // inner for-loop + + if ((ILM_FALSE == found) && (ILM_TRUE == gdp_surfaces[count].created)) { + gdp_surfaces[count].created = ILM_FALSE; + sd_journal_print(LOG_DEBUG, + "Debug: surface id: %i disappeared (from layer: %i)\n", + gdp_surfaces[count].id_surface, + gdp_surfaces[count].id_layer); + } + } // outer for-loop +} + +/** + * \brief poll for surface appearance + * + * This function gets all surface IDs and compares them with a previous + * copy to find out if a new surface did appear or an existing vanished. + */ +static gboolean surface_create_poll(gpointer data) +{ + int count = 0; + unsigned int* array = NULL; + ilmErrorTypes callResult = ILM_FAILED; + + // retrieve all surface ID(s) + callResult = ilm_getSurfaceIDs(&count, &array); + if (ILM_SUCCESS != callResult) { + sd_journal_print(LOG_ERR, + "Error: surface_create_poll ilm_getSurfaceIDs - %s.\n", + ILM_ERROR_STRING(callResult)); + } else if (count != surfacesArrayCount) { + unsigned int* oldArray = surfacesArray; + + // new previously unknown surface(s) appeared + + if (surfacesArrayCount < count) { + sd_journal_print(LOG_DEBUG, + "Debug: surface_create_poll surfaces = %i (++)\n", count); + surfaces_appear_check(count, array); + } else if (surfacesArrayCount > count) { + sd_journal_print(LOG_DEBUG, + "Debug: surface_create_poll surfaces = %i (--)\n", count); + surfaces_disappear_check(count, array); + } + + surfacesArray = array; + surfacesArrayCount = count; + array = oldArray; + } + + // free 'array' that had been allocated by ilm_getSurfaceIDs() + if (NULL != array) + free(array); + + return TRUE; +} + +/** + * \brief signal handler + * + * This function shall handle all signals of type 'SIGINT', 'SIGTERM', + * 'SIGUSR1' and 'SIGUSR2'. + * + */ +static void sig_handler(int signo) +{ + sd_journal_print(LOG_DEBUG, "Debug: sig_handler() - %d\n", signo); + + switch(signo) { + case SIGINT: + sd_journal_print(LOG_DEBUG, "Debug: Interrupt from keyboard.\n"); + // fall-through + case SIGTERM: + g_main_loop_quit(gMainLoop); // stop the main loop in main() + break; + case SIGUSR1: + if (ILM_TRUE == gdp_surfaces[1].created) { + launcher_show(gdp_surfaces[1]); + } + sd_journal_print(LOG_DEBUG, "Debug: show launcher (%s)\n", + (ILM_TRUE == gdp_surfaces[1].created) ? "true" : "false"); + break; + case SIGUSR2: + if (ILM_TRUE == gdp_surfaces[2].created) { + surface_control(gdp_surfaces[2]); + } + sd_journal_print(LOG_DEBUG, "Debug: show background\n"); + break; + default: + sd_journal_print(LOG_DEBUG, "Debug: signal (%d) unknown\n", signo); + break; + } // switch +} + +/** + * \brief print help message to stderr + * + * This function does print a help message to stderr explaining the usage + * of the executable \p name. + * + * \param name The name of this executable. + */ +static void help(const char *name) +{ + fprintf(stderr, "Usage: %s [args...]\n", name); + fprintf(stderr, " -s, --surface Use surface with specified ID\n"); + fprintf(stderr, " -v, --verbose Be verbose\n"); + fprintf(stderr, " -h, --help Display this help message\n"); +} + +/** + * \brief main thread + * + * This function is the main entry point of this executable. + * It reads and interprets command line options given by user, + * creates some layers, waits for surfaces to appear and once + * it did, assign the surface to a layer and have it rendered. + */ +int main(int argc, char * const* argv) +{ + int fd = -1; + int rtn = -1; + t_ilm_surface surfaceId = 0; + ilmErrorTypes callResult = ILM_FAILED; + + sd_journal_print(LOG_INFO, "GDP HMI Controller (main)\n"); + + // establish signal handling + if ((void *)-1 == signal(SIGTERM, sig_handler)) { + sd_journal_print(LOG_ERR, "Error: signal(SIGTERM)\n"); + exit(EXIT_FAILURE); + } + if ((void *)-1 == signal(SIGINT, sig_handler)) { + sd_journal_print(LOG_ERR, "Error: signal(SIGINT)\n"); + exit(EXIT_FAILURE); + } + if ((void *)-1 == signal(SIGUSR1, sig_handler)) { + sd_journal_print(LOG_ERR, "Error: signal(SIGUSR1)\n"); + exit(EXIT_FAILURE); + } + if ((void *)-1 == signal(SIGUSR2, sig_handler)) { + sd_journal_print(LOG_ERR, "Error: signal(SIGUSR2)\n"); + exit(EXIT_FAILURE); + } + + // read and interpret command line options + while (1){ + struct option opts[] = { + { "surface", required_argument, NULL, 's' }, + { "verbose", no_argument, NULL, 'v' }, + { "help", no_argument, NULL, 'h' }, + { 0, 0, NULL, 0 } + }; + + int c = getopt_long(argc, argv, "s:vh", opts, NULL); + if (-1 == c) // no more options + break; + + switch(c){ + default: + sd_journal_print(LOG_ERR, + "Error: Unrecognized option '%s'\n", optarg); + break; + case 's': + surfaceId = strtol(optarg, NULL, 0); + break; + case 'v': + verbose = 1; + break; + case 'h': + help("gdp-hmi-controller"); + exit(EXIT_FAILURE); + break; + } + } + + fd = create_pid_file(argv[0], GDP_HMI_PID_FILENAME); + + /* + * make ourselves available on the d-bus session bus + * + * currently this interface is only used by the launcher to tell the + * controller (us), to power off, which application (systemd unit) to + * launch or give focus and bring to front/into view. + * + * The 'home' button activation is signaled via USR1. + */ + + DBus::default_dispatcher = &dispatcher; + dispatcher.attach(NULL); + DBus::Connection conn = DBus::Connection::SessionBus(); + conn.request_name(GDP_DBUS_SERVICE_NAME); + HmiService service(conn); + sd_journal_print(LOG_INFO, "GDP HMI Controller (dbus) - %s\n", + GDP_DBUS_SERVICE_NAME); + // make a connection to systemd on the session bus + DBus::Connection sessionBus = DBus::Connection::SessionBus(); + SystemdService systemdSession(sessionBus, + SYSTEMD_DBUS_SERVICE_PATH, SYSTEMD_DBUS_SERVICE_NAME); + gSystemdSession = &systemdSession; + std::string systemdVersion = systemdSession.Version(); + sd_journal_print(LOG_INFO, "GDP HMI Control -> systemd (session)" + " systemd version: %s\n", systemdVersion.c_str()); + // make a connection to systemd on the system bus + DBus::Connection systemBus = DBus::Connection::SystemBus(); + SystemdService systemd(systemBus, + SYSTEMD_DBUS_SERVICE_PATH, SYSTEMD_DBUS_SERVICE_NAME); + gSystemd = &systemd; + systemdVersion = systemd.Version(); + sd_journal_print(LOG_INFO, "GDP HMI Control -> systemd (system)" + " systemd version: %s\n", systemdVersion.c_str()); + + // initializes the IVI LayerManagement Client + callResult = ilm_init(); + if (ILM_SUCCESS != callResult) { + sd_journal_print(LOG_ERR, + "Error: ilm_init - %s. Exiting.\n", + ILM_ERROR_STRING(callResult)); + exit(EXIT_FAILURE); + } + + // create all the layers needed + layer_create(); + + // fill 'surfacesArray' global with already existing surfaces + callResult = ilm_getSurfaceIDs(&surfacesArrayCount, &surfacesArray); + if (ILM_SUCCESS != callResult) { + sd_journal_print(LOG_ERR, "Error: ilm_getSurfaceIDs - %s.\n", + ILM_ERROR_STRING(callResult)); + } else { + sd_journal_print(LOG_DEBUG, + "Debug: main surfaces = %i\n", surfacesArrayCount); + } + + // go into a loop, poll for surfaces every second + gMainLoop = g_main_loop_new (NULL, FALSE); + g_timeout_add_seconds(1, surface_create_poll, NULL); + g_main_loop_run(gMainLoop); + + // close and delete PID file + if (-1 != fd) + close (fd); + unlink (GDP_HMI_PID_FILENAME); + + // destroy the IVI LayerManagement Client + callResult = ilm_destroy(); + if (ILM_SUCCESS != callResult) { + sd_journal_print(LOG_ERR, + "Error: ilm_destroy - %s. Exiting.\n", + ILM_ERROR_STRING(callResult)); + exit(EXIT_FAILURE); + } + + return EXIT_SUCCESS; +} -- cgit v1.2.1