diff options
Diffstat (limited to 'src/gdp-hmi-controller.cpp')
-rw-r--r-- | src/gdp-hmi-controller.cpp | 705 |
1 files changed, 705 insertions, 0 deletions
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 <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <glib.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <unistd.h> +#include <dbus/dbus.h> +#include <systemd/sd-journal.h> + +#include <ilm/ilm_types.h> +#include <ilm/ilm_client.h> +#include <ilm/ilm_control.h> + +#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; +} |