diff options
author | fukubayashi.akio <fukubayashi.akio@genetec.co.jp> | 2019-06-03 17:59:13 +0900 |
---|---|---|
committer | fukubayashi.akio <fukubayashi.akio@genetec.co.jp> | 2019-06-03 17:59:13 +0900 |
commit | 98006b6538c5be44350746ec3756f004a5c68af8 (patch) | |
tree | f76ed8991d3837678c00722a23b779c4e2dcb67b /src | |
parent | b6644e5cffa84e40d62e38f4ee0c14e64e0faf48 (diff) |
Add boot sequence and multi ecu transfer
Signed-off-by: fukubayashi.akio <fukubayashi.akio@genetec.co.jp>
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 15 | ||||
-rw-r--r-- | src/applist.cpp | 49 | ||||
-rw-r--r-- | src/applist.hpp | 1 | ||||
-rw-r--r-- | src/config/areas.json | 306 | ||||
-rw-r--r-- | src/config/connection.json | 48 | ||||
-rw-r--r-- | src/config/old_roles.json | 68 | ||||
-rw-r--r-- | src/config/timeout.json | 4 | ||||
-rw-r--r-- | src/config/weston.json | 4 | ||||
-rw-r--r-- | src/json_helper.cpp | 12 | ||||
-rw-r--r-- | src/json_helper.hpp | 2 | ||||
-rw-r--r-- | src/low_can_client.cpp | 187 | ||||
-rw-r--r-- | src/low_can_client.hpp | 113 | ||||
-rw-r--r-- | src/main.cpp | 375 | ||||
-rw-r--r-- | src/pm_wrapper.cpp | 193 | ||||
-rw-r--r-- | src/pm_wrapper.hpp | 3 | ||||
-rw-r--r-- | src/request.cpp | 9 | ||||
-rw-r--r-- | src/request.hpp | 35 | ||||
-rw-r--r-- | src/util.cpp | 55 | ||||
-rw-r--r-- | src/util.hpp | 12 | ||||
-rw-r--r-- | src/window_manager.cpp | 1860 | ||||
-rw-r--r-- | src/window_manager.hpp | 131 | ||||
-rw-r--r-- | src/wm_client.cpp | 255 | ||||
-rw-r--r-- | src/wm_client.hpp | 45 | ||||
-rw-r--r-- | src/wm_connection.cpp | 845 | ||||
-rw-r--r-- | src/wm_connection.hpp | 117 | ||||
-rw-r--r-- | src/wm_layer.cpp | 14 | ||||
-rw-r--r-- | src/wm_layer.hpp | 4 | ||||
-rw-r--r-- | src/wm_layer_control.cpp | 448 | ||||
-rw-r--r-- | src/wm_layer_control.hpp | 38 |
29 files changed, 4655 insertions, 593 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fc19a18..093b356 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -35,7 +35,9 @@ add_library(${TARGETS_WM} MODULE wm_client.cpp wm_error.cpp wm_layer.cpp - wm_layer_control.cpp) + wm_layer_control.cpp + wm_connection.cpp + low_can_client.cpp) target_include_directories(${TARGETS_WM} PRIVATE @@ -56,7 +58,7 @@ target_link_libraries(${TARGETS_WM} target_compile_definitions(${TARGETS_WM} PRIVATE - AFB_BINDING_VERSION=3 + AFB_BINDING_VERSION=2 # We do not want source location of messages AFB_BINDING_PRAGMA_NO_VERBOSE_DETAILS WINMAN_VERSION_STRING="${PACKAGE_VERSION}" @@ -70,7 +72,7 @@ endif() target_compile_options(${TARGETS_WM} PRIVATE - -Wall -Wextra -Wno-unused-parameter -Wno-comment -Wno-missing-field-initializers) + -Wall -Wextra -Wno-unused-parameter -Wno-comment) set_target_properties(${TARGETS_WM} PROPERTIES @@ -111,8 +113,11 @@ add_custom_command(TARGET ${TARGETS_WM} POST_BUILD COMMAND mkdir -p ${PROJECT_BINARY_DIR}/package/root/lib COMMAND cp -rf ${PROJECT_BINARY_DIR}/src/${TARGETS_WM}.so ${PROJECT_BINARY_DIR}/package/root/lib COMMAND mkdir -p ${PROJECT_BINARY_DIR}/package/root/etc - COMMAND cp -f ${CMAKE_SOURCE_DIR}/conf/layers.json ${PROJECT_BINARY_DIR}/package/root/etc - COMMAND cp -f ${CMAKE_SOURCE_DIR}/conf/areas.json ${PROJECT_BINARY_DIR}/package/root/etc + COMMAND cp -f ${PROJECT_SOURCE_DIR}/layers.json ${PROJECT_BINARY_DIR}/package/root/etc + COMMAND cp -f ${PROJECT_SOURCE_DIR}/src/config/old_roles.json ${PROJECT_BINARY_DIR}/package/root/etc + COMMAND cp -f ${PROJECT_SOURCE_DIR}/src/config/areas.json ${PROJECT_BINARY_DIR}/package/root/etc + COMMAND cp -f ${PROJECT_SOURCE_DIR}/src/config/connection.json ${PROJECT_BINARY_DIR}/package/root/etc + COMMAND cp -f ${PROJECT_SOURCE_DIR}/src/config/timeout.json ${PROJECT_BINARY_DIR}/package/root/etc ) add_custom_target(package DEPENDS ${PROJECT_BINARY_DIR}/package/root diff --git a/src/applist.cpp b/src/applist.cpp index 473d687..8ef08dd 100644 --- a/src/applist.cpp +++ b/src/applist.cpp @@ -82,27 +82,6 @@ void AppList::addClient(const string &appid, unsigned layer, const string &role) } /** - * Add Client to the list - * - * This function is overload function. - * But this function just register application. - * So an application does not have role, surface, layer. - * Client need to register role and layer afterward. - * - * @param string[in] Application id. This will be the key to withdraw the information. - * @return None - * @attention This function should be called once for the app - * Caller should take care not to be called more than once. - */ -void AppList::addClient(const string &appid) -{ - std::lock_guard<std::mutex> lock(this->mtx); - shared_ptr<WMClient> client = std::make_shared<WMClient>(appid, 0, ""); - this->app2client[appid] = client; - this->clientDump(); -} - -/** * Remove WMClient from the list * * @param string[in] Application id. This will be the key to withdraw the information. @@ -332,8 +311,8 @@ const vector<struct WMAction> &AppList::getActions(unsigned req_num, bool* found } HMI_SEQ_ERROR(req_num, "Couldn't get action with the request : %d", req_num); { - static vector<struct WMAction> empty; - return empty; + static vector<struct WMAction> empty; + return empty; } } @@ -402,7 +381,7 @@ WMError AppList::setAction(unsigned req_num, shared_ptr<WMClient> client, const } // If visible task is not invisible, redraw is required -> true bool edraw_f = (visible != TaskVisible::INVISIBLE) ? false : true; - WMAction action{req_num, client, role, area, visible, edraw_f}; + WMAction action{req_num, client, role, area, visible, edraw_f, TaskCarState::NO_TASK}; x.sync_draw_req.push_back(action); result = WMError::SUCCESS; @@ -438,11 +417,23 @@ bool AppList::setEndDrawFinished(unsigned req_num, const string &appid, const st { for (auto &y : x.sync_draw_req) { - if (y.client->appID() == appid && y.role == role) + if (nullptr != y.client) + { + if (y.client->appID() == appid && y.role == role) + { + HMI_SEQ_INFO(req_num, "Role %s finish redraw", y.role.c_str()); + y.end_draw_finished = true; + result = true; + } + } + else { - HMI_SEQ_INFO(req_num, "Role %s finish redraw", y.role.c_str()); - y.end_draw_finished = true; - result = true; + if (y.role == role) + { + HMI_SEQ_INFO(req_num, "Role %s finish redraw", y.role.c_str()); + y.end_draw_finished = true; + result = true; + } } } } @@ -553,7 +544,7 @@ void AppList::reqDump() { DUMP( "Action : (APPID :%s, ROLE :%s, AREA :%s, VISIBLE : %s, END_DRAW_FINISHED: %d)", - y.client->appID().c_str(), + (y.client) ? y.client->appID().c_str() : "-", y.role.c_str(), y.area.c_str(), (y.visible == TaskVisible::INVISIBLE) ? "invisible" : "visible", diff --git a/src/applist.hpp b/src/applist.hpp index 0fe3bbd..085504a 100644 --- a/src/applist.hpp +++ b/src/applist.hpp @@ -45,7 +45,6 @@ class AppList void addClient(const std::string &appid, unsigned layer, unsigned surface, const std::string &role); void addClient(const std::string &appid, unsigned layer, const std::string &role); - void addClient(const std::string &appid); void removeClient(const std::string &appid); bool contains(const std::string &appid) const; int countClient() const; diff --git a/src/config/areas.json b/src/config/areas.json new file mode 100644 index 0000000..cd54725 --- /dev/null +++ b/src/config/areas.json @@ -0,0 +1,306 @@ +{ + "ecus": [ + { + "name": "master", + "screens": [ + { + "id": 0, + "areas": [ + { + "name": "fullscreen", + "rect": { + "x": 0, + "y": 0, + "w": 1920, + "h": 1080 + } + }, + { + "name": "normal.full", + "rect": { + "x": 0, + "y": 180, + "w": 1920, + "h": 720 + } + }, + { + "name": "split.main", + "rect": { + "x": 0, + "y": 180, + "w": 1280, + "h": 720 + } + }, + { + "name": "split.sub", + "rect": { + "x": 1280, + "y": 180, + "w": 640, + "h": 720 + } + }, + { + "name": "software_keyboard", + "rect": { + "x": 0, + "y": 962, + "w": 1080, + "h": 744 + } + }, + { + "name": "restriction.normal", + "rect": { + "x": 0, + "y": 0, + "w": 1920, + "h": 1080 + } + }, + { + "name": "restriction.split.main", + "rect": { + "x": 0, + "y": 0, + "w": 1920, + "h": 540 + } + }, + { + "name": "restriction.split.sub", + "rect": { + "x": 0, + "y": 540, + "w": 1920, + "h": 540 + } + }, + { + "name": "on_screen", + "rect": { + "x": 1280, + "y": 0, + "w": 640, + "h": 720 + } + }, + { + "name": "master.split.sub", + "rect": { + "x": 1280, + "y": 0, + "w": 640, + "h": 720 + } + }, + { + "name": "hud.upper.left", + "rect": { + "x": 0, + "y": 0, + "w": 480, + "h": 180 + } + } + ] + } + ] + }, + { + "name": "slave", + "screens": [ + { + "id": 0, + "areas": [ + { + "name": "fullscreen", + "rect": { + "x": 0, + "y": 0, + "w": 1080, + "h": 1920 + } + }, + { + "name": "normal.full", + "rect": { + "x": 0, + "y": 218, + "w": 1080, + "h": 1488 + } + }, + { + "name": "split.main", + "rect": { + "x": 0, + "y": 218, + "w": 1080, + "h": 744 + } + }, + { + "name": "split.sub", + "rect": { + "x": 0, + "y": 962, + "w": 1080, + "h": 744 + } + }, + { + "name": "software_keyboard", + "rect": { + "x": 0, + "y": 962, + "w": 1080, + "h": 744 + } + }, + { + "name": "restriction.normal", + "rect": { + "x": 0, + "y": 218, + "w": 1080, + "h": 1488 + } + }, + { + "name": "restriction.split.main", + "rect": { + "x": 0, + "y": 218, + "w": 1080, + "h": 744 + } + }, + { + "name": "restriction.split.sub", + "rect": { + "x": 0, + "y": 962, + "w": 1080, + "h": 744 + } + }, + { + "name": "on_screen", + "rect": { + "x": 0, + "y": 218, + "w": 1080, + "h": 1488 + } + }, + { + "name": "master.split.sub", + "rect": { + "x": 0, + "y": 180, + "w": 640, + "h": 720 + } + }, + { + "name": "rse1.normal.full", + "rect": { + "x": 0, + "y": 0, + "w": 1920, + "h": 720 + } + }, + { + "name": "rse2.normal.full", + "rect": { + "x": 0, + "y": 0, + "w": 1920, + "h": 720 + } + }, + { + "name": "hud.normal.full", + "rect": { + "x": 0, + "y": 0, + "w": 1920, + "h": 720 + } + } + ] + } + ] + }, + { + "name": "rse1", + "screens": [ + { + "id": 0, + "areas": [ + { + "name": "rse1.normal.full", + "rect": { + "x": 0, + "y": 0, + "w": 1920, + "h": 720 + } + } + ] + } + ] + }, + { + "name": "rse2", + "screens": [ + { + "id": 0, + "areas": [ + { + "name": "rse2.normal.full", + "rect": { + "x": 0, + "y": 0, + "w": 1920, + "h": 720 + } + } + ] + } + ] + }, + { + "name": "hud", + "screens": [ + { + "id": 0, + "areas": [ + { + "name": "hud.normal.full", + "rect": { + "x": 0, + "y": 0, + "w": 1920, + "h": 720 + } + }, + { + "name": "hud.upper.left", + "rect": { + "x": 0, + "y": 0, + "w": 480, + "h": 180 + } + } + ] + } + ] + }, + ] +} diff --git a/src/config/connection.json b/src/config/connection.json new file mode 100644 index 0000000..18dc7ad --- /dev/null +++ b/src/config/connection.json @@ -0,0 +1,48 @@ +{ + "screen_name": "master", + "wm_port": 54400, + "areas": [ + { + "area_name": "fullscreen", + "transmitter_port": 54401, + "width": 1920, + "height": 1080 + } + ], + "connections": [ + { + "screen_name": "slave", + "ip": "192.168.200.101", + "wm_port": 54410, + "master_mode": false, + "areas": [ + { + "area_name": "split.sub", + "transmitter_port": 54411, + "width": 640, + "height": 720 + } + ] + }, + { + "screen_name": "hud", + "ip": "192.168.200.102", + "wm_port": 54420, + "master_mode": false, + "areas": [ + { + "area_name": "fullscreen", + "transmitter_port": 54421, + "width": 1920, + "height": 1080 + }, + { + "area_name": "leftup", + "transmitter_port": 54422, + "width": 640, + "height": 720 + } + ] + } + ] +} diff --git a/src/config/old_roles.json b/src/config/old_roles.json new file mode 100644 index 0000000..02a4c2d --- /dev/null +++ b/src/config/old_roles.json @@ -0,0 +1,68 @@ +{ + "old_roles": [ + { + "name": "HomeScreen", + "new": "homescreen" + }, + { + "name": "Music", + "new": "music" + }, + { + "name": "MediaPlayer", + "new": "music" + }, + { + "name": "Video", + "new": "video" + }, + { + "name": "VideoPlayer", + "new": "video" + }, + { + "name": "WebBrowser", + "new": "browser" + }, + { + "name": "Radio", + "new": "radio" + }, + { + "name": "Phone", + "new": "phone" + }, + { + "name": "Navigation", + "new": "map" + }, + { + "name": "HVAC", + "new": "hvac" + }, + { + "name": "Settings", + "new": "settings" + }, + { + "name": "Dashboard", + "new": "dashboard" + }, + { + "name": "POI", + "new": "poi" + }, + { + "name": "Mixer", + "new": "mixer" + }, + { + "name": "Restriction", + "new": "restriction" + }, + { + "name": "^OnScreen.*", + "new": "on_screen" + } + ] +} diff --git a/src/config/timeout.json b/src/config/timeout.json new file mode 100644 index 0000000..a3e4419 --- /dev/null +++ b/src/config/timeout.json @@ -0,0 +1,4 @@ +{ + "times": 60000, + "sleep": 50 +} diff --git a/src/config/weston.json b/src/config/weston.json new file mode 100644 index 0000000..44e379c --- /dev/null +++ b/src/config/weston.json @@ -0,0 +1,4 @@ +{ + "times": 60000, + "sleep": 50 +} diff --git a/src/json_helper.cpp b/src/json_helper.cpp index 72ae36a..d9cf5eb 100644 --- a/src/json_helper.cpp +++ b/src/json_helper.cpp @@ -69,6 +69,18 @@ int getIntFromJson(json_object *obj, const char *key) return json_object_get_int(tmp); } +double getDoubleFromJson(json_object *obj, const char *key) +{ + json_object *tmp; + if (!json_object_object_get_ex(obj, key, &tmp)) + { + HMI_DEBUG("Not found key \"%s\"", key); + return 0; + } + + return json_object_get_double(tmp); +} + json_bool getBoolFromJson(json_object *obj, const char *key) { json_object *tmp; diff --git a/src/json_helper.hpp b/src/json_helper.hpp index 6ccbcc1..d4ae85a 100644 --- a/src/json_helper.hpp +++ b/src/json_helper.hpp @@ -21,12 +21,12 @@ #include <vector> struct json_object; - json_object *to_json(std::vector<uint32_t> const &v); namespace jh { const char* getStringFromJson(json_object* obj, const char* key); int getIntFromJson(json_object *obj, const char *key); +double getDoubleFromJson(json_object *obj, const char *key); json_bool getBoolFromJson(json_object *obj, const char *key); int inputJsonFilie(const char* file, json_object** obj); } // namespace jh diff --git a/src/low_can_client.cpp b/src/low_can_client.cpp new file mode 100644 index 0000000..090aa14 --- /dev/null +++ b/src/low_can_client.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2018 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "low_can_client.hpp" +#include "json_helper.hpp" +#include "util.hpp" + +extern "C" +{ +#include <afb/afb-binding.h> +} + +namespace wm +{ + +LowCanClient::LowCanClient() + : vehicle_speed(0), + trans_gear_pos(0), + headlamp_status(FALSE), + parking_brake_status(TRUE), + accel_pedal_pos(0), + accel_pedal_stt(FALSE), + lightstatus_brake_status(TRUE), + is_changed_accel_pedal_stt(false) +{ +} + +void LowCanClient::initialize() +{ + int ret; + + // Require API "low-can" + ret = afb_daemon_require_api_v2("low-can", 1); + if (0 > ret) + { + HMI_INFO("Requirement API \"low-can\" failed"); + return; + } + + // Subscribe low-level-can + // low-can subscribe { "event": "vehicle.speed" } + // low-can subscribe { "event": "transmission_gear_position" } + // low-can subscribe { "event": "headlamp_status" } + // low-can subscribe { "event": "parking_brake_status" } + // low-can subscribe { "event": "accelerator.pedal.position" } + // low-can subscribe { "event": "lightstatus.brake" } + for (int i = SignalNoMin; i <= SignalNoMax; i++) + { + // Set Event + json_object *json_obj = json_object_new_object(); + json_object_object_add(json_obj, "event", + json_object_new_string(this->kSignalName[i])); + + // Set filter + if (0 != strcmp("", this->kFilterValue[i])) + { + json_object_object_add(json_obj, "filter", + json_tokener_parse(this->kFilterValue[i])); + } + HMI_DEBUG("subscribe message:%s", json_object_get_string(json_obj)); + + // Subscribe + afb_service_call("low-can", "subscribe", json_obj, + [](void *closure, int status, json_object *result) { + HMI_DEBUG("subscribe result:%s", json_object_get_string(result)); + }, + nullptr); + } + + return; +} + +const char *LowCanClient::analyzeCanSignal(struct json_object *object) +{ + HMI_DEBUG("object:%s", json_object_get_string(object)); + + const char *name = jh::getStringFromJson(object, "name"); + HMI_DEBUG("CAN signal name:%s", name); + + if (strstr(name, this->kSignalName[SignalNoVehicliSpeed])) + { + // Update vehicle speed + this->vehicle_speed = jh::getIntFromJson(object, "value"); + HMI_DEBUG("Update vehicle speed:%d", this->vehicle_speed); + } + else if (strstr(name, this->kSignalName[SignalNoTransGearPos])) + { + // Update transmission gear position + this->trans_gear_pos = jh::getIntFromJson(object, "value"); + HMI_DEBUG("Update transmission gear position:%d", this->trans_gear_pos); + } + else if (strstr(name, this->kSignalName[SignalNoHeadlame])) + { + // Update headlamp status + this->headlamp_status = jh::getBoolFromJson(object, "value"); + HMI_DEBUG("Update headlamp status:%d", this->headlamp_status); + } + else if (strstr(name, this->kSignalName[SignalNoParkingBrake])) + { + // Update parking gear status + this->parking_brake_status = jh::getBoolFromJson(object, "value"); + HMI_DEBUG("Update parking brake status:%d", this->parking_brake_status); + } + else if (strstr(name, this->kSignalName[SignalNoAccelPedalPos])) + { + // Clear flag for whether accel pedal state is changed + this->is_changed_accel_pedal_stt = false; + + // Update accelerator pedal status + this->accel_pedal_pos = jh::getDoubleFromJson(object, "value"); + HMI_DEBUG("Update accelerator pedal position:%lf", this->accel_pedal_pos); + + bool accel_pedal_stt; + if (0 != this->accel_pedal_pos) + { + accel_pedal_stt = true; + } + else + { + accel_pedal_stt = false; + } + + if (accel_pedal_stt != this->accel_pedal_stt) + { + this->is_changed_accel_pedal_stt = true; + this->accel_pedal_stt = accel_pedal_stt; + } + } + else if (strstr(name, this->kSignalName[SignalNoLightstatusBrake])) + { + // Update lightstatus brake status + this->lightstatus_brake_status = jh::getBoolFromJson(object, "value"); + HMI_DEBUG("Update lightstatus brake status:%d", this->lightstatus_brake_status); + } + + return name; +} + +bool LowCanClient::isChangedAccelPedalState() +{ + return this->is_changed_accel_pedal_stt; +} + +int LowCanClient::getCurrentTransGearState() +{ + return this->trans_gear_pos; +} + +bool LowCanClient::getCurrentHeadlampState() +{ + return (bool)this->headlamp_status; +} + +bool LowCanClient::getCurrentParkingBrakeState() +{ + return (bool)this->parking_brake_status; +} + +double LowCanClient::getCurrentAccelPedalPosition() +{ + return this->accel_pedal_pos; +} + +bool LowCanClient::getCurrentAccelPedalState() +{ + return this->accel_pedal_stt; +} + +bool LowCanClient::getCurrentLightstatusBrakeState() +{ + return (bool)this->lightstatus_brake_status; +} + +} // namespace wm diff --git a/src/low_can_client.hpp b/src/low_can_client.hpp new file mode 100644 index 0000000..9b7f509 --- /dev/null +++ b/src/low_can_client.hpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2017 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TMCAGLWM_LOW_CAN_CLIENT_HPP +#define TMCAGLWM_LOW_CAN_CLIENT_HPP + +#include <string> +#include <vector> +#include <json-c/json.h> + +namespace wm +{ + +class LowCanClient +{ + + public: + explicit LowCanClient(); + ~LowCanClient() = default; + + enum SignalNo + { + SignalNoVehicliSpeed = 0, + SignalNoTransGearPos, + SignalNoHeadlame, + SignalNoParkingBrake, + SignalNoAccelPedalPos, + SignalNoLightstatusBrake, + + SignalNum, + + SignalNoMin = SignalNoVehicliSpeed, + SignalNoMax = SignalNum - 1, + }; + + const std::vector<const char *> kSignalName{ + "vehicle.speed", + "transmission_gear_position", + "headlamp_status", + "parking_brake_status", + "accelerator.pedal.position", + "lightstatus.brake", + }; + + void initialize(); + const char *analyzeCanSignal(struct json_object *object); + + int getCurrentTransGearState(); + bool getCurrentHeadlampState(); + bool getCurrentParkingBrakeState(); + double getCurrentAccelPedalPosition(); + bool getCurrentAccelPedalState(); + bool getCurrentLightstatusBrakeState(); + + bool isChangedAccelPedalState(); + + private: + // Disable copy and move + LowCanClient(LowCanClient const &) = delete; + LowCanClient &operator=(LowCanClient const &) = delete; + LowCanClient(LowCanClient &&) = delete; + LowCanClient &operator=(LowCanClient &&) = delete; + + enum TransGearPosVal + { + TransGearPosValD1 = 1, + TransGearPosValD2, + TransGearPosValD3, + TransGearPosValD4, + TransGearPosValD5, + TransGearPosValD6, + TransGearPosValD7, + TransGearPosValD8, + TransGearPosValR, + TransGearPosValN, + }; + + const std::vector<const char *> kFilterValue{ + "", // vehicle.speed + "", // transmission_gear_position + "", // headlamp_status + "", // parking_brake_status + "", // accelerator.pedal.position + "", // lightstatus.brake + }; + + int vehicle_speed; + int trans_gear_pos; + json_bool headlamp_status; + json_bool parking_brake_status; + double accel_pedal_pos; + bool accel_pedal_stt; + json_bool lightstatus_brake_status; + + bool is_changed_accel_pedal_stt; +}; + +} // namespace wm + +#endif // TMCAGLWM_LOW_CAN_CLIENT_HPP diff --git a/src/main.cpp b/src/main.cpp index 6483655..6fff161 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,6 +18,9 @@ #include <algorithm> #include <mutex> #include <json.h> +#include <stdlib.h> +#include <vector> +#include "util.hpp" #include "window_manager.hpp" #include "json_helper.hpp" @@ -56,7 +59,7 @@ int afb_instance::init() return this->wmgr.init(); } -static int _binding_init() +int _binding_init() { HMI_NOTICE("WinMan ver. %s", WINMAN_VERSION_STRING); @@ -78,7 +81,7 @@ error: return -1; } -static int binding_init (afb_api_t api) noexcept +int binding_init() noexcept { try { @@ -110,20 +113,21 @@ static void cbRemoveClientCtxt(void *data) delete ctxt; } -static void createSecurityContext(afb_req_t req, const char* appid, const char* role) +static void createSecurityContext(afb_req req, const char* appid, const char* role) { WMClientCtxt *ctxt = (WMClientCtxt *)afb_req_context_get(req); if (!ctxt) { // Create Security Context at first time - WMClientCtxt *ctxt = new WMClientCtxt(appid, role); + const char *new_role = g_afb_instance->wmgr.convertRoleOldToNew(role); + WMClientCtxt *ctxt = new WMClientCtxt(appid, new_role); HMI_DEBUG("create session for %s", ctxt->name.c_str()); afb_req_session_set_LOA(req, 1); afb_req_context_set(req, ctxt, cbRemoveClientCtxt); } } -void windowmanager_requestsurface(afb_req_t req) noexcept +void windowmanager_requestsurface(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); if (g_afb_instance == nullptr) @@ -169,7 +173,7 @@ void windowmanager_requestsurface(afb_req_t req) noexcept } } -void windowmanager_requestsurfacexdg(afb_req_t req) noexcept +void windowmanager_requestsurfacexdg(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); if (g_afb_instance == nullptr) @@ -222,7 +226,50 @@ void windowmanager_requestsurfacexdg(afb_req_t req) noexcept } } -void windowmanager_activatewindow(afb_req_t req) noexcept +void windowmanager_setrole(afb_req req) noexcept +{ + std::lock_guard<std::mutex> guard(binding_m); + if (g_afb_instance == nullptr) + { + afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); + return; + } + try + { + json_object *jreq = afb_req_json(req); + + json_object *j_role = nullptr; + if (!json_object_object_get_ex(jreq, "role", &j_role)) + { + afb_req_fail(req, "failed", "Need char const* argument role"); + return; + } + char const *a_role = json_object_get_string(j_role); + char *appid = afb_req_get_application_id(req); + + if(appid) + { + auto ret = g_afb_instance->wmgr.api_set_role(appid, a_role); + if (!ret) + { + afb_req_fail(req, "failed", "Couldn't register"); + } + else + { + createSecurityContext(req, appid, a_role); + afb_req_success(req, NULL, "success"); + } + free(appid); + } + } + catch (std::exception &e) + { + afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what()); + return; + } +} + +void windowmanager_activatewindow(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); if (g_afb_instance == nullptr) @@ -250,17 +297,40 @@ void windowmanager_activatewindow(afb_req_t req) noexcept char* appid = afb_req_get_application_id(req); if(appid) { - g_afb_instance->wmgr.api_activate_window( - appid, a_drawing_name, a_drawing_area, - [&req](const char *errmsg) { - if (errmsg != nullptr) - { - HMI_ERROR(errmsg); - afb_req_fail(req, "failed", errmsg); - return; - } - afb_req_success(req, NULL, "success"); - }); + auto reply = [&req](const char *errmsg) { + if (errmsg != nullptr) + { + HMI_ERROR(errmsg); + afb_req_fail(req, "failed", errmsg); + return; + } + afb_req_success(req, NULL, "success"); + }; + + if (!g_afb_instance->wmgr.wmcon.isRemoteArea(a_drawing_area)) + { + g_afb_instance->wmgr.api_activate_window( + appid, a_drawing_name, a_drawing_area, reply); + } + else + { + std::string ecu_name; + ecu_name = g_afb_instance->wmgr.wmcon.getAreaToEcuName(a_drawing_area); + + // TODO: temporarily + if (!g_afb_instance->wmgr.wmcon.isConnectionMode()) + { + HMI_ERROR("WM Standalone Mode"); + afb_req_fail(req, "failed", "Standalone Mode"); + } + else + { + // If Window Manager is slave and this request is for master, + // request activateWindow to master + g_afb_instance->wmgr.api_activate_surface_to_master( + appid, a_drawing_name, a_drawing_area, reply); + } + } free(appid); } } @@ -272,7 +342,7 @@ void windowmanager_activatewindow(afb_req_t req) noexcept } } -void windowmanager_deactivatewindow(afb_req_t req) noexcept +void windowmanager_deactivatewindow(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); if (g_afb_instance == nullptr) @@ -293,17 +363,30 @@ void windowmanager_deactivatewindow(afb_req_t req) noexcept char* appid = afb_req_get_application_id(req); if(appid) { - g_afb_instance->wmgr.api_deactivate_window( - appid, a_drawing_name, - [&req](const char *errmsg) { - if (errmsg != nullptr) - { - HMI_ERROR(errmsg); - afb_req_fail(req, "failed", errmsg); - return; - } - afb_req_success(req, NULL, "success"); - }); + auto reply = [&req](const char *errmsg) { + if (errmsg != nullptr) + { + HMI_ERROR(errmsg); + afb_req_fail(req, "failed", errmsg); + return; + } + afb_req_success(req, NULL, "success"); + }; + + // TODO: Check whether role is tbtnavi to request remote invisible + if (g_afb_instance->wmgr.wmcon.getAppIdToEcuName(appid) == "" || + ("tbtnavi" != std::string(a_drawing_name))) + { + g_afb_instance->wmgr.api_deactivate_window( + appid, a_drawing_name, reply); + } + else + { + // If Window Manager is slave and this request is for master, + // request deactivateWindow to master + g_afb_instance->wmgr.api_deactivate_surface_to_master( + appid, a_drawing_name, reply); + } free(appid); } } @@ -315,7 +398,7 @@ void windowmanager_deactivatewindow(afb_req_t req) noexcept } } -void windowmanager_enddraw(afb_req_t req) noexcept +void windowmanager_enddraw(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); if (g_afb_instance == nullptr) @@ -337,8 +420,18 @@ void windowmanager_enddraw(afb_req_t req) noexcept char* appid = afb_req_get_application_id(req); if(appid) { - g_afb_instance->wmgr.api_enddraw(appid, a_drawing_name); - free(appid); + if (g_afb_instance->wmgr.wmcon.getAppIdToEcuName(appid) == "" || + !g_afb_instance->wmgr.wmcon.isSyncDrawingForRemote(appid)) + { + g_afb_instance->wmgr.api_enddraw(appid, a_drawing_name); + } + else + { + // If Window Manager is slave and requesting app is syncDrawing, + // request endDraw to master + g_afb_instance->wmgr.api_enddraw_for_remote(appid, a_drawing_name); + } + free(appid); } } catch (std::exception &e) @@ -349,7 +442,7 @@ void windowmanager_enddraw(afb_req_t req) noexcept } } -void windowmanager_getdisplayinfo_thunk(afb_req_t req) noexcept +void windowmanager_getdisplayinfo_thunk(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); if (g_afb_instance == nullptr) @@ -376,7 +469,7 @@ void windowmanager_getdisplayinfo_thunk(afb_req_t req) noexcept } } -void windowmanager_getareainfo_thunk(afb_req_t req) noexcept +void windowmanager_getareainfo_thunk(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); if (g_afb_instance == nullptr) @@ -413,14 +506,132 @@ void windowmanager_getareainfo_thunk(afb_req_t req) noexcept } } -void windowmanager_get_area_list(afb_req_t req) noexcept +void windowmanager_getcarinfo_thunk(afb_req req) noexcept +{ + std::lock_guard<std::mutex> guard(binding_m); + if (g_afb_instance == nullptr) + { + afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); + return; + } + + try + { + json_object *jreq = afb_req_json(req); + + json_object *j_label = nullptr; + if (! json_object_object_get_ex(jreq, "label", &j_label)) + { + afb_req_fail(req, "failed", "Need char const* argument label"); + return; + } + char const* a_label = json_object_get_string(j_label); + + auto ret = g_afb_instance->wmgr.api_get_car_info(a_label); + if (ret.is_err()) + { + afb_req_fail(req, "failed", ret.unwrap_err()); + return; + } + + afb_req_success(req, ret.unwrap(), "success"); + } + catch (std::exception &e) + { + afb_req_fail_f(req, "failed", "Uncaught exception while calling getcarinfo: %s", e.what()); + return; + } +} + +void windowmanager_set_render_order(afb_req req) noexcept +{ + std::lock_guard<std::mutex> guard(binding_m); + if (g_afb_instance == nullptr) + { + afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); + return; + } + + char* appid = afb_req_get_application_id(req); + if(appid) + { + json_object *jreq = afb_req_json(req); + json_object *j_ro; // Do not free this. binder frees jreq, then free j_ro + if (json_object_object_get_ex(jreq, "render_order", &j_ro)) + { + int size = json_object_array_length(j_ro); + std::vector<std::string> ro(size); + for(int i = 0; i < size; i++) + { + ro[i] = json_object_get_string(json_object_array_get_idx(j_ro, i)); + } + + auto ret = g_afb_instance->wmgr.api_client_set_render_order(appid, ro); + if (!ret) + { + afb_req_fail(req, "failed", nullptr); + } + else + { + afb_req_success(req, nullptr, nullptr); + } + } + free(appid); + } + else + { + afb_req_fail(req, "failed", nullptr); + } +} + +void windowmanager_attach_app(afb_req req) noexcept +{ + std::lock_guard<std::mutex> guard(binding_m); + if (g_afb_instance == nullptr) + { + afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); + return; + } + + char* appid = afb_req_get_application_id(req); + if(appid) + { + json_object *jreq = afb_req_json(req); + json_object *j_dest, *j_id; // Do not free this. binder frees jreq, then free j_ro + if (json_object_object_get_ex(jreq, "destination", &j_dest) && + json_object_object_get_ex(jreq, "service_surface", &j_id)) + { + const char* dest_app = json_object_get_string(j_dest); + const char* service = json_object_get_string(j_id); + + std::string uuid = g_afb_instance->wmgr.api_client_attach_service_surface(appid, dest_app, service); + if (uuid.empty()) + { + afb_req_fail(req, "failed", nullptr); + } + else + { + json_object *resp = json_object_new_object(); + json_object_object_add(resp, "uuid", json_object_new_string(uuid.c_str())); + afb_req_success(req, resp, nullptr); + } + } + free(appid); + } + else + { + afb_req_fail(req, "failed", nullptr); + } +} + +void windowmanager_get_area_list(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); json_object* ret = g_afb_instance->wmgr.api_get_area_list(); afb_req_success(req, ret, nullptr); } -void windowmanager_change_area_size(afb_req_t req) noexcept +void windowmanager_change_area_size(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); if (g_afb_instance == nullptr) @@ -480,7 +691,7 @@ void windowmanager_change_area_size(afb_req_t req) noexcept } } -void windowmanager_wm_subscribe(afb_req_t req) noexcept +void windowmanager_wm_subscribe(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); if (g_afb_instance == nullptr) @@ -498,15 +709,20 @@ void windowmanager_wm_subscribe(afb_req_t req) noexcept afb_req_fail(req, "failed", "Need char const* argument event"); return; } - wm::WindowManager::EventType event_id = (wm::WindowManager::EventType)json_object_get_int(j); - bool ret = g_afb_instance->wmgr.api_subscribe(req, event_id); + int event_id = json_object_get_int(j); + int ret = g_afb_instance->wmgr.api_subscribe(req, event_id); - if (!ret) + if (ret) { afb_req_fail(req, "failed", "Error: afb_req_subscribe()"); return; } afb_req_success(req, NULL, "success"); + + if (event_id == g_afb_instance->wmgr.Event_Handshake) + { + g_afb_instance->wmgr.api_handshake(); + } } catch (std::exception &e) { @@ -515,7 +731,24 @@ void windowmanager_wm_subscribe(afb_req_t req) noexcept } } -void windowmanager_ping(afb_req_t req) noexcept +void windowmanager_connect(afb_req req) noexcept +{ + std::lock_guard<std::mutex> guard(binding_m); + + HMI_DEBUG("WM - HS Connect"); + + if (g_afb_instance == nullptr) + { + afb_req_fail(req, "Failed", "Not Start WindowManager"); + return; + } + else + { + afb_req_success(req, NULL, "success"); + } +} + +void windowmanager_ping(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); @@ -530,7 +763,7 @@ void windowmanager_ping(afb_req_t req) noexcept } } -void windowmanager_debug_terminate(afb_req_t req) noexcept +void windowmanager_debug_terminate(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); if (g_afb_instance == nullptr) @@ -557,32 +790,30 @@ void windowmanager_debug_terminate(afb_req_t req) noexcept } } -const afb_verb_t windowmanager_verbs[] = { - { .verb = "requestSurface", .callback = windowmanager_requestsurface }, - { .verb = "requestSurfaceXDG", .callback = windowmanager_requestsurfacexdg }, - { .verb = "activateWindow", .callback = windowmanager_activatewindow }, - { .verb = "deactivateWindow", .callback = windowmanager_deactivatewindow }, - { .verb = "endDraw", .callback = windowmanager_enddraw }, - { .verb = "getDisplayInfo", .callback = windowmanager_getdisplayinfo_thunk }, - { .verb = "getAreaInfo", .callback = windowmanager_getareainfo_thunk }, - { .verb = "changeAreaSize", .callback = windowmanager_change_area_size }, - { .verb = "getAreaList", .callback = windowmanager_get_area_list }, - { .verb = "wm_subscribe", .callback = windowmanager_wm_subscribe }, - { .verb = "ping", .callback = windowmanager_ping }, - { .verb = "debug_terminate", .callback = windowmanager_debug_terminate }, - {} }; - -extern "C" const afb_binding_t afbBindingExport = { - .api = "windowmanager", - .specification = "windowmanager", - .info = "windowmanager", - .verbs = windowmanager_verbs, - .preinit = nullptr, - .init = binding_init, - .onevent = nullptr, - .userdata = nullptr, - .provide_class = nullptr, - .require_class = nullptr, - .require_api = nullptr, - .noconcurrency = 0 -}; +void on_event(const char *event, struct json_object *object) +{ + g_afb_instance->wmgr.analyzeReceivedEvent(event, object); +} + +const struct afb_verb_v2 windowmanager_verbs[] = { + {"requestSurface", windowmanager_requestsurface, nullptr, nullptr, AFB_SESSION_NONE}, + {"requestSurfaceXdg", windowmanager_requestsurfacexdg, nullptr, nullptr, AFB_SESSION_NONE}, + {"setRole", windowmanager_setrole, nullptr, nullptr, AFB_SESSION_NONE}, + {"activateWindow", windowmanager_activatewindow, nullptr, nullptr, AFB_SESSION_NONE}, + {"deactivateWindow", windowmanager_deactivatewindow, nullptr, nullptr, AFB_SESSION_NONE}, + {"endDraw", windowmanager_enddraw, nullptr, nullptr, AFB_SESSION_NONE}, + {"getDisplayInfo", windowmanager_getdisplayinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE}, + {"getAreaInfo", windowmanager_getareainfo_thunk, nullptr, nullptr, AFB_SESSION_NONE}, + {"getCarInfo", windowmanager_getcarinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE }, + {"setRenderOrder", windowmanager_set_render_order, nullptr, nullptr, AFB_SESSION_NONE}, + {"changeAreaSize", windowmanager_change_area_size, nullptr, nullptr, AFB_SESSION_NONE}, + {"getAreaList", windowmanager_get_area_list, nullptr, nullptr, AFB_SESSION_NONE}, + {"attachApp", windowmanager_attach_app, nullptr, nullptr, AFB_SESSION_NONE}, + {"wm_subscribe", windowmanager_wm_subscribe, nullptr, nullptr, AFB_SESSION_NONE}, + {"wm_connect", windowmanager_connect, nullptr, nullptr, AFB_SESSION_NONE}, + {"ping", windowmanager_ping, nullptr, nullptr, AFB_SESSION_NONE}, + {"debug_terminate", windowmanager_debug_terminate, nullptr, nullptr, AFB_SESSION_NONE}, + {}}; + +extern "C" const struct afb_binding_v2 afbBindingV2 = { + "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, on_event, 0}; diff --git a/src/pm_wrapper.cpp b/src/pm_wrapper.cpp index 8706128..7cf90f0 100644 --- a/src/pm_wrapper.cpp +++ b/src/pm_wrapper.cpp @@ -43,14 +43,14 @@ static void onError(json_object *json_out) PMWrapper::PMWrapper() {} -int PMWrapper::initialize() +int PMWrapper::initialize(std::string ecu_name) { int ret = 0; - ret = this->pm.initialize(); + ret = this->pm.initialize(ecu_name); if (0 > ret) { - HMI_ERROR("Faild to initialize PolicyManager"); + HMI_ERROR("wm:pmw", "Faild to initialize PolicyManager"); } g_context = this; @@ -81,7 +81,39 @@ int PMWrapper::setInputEventData(Task task, std::string role, std::string area) { event = "deactivate"; } - else + else if (Task::TASK_PARKING_BRAKE_OFF == task) + { + event = "parking_brake_off"; + } + else if (Task::TASK_PARKING_BRAKE_ON == task) + { + event = "parking_brake_on"; + } + else if (Task::TASK_ACCEL_PEDAL_OFF == task) + { + event = "accel_pedal_off"; + } + else if (Task::TASK_ACCEL_PEDAL_ON == task) + { + event = "accel_pedal_on"; + } + else if (Task::TASK_HEDLAMP_OFF == task) + { + event = "headlamp_off"; + } + else if (Task::TASK_HEDLAMP_ON == task) + { + event = "headlamp_on"; + } + else if (Task::TASK_LIGHTSTATUS_BRAKE_OFF == task) + { + event = "lightstatus_brake_off"; + } + else if (Task::TASK_LIGHTSTATUS_BRAKE_ON == task) + { + event = "lightstatus_brake_on"; + } + else { event = ""; } @@ -95,7 +127,7 @@ int PMWrapper::setInputEventData(Task task, std::string role, std::string area) ret = this->pm.setInputEventData(json_in); if (0 > ret) { - HMI_ERROR("Faild to set input event data to PolicyManager"); + HMI_ERROR("wm:pmw", "Faild to set input event data to PolicyManager"); } json_object_put(json_in); @@ -108,7 +140,7 @@ int PMWrapper::executeStateTransition() ret = this->pm.executeStateTransition(); if (0 > ret) { - HMI_ERROR("Failed to execute state transition for PolicyManager"); + HMI_ERROR("wm:pmw", "Failed to execute state transition for PolicyManager"); } return ret; @@ -127,11 +159,151 @@ void PMWrapper::updateStates(json_object *json_out) HMI_DEBUG("json_out dump:%s", json_object_get_string(json_out)); + this->createCarStateChangeAction(json_out, actions); this->createLayoutChangeAction(json_out, actions); this->on_state_transitioned(actions); } +void PMWrapper::createCarStateChangeAction(json_object *json_out, std::vector<WMAction> &actions) +{ + json_object *json_car_ele; + if (!json_object_object_get_ex(json_out, "car_elements", &json_car_ele)) + { + HMI_DEBUG("Not found key \"car_elements\""); + return; + } + + int len = json_object_array_length(json_car_ele); + HMI_DEBUG("json_car_ele len:%d", len); + + for (int i = 0; i < len; i++) + { + json_object *json_tmp = json_object_array_get_idx(json_car_ele, i); + + std::string car_ele_name = jh::getStringFromJson(json_tmp, "name"); + std::string state = jh::getStringFromJson(json_tmp, "state"); + json_bool changed = jh::getBoolFromJson(json_tmp, "changed"); + HMI_DEBUG("car_element:%s changed:%d", car_ele_name.c_str(), changed); + + if (changed) + { + TaskCarState task = TaskCarState::NO_TASK; + if ("parking_brake" == car_ele_name) + { + if ("off" == state) + { + task = TaskCarState::PARKING_BRAKE_OFF; + } + else if ("on" == state) + { + task = TaskCarState::PARKING_BRAKE_ON; + } + else + { + HMI_DEBUG("Unknown parking brake state: %s", state.c_str()); + } + } + else if ("accel_pedal" == car_ele_name) + { + if ("off" == state) + { + task = TaskCarState::ACCEL_PEDAL_OFF; + } + else if ("on" == state) + { + task = TaskCarState::ACCEL_PEDAL_ON; + } + else + { + HMI_DEBUG("Unknown accel pedal state: %s", state.c_str()); + } + } + else if ("lamp" == car_ele_name) + { + if ("off" == state) + { + task = TaskCarState::HEDLAMP_OFF; + } + else if ("on" == state) + { + task = TaskCarState::HEDLAMP_ON; + } + else + { + HMI_DEBUG("Unknown lamp state: %s", state.c_str()); + } + } + else if ("lightstatus_brake" == car_ele_name) + { + if ("off" == state) + { + task = TaskCarState::LIGHTSTATUS_BRAKE_OFF; + } + else if ("on" == state) + { + task = TaskCarState::LIGHTSTATUS_BRAKE_ON; + } + else + { + HMI_DEBUG("Unknown lightstatus brake state: %s", state.c_str()); + } + } + else if ("running" == car_ele_name) + { + if ("stop" == state) + { + task = TaskCarState::CAR_STOP; + } + else if ("run" == state) + { + task = TaskCarState::CAR_RUN; + } + else + { + HMI_DEBUG("Unknown car state: %s", state.c_str()); + } + } + else if ("restriction_mode" == car_ele_name) + { + if ("off" == state) + { + task = TaskCarState::RESTRICTION_MODE_OFF; + } + else if ("on" == state) + { + task = TaskCarState::RESTRICTION_MODE_ON; + } + else + { + HMI_DEBUG("Unknown car state: %s", state.c_str()); + } + } + else + { + HMI_DEBUG("Unknown car element: %s", car_ele_name.c_str()); + } + + // Set action + if (TaskCarState::NO_TASK != task) + { + bool end_draw_finished = true; + WMAction act + { + 0, + nullptr, + "", + "", + TaskVisible::NO_CHANGE, + end_draw_finished, + task + }; + actions.push_back(act); + } + } + } +} + void PMWrapper::createLayoutChangeAction(json_object *json_out, std::vector<WMAction> &actions) { // Get displayed roles from previous layout @@ -197,7 +369,8 @@ void PMWrapper::createLayoutChangeAction(json_object *json_out, std::vector<WMAc role_name, area_name, TaskVisible::VISIBLE, - end_draw_finished + end_draw_finished, + TaskCarState::NO_TASK }; actions.push_back(act); } @@ -220,7 +393,8 @@ void PMWrapper::createLayoutChangeAction(json_object *json_out, std::vector<WMAc role_name, area_name, TaskVisible::VISIBLE, - end_draw_finished + end_draw_finished, + TaskCarState::NO_TASK }; actions.push_back(act); } @@ -245,7 +419,8 @@ void PMWrapper::createLayoutChangeAction(json_object *json_out, std::vector<WMAc i_prv.first, "", TaskVisible::INVISIBLE, - end_draw_finished + end_draw_finished, + TaskCarState::NO_TASK }; actions.push_back(act); } diff --git a/src/pm_wrapper.hpp b/src/pm_wrapper.hpp index 31ec002..84d68df 100644 --- a/src/pm_wrapper.hpp +++ b/src/pm_wrapper.hpp @@ -41,7 +41,7 @@ class PMWrapper using StateTransitionHandler = std::function<void(std::vector<WMAction>)>; using ErrorHandler = std::function<void(void)>; - int initialize(); + int initialize(std::string ecu_name); void registerCallback(StateTransitionHandler on_state_transitioned, ErrorHandler on_error); int setInputEventData(Task task, std::string role, std::string area); @@ -67,6 +67,7 @@ class PMWrapper std::map<std::string, RoleState> prvlayer2rolestate; std::map<std::string, RoleState> crrlayer2rolestate; + void createCarStateChangeAction(json_object *json_out, std::vector<WMAction> &actions); void createLayoutChangeAction(json_object *json_out, std::vector<WMAction> &actions); }; diff --git a/src/request.cpp b/src/request.cpp index 069f8ff..0d8e5d4 100644 --- a/src/request.cpp +++ b/src/request.cpp @@ -30,6 +30,13 @@ WMRequest::WMRequest(string appid, string role, string area, Task task) { } +WMRequest::WMRequest(Task task) + : req_num(0), + trigger{"", "", "", task}, + sync_draw_req(0) +{ +} + WMRequest::~WMRequest() { } @@ -41,4 +48,4 @@ WMRequest::WMRequest(const WMRequest &obj) this->sync_draw_req = obj.sync_draw_req; } -} // namespace wm
\ No newline at end of file +} // namespace wm diff --git a/src/request.hpp b/src/request.hpp index 0f0e199..9827627 100644 --- a/src/request.hpp +++ b/src/request.hpp @@ -31,6 +31,16 @@ enum Task TASK_ALLOCATE, TASK_RELEASE, TASK_CHANGE_AREA, + TASK_PARKING_BRAKE_OFF, + TASK_PARKING_BRAKE_ON, + TASK_ACCEL_PEDAL_OFF, + TASK_ACCEL_PEDAL_ON, + TASK_HEDLAMP_OFF, + TASK_HEDLAMP_ON, + TASK_LIGHTSTATUS_BRAKE_OFF, + TASK_LIGHTSTATUS_BRAKE_ON, + TASK_RESTRICTION_MODE_OFF, + TASK_RESTRICTION_MODE_ON, TASK_INVALID }; @@ -38,9 +48,30 @@ enum TaskVisible { VISIBLE, INVISIBLE, + REQ_REMOTE_VISIBLE, + REQ_REMOTE_INVISIBLE, + REMOTE_VISIBLE, + REMOTE_INVISIBLE, NO_CHANGE }; +enum TaskCarState +{ + PARKING_BRAKE_OFF, + PARKING_BRAKE_ON, + ACCEL_PEDAL_OFF, + ACCEL_PEDAL_ON, + HEDLAMP_OFF, + HEDLAMP_ON, + LIGHTSTATUS_BRAKE_OFF, + LIGHTSTATUS_BRAKE_ON, + CAR_STOP, + CAR_RUN, + RESTRICTION_MODE_OFF, + RESTRICTION_MODE_ON, + NO_TASK, +}; + struct WMTrigger { std::string appid; @@ -57,6 +88,7 @@ struct WMAction std::string area; TaskVisible visible; bool end_draw_finished; + TaskCarState car_state; }; struct WMRequest @@ -64,6 +96,7 @@ struct WMRequest WMRequest(); explicit WMRequest(std::string appid, std::string role, std::string area, Task task); + explicit WMRequest(Task task); virtual ~WMRequest(); WMRequest(const WMRequest &obj); @@ -74,4 +107,4 @@ struct WMRequest } // namespace wm -#endif //WMREQUEST_HPP
\ No newline at end of file +#endif //WMREQUEST_HPP diff --git a/src/util.cpp b/src/util.cpp index 0591d55..7d000b8 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,6 +1,5 @@ /* * Copyright (c) 2017 TOYOTA MOTOR CORPORATION - * Copyright (c) 2018 Konsulko Group * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,11 +16,11 @@ #include "util.hpp" +#include <sstream> #include <time.h> #include <stdio.h> #include <stdarg.h> #include <stdlib.h> -#include <fstream> #include <unistd.h> @@ -31,7 +30,7 @@ void rectangle::fit(unsigned long to_width, unsigned long to_height) { // fit rect within (to_width x to_height) - if (to_width <= (unsigned long)width()) { + if (to_width <= width()) { // scale to fit with set_bottom(top() + (static_cast<long>(to_width) * height() / width()) - 1); set_right(left() + to_width - 1); @@ -143,38 +142,32 @@ void _DUMP(enum LOG_LEVEL level, const char *log, ...) free(message); } -std::string get_file_path(const char *file_name, const char *root_path) +std::vector<std::string> parseString(std::string str, char delimiter) { - char const *default_base_path = root_path; - std::string path(""); - - if(!file_name) { - return path; - } - - if (!default_base_path) { - default_base_path = getenv("AFM_APP_INSTALL_DIR"); - if (!default_base_path) { - HMI_ERROR("AFM_APP_INSTALL_DIR is not defined"); + // Parse string by delimiter + std::vector<std::string> vct; + std::stringstream ss{str}; + std::string buf; + while (std::getline(ss, buf, delimiter)) + { + if (!buf.empty()) + { + // Delete space and push back to vector + vct.push_back(deleteSpace(buf)); } } - if (default_base_path) { - path = default_base_path; - path.append("/etc/"); - path.append(file_name); - } + return vct; +} - // Check for over-ride in /etc/xdg/windowmanager - std::string override_path("/etc/xdg/windowmanager/"); - override_path.append(file_name); - std::ifstream i(override_path); - if (i.good()) { - path = override_path; +std::string deleteSpace(std::string str) +{ + std::string ret = str; + size_t pos; + while ((pos = ret.find_first_of(" ")) != std::string::npos) + { + ret.erase(pos, 1); } - i.close(); - - HMI_INFO("Using %s", path.c_str()); - return path; + return ret; } void ChangeAreaReq::dump() @@ -192,4 +185,4 @@ void ChangeAreaReq::dump() DUMP("update change app : %s, area:%s", req.first.c_str(), req.second.c_str()); } DUMP("======== dump end ========="); -} +}
\ No newline at end of file diff --git a/src/util.hpp b/src/util.hpp index 9540772..4c3870f 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -1,6 +1,5 @@ /* * Copyright (c) 2017 TOYOTA MOTOR CORPORATION - * Copyright (c) 2018 Konsulko Group * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +19,8 @@ #include <functional> #include <thread> +#include <string> +#include <vector> #include <unordered_map> #include <sys/poll.h> #include <string.h> @@ -54,6 +55,9 @@ void _HMI_LOG(enum LOG_LEVEL level, const char* file, const char* func, const in void _HMI_SEQ_LOG(enum LOG_LEVEL level, const char* file, const char* func, const int line, unsigned seq_num, const char* log, ...); void _DUMP(enum LOG_LEVEL level, const char *log, ...); +std::vector<std::string> parseString(std::string str, char delimiter); +std::string deleteSpace(std::string str); + struct rect { int32_t w, h; @@ -119,9 +123,6 @@ class rectangle long _bottom; }; -// Configuration file path helper -std::string get_file_path(const char *file_name, const char *root_path = NULL); - typedef struct ChangeAreaReq { std::string appname; std::unordered_map<std::string, struct rect> area_req; @@ -132,5 +133,4 @@ typedef struct ChangeAreaReq { ChangeAreaReq(const ChangeAreaReq& val) = default; void dump(); } ChangeAreaReq; - -#endif // WM_UTIL_HPP +#endif // !WM_UTIL_HPP diff --git a/src/window_manager.cpp b/src/window_manager.cpp index f9070f6..1432769 100644 --- a/src/window_manager.cpp +++ b/src/window_manager.cpp @@ -26,6 +26,8 @@ extern "C" #include <systemd/sd-event.h> } +#define WM_LASTMODE_PATH "/etc/lastmode.json" + using std::string; using std::vector; using std::unordered_map; @@ -65,13 +67,33 @@ static const vector<string> kListEventName{ "syncDraw", "flushDraw", "screenUpdated", + "handshake", + "headlampOff", + "headlampOn", + "parkingBrakeOff", + "parkingBrakeOn", + "lightstatusBrakeOff", + "lightstatusBrakeOn", + "carStop", + "carRun", "error"}; +static const char kPathOldRolesConfigFile[] = "/etc/old_roles.json"; static sd_event_source *g_timer_ev_src = nullptr; static AppList g_app_list; static WindowManager *g_context; static vector<string> white_list_area_size_change = { - "homescreen", "settings" + "homescreen" +}; + +struct AfbClosure { +public: + AfbClosure(unsigned pid, unsigned ppid, unsigned surface) + : pid(pid), ppid(ppid), surface(surface) {} + ~AfbClosure() = default; + unsigned pid; + unsigned ppid; + unsigned surface; }; namespace @@ -93,14 +115,22 @@ static void onError() { g_context->processError(WMError::LAYOUT_CHANGE_FAIL); } + +static void onReceiveRemoteRequest(json_object *data) +{ + g_context->processForRemoteRequest(data); +} } // namespace /** * WindowManager Impl */ WindowManager::WindowManager() - : id_alloc{} + : wmcon{}, + id_alloc{} { + this->end_init = false; + const char *path = getenv("AFM_APP_INSTALL_DIR"); if (!path) { @@ -108,39 +138,61 @@ WindowManager::WindowManager() } string root = path; - this->lc = std::make_shared<LayerControl>(root); + // TODO: ECU name should be decide by config file + // Get mode and decide ECU name + string ecu_name = this->wmcon.getEcuName(); + + this->lc = std::make_shared<LayerControl>(root, ecu_name); HMI_DEBUG("Layer Controller initialized"); } int WindowManager::init() { + WMError err; + LayerControlCallbacks lmcb; lmcb.surfaceCreated = [&](unsigned pid, unsigned surface){ - this->surface_created(surface); + this->surface_created(pid, surface); }; lmcb.surfaceDestroyed = [&](unsigned surface){ this->surface_removed(surface); }; - if(this->lc->init(lmcb) != WMError::SUCCESS) + err = this->lc->init(lmcb); + if (err == WMError::FAIL) { + HMI_ERROR("Could not connect to weston"); return -1; } + // TODO: application requests by old role, + // so create role map (old, new) + // Load old_roles config file + this->loadOldRolesConfigFile(); + + // Initialize LowCanClient + this->lcc.initialize(); + // Store my context for calling callback from PolicyManager g_context = this; // Initialize PMWrapper - this->pmw.initialize(); + this->pmw.initialize(this->wmcon.getEcuName()); // Register callback to PolicyManager this->pmw.registerCallback(onStateTransitioned, onError); - // Make afb event for subscriber - for (int i = Event_ScreenUpdated; i < Event_Error; i++) + // Initialize WMConnection + this->wmcon.initialize(); + + // Register callback to WMConnection + this->wmcon.registerCallback(onReceiveRemoteRequest); + + // Make afb event + for (int i = Event_Val_Min; i <= Event_Val_Max; i++) { - map_afb_event[kListEventName[i]] = afb_api_make_event(afbBindingV3root, kListEventName[i].c_str()); + map_afb_event[kListEventName[i]] = afb_daemon_make_event(kListEventName[i].c_str()); } const struct rect css_bg = this->lc->getAreaSize("fullscreen"); @@ -156,47 +208,65 @@ int WindowManager::init() double scale = static_cast<double>(dp_bg.height()) / css_bg.h; this->lc->setupArea(dp_bg, scale); - return 0; + this->end_init = true; + + return 0; //init_layers(); } result<int> WindowManager::api_request_surface(char const *appid, char const *drawing_name) { - string str_id = appid; - string role = drawing_name; - unsigned lid = 0; - - if(!g_app_list.contains(str_id)) + // TODO: application requests by old role, + // so convert role old to new + const char *role = this->convertRoleOldToNew(drawing_name); + string l_name; + string s_appid = appid; + string s_role = role; + + if(!g_app_list.contains(s_appid)) { - lid = this->generateLayerForClient(role); - if (lid == 0) + unsigned l_id = this->lc->getNewLayerID(s_role, &l_name); + if (l_id == 0) { - return Err<int>("Designated role does not match any role, fallback is disabled"); + // register drawing_name as fallback and make it displayed. + l_id = this->lc->getNewLayerID("fallback", &l_name); + HMI_DEBUG("%s is not registered in layers.json, then fallback as normal app", role); + if (l_id == 0) + { + return Err<int>("Designated role does not match any role, fallback is disabled"); + } } - // add client into the db - g_app_list.addClient(str_id, lid, role); - } - else - { - // This case occurs when an client calls "subscribe" before request_surface. - // Then application doesn't have layer and role yet. - auto client = g_app_list.lookUpClient(str_id); - if(client->layerID() == 0) + + // TODO: remote layer size is fixed value + if ("Remote" == l_name) + { + this->lc->createNewRemoteLayer(l_id); + } + else { - client->setLayerID(this->generateLayerForClient(role)); + this->lc->createNewLayer(l_id); } - client->setRole(role); + + // add client into the db + g_app_list.addClient(s_appid, l_id, s_role); } // generate surface ID for ivi-shell application - auto rname = this->id_alloc.lookup(role); + + auto rname = this->id_alloc.lookup(string(role)); if (!rname) { // name does not exist yet, allocate surface id... auto id = int(this->id_alloc.generate_id(role)); - this->tmp_surface2app[id] = {str_id, lid}; + this->tmp_surface2app[id] = {s_appid, 0}; + + // Work Around + HMI_NOTICE("WORK AROUND: add surface on request surface"); + auto client = g_app_list.lookUpClient(s_appid); + client->addSurface(id); + /////////////// - auto client = g_app_list.lookUpClient(str_id); - client->registerSurface(id); + // Set role map of (new, old) + this->rolenew2old[role] = string(drawing_name); return Ok<int>(id); } @@ -208,10 +278,8 @@ result<int> WindowManager::api_request_surface(char const *appid, char const *dr char const *WindowManager::api_request_surface(char const *appid, char const *drawing_name, char const *ivi_id) { - string str_id = appid; - string role = drawing_name; - unsigned sid = std::stol(ivi_id); + HMI_DEBUG("This API(requestSurfaceXDG) is for XDG Application using runXDG"); /* * IVI-shell doesn't send surface_size event via ivi-wm protocol @@ -226,30 +294,45 @@ char const *WindowManager::api_request_surface(char const *appid, char const *dr return "fail"; } - if(!g_app_list.contains(str_id)) + // TODO: application requests by old role, + // so convert role old to new + const char *role = this->convertRoleOldToNew(drawing_name); + string s_role = role; + string s_appid = appid; + string l_name; + + if(!g_app_list.contains(s_appid)) { - unsigned l_id = this->generateLayerForClient(role); + // auto lid = this->layers.get_layer_id(string(role)); + unsigned l_id = this->lc->getNewLayerID(s_role, &l_name); if (l_id == 0) { - return "Designated role does not match any role, fallback is disabled"; + /** + * register drawing_name as fallback and make it displayed. + */ + l_id = this->lc->getNewLayerID("fallback", &l_name); + HMI_DEBUG("%s is not registered in layers.json, then fallback as normal app", role); + if (l_id == 0) + { + return "Designated role does not match any role, fallback is disabled"; + } } - // add client into the db - g_app_list.addClient(str_id, l_id, role); - } - else - { - // This case occurs when an client calls "subscribe" before request_surface. - // Then application doesn't have layer and role yet. - auto client = g_app_list.lookUpClient(str_id); - if(client->layerID() == 0) + + // TODO: remote layer size is fixed value + if ("Remote" == l_name) { - client->setLayerID(this->generateLayerForClient(role)); + this->lc->createNewRemoteLayer(l_id); + } + else + { + this->lc->createNewLayer(l_id); } - client->setRole(role); - } - auto rname = this->id_alloc.lookup(role); + // add client into the db + g_app_list.addClient(s_appid, l_id, s_role); + } + auto rname = this->id_alloc.lookup(s_role); if (rname) { return "Surface already present"; @@ -258,17 +341,121 @@ char const *WindowManager::api_request_surface(char const *appid, char const *dr // register pair drawing_name and ivi_id this->id_alloc.register_name_id(role, sid); - auto client = g_app_list.lookUpClient(str_id); + auto client = g_app_list.lookUpClient(s_appid); client->addSurface(sid); + // Set role map of (new, old) + this->rolenew2old[role] = string(drawing_name); + return nullptr; } +bool WindowManager::api_set_role(char const *appid, char const *drawing_name) +{ + bool ret = false; + + // TODO: application requests by old role, + // so convert role old to new + const char *role = this->convertRoleOldToNew(drawing_name); + string s_role = role; + string s_appid = appid; + string l_name; + + // Create WMClient + if(!g_app_list.contains(s_appid)) + { + // auto lid = this->layers.get_layer_id(string(role)); + unsigned l_id = this->lc->getNewLayerID(s_role, &l_name); + if (l_id == 0) + { + /** + * register drawing_name as fallback and make it displayed. + */ + l_id = this->lc->getNewLayerID("fallback", &l_name); + HMI_DEBUG("%s is not registered in layers.json, then fallback as normal app", role); + if (l_id == 0) + { + HMI_ERROR("Designated role does not match any role, fallback is disabled"); + return ret; + } + } + + // TODO: remote layer size is fixed value + if ("Remote" == l_name) + { + this->lc->createNewRemoteLayer(l_id); + } + else + { + this->lc->createNewLayer(l_id); + } + + // add client into the db + g_app_list.addClient(s_appid, l_id, s_role); + // Set role map of (new, old) + this->rolenew2old[role] = string(drawing_name); + } + + // for(auto itr = this->tmp_surface2app.begin(); + // itr != this->tmp_surface2app.end() ; ++itr) + // { + for(auto& x : this->tmp_surface2app) + { + if(x.second.appid == s_appid) + { + unsigned surface = x.first; + auto client = g_app_list.lookUpClient(s_appid); + client->addSurface(surface); + this->tmp_surface2app.erase(surface); + this->id_alloc.register_name_id(s_role, surface); + break; + } + } + +/* if(0 != pid){ + // search floating surfaceID from pid if pid is designated. + wm_err = g_app_list.popFloatingSurface(pid, &surface); + } + else{ + // get floating surface with appid. If WM queries appid from pid, + // WM can bind surface and role with appid(not implemented yet) + //wm_err = g_app_list.popFloatingSurface(id); + } + if(wm_err != WMError::SUCCESS){ + HMI_ERROR("No floating surface for app: %s", id.c_str()); + g_app_list.addFloatingClient(id, lid, role); + HMI_NOTICE("%s : Waiting for surface creation", id.c_str()); + return ret; + } + + ret = true; + if (g_app_list.contains(id)) + { + HMI_INFO("Add role: %s with surface: %d. Client %s has multi surfaces.", + role.c_str(), surface, id.c_str()); + auto client = g_app_list.lookUpClient(id); + client->appendRole(role); + } + else{ + HMI_INFO("Create new client: %s, surface: %d into layer: %d with role: %s", + id.c_str(), surface, lid, role.c_str()); + g_app_list.addClient(id, lid, role); + } */ + + // register pair drawing_name and ivi_id + + return true; +} + void WindowManager::api_activate_window(char const *appid, char const *drawing_name, char const *drawing_area, const reply_func &reply) { + // TODO: application requests by old role, + // so convert role old to new + const char *c_role = this->convertRoleOldToNew(drawing_name); + string id = appid; - string role = drawing_name; + string role = c_role; string area = drawing_area; if(!g_app_list.contains(id)) @@ -278,12 +465,51 @@ void WindowManager::api_activate_window(char const *appid, char const *drawing_n } auto client = g_app_list.lookUpClient(id); + // unsigned srfc = client->surfaceID(role); + // unsigned layer = client->layerID(); + + // g_app_list.removeFloatingSurface(client->surfaceID()); + // g_app_list.removeFloatingSurface(client);i + unsigned layer = client->layerID(); + + //TODO Deactivate remote viewing app for remote view change to local view. + if(this->lc->hasRemoteLayer(layer) && this->wmcon.getAppIdToEcuName(appid) != "") + { + HMI_DEBUG("Deactivate remote App %s", drawing_name); + std::string tmp_area = this->wmcon.getAppIdToEcuName(appid) + ".split.sub"; + HMI_DEBUG("Deactivate area name: %s", tmp_area.c_str()); + this->wmcon.sendRequest("deactivateWindow", appid, drawing_name, tmp_area.c_str()); + + unsigned req_num = g_app_list.currentRequestNumber(); + const char *c_role = this->convertRoleOldToNew(drawing_name); + bool end_draw_finished = true; + WMAction act + { + req_num, + client, + string(c_role), + "", + TaskVisible::REMOTE_INVISIBLE, + end_draw_finished, + TaskCarState::NO_TASK + }; + + this->lc->visibilityChange(act); + this->lc->renderLayers(); + + this->emit_invisible(role); + this->emit_deactivated(role); + } + Task task = Task::TASK_ALLOCATE; unsigned req_num = 0; WMError ret = WMError::UNKNOWN; ret = this->setRequest(id, role, area, task, &req_num); + //vector<WMLayerState> current_states = this->lc->getCurrentStates(); + // ret = this->setRequest(id, role, area, task, current_states, &req_num); + if(ret != WMError::SUCCESS) { HMI_ERROR(errorDescription(ret)); @@ -291,6 +517,8 @@ void WindowManager::api_activate_window(char const *appid, char const *drawing_n return; } + this->wmcon.setAppIdToEcuName(id, ""); + reply(nullptr); if (req_num != g_app_list.currentRequestNumber()) { @@ -299,7 +527,9 @@ void WindowManager::api_activate_window(char const *appid, char const *drawing_n return; } - // Do allocate tasks + /* + * Do allocate tasks + */ ret = this->checkPolicy(req_num); if (ret != WMError::SUCCESS) @@ -311,12 +541,156 @@ void WindowManager::api_activate_window(char const *appid, char const *drawing_n } } +void WindowManager::api_activate_surface_for_slave( + char const *appid, char const *drawing_name, + char const *drawing_area, const reply_func &reply) +{ + // TODO: application requests by old role, + // so convert role old to new + const char *c_role = this->convertRoleOldToNew(drawing_name); + + string id = appid; + string role = c_role; + string area = drawing_area; + + if(!g_app_list.contains(id)) + { + // Request surface of app in slave to register app information + this->api_request_surface(appid, drawing_name); + + // Set role of app in slave to register app information + this->api_set_role(appid, drawing_name); + } + auto client = g_app_list.lookUpClient(id); + + // unsigned srfc = client->surfaceID(role); + // unsigned layer = client->layerID(); + + // g_app_list.removeFloatingSurface(client->surfaceID()); + // g_app_list.removeFloatingSurface(client); + + Task task = Task::TASK_ALLOCATE; + unsigned req_num = 0; + WMError ret = WMError::UNKNOWN; + + ret = this->setRequestForSlave(id, role, area, task, &req_num); + + //vector<WMLayerState> current_states = this->lc->getCurrentStates(); + // ret = this->setRequest(id, role, area, task, current_states, &req_num); + + if(ret != WMError::SUCCESS) + { + HMI_ERROR(errorDescription(ret)); + reply("Failed to set request"); + return; + } + + this->wmcon.setAppIdToReceivedEcuName(id); + + reply(nullptr); + if (req_num != g_app_list.currentRequestNumber()) + { + // Add request, then invoked after the previous task is finished + HMI_SEQ_DEBUG(req_num, "request is accepted"); + return; + } + + /* + * Do allocate tasks + */ + ret = this->checkPolicyForSlave(req_num); + + if (ret != WMError::SUCCESS) + { + //this->emit_error() + HMI_SEQ_ERROR(req_num, errorDescription(ret)); + g_app_list.removeRequest(req_num); + this->processNextRequest(); + } +} + +void WindowManager::api_activate_surface_to_master( + char const *appid, char const *drawing_name, + char const *drawing_area, const reply_func &reply) +{ + // TODO: application requests by old role, + // so convert role old to new + const char *c_role = this->convertRoleOldToNew(drawing_name); + + string id = appid; + string role = c_role; + string area = drawing_area; + + if(!g_app_list.contains(id)) + { + reply("app doesn't request 'requestSurface' or 'setRole' yet"); + return; + } + auto client = g_app_list.lookUpClient(id); + + // unsigned srfc = client->surfaceID(role); + // unsigned layer = client->layerID(); + + // g_app_list.removeFloatingSurface(client->surfaceID()); + // g_app_list.removeFloatingSurface(client); + + Task task = Task::TASK_ALLOCATE; + unsigned req_num = 0; + WMError ret = WMError::UNKNOWN; + + ret = this->setRequest(id, role, area, task, &req_num); + + //vector<WMLayerState> current_states = this->lc->getCurrentStates(); + // ret = this->setRequest(id, role, area, task, current_states, &req_num); + + if(ret != WMError::SUCCESS) + { + HMI_ERROR(errorDescription(ret)); + reply("Failed to set request"); + return; + } + + std::string ecu_name; + ecu_name = this->wmcon.getAreaToEcuName(area.c_str()); + + this->wmcon.setAppIdToEcuName(id, ecu_name); + + reply(nullptr); + if (req_num != g_app_list.currentRequestNumber()) + { + // Add request, then invoked after the previous task is finished + HMI_SEQ_DEBUG(req_num, "request is accepted"); + return; + } + + /* + * Do allocate tasks + */ + int i_ret = this->wmcon.sendRequest("activateWindow", appid, + drawing_name, drawing_area); + if (0 > i_ret) + { + //this->emit_error() + HMI_SEQ_ERROR(req_num, errorDescription(ret)); + g_app_list.removeRequest(req_num); + this->processNextRequest(); + } + + this->setTimer(); +} + void WindowManager::api_deactivate_window(char const *appid, char const *drawing_name, const reply_func &reply) { - // Check Phase + // TODO: application requests by old role, + // so convert role old to new + const char *c_role = this->convertRoleOldToNew(drawing_name); + + /* + * Check Phase + */ string id = appid; - string role = drawing_name; + string role = c_role; string area = ""; //drawing_area; Task task = Task::TASK_RELEASE; unsigned req_num = 0; @@ -339,7 +713,9 @@ void WindowManager::api_deactivate_window(char const *appid, char const *drawing return; } - // Do allocate tasks + /* + * Do allocate tasks + */ ret = this->checkPolicy(req_num); if (ret != WMError::SUCCESS) @@ -351,10 +727,112 @@ void WindowManager::api_deactivate_window(char const *appid, char const *drawing } } +void WindowManager::api_deactivate_surface_for_slave(char const *appid, char const *drawing_name, + const reply_func &reply) +{ + // TODO: application requests by old role, + // so convert role old to new + const char *c_role = this->convertRoleOldToNew(drawing_name); + + /* + * Check Phase + */ + string id = appid; + string role = c_role; + string area = "";//drawing_area; + Task task = Task::TASK_RELEASE; + unsigned req_num = 0; + WMError ret = WMError::UNKNOWN; + + ret = this->setRequest(id, role, area, task, &req_num); + + if (ret != WMError::SUCCESS) + { + HMI_ERROR(errorDescription(ret)); + reply("Failed to set request"); + return; + } + + reply(nullptr); + if (req_num != g_app_list.currentRequestNumber()) + { + // Add request, then invoked after the previous task is finished + HMI_SEQ_DEBUG(req_num, "request is accepted"); + return; + } + + /* + * Do allocate tasks + */ + ret = this->checkPolicyForSlave(req_num); + + if (ret != WMError::SUCCESS) + { + //this->emit_error() + HMI_SEQ_ERROR(req_num, errorDescription(ret)); + g_app_list.removeRequest(req_num); + this->processNextRequest(); + } +} + +void WindowManager::api_deactivate_surface_to_master(char const *appid, char const *drawing_name, + const reply_func &reply) +{ + // TODO: application requests by old role, + // so convert role old to new + const char *c_role = this->convertRoleOldToNew(drawing_name); + + /* + * Check Phase + */ + string id = appid; + string role = c_role; + string area = "";//drawing_area; + Task task = Task::TASK_RELEASE; + unsigned req_num = 0; + WMError ret = WMError::UNKNOWN; + + ret = this->setRequest(id, role, area, task, &req_num); + + if (ret != WMError::SUCCESS) + { + HMI_ERROR(errorDescription(ret)); + reply("Failed to set request"); + return; + } + + reply(nullptr); + if (req_num != g_app_list.currentRequestNumber()) + { + // Add request, then invoked after the previous task is finished + HMI_SEQ_DEBUG(req_num, "request is accepted"); + return; + } + + /* + * Do allocate tasks + */ + int i_ret = this->wmcon.sendRequest("deactivateWindow", appid, + drawing_name, ""); + if (0 > i_ret) + { + //this->emit_error() + HMI_SEQ_ERROR(req_num, errorDescription(ret)); + g_app_list.removeRequest(req_num); + this->processNextRequest(); + } + + this->setTimer(); +} + void WindowManager::api_enddraw(char const *appid, char const *drawing_name) { + // TODO: application requests by old role, + // so convert role old to new + const char *c_role = this->convertRoleOldToNew(drawing_name); + string id = appid; - string role = drawing_name; + string role = c_role; unsigned current_req = g_app_list.currentRequestNumber(); bool result = g_app_list.setEndDrawFinished(current_req, id, role); @@ -381,6 +859,8 @@ void WindowManager::api_enddraw(char const *appid, char const *drawing_name) this->emitScreenUpdated(current_req); HMI_SEQ_INFO(current_req, "Finish request status: %s", errorDescription(ret)); + this->saveLastModeData(current_req); + g_app_list.removeRequest(current_req); this->processNextRequest(); @@ -392,6 +872,67 @@ void WindowManager::api_enddraw(char const *appid, char const *drawing_name) } } +int WindowManager::api_subscribe(afb_req req, int event_id) +{ + struct afb_event event = this->map_afb_event[kListEventName[event_id]]; + return afb_req_subscribe(req, event); +} + +void WindowManager::api_handshake() +{ + if (this->end_init && this->wmcon.getEndInit()) + { + this->send_event(kListEventName[Event_Handshake]); + } +} + +void WindowManager::api_enddraw_for_remote(char const *appid, char const *drawing_name) +{ + int ret = this->wmcon.sendRequest("endDraw", appid, drawing_name, ""); + if (0 > ret) + { + //this->emit_error() + + this->pmw.undoState(); + this->lc->undoUpdate(); + + unsigned current_req = g_app_list.currentRequestNumber(); + g_app_list.removeRequest(current_req); + this->processNextRequest(); + + return; + } + + this->api_enddraw(appid, drawing_name); +} + +bool WindowManager::api_client_set_render_order(char const* appid, const vector<string>& render_order) +{ + bool ret = false; + string id = appid; + auto client = g_app_list.lookUpClient(id); + if(client) + { + client->setRenderOrder(render_order); + } + return ret; +} + +string WindowManager::api_client_attach_service_surface + (const char* appid, const char* dest, const char* service_surface) +{ + string uuid, s_dest = dest; + auto client = g_app_list.lookUpClient(s_dest); + if(!client) + { + HMI_ERROR("Failed to look up destination [%s]", dest); + return uuid; + } + uuid = client->attachTmpServiceSurface(appid, service_surface); + this->tmp_services.emplace_back(TmpService{appid, dest, service_surface, uuid}); + return uuid; +} + json_object* WindowManager::api_get_area_list() { json_object* ret = json_object_new_object(); @@ -480,46 +1021,9 @@ void WindowManager::api_change_area_size(ChangeAreaReq &areas) // Request change size to applications for(const auto &action : g_app_list.getActions(req_num, &found)) { - struct rect r = this->lc->getAreaSize(action.area); - action.client->emitSyncDraw(action.area, r); - } -} - -bool WindowManager::api_subscribe(afb_req_t req, EventType event_id) -{ - bool ret = false; - char* appid = afb_req_get_application_id(req); - if(event_id < Event_Val_Min || event_id > Event_Val_Max) - { - HMI_ERROR("not defined in Window Manager", event_id); - return ret; - } - HMI_INFO("%s subscribe %s : %d", appid, kListEventName[event_id].c_str(), event_id); - if(event_id == Event_ScreenUpdated) - { - // Event_ScreenUpdated should be emitted to subscriber - afb_event_t event = this->map_afb_event[kListEventName[event_id]]; - int rc = afb_req_subscribe(req, event); - if(rc == 0) - { - ret = true; - } - } - else if(appid) - { - string id = appid; - free(appid); - if(!g_app_list.contains(id)) - { - g_app_list.addClient(id); - } - g_app_list.lookUpClient(id)->subscribe(req, kListEventName[event_id]); - } - else - { - HMI_ERROR("appid is not set"); + string old_role = this->rolenew2old[action.role]; + this->emit_syncdraw(old_role, action.area); } - return ret; } result<json_object *> WindowManager::api_get_display_info() @@ -541,7 +1045,9 @@ result<json_object *> WindowManager::api_get_area_info(char const *drawing_name) { HMI_DEBUG("called"); - string role = drawing_name; + // TODO: application requests by old role, + // so convert role old to new + const char *role = this->convertRoleOldToNew(drawing_name); // Check drawing name, surface/layer id auto const &surface_id = this->id_alloc.lookup(role); @@ -551,7 +1057,7 @@ result<json_object *> WindowManager::api_get_area_info(char const *drawing_name) } // Set area rectangle - struct rect area_info = this->area_info[*surface_id]; + rect area_info = this->area_info[*surface_id]; json_object *object = json_object_new_object(); json_object_object_add(object, kKeyX, json_object_new_int(area_info.x)); json_object_object_add(object, kKeyY, json_object_new_int(area_info.y)); @@ -561,10 +1067,166 @@ result<json_object *> WindowManager::api_get_area_info(char const *drawing_name) return Ok<json_object *>(object); } +result<json_object *> WindowManager::api_get_car_info(char const *label) +{ + json_object *j_in = nullptr; + json_object *j_out = nullptr; + + if (0 == strcmp("parking_brake_status", label)) + { + // Get parking brake status + json_bool val = (this->crr_car_info.parking_brake_stt) ? TRUE : FALSE; + j_in = json_object_new_boolean(val); + } + else if (0 == strcmp("accelerator.pedal.position", label)) + { + // Get accelerator pedal position + double val = this->crr_car_info.accel_pedal_pos; + j_in = json_object_new_double(val); + } + else if (0 == strcmp("car_state", label)) + { + // Get running state + const char* val = (this->crr_car_info.running_stt) ? "run" : "stop"; + j_in = json_object_new_string(val); + } + else if (0 == strcmp("lightstatus.brake", label)) { + // Get lightstatus brake status + json_bool val = (this->crr_car_info.lightstatus_brake_stt) ? TRUE : FALSE; + j_in = json_object_new_boolean(val); + } + else + { + return Err<json_object *>("Car info does not exist"); + } + + // Create output object + j_out = json_object_new_object(); + json_object_object_add(j_out, "value", j_in); + + return Ok<json_object *>(j_out); +} + +void WindowManager::send_event(const string& evname) +{ + HMI_DEBUG("%s: %s", __func__, evname.c_str()); + + int ret = afb_event_push(this->map_afb_event[evname], nullptr); + if (ret != 0) + { + HMI_DEBUG("afb_event_push: %m"); + } +} + +void WindowManager::send_event(const string& evname, const string& role) +{ + HMI_DEBUG("%s: %s(%s)", __func__, evname.c_str(), role.c_str()); + + json_object *j = json_object_new_object(); + json_object_object_add(j, kKeyDrawingName, json_object_new_string(role.c_str())); + + int ret = afb_event_push(this->map_afb_event[evname], j); + if (ret != 0) + { + HMI_DEBUG("afb_event_push failed: %m"); + } +} + +void WindowManager::send_event(const string& evname, const string& role, const string& area, + int x, int y, int w, int h) +{ + HMI_DEBUG("%s: %s(%s, %s) x:%d y:%d w:%d h:%d", + __func__, evname.c_str(), role.c_str(), area.c_str(), x, y, w, h); + + json_object *j_rect = json_object_new_object(); + json_object_object_add(j_rect, kKeyX, json_object_new_int(x)); + json_object_object_add(j_rect, kKeyY, json_object_new_int(y)); + json_object_object_add(j_rect, kKeyWidth, json_object_new_int(w)); + json_object_object_add(j_rect, kKeyHeight, json_object_new_int(h)); + + json_object *j = json_object_new_object(); + json_object_object_add(j, kKeyDrawingName, json_object_new_string(role.c_str())); + json_object_object_add(j, kKeyDrawingArea, json_object_new_string(area.c_str())); + json_object_object_add(j, kKeyDrawingRect, j_rect); + + int ret = afb_event_push(this->map_afb_event[evname], j); + if (ret != 0) + { + HMI_DEBUG("afb_event_push failed: %m"); + } +} + +string WindowManager::searchApp(unsigned pid, unsigned ppid, unsigned surface, json_object* resp) +{ + // retrieve appid from pid from application manager + string appid; + // check appid then add it to the client + HMI_INFO("Runners:%s", json_object_get_string(resp)); + int size = json_object_array_length(resp); + HMI_INFO("pid %d, ppid %d, surface %d",pid, ppid, surface); + for(int i = 0; i < size; i++) + { + json_object *j = json_object_array_get_idx(resp, i); + int runid = jh::getIntFromJson(j, "runid"); + const char* id = jh::getStringFromJson(j, "id"); + HMI_DEBUG("Appid %s, runid %d", id, runid); + if(id && (runid == ppid)) + { + string s_id = id; + s_id.erase(s_id.find('@')); + appid = s_id; + HMI_INFO("App found %s", appid.c_str()); + break; + } + } + if(appid.empty()) + { + HMI_WARNING("Failed to retrieve id"); + } + return appid; +} + +void WindowManager::storeSurface(const string& appid, unsigned ppid, unsigned surface) +{ + auto elem = std::find_if(this->tmp_services.begin(), this->tmp_services.end(), + [&appid](TmpService& ts){ + return (ts.dest == appid ); + }); + + this->lc->setXDGSurfaceOriginSize(surface); + if(elem != this->tmp_services.end()) + { + // attachApp + auto client = g_app_list.lookUpClient(elem->dest); + if(client == nullptr) + { + return; + } + HMI_INFO("Attach surface %d (service %s) to app %s", surface, elem->service.c_str(), elem->dest.c_str()); + client->attachServiceSurface(elem->service, surface); + } + else + { + // setRole + auto client = g_app_list.lookUpClient(appid); + if(client != nullptr) + { + client->addSurface(surface); + this->id_alloc.register_name_id(client->role(), surface); + } + else + { + // Store tmp surface and appid for application + // who requests setRole after creating shell surface + this->tmp_surface2app.emplace(surface, TmpClient{appid, ppid}); + } + } +} + /** * proxied events */ -void WindowManager::surface_created(unsigned surface_id) +void WindowManager::surface_created(unsigned pid, unsigned surface_id) { // requestSurface if(this->tmp_surface2app.count(surface_id) != 0) @@ -582,6 +1244,52 @@ void WindowManager::surface_created(unsigned surface_id) } this->tmp_surface2app.erase(surface_id); } + else + { + HMI_NOTICE("Unknown surface %d", surface_id); + // retrieve ppid + std::ostringstream os; + os << pid ; + string path = "/proc/" + os.str() + "/stat"; + std::ifstream ifs(path.c_str()); + string str; + unsigned ppid = 0; + if(!ifs.fail() && std::getline(ifs, str)) + { + std::sscanf(str.data(), "%*d %*s %*c %d", &ppid); + HMI_INFO("Retrieve ppid %d", ppid); + } + else + { + HMI_ERROR("Failed to open /proc/%d/stat", pid); + HMI_ERROR("File system may be different"); + return; + } + struct AfbClosure* c = new struct AfbClosure(pid, ppid, surface_id); + // search pid from surfaceID + afb_service_call("afm-main", "runners", json_object_new_object(), + [](void* closure, int stat, json_object* resp){ + HMI_DEBUG("check %s", json_object_get_string(resp)); + struct AfbClosure* c = static_cast<struct AfbClosure*>(closure); + HMI_DEBUG("check"); + if(stat != 0) + { + HMI_ERROR("Failed to call runners"); + } + else + { + json_object* j; + json_object_object_get_ex(resp, "response", &j); + string appid = g_context->searchApp(c->pid, c->ppid, c->surface, j); + if(!appid.empty()) + { + g_context->storeSurface(appid, c->ppid, c->surface); + } + } + json_object_put(resp); + delete c; + }, c); + } } void WindowManager::surface_removed(unsigned surface_id) @@ -608,6 +1316,25 @@ void WindowManager::exceptionProcessForTransition() this->processNextRequest(); } +void WindowManager::analyzeReceivedEvent(const char *event, struct json_object *object) +{ + HMI_DEBUG("event:%s", event); + + // If receive low can signal + if (strstr(event, "low-can")) + { + // Analyze low can signal + const char *signal_name = this->lcc.analyzeCanSignal(object); + + // Create task for car state and input it to PolicyManager + Task task = this->convertCanSignalToCarStateTask(signal_name); + if (Task::TASK_INVALID != task) + { + this->inputCarStateTask(task); + } + } +} + void WindowManager::timerHandler() { unsigned req_num = g_app_list.currentRequestNumber(); @@ -619,8 +1346,10 @@ void WindowManager::timerHandler() void WindowManager::startTransitionWrapper(vector<WMAction> &actions) { - WMError ret; + WMError ret = WMError::UNKNOWN; + // req_num is guaranteed by Window Manager unsigned req_num = g_app_list.currentRequestNumber(); + Task task = Task::TASK_INVALID; if (actions.empty()) { @@ -636,27 +1365,58 @@ void WindowManager::startTransitionWrapper(vector<WMAction> &actions) } } + // Check weather there is the no request task + // [The no request task] + // - TaskCarState::RESTRICTION_MODE_OFF + // - TaskCarState::RESTRICTION_MODE_ON + for (const auto &act : actions) + { + if (TaskCarState::RESTRICTION_MODE_OFF == act.car_state) + { + task = Task::TASK_RESTRICTION_MODE_OFF; + break; + } + else if (TaskCarState::RESTRICTION_MODE_ON == act.car_state) + { + task = Task::TASK_RESTRICTION_MODE_ON; + break; + } + } + + // If there is the request-less task, set request here + if (Task::TASK_INVALID != task) { + unsigned req_num; + ret = this->setRequest(task, &req_num); + + if(ret != WMError::SUCCESS) + { + goto error; + } + } + for (auto &act : actions) { if ("" != act.role) { bool found; - auto const &surface_id = this->id_alloc.lookup(act.role); + auto const &surface_id = this->id_alloc.lookup(act.role.c_str()); if(surface_id == nullopt) { - goto proc_remove_request; + HMI_SEQ_DEBUG(req_num, "There is not surface id for role:%s", act.role.c_str()); + continue; } + string appid = g_app_list.getAppID(*surface_id, &found); if (!found) { if (TaskVisible::INVISIBLE == act.visible) { - // App is killed, so do not set this action + HMI_SEQ_DEBUG(req_num, "role:%s is killed, so do not set this action", act.role.c_str()); continue; } else { - HMI_SEQ_ERROR(req_num, "appid which is visible is not found"); + HMI_SEQ_ERROR(req_num, "appid of role:%s which is visible is not found", act.role.c_str()); ret = WMError::FAIL; goto error; } @@ -664,6 +1424,20 @@ void WindowManager::startTransitionWrapper(vector<WMAction> &actions) auto client = g_app_list.lookUpClient(appid); act.req_num = req_num; act.client = client; + + if (this->wmcon.getAppIdToEcuName(appid) != "") + { + if (TaskVisible::VISIBLE == act.visible && this->wmcon.getAreaToEcuName(act.area.c_str()) == this->wmcon.getEcuName()) + { + HMI_DEBUG("Set TaskVisible::REQ_REMOTE_VISIBLE"); + act.visible = TaskVisible::REQ_REMOTE_VISIBLE; + } + else + { + HMI_DEBUG("Set TaskVisible::REQ_REMOTE_INVISIBLE"); + act.visible = TaskVisible::REQ_REMOTE_INVISIBLE; + } + } } ret = g_app_list.setAction(req_num, act); @@ -711,22 +1485,246 @@ void WindowManager::processError(WMError error) this->processNextRequest(); } -unsigned WindowManager::generateLayerForClient(const string& role) +void WindowManager::processForRemoteRequest(json_object *data) { - unsigned lid = this->lc->getNewLayerID(role); - if (lid == 0) + const char *req = jh::getStringFromJson(data, "req"); + const char *appid = jh::getStringFromJson(data, "appid"); + const char *drawing_name = jh::getStringFromJson(data, "drawing_name"); + const char *drawing_area = jh::getStringFromJson(data, "drawing_area"); + string request = req; + string role = drawing_name; + string area = drawing_area; + + if (!req || !drawing_name) { - // register drawing_name as fallback and make it displayed. - lid = this->lc->getNewLayerID(string("fallback")); - HMI_DEBUG("%s is not registered in layers.json, then fallback as normal app", role.c_str()); - if (lid == 0) + HMI_ERROR("Parse Error!!"); + return; + } + + if (this->wmcon.getAreaToEcuName(drawing_area) == this->wmcon.getEcuName()) + { + if (!appid) { - return lid; + HMI_ERROR("Parse Error!!"); + return; + } + + auto reply = [](const char *errmsg) { + if (errmsg != nullptr) + { + HMI_ERROR(errmsg); + return; + } + }; + + if ("activateWindow" == request) + { + if (!drawing_area) + { + HMI_ERROR("Parse Error!!"); + return; + } + + this->api_activate_surface_for_slave( + appid, drawing_name, drawing_area, reply); + } + else if ("deactivateWindow" == request) + { + this->api_deactivate_surface_for_slave( + appid, drawing_name, reply); + } + else if ("endDraw" == request) + { + this->api_enddraw(appid, drawing_name); } } - this->lc->createNewLayer(lid); - // add client into the db - return lid; + else + { + if ("syncDraw" == request) + { + this->stopTimer(); + + if (!appid || !drawing_area) + { + HMI_ERROR("Parse Error!!"); + return; + } + + unsigned req_num = g_app_list.currentRequestNumber(); + auto client = g_app_list.lookUpClient(appid); + + // TODO: application requests by old role, + // so convert role old to new + const char *c_role = this->convertRoleOldToNew(drawing_name); + + // Create action + bool end_draw_finished = false; + WMAction act + { + req_num, + client, + string(c_role), + area, + TaskVisible::REMOTE_VISIBLE, + end_draw_finished, + TaskCarState::NO_TASK + }; + + // Set action + WMError ret = g_app_list.setAction(req_num, act); + if (ret != WMError::SUCCESS) + { + HMI_SEQ_ERROR(req_num, "Setting action is failed"); + return; + } + + this->emit_syncdraw(role, area); + this->wmcon.startSyncDrawForRemote(appid); + this->setTimer(); + } + else if ("activated" == request) + { + this->emit_visible(role); + this->emit_activated(area); + } + else if ("deactivated" == request) + { + this->stopTimer(); + + if (!appid || !drawing_area) + { + HMI_ERROR("Parse Error!!"); + return; + } + + unsigned req_num = g_app_list.currentRequestNumber(); + auto client = g_app_list.lookUpClient(appid); + + // TODO: application requests by old role, + // so convert role old to new + const char *c_role = this->convertRoleOldToNew(drawing_name); + + if(!this->lc->hasRemoteLayer(client->layerID())) + { + HMI_DEBUG("Deactivated"); + return; + } + + // Create action + bool end_draw_finished = true; + WMAction act + { + req_num, + client, + string(c_role), + "", + TaskVisible::REMOTE_INVISIBLE, + end_draw_finished, + TaskCarState::NO_TASK + }; + + this->lc->visibilityChange(act); + this->lc->renderLayers(); + + this->emit_invisible(role); + this->emit_deactivated(role); + } + else if ("flushDraw" == request) + { + this->emit_flushdraw(role); + } + } +} + +/* + ******* Private Functions ******* + */ + +void WindowManager::emit_activated(const string& role) +{ + this->send_event(kListEventName[Event_Active], role); +} + +void WindowManager::emit_deactivated(const string& role) +{ + this->send_event(kListEventName[Event_Inactive], role); +} + +void WindowManager::emit_syncdraw(const string& role, char const *area, int x, int y, int w, int h) +{ + this->send_event(kListEventName[Event_SyncDraw], role, area, x, y, w, h); +} + +void WindowManager::emit_syncdraw(const string &role, const string &area) +{ + struct rect rect = this->lc->getAreaSize(area); + this->send_event(kListEventName[Event_SyncDraw], + role.c_str(), area.c_str(), rect.x, rect.y, rect.w, rect.h); +} + +void WindowManager::emit_flushdraw(const string& role) +{ + this->send_event(kListEventName[Event_FlushDraw], role); +} + +void WindowManager::emit_visible(const string& role, bool is_visible) +{ + this->send_event(is_visible ? kListEventName[Event_Visible] : kListEventName[Event_Invisible], role); +} + +void WindowManager::emit_invisible(const string& role) +{ + return emit_visible(role, false); +} + +void WindowManager::emit_visible(const string& role) { return emit_visible(role, true); } + +void WindowManager::emitHeadlampOff() +{ + // Send HeadlampOff event for all application + this->send_event(kListEventName[Event_HeadlampOff]); +} + +void WindowManager::emitHeadlampOn() +{ + // Send HeadlampOn event for all application + this->send_event(kListEventName[Event_HeadlampOn]); +} + +void WindowManager::emitParkingBrakeOff() +{ + // Send ParkingBrakeOff event for all application + this->send_event(kListEventName[Event_ParkingBrakeOff]); +} + +void WindowManager::emitParkingBrakeOn() +{ + // Send ParkingBrakeOn event for all application + this->send_event(kListEventName[Event_ParkingBrakeOn]); +} + +void WindowManager::emitLightstatusBrakeOff() +{ + // Send LightstatusBrakeOff event for all application + this->send_event(kListEventName[Event_LightstatusBrakeOff]); +} + +void WindowManager::emitLightstatusBrakeOn() +{ + // Send LightstatusBrakeOn event for all application + this->send_event(kListEventName[Event_LightstatusBrakeOn]); +} + +void WindowManager::emitCarStop() +{ + // Send CarStop event for all application + this->send_event(kListEventName[Event_CarStop]); +} + +void WindowManager::emitCarRun() +{ + // Send CarRun event for all application + this->send_event(kListEventName[Event_CarRun]); } WMError WindowManager::setRequest(const string& appid, const string &role, const string &area, @@ -761,6 +1759,48 @@ WMError WindowManager::setRequest(const string& appid, const string &role, const return WMError::SUCCESS; } +WMError WindowManager::setRequest(Task task, unsigned* req_num) +{ + /* + * Queueing Phase + */ + unsigned current = g_app_list.currentRequestNumber(); + + WMRequest req = WMRequest(task); + unsigned new_req = g_app_list.addRequest(req); + *req_num = new_req; + g_app_list.reqDump(); + + HMI_SEQ_DEBUG(current, "start sequence for task:%d", task); + + return WMError::SUCCESS; +} + +WMError WindowManager::setRequestForSlave(const string& appid, const string &role, const string &area, + Task task, unsigned* req_num) +{ + /* + * Queueing Phase + */ + unsigned current = g_app_list.currentRequestNumber(); + unsigned requested_num = g_app_list.getRequestNumber(appid); + if (requested_num != 0) + { + HMI_SEQ_INFO(requested_num, + "%s %s %s request is already queued", appid.c_str(), role.c_str(), area.c_str()); + return REQ_REJECTED; + } + + WMRequest req = WMRequest(appid, role, area, task); + unsigned new_req = g_app_list.addRequest(req); + *req_num = new_req; + g_app_list.reqDump(); + + HMI_SEQ_DEBUG(current, "%s start sequence with %s, %s", appid.c_str(), role.c_str(), area.c_str()); + + return WMError::SUCCESS; +} + WMError WindowManager::checkPolicy(unsigned req_num) { /* @@ -777,6 +1817,54 @@ WMError WindowManager::checkPolicy(unsigned req_num) } string req_area = trigger.area; + if (trigger.task == Task::TASK_ALLOCATE) + { + const char *msg = this->check_surface_exist(trigger.role.c_str()); + + if (msg) + { + HMI_SEQ_ERROR(req_num, msg); + return ret; + } + } + + // Input event data to PolicyManager + if (0 > this->pmw.setInputEventData(trigger.task, trigger.role, trigger.area)) + { + HMI_SEQ_ERROR(req_num, "Failed to set input event data to PolicyManager"); + return ret; + } + + // Execute state transition of PolicyManager + if (0 > this->pmw.executeStateTransition()) + { + HMI_SEQ_ERROR(req_num, "Failed to execute state transition of PolicyManager"); + return ret; + } + + ret = WMError::SUCCESS; + + g_app_list.reqDump(); + + return ret; +} + +WMError WindowManager::checkPolicyForSlave(unsigned req_num) +{ + /* + * Check Policy + */ + // get current trigger + bool found = false; + WMError ret = WMError::LAYOUT_CHANGE_FAIL; + auto trigger = g_app_list.getRequest(req_num, &found); + if (!found) + { + ret = WMError::NO_ENTRY; + return ret; + } + string req_area = trigger.area; + // Input event data to PolicyManager if (0 > this->pmw.setInputEventData(trigger.task, trigger.role, trigger.area)) { @@ -815,11 +1903,28 @@ WMError WindowManager::startTransition(unsigned req_num) g_app_list.reqDump(); for (const auto &action : actions) { + // TODO: application requests by old role, + // so convert role new to old for emitting event + string old_role = this->rolenew2old[action.role]; + if (action.visible == TaskVisible::VISIBLE) { sync_draw_happen = true; - struct rect r = this->lc->getAreaSize(action.area); - action.client->emitSyncDraw(action.area, r); + + this->emit_syncdraw(old_role, action.area); + /* TODO: emit event for app not subscriber + if(g_app_list.contains(y.appid)) + g_app_list.lookUpClient(y.appid)->emit_syncdraw(y.role, y.area); */ + } + else if(action.visible == TaskVisible::REQ_REMOTE_VISIBLE) + { + // If this action is for slave, send to slave + this->wmcon.sendRequest("syncDraw", action.client->appID().c_str(), + old_role.c_str(), action.area.c_str()); + } + else if (action.car_state != TaskCarState::NO_TASK) + { + this->transitionCarState(action.car_state); } } @@ -834,7 +1939,28 @@ WMError WindowManager::startTransition(unsigned req_num) for (const auto &x : actions) { this->lc->visibilityChange(x); - x.client->emitVisible(false); + string old_role = this->rolenew2old[x.role]; + + if (x.visible == TaskVisible::INVISIBLE) + { + emit_deactivated(old_role); + } + else if (x.visible == TaskVisible::REQ_REMOTE_INVISIBLE) + { + // If this action is for slave, send to slave + int i_ret = this->wmcon.sendRequest("deactivated", x.client->appID().c_str(), + old_role.c_str(), ""); + if (0 > i_ret) + { + ret = WMError::FAIL; + } + } + + /* if (g_app_list.contains(x.appid)) + { + auto client = g_app_list.lookUpClient(x.appid); + //this->deactivate(client->surfaceID(x.role)); + } */ } this->lc->renderLayers(); ret = WMError::NO_LAYOUT_CHANGE; @@ -842,10 +1968,63 @@ WMError WindowManager::startTransition(unsigned req_num) return ret; } +void WindowManager::transitionCarState(TaskCarState task) +{ + if (TaskCarState::PARKING_BRAKE_OFF == task) + { + this->crr_car_info.parking_brake_stt = false; + this->emitParkingBrakeOff(); + } + else if (TaskCarState::PARKING_BRAKE_ON == task) + { + this->crr_car_info.parking_brake_stt = true; + this->emitParkingBrakeOn(); + } + else if (TaskCarState::ACCEL_PEDAL_OFF == task) + { + this->crr_car_info.accel_pedal_stt = false; + } + else if (TaskCarState::ACCEL_PEDAL_ON == task) + { + this->crr_car_info.accel_pedal_stt = true; + } + else if (TaskCarState::HEDLAMP_OFF == task) + { + this->crr_car_info.headlamp_stt = false; + this->emitHeadlampOff(); + } + else if (TaskCarState::HEDLAMP_ON == task) + { + this->crr_car_info.headlamp_stt = true; + this->emitHeadlampOn(); + } + else if (TaskCarState::LIGHTSTATUS_BRAKE_OFF == task) + { + this->crr_car_info.lightstatus_brake_stt = false; + this->emitLightstatusBrakeOff(); + } + else if (TaskCarState::LIGHTSTATUS_BRAKE_ON == task) + { + this->crr_car_info.lightstatus_brake_stt = true; + this->emitLightstatusBrakeOn(); + } + else if (TaskCarState::CAR_STOP == task) + { + this->crr_car_info.running_stt = false; + this->emitCarStop(); + } + else if (TaskCarState::CAR_RUN == task) + { + this->crr_car_info.running_stt = true; + this->emitCarRun(); + } +} + WMError WindowManager::doEndDraw(unsigned req_num) { // get actions bool found; + bool trigger_homescreen = false; auto actions = g_app_list.getActions(req_num, &found); WMError ret = WMError::SUCCESS; if (!found) @@ -853,6 +2032,13 @@ WMError WindowManager::doEndDraw(unsigned req_num) ret = WMError::NO_ENTRY; return ret; } + auto trigger = g_app_list.getRequest(req_num, &found); + HMI_SEQ_INFO(req_num, "trigger.role = %s", trigger.role.c_str()); + + if(trigger.role == "homescreen") + { + trigger_homescreen = true; + } HMI_SEQ_INFO(req_num, "do endDraw"); @@ -869,8 +2055,46 @@ WMError WindowManager::doEndDraw(unsigned req_num) "Failed to manipulate surfaces while state change : %s", errorDescription(ret)); return ret; } - ret = this->lc->visibilityChange(act); - act.client->emitVisible((act.visible == VISIBLE)); + + if(trigger_homescreen && (act.visible == TaskVisible::INVISIBLE)) + { + HMI_SEQ_NOTICE(req_num, "don't change visible if homescreen role is trigger"); + } + else + { + ret = this->lc->visibilityChange(act); + } + + // Emit active/deactive event + string old_role = this->rolenew2old[act.role]; + switch(act.visible) + { + case TaskVisible::VISIBLE : + emit_visible(old_role); + emit_activated(old_role); + break; + case TaskVisible::REQ_REMOTE_VISIBLE : + { + // If this action is for slave, send to slave + int i_ret = this->wmcon.sendRequest("activated", "", old_role.c_str(), ""); + if (0 > i_ret) + { + ret = WMError::FAIL; + } + break; + } + case TaskVisible::INVISIBLE : + if(!trigger_homescreen) + { + emit_invisible(old_role); + emit_deactivated(old_role); + } + break; + default : + // TaskVisible::REMOTE_VISIBLE, TaskVisible::REMOTE_INVISIBLE is this case + // If this action is for slave, send to slave + break; + } if (ret != WMError::SUCCESS) { @@ -887,9 +2111,18 @@ WMError WindowManager::doEndDraw(unsigned req_num) for(const auto &act_flush : actions) { + // TODO: application requests by old role, + // so convert role new to old for emitting event + string old_role = this->rolenew2old[act_flush.role]; + if(act_flush.visible == TaskVisible::VISIBLE) { - act_flush.client->emitFlushDraw(); + this->emit_flushdraw(old_role); + } + else if(act_flush.visible == TaskVisible::REQ_REMOTE_VISIBLE) + { + // If this action is for slave, send to slave + this->wmcon.sendRequest("flushDraw", "", old_role.c_str(), ""); } } @@ -902,7 +2135,8 @@ void WindowManager::emitScreenUpdated(unsigned req_num) HMI_SEQ_DEBUG(req_num, "emit screen updated"); bool found = false; auto actions = g_app_list.getActions(req_num, &found); - if (!found) + + if(!found) { HMI_SEQ_ERROR(req_num, "Window Manager bug :%s : Action is not set", @@ -910,13 +2144,15 @@ void WindowManager::emitScreenUpdated(unsigned req_num) return; } + HMI_DEBUG("@@@@@"); // create json object json_object *j = json_object_new_object(); json_object *jarray = json_object_new_array(); for(const auto& action: actions) { - if(action.visible != TaskVisible::INVISIBLE) + if((action.visible == TaskVisible::VISIBLE) || + (action.visible == TaskVisible::REMOTE_VISIBLE)) { json_object_array_add(jarray, json_object_new_string(action.client->appID().c_str())); } @@ -926,7 +2162,7 @@ void WindowManager::emitScreenUpdated(unsigned req_num) int ret = afb_event_push( this->map_afb_event[kListEventName[Event_ScreenUpdated]], j); - if (ret < 0) + if (ret != 0) { HMI_DEBUG("afb_event_push failed: %m"); } @@ -944,7 +2180,7 @@ void WindowManager::setTimer() if (g_timer_ev_src == nullptr) { // firsttime set into sd_event - int ret = sd_event_add_time(afb_api_get_event_loop(afbBindingV3root), &g_timer_ev_src, + int ret = sd_event_add_time(afb_daemon_get_event_loop(), &g_timer_ev_src, CLOCK_BOOTTIME, (uint64_t)(ts.tv_sec + kTimeOut) * 1000000ULL, 1, processTimerHandler, this); if (ret < 0) { @@ -990,4 +2226,374 @@ void WindowManager::processNextRequest() } } +const char* WindowManager::convertRoleOldToNew(char const *old_role) +{ + const char *new_role = nullptr; + + for (auto const &on : this->roleold2new) + { + std::regex regex = std::regex(on.first); + if (std::regex_match(old_role, regex)) + { + // role is old. So convert to new. + new_role = on.second.c_str(); + break; + } + } + + if (nullptr == new_role) + { + // role is new or fallback. + new_role = old_role; + } + + HMI_DEBUG("old:%s -> new:%s", old_role, new_role); + + return new_role; +} + +int WindowManager::loadOldRolesConfigFile() +{ + // Get afm application installed dir + char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR"); + HMI_DEBUG("afm_app_install_dir:%s", afm_app_install_dir); + + string file_name; + if (!afm_app_install_dir) + { + HMI_ERROR("AFM_APP_INSTALL_DIR is not defined"); + } + else + { + file_name = string(afm_app_install_dir) + string(kPathOldRolesConfigFile); + } + + // Load old_rolea config file + json_object* json_obj; + int ret = jh::inputJsonFilie(file_name.c_str(), &json_obj); + if (0 > ret) + { + HMI_ERROR("Could not open %s, so use default old_roles information", kPathOldRolesConfigFile); + json_obj = json_tokener_parse(kDefaultOldRolesConfig); + } + HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj)); + + // Perse apps + json_object* json_cfg; + if (!json_object_object_get_ex(json_obj, "old_roles", &json_cfg)) + { + HMI_ERROR("Parse Error!!"); + return -1; + } + + int len = json_object_array_length(json_cfg); + HMI_DEBUG("json_cfg len:%d", len); + HMI_DEBUG("json_cfg dump:%s", json_object_get_string(json_cfg)); + + for (int i=0; i<len; i++) + { + json_object* json_tmp = json_object_array_get_idx(json_cfg, i); + + const char* old_role = jh::getStringFromJson(json_tmp, "name"); + if (nullptr == old_role) + { + HMI_ERROR("Parse Error!!"); + return -1; + } + + const char* new_role = jh::getStringFromJson(json_tmp, "new"); + if (nullptr == new_role) + { + HMI_ERROR("Parse Error!!"); + return -1; + } + + this->roleold2new[old_role] = string(new_role); + } + + // Check + for(auto itr = this->roleold2new.begin(); + itr != this->roleold2new.end(); ++itr) + { + HMI_DEBUG(">>> role old:%s new:%s", + itr->first.c_str(), itr->second.c_str()); + } + + // Release json_object + json_object_put(json_obj); + + return 0; +} + +int WindowManager::saveLastModeData(unsigned req_num) +{ + bool found; + auto actions = g_app_list.getActions(req_num, &found); + + HMI_DEBUG("Save LastMode data"); + + if (!found) + { + HMI_DEBUG("Not Found Entry"); + return -1; + } + + json_object *j_obj = json_object_new_object(); + json_object *j_array = json_object_new_array(); + + for (const auto &act : actions) + { + if (act.visible == TaskVisible::VISIBLE) + { + unsigned layer = act.client->layerID(); + unsigned surface = act.client->surfaceID(); + + t_ilm_bool visibility; + + ilm_layerGetVisibility(layer, &visibility); + + if (visibility == ILM_FALSE) + { + continue; + } + + ilmSurfaceProperties sp; + ilm_getPropertiesOfSurface(surface, &sp); + + json_object *j_array_obj = json_object_new_object(); + json_object_object_add(j_array_obj, "role", json_object_new_string(act.role.c_str())); + json_object_object_add(j_array_obj, "visible", + json_object_new_string((visibility ? "true" : "false"))); + json_object_object_add(j_array_obj, "area", json_object_new_string(act.area.c_str())); + json_object_object_add(j_array_obj, "destX", json_object_new_int(sp.destX)); + json_object_object_add(j_array_obj, "destY", json_object_new_int(sp.destY)); + json_object_object_add(j_array_obj, "destWidth", json_object_new_int(sp.destWidth)); + json_object_object_add(j_array_obj, "destHeight", json_object_new_int(sp.destHeight)); + json_object_object_add(j_array_obj, "sourceX", json_object_new_int(sp.sourceX)); + json_object_object_add(j_array_obj, "sourceY", json_object_new_int(sp.sourceY)); + json_object_object_add(j_array_obj, "sourceWidth", json_object_new_int(sp.sourceWidth)); + json_object_object_add(j_array_obj, "sourceHeight", json_object_new_int(sp.sourceHeight)); + + json_object_array_add(j_array, j_array_obj); + } + } + + json_object_object_add(j_obj, "LastModeData", j_array); + + const char *buf = json_object_to_json_string(j_obj); + + std::string root = getenv("AFM_APP_INSTALL_DIR"); + std::string lastmode_path = root + WM_LASTMODE_PATH; + + FILE *fp = fopen(lastmode_path.c_str(), "wb"); + if (nullptr == fp) + { + HMI_ERROR("Could not open file"); + return -1; + } + + int len = strlen(buf); + fwrite(buf, len, 1, fp); + + fclose(fp); + + json_object_put(j_obj); + + return 0; +} + +Task WindowManager::convertCanSignalToCarStateTask(const char *signal_name) +{ + wm::LowCanClient *lcc = &(this->lcc); + Task task = Task::TASK_INVALID; + + // If car info is updated, set car state change event + if (strstr(signal_name, lcc->kSignalName[lcc->SignalNoParkingBrake])) + { + HMI_DEBUG("Parking Brake state is changed"); + + if (lcc->getCurrentParkingBrakeState()) + { + task = wm::Task::TASK_PARKING_BRAKE_ON; + } + else + { + task = wm::Task::TASK_PARKING_BRAKE_OFF; + } + } + else if (strstr(signal_name, lcc->kSignalName[lcc->SignalNoAccelPedalPos])) + { + // Update accel pedal position + this->crr_car_info.accel_pedal_pos = lcc->getCurrentAccelPedalPosition(); + + if (lcc->isChangedAccelPedalState()) + { + HMI_DEBUG("Accelerator Pedal state is changed"); + + if (lcc->getCurrentAccelPedalState()) + { + task = wm::Task::TASK_ACCEL_PEDAL_ON; + } + else + { + task = wm::Task::TASK_ACCEL_PEDAL_OFF; + } + } + } + else if (strstr(signal_name, lcc->kSignalName[lcc->SignalNoHeadlame])) + { + HMI_DEBUG("Headlamp state is changed"); + + if (lcc->getCurrentHeadlampState()) + { + task = wm::Task::TASK_HEDLAMP_ON; + } + else + { + task = wm::Task::TASK_HEDLAMP_OFF; + } + } + else if (strstr(signal_name, lcc->kSignalName[lcc->SignalNoLightstatusBrake])) + { + HMI_DEBUG("Lightstatus Brake state is changed"); + + if (lcc->getCurrentLightstatusBrakeState()) + { + task = wm::Task::TASK_LIGHTSTATUS_BRAKE_ON; + } + else + { + task = wm::Task::TASK_LIGHTSTATUS_BRAKE_OFF; + } + } + return task; +} + +void WindowManager::inputCarStateTask(Task task) +{ + unsigned req_num = 0; + WMError ret = WMError::UNKNOWN; + + ret = this->setRequest(task, &req_num); + + if(ret != WMError::SUCCESS) + { + HMI_ERROR(errorDescription(ret)); + return; + } + + if (req_num != g_app_list.currentRequestNumber()) + { + // Add request, then invoked after the previous task is finished + HMI_SEQ_DEBUG(req_num, "request is accepted"); + return; + } + + /* + * Do allocate tasks + */ + ret = this->checkPolicy(req_num); + + if (ret != WMError::SUCCESS) + { + //this->emit_error() + HMI_SEQ_ERROR(req_num, errorDescription(ret)); + g_app_list.removeRequest(req_num); + this->processNextRequest(); + } +} + +const char *WindowManager::check_surface_exist(const char *drawing_name) +{ + auto const &surface_id = this->id_alloc.lookup(string(drawing_name)); + if (!surface_id) + { + return "Surface does not exist"; + } + + /* if (!this->controller->surface_exists(*surface_id)) + { + return "Surface does not exist in controller!"; + } */ + + /* auto layer_id = this->layers.get_layer_id(*surface_id); + + if (!layer_id) + { + return "Surface is not on any layer!"; + } */ + + HMI_DEBUG("surface %d is detected", *surface_id); + return nullptr; +} + +const char* WindowManager::kDefaultOldRolesConfig = "{ \ + \"old_roles\": [ \ + { \ + \"name\": \"HomeScreen\", \ + \"new\": \"homescreen\" \ + }, \ + { \ + \"name\": \"Music\", \ + \"new\": \"music\" \ + }, \ + { \ + \"name\": \"MediaPlayer\", \ + \"new\": \"music\" \ + }, \ + { \ + \"name\": \"Video\", \ + \"new\": \"video\" \ + }, \ + { \ + \"name\": \"VideoPlayer\", \ + \"new\": \"video\" \ + }, \ + { \ + \"name\": \"WebBrowser\", \ + \"new\": \"browser\" \ + }, \ + { \ + \"name\": \"Radio\", \ + \"new\": \"radio\" \ + }, \ + { \ + \"name\": \"Phone\", \ + \"new\": \"phone\" \ + }, \ + { \ + \"name\": \"Navigation\", \ + \"new\": \"map\" \ + }, \ + { \ + \"name\": \"HVAC\", \ + \"new\": \"hvac\" \ + }, \ + { \ + \"name\": \"Settings\", \ + \"new\": \"settings\" \ + }, \ + { \ + \"name\": \"Dashboard\", \ + \"new\": \"dashboard\" \ + }, \ + { \ + \"name\": \"POI\", \ + \"new\": \"poi\" \ + }, \ + { \ + \"name\": \"Mixer\", \ + \"new\": \"mixer\" \ + }, \ + { \ + \"name\": \"Restriction\", \ + \"new\": \"restriction\" \ + }, \ + { \ + \"name\": \"^OnScreen.*\", \ + \"new\": \"on_screen\" \ + } \ + ] \ +}"; + } // namespace wm diff --git a/src/window_manager.hpp b/src/window_manager.hpp index 4c2c49b..da6a267 100644 --- a/src/window_manager.hpp +++ b/src/window_manager.hpp @@ -27,6 +27,8 @@ #include "request.hpp" #include "wm_error.hpp" #include "wm_layer_control.hpp" +#include "wm_connection.hpp" +#include "low_can_client.hpp" extern "C" { #include <afb/afb-binding.h> @@ -131,7 +133,37 @@ struct id_allocator struct TmpClient { std::string appid; - unsigned layer; + unsigned pid; +}; + +struct TmpService +{ + std::string appid; // Used to search who create service surface + std::string dest; // Used to attach service to destination application + std::string service;// The name of service surface + std::string uuid; // uuid + TmpService(const std::string& app, const std::string& dst, + const std::string& svc, const std::string& uuid) + : appid(app), dest(dst), service(svc), uuid(uuid) {} +}; + +struct CarInfo +{ + CarInfo() + : parking_brake_stt(true), + accel_pedal_stt(false), + accel_pedal_pos(0.0), + running_stt(false), + headlamp_stt(false), + lightstatus_brake_stt(true) + {}; + + bool parking_brake_stt; + bool accel_pedal_stt; + double accel_pedal_pos; + bool running_stt; + bool headlamp_stt; + bool lightstatus_brake_stt; }; class WindowManager @@ -155,14 +187,33 @@ class WindowManager Event_ScreenUpdated, + Event_Handshake, + + Event_HeadlampOff, + Event_HeadlampOn, + + Event_ParkingBrakeOff, + Event_ParkingBrakeOn, + + Event_LightstatusBrakeOff, + Event_LightstatusBrakeOn, + + Event_CarStop, + Event_CarRun, + Event_Error, Event_Val_Max = Event_Error, }; + enum WM_Mode + { + Mode_Standalone = 0, + Mode_Connection, + }; + explicit WindowManager(); ~WindowManager() = default; - WindowManager(WindowManager const &) = delete; WindowManager &operator=(WindowManager const &) = delete; WindowManager(WindowManager &&) = delete; @@ -172,33 +223,81 @@ class WindowManager result<int> api_request_surface(char const *appid, char const *role); char const *api_request_surface(char const *appid, char const *role, char const *ivi_id); + bool api_set_role(char const *appid, char const *role); void api_activate_window(char const *appid, char const *role, char const *drawing_area, const reply_func &reply); + void api_activate_surface_for_slave(char const *appid, char const *drawing_name, + char const *drawing_area, const reply_func &reply); + void api_activate_surface_to_master(char const *appid, char const *drawing_name, + char const *drawing_area, const reply_func &reply); void api_deactivate_window(char const *appid, char const *role, const reply_func &reply); + void api_deactivate_surface_for_slave(char const *appid, char const *drawing_name, + const reply_func &reply); + void api_deactivate_surface_to_master(char const *appid, char const *drawing_name, + const reply_func &reply); void api_enddraw(char const *appid, char const *role); + int api_subscribe(afb_req req, int event_id); + void api_handshake(); + void api_enddraw_for_remote(char const *appid, char const *drawing_name); + bool api_client_set_render_order(const char *appid, const std::vector<std::string> &render_order); + std::string api_client_attach_service_surface(const char* appid, const char* dest, const char* service_surface); json_object* api_get_area_list(); void api_change_area_size(ChangeAreaReq &areas); - bool api_subscribe(afb_req_t req, EventType event_id); result<json_object *> api_get_display_info(); result<json_object *> api_get_area_info(char const *role); + result<json_object *> api_get_car_info(char const *label); + void send_event(const std::string& evname); + void send_event(const std::string& evname, const std::string& role); + void send_event(const std::string& evname, const std::string& role, const std::string& area, int x, int y, int w, int h); // Events from the compositor we are interested in - void surface_created(unsigned surface_id); + void surface_created(unsigned pid, unsigned surface_id); void surface_removed(unsigned surface_id); void removeClient(const std::string &appid); void exceptionProcessForTransition(); + const char* convertRoleOldToNew(char const *role); + + void analyzeReceivedEvent(const char *event, struct json_object *object); + // Do not use this function void timerHandler(); void startTransitionWrapper(std::vector<WMAction> &actions); void processError(WMError error); + void processForRemoteRequest(json_object *data); + std::string searchApp(unsigned pid, unsigned ppid, unsigned surface, json_object* resp); + void storeSurface(const std::string& appid, unsigned ppid, unsigned surface); + + WMConnection wmcon; private: - unsigned generateLayerForClient(const std::string &role); + // WM Events to clients + void emit_activated(const std::string& role); + void emit_deactivated(const std::string& role); + void emit_syncdraw(const std::string& role, char const *area, int x, int y, int w, int h); + void emit_syncdraw(const std::string &role, const std::string &area); + void emit_flushdraw(const std::string& role); + void emit_visible(const std::string& role, bool is_visible); + void emit_invisible(const std::string& role); + void emit_visible(const std::string& role); + void emitHeadlampOff(); + void emitHeadlampOn(); + void emitParkingBrakeOff(); + void emitParkingBrakeOn(); + void emitLightstatusBrakeOff(); + void emitLightstatusBrakeOn(); + void emitCarStop(); + void emitCarRun(); + WMError setRequest(const std::string &appid, const std::string &role, const std::string &area, Task task, unsigned *req_num); + WMError setRequest(Task task, unsigned* req_num); + WMError setRequestForSlave(const std::string& appid, const std::string &role, + const std::string &area, Task task, unsigned* req_num); WMError checkPolicy(unsigned req_num); + WMError checkPolicyForSlave(unsigned req_num); WMError startTransition(unsigned req_num); + void transitionCarState(TaskCarState task); WMError doEndDraw(unsigned req_num); void emitScreenUpdated(unsigned req_num); @@ -207,16 +306,34 @@ class WindowManager void stopTimer(); void processNextRequest(); + int loadOldRolesConfigFile(); + + int saveLastModeData(unsigned req_num); + + Task convertCanSignalToCarStateTask(const char *signal_name); + void inputCarStateTask(Task task); + + const char *check_surface_exist(const char *role); + private: - std::map<std::string, afb_event_t> map_afb_event; - std::unordered_map<std::string, struct rect> area2size; + std::map<std::string, struct afb_event> map_afb_event; + std::unordered_map<std::string, std::string> roleold2new; + std::unordered_map<std::string, std::string> rolenew2old; std::shared_ptr<LayerControl> lc; + + LowCanClient lcc; + CarInfo crr_car_info; + PMWrapper pmw; rect_map area_info; struct id_allocator id_alloc; + bool end_init; + // ID allocation and proxy methods for lookup std::unordered_map<unsigned, struct TmpClient> tmp_surface2app; + std::vector<struct TmpService> tmp_services; + static const char* kDefaultOldRolesConfig; }; } // namespace wm diff --git a/src/wm_client.cpp b/src/wm_client.cpp index 4bccb8c..3acf09e 100644 --- a/src/wm_client.cpp +++ b/src/wm_client.cpp @@ -16,7 +16,10 @@ #include <json-c/json.h> #include "wm_client.hpp" +#include "util.hpp" #include <ilm/ilm_control.h> +#include <uuid/uuid.h> + #define INVALID_SURFACE_ID 0 @@ -26,34 +29,19 @@ using std::vector; namespace wm { -static const char kActive[] = "active"; -static const char kInactive[] = "inactive"; -static const char kVisible[] = "visible"; -static const char kInvisible[] = "invisible"; -static const char kSyncDraw[] = "syncDraw"; -static const char kFlushDraw[] = "flushDraw"; +static const vector<string> kWMEvents = { + // Private event for applications + "syncDraw", "flushDraw", "visible", "invisible", "active", "inactive", "error"}; +static const vector<string> kErrorDescription = { + "unknown-error"}; + static const char kKeyDrawingName[] = "drawing_name"; -static const char kKeyDrawingArea[] = "drawing_area"; -static const char kKeyRole[] = "role"; -static const char kKeyArea[] = "area"; static const char kKeyrole[] = "role"; static const char kKeyError[] = "error"; -static const char kKeyErrorDesc[] = "errorDescription"; -static const char kKeyX[] = "x"; -static const char kKeyY[] = "y"; -static const char kKeyWidth[] = "width"; -static const char kKeyHeight[] = "height"; -static const char kKeyDrawingRect[] = "drawing-rect"; - -static const vector<string> kWMEvents = { - // Private event for applications - kActive, kInactive, - kVisible, kInvisible, - kSyncDraw, kFlushDraw, - kKeyError}; +static const char kKeyErrorDesc[] = "kErrorDescription"; WMClient::WMClient(const string &appid, unsigned layer, unsigned surface, const string &role) - : id(appid), layer(layer), is_source_set(false), + : id(appid), layer(layer), role2surface(0) { role2surface[role] = surface; @@ -62,7 +50,7 @@ WMClient::WMClient(const string &appid, unsigned layer, unsigned surface, const #if GTEST_ENABLED string ev = x; #else - afb_event_t ev = afb_api_make_event(afbBindingV3root, x.c_str()); + afb_event ev = afb_daemon_make_event(x.c_str()); #endif evname2afb_event[x] = ev; } @@ -71,9 +59,6 @@ WMClient::WMClient(const string &appid, unsigned layer, unsigned surface, const WMClient::WMClient(const string &appid, const string &role) : id(appid), layer(0), - is_source_set(false), - is_active(false), - main_role(role), role2surface(0), evname2afb_event(0) { @@ -83,7 +68,7 @@ WMClient::WMClient(const string &appid, const string &role) #if GTEST_ENABLED string ev = x; #else - afb_event_t ev = afb_api_make_event(afbBindingV3root, x.c_str()); + afb_event ev = afb_daemon_make_event(x.c_str()); #endif evname2afb_event[x] = ev; } @@ -92,8 +77,6 @@ WMClient::WMClient(const string &appid, const string &role) WMClient::WMClient(const string &appid, unsigned layer, const string &role) : id(appid), layer(layer), - is_source_set(false), - is_active(false), main_role(role), role2surface(0), evname2afb_event(0) @@ -104,7 +87,7 @@ WMClient::WMClient(const string &appid, unsigned layer, const string &role) #if GTEST_ENABLED string ev = x; #else - afb_event_t ev = afb_api_make_event(afbBindingV3root, x.c_str()); + afb_event ev = afb_daemon_make_event(x.c_str()); #endif evname2afb_event[x] = ev; } @@ -120,45 +103,16 @@ string WMClient::role() const return this->main_role; } -void WMClient::setRole(const string& role) -{ - this->main_role = role; -} - unsigned WMClient::layerID() const { return this->layer; } -void WMClient::setLayerID(unsigned id) -{ - this->layer = id; -} - unsigned WMClient::surfaceID() const { return this->surface; } -void WMClient::registerSurface(unsigned surface) -{ - this->surface = surface; -} - -void WMClient::activate() -{ - if(!this->isActive()) - this->emitActive(true); // emit when state is changed - this->is_active = true; -} - -void WMClient::deactivate() -{ - if(this->isActive()) - this->emitActive(false); // emit when state is changed - this->is_active = false; -} - /** * Add surface to the client * @@ -179,16 +133,6 @@ WMError WMClient::addSurface(unsigned surface) return (err == ILM_SUCCESS) ? WMError::SUCCESS : WMError::FAIL; } -void WMClient::setSurfaceSizeCorrectly() -{ - this->is_source_set = true; -} - -bool WMClient::isSourceSizeSet() -{ - return this->is_source_set; -} - bool WMClient::removeSurfaceIfExist(unsigned surface) { bool ret = false; @@ -197,152 +141,131 @@ bool WMClient::removeSurfaceIfExist(unsigned surface) this->surface = INVALID_SURFACE_ID; ret = true; } - return ret; -} - -bool WMClient::subscribe(afb_req_t req, const string &evname) -{ - int ret = afb_req_subscribe(req, this->evname2afb_event[evname]); - if (ret) + else { - HMI_DEBUG("Failed to subscribe %s", evname.c_str()); - return false; + for(auto &x : this->service2surfaces) + { + if(x.second == surface) + { + ret = true; + string key = x.first; + this->service2surfaces.erase(key); + this->service2supplier.erase(key); + } + } } - return true; + return ret; } -void WMClient::emitVisible(bool visible) +WMError WMClient::setRenderOrder(const vector<string> &order) { - // error check - bool allow_send = false; - if(visible) + WMError ret = WMError::SUCCESS; + this->surface_render_order.clear(); + for(const auto& x : order) { - allow_send = afb_event_is_valid(this->evname2afb_event[kVisible]); - } - else - { - allow_send = afb_event_is_valid(this->evname2afb_event[kInvisible]); - } - if(allow_send) - { - json_object* j = json_object_new_object(); - json_object_object_add(j, kKeyRole, json_object_new_string(this->role().c_str())); - json_object_object_add(j, kKeyDrawingName, json_object_new_string(this->role().c_str())); - - if(visible) + unsigned s; // surface + if(x == this->role()) { - afb_event_push(this->evname2afb_event[kVisible], j); + s = this->surfaceID(); + } + else if(this->service2surfaces.count(x) != 0) + { + s = this->service2surfaces[x]; } else { - afb_event_push(this->evname2afb_event[kInvisible], j); + ret = WMError::NOT_REGISTERED; + break; } + this->surface_render_order.push_back(s); } - else - { - HMI_ERROR("Failed to send %s", __func__); - } -} - -void WMClient::emitActive(bool active) -{ - // error check - bool allow_send = false; - if(active) - { - allow_send = afb_event_is_valid(this->evname2afb_event[kActive]); - } - else + if(ret == WMError::SUCCESS) { - allow_send = afb_event_is_valid(this->evname2afb_event[kInactive]); - } - if(allow_send) - { - json_object* j = json_object_new_object(); - json_object_object_add(j, kKeyRole, json_object_new_string(this->role().c_str())); - json_object_object_add(j, kKeyDrawingName, json_object_new_string(this->role().c_str())); - - if(active) + int count = 0; + t_ilm_layer* id_array = new t_ilm_surface[this->surface_render_order.size()]; + if(id_array == nullptr) { - afb_event_push(this->evname2afb_event[kActive], j); + HMI_WARNING("short memory"); + ret = WMError::FAIL; } else { - afb_event_push(this->evname2afb_event[kInactive], j); + for(const auto& i : this->surface_render_order) + { + id_array[count] = i; + ++count; + } + ilm_layerSetRenderOrder(this->layerID(), + id_array, this->surface_render_order.size()); + delete id_array; } } - else - { - HMI_ERROR("Failed to send %s", __func__); - } + return ret; } -void WMClient::emitSyncDraw(const string& area, struct rect& r) +string WMClient::attachTmpServiceSurface(const string& supplier, const string& service_surface) { - HMI_NOTICE("trace"); - if(afb_event_is_valid(this->evname2afb_event[kSyncDraw])) - { - json_object *j_rect = json_object_new_object(); - json_object_object_add(j_rect, kKeyX, json_object_new_int(r.x)); - json_object_object_add(j_rect, kKeyY, json_object_new_int(r.y)); - json_object_object_add(j_rect, kKeyWidth, json_object_new_int(r.w)); - json_object_object_add(j_rect, kKeyHeight, json_object_new_int(r.h)); - - json_object* j = json_object_new_object(); - json_object_object_add(j, kKeyRole, json_object_new_string(this->role().c_str())); - json_object_object_add(j, kKeyDrawingName, json_object_new_string(this->role().c_str())); - json_object_object_add(j, kKeyDrawingArea, json_object_new_string(area.c_str())); - json_object_object_add(j, kKeyArea, json_object_new_string(this->role().c_str())); + string uuid; + uuid_t u; + char out[37]; // uuid is 36 characters + uuid_generate_random(u); + uuid_unparse(u, out); + uuid = out; + this->service2supplier.emplace(service_surface, supplier); + return uuid; +} - json_object_object_add(j, kKeyDrawingRect, j_rect); - afb_event_push(this->evname2afb_event[kSyncDraw], j); - } - else +WMError WMClient::attachServiceSurface(const string& service_surface, unsigned surface) +{ + WMError ret = WMError::NOT_REGISTERED; + if(this->service2supplier.count(service_surface) != 0) { - HMI_ERROR("Failed to send %s", __func__); + this->service2surfaces.emplace(service_surface, surface); + ret = WMError::SUCCESS; } + return ret; } -void WMClient::emitFlushDraw() +#if GTEST_ENABLED +bool WMClient::subscribe(afb_req req, const string &evname) { - if(afb_event_is_valid(this->evname2afb_event[kFlushDraw])) - { - json_object* j = json_object_new_object(); - json_object_object_add(j, kKeyRole, json_object_new_string(this->role().c_str())); - json_object_object_add(j, kKeyDrawingName, json_object_new_string(this->role().c_str())); - afb_event_push(this->evname2afb_event[kFlushDraw], nullptr); + if(evname != kKeyError){ + HMI_DEBUG("error is only enabeled for now"); + return false; } - else + int ret = afb_req_subscribe(req, this->evname2afb_event[evname]); + if (ret) { - HMI_ERROR("Failed to send %s", __func__); + HMI_DEBUG("Failed to subscribe %s", evname.c_str()); + return false; } + return true; } -void WMClient::emitError(WMError error) +void WMClient::emitError(WM_CLIENT_ERROR_EVENT ev) { if (!afb_event_is_valid(this->evname2afb_event[kKeyError])){ HMI_ERROR("event err is not valid"); return; } json_object *j = json_object_new_object(); - json_object_object_add(j, kKeyError, json_object_new_int(error)); - json_object_object_add(j, kKeyErrorDesc, json_object_new_string(errorDescription(error))); - HMI_DEBUG("error: %d, description:%s", error, errorDescription(error)); + json_object_object_add(j, kKeyError, json_object_new_int(ev)); + json_object_object_add(j, kKeyErrorDesc, json_object_new_string(kErrorDescription[ev].c_str())); + HMI_DEBUG("error: %d, description:%s", ev, kErrorDescription[ev].c_str()); + int ret = afb_event_push(this->evname2afb_event[kKeyError], j); if (ret != 0) { HMI_DEBUG("afb_event_push failed: %m"); } } +#endif void WMClient::dumpInfo() { DUMP("APPID : %s", id.c_str()); DUMP(" LAYER : %d", layer); - for (const auto &x : this->role2surface) - { - DUMP(" ROLE : %s , SURFACE : %d", x.first.c_str(), x.second); - } + DUMP(" ROLE : %s , SURFACE : %d", main_role.c_str(), surface); } } // namespace wm
\ No newline at end of file diff --git a/src/wm_client.hpp b/src/wm_client.hpp index 7df4dea..fc171f4 100644 --- a/src/wm_client.hpp +++ b/src/wm_client.hpp @@ -20,17 +20,22 @@ #include <vector> #include <string> #include <unordered_map> -#include "util.hpp" #include "wm_error.hpp" extern "C" { +#define AFB_BINDING_VERSION 2 #include <afb/afb-binding.h> } namespace wm { +enum WM_CLIENT_ERROR_EVENT +{ + UNKNOWN_ERROR +}; + class WMClient { public: @@ -45,47 +50,43 @@ class WMClient std::string appID() const; std::string role() const; - void setRole(const std::string& role); unsigned layerID() const; - void setLayerID(unsigned id); unsigned surfaceID() const; - void registerSurface(unsigned surface); - void activate(); - void deactivate(); - std::string area() const {return this->app_area;}; - void setArea(const std::string area) {this->app_area = area;} + // void setRole(const std::string& role); + // void appendRole(const std::string& role); WMError addSurface(unsigned surface); - bool isSourceSizeSet(); - void setSurfaceSizeCorrectly(); - bool isActive() { return this->is_active;} bool removeSurfaceIfExist(unsigned surface); + // bool removeRole(const std::string& role); + std::vector<unsigned> renderOrder() const; + WMError setRenderOrder(const std::vector<std::string>& order); + std::string attachTmpServiceSurface(const std::string& from, const std::string& service_surface); + WMError attachServiceSurface(const std::string& service_surface, unsigned surface); - bool subscribe(afb_req_t req, const std::string &event_name); - void emitActive(bool active); - void emitVisible(bool visible); - void emitSyncDraw(const std::string& area, struct rect& r); - void emitFlushDraw(); - void emitError(WMError error); +#if GTEST_ENABLED + bool subscribe(afb_req req, const std::string &event_name); + void emitError(WM_CLIENT_ERROR_EVENT ev); +#endif void dumpInfo(); private: std::string id; unsigned layer; - bool is_source_set; - bool is_active; std::string main_role; - std::string app_area; + std::string area; unsigned surface; // currently, main application has only one surface. //std::vector<std::string> role_list; + std::vector<unsigned> surface_render_order; + std::unordered_map<std::string, unsigned> service2surfaces; std::unordered_map<std::string, unsigned> role2surface; + std::unordered_map<std::string, std::string> service2supplier; #if GTEST_ENABLED // This is for unit test. afb_make_event occurs sig11 if call not in afb-binding std::unordered_map<std::string, std::string> evname2afb_event; #else - std::unordered_map<std::string, afb_event_t> evname2afb_event; + std::unordered_map<std::string, struct afb_event> evname2afb_event; #endif }; } // namespace wm -#endif +#endif
\ No newline at end of file diff --git a/src/wm_connection.cpp b/src/wm_connection.cpp new file mode 100644 index 0000000..af970f5 --- /dev/null +++ b/src/wm_connection.cpp @@ -0,0 +1,845 @@ +/* + * Copyright (c) 2017 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wm_connection.hpp" +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include "json_helper.hpp" +#include "util.hpp" + +extern "C" +{ +#include <afb/afb-binding.h> +#include <systemd/sd-event.h> +} + + +/** + * namespace wm + */ +namespace wm +{ + + +namespace +{ + +static const char kPathConnectionConfigFile[] = "/etc/hmi-config/connection.json"; +static const char kPathTimeoutConfigFile[] = "/etc/timeout.json"; +static const char kDefaultIpAddr[] = "192.168.10.10"; +static const int kDefaultPort = 4000; +static const uint64_t kDefaultTimes = 60000; +static const uint64_t kDefaultSleep = 50; +static struct sd_event_source *g_limit_timer_src = nullptr; +static struct sd_event_source *g_sleep_timer_src = nullptr; + +static int setTimer(sd_event_source **src, uint64_t usec, void* handler, void* data) +{ + int ret = sd_event_add_time(afb_daemon_get_event_loop(), src, + CLOCK_BOOTTIME, usec, 1, (sd_event_time_handler_t)handler, data); + + if (ret < 0) + { + HMI_ERROR("Colud't set timer"); + } + + return ret; +} + +static void updateTimer(sd_event_source *src, uint64_t usec) +{ + sd_event_source_set_time(src, usec); + sd_event_source_set_enabled(src, SD_EVENT_ONESHOT); +} + +static void stopEvent(sd_event_source *src) +{ + int ret = sd_event_source_set_enabled(src, SD_EVENT_OFF); + if (ret < 0) + { + HMI_ERROR("Not set SD_EVENT_OFF (%s)", strerror(-ret)); + } + sd_event_source_unref(src); +} + +static int onIoEventReceive(sd_event_source *src, int fd, uint32_t revents, void * data) +{ + WMConnection *p_wmcon = (WMConnection*)data; + + json_object *j_out[10]; + int j_cnt; + int ret = p_wmcon->receive(j_out, &j_cnt, fd); + if (0 > ret) + { + return 0; + } + + for(int i = 0; i < j_cnt; i++) + { + const char* rq = jh::getStringFromJson(j_out[i], "req"); + const char* id = jh::getStringFromJson(j_out[i], "appid"); + const char* dn = jh::getStringFromJson(j_out[i], "drawing_name"); + const char* da = jh::getStringFromJson(j_out[i], "drawing_area"); + + HMI_DEBUG("req:%s appid:%s, drawing_name:%s, drawing_area:%s", rq, id, dn, da); + + // Callback + p_wmcon->callOnReceivedHandler(j_out[i]); + } + + return 0; +} + +static int onIoEventAccept(sd_event_source *src, int fd, uint32_t revents, void * data) +{ + WMConnection *p_wmcon = (WMConnection*)data; + + p_wmcon->serverAccept(fd); + + return 0; +} + +static int onIoEventConnected(sd_event_source *src, int fd, uint32_t revents, void * data) +{ + WMConnection *p_wmcon = (WMConnection*)data; + + int ret = p_wmcon->connectedToServer(fd); + + if (ret == 0) + { + stopEvent(src); + + ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr, + fd, EPOLLIN, onIoEventReceive, p_wmcon); + } + + return ret; +} + +static int sleepTimerHandler(sd_event_source *s, uint64_t usec, void *userdata) +{ + WMConnection *p_wmcon = (WMConnection*)userdata; + + int ret = p_wmcon->connectToEcu(); + + return ret; +} + +static void limitTimerHandler(sd_event_source *s, uint64_t usec, void *userdata) +{ + WMConnection *p_wmcon = (WMConnection*)userdata; + + p_wmcon->connectionTimeLimit(); +} + +} // namespace + +WMConnection::WMConnection() +{ + this->end_init = false; + + //Load timeout config file + this->loadTimeoutConfigFile(); + + // Load connection config file + this->loadConnectionConfigFile(); + + // TODO: ECU name should be decide by config file + this->ecu_name = this->mode; +} + +int WMConnection::initialize() +{ + int ret; + uint64_t sleepTime, limitTime; + + // Initialize for Master/Slave + ret = this->initializeServer(); + + sleepTime = getNextTimerTime(this->sleep); + + if (sleepTime <= 0) + { + HMI_ERROR("Cloud't get Next Timer"); + goto connection_init_error; + } + + ret = setTimer(&g_sleep_timer_src, sleepTime, (void *)sleepTimerHandler, this); + sd_event_source_set_enabled(g_sleep_timer_src, SD_EVENT_OFF); + + limitTime = getNextTimerTime(this->times); + + if (limitTime <= 0) + { + HMI_ERROR("Cloud't get Next Timer"); + goto connection_init_error; + } + + ret = setTimer(&g_limit_timer_src, limitTime, (void *)limitTimerHandler, this); + + this->connectToEcu(); + + return ret; + + +connection_init_error: + HMI_ERROR("Connection Initialize Failed"); + return -1; +} + +void WMConnection::registerCallback(ReceivedHandler on_received) +{ + this->onReceived = on_received; +} + +int WMConnection::sendRequest(char const *req, char const *appid, + char const *drawing_name, char const *drawing_area) +{ + int ret; + json_object *j_obj = json_object_new_object(); + json_object_object_add(j_obj, "req", json_object_new_string(req)); + json_object_object_add(j_obj, "appid", json_object_new_string(appid)); + json_object_object_add(j_obj, "drawing_name", json_object_new_string(drawing_name)); + json_object_object_add(j_obj, "drawing_area", json_object_new_string(drawing_area)); + + std::string ecu_name = getAppIdToEcuName(appid); + + HMI_DEBUG("send ecu_name %s", ecu_name.c_str()); + + ret = this->send(j_obj, ecu_name); + + json_object_put(j_obj); + + return ret; +} + +int WMConnection::send(struct json_object* j_in, std::string ecu_name) +{ + SocketInfo *socketData = &this->wm_socket[ecu_name]; + + // Convert json_object to string to send + const char *buf = json_object_to_json_string(j_in); + if (nullptr == buf) + { + HMI_ERROR("Failed to convert json_object to string"); + return -1; + } + + int len = strlen(buf); + + HMI_DEBUG("Send data(len:%d): %s", len, buf); + + int n = write(socketData->connectedSocket(), buf, len); + if(0 > n) + { + HMI_ERROR("Failed to send data (%s)", strerror(errno)); + return -1; + } + + return 0; +} + +bool WMConnection::isRemoteArea(const char* area) +{ + if (nullptr == area) + { + return false; + } + + std::string str_area = std::string(area); + if ("" == str_area) + { + return false; + } + + std::vector<std::string> elements; + elements = parseString(str_area, '.'); + + for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr) + { + if (itr->first == elements[0]) + { + if (itr->first != this->ecu_name) + { + return true; + } + else + { + return false; + } + } + } + + return false; +} + +bool WMConnection::isConnecting(std::string ecu_name) +{ + return (0 > this->wm_socket[ecu_name].connectedSocket()) ? false : true; +} + +bool WMConnection::isConnectionMode() +{ + return (Mode_Connection == this->wm_mode) ? true : false; +} + +std::string WMConnection::parseMasterArea(const char* area) +{ + std::string ret_area = ""; + std::vector<std::string> elements; + elements = parseString(std::string(area), '.'); + + if ("master" != elements[0]) + { + return std::string(area); + } + + for (auto itr = (elements.begin() + 1); itr != elements.end(); ++itr) + { + ret_area += *itr; + + if ((elements.end() - 1) != itr) + { + ret_area += "."; + } + } + return ret_area; +} + +bool WMConnection::isSyncDrawingForRemote(const char* appid) +{ + if (std::string(appid) == this->syndDrawingAppId) + { + return true; + } + else + { + return false; + } +} + +void WMConnection::startSyncDrawForRemote(const char* appid) +{ + this->syndDrawingAppId = std::string(appid); +} + +void WMConnection::finishSyncDrawForRemote(const char* appid) +{ + if (std::string(appid) == this->syndDrawingAppId) + { + this->syndDrawingAppId = ""; + } +} + +std::string WMConnection::getAreaToEcuName(const char* area) +{ + std::string result; + std::string str_area = std::string(area); + + if (str_area.find('.') != std::string::npos) + { + std::vector<std::string> elements; + elements = parseString(str_area, '.'); + result = elements[0]; + } + else + { + result = str_area; + } + + return result; +} + +std::string WMConnection::getSocketToEcuName(int socket) +{ + for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr) + { + if (socket == itr->second.connectedSocket()) + { + return itr->first; + } + } + + return ""; +} + +std::string WMConnection::getMySocketToEcuName(int socket) +{ + for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr) + { + if (socket == itr->second.mySocket()) + { + return itr->first; + } + } + + return ""; +} + +std::string WMConnection::getAppIdToEcuName(std::string appid) +{ + if (appid2ecuName.count(appid) == 1) + { + return this->appid2ecuName[appid]; + } + else + { + return ""; + } +} + +std::string WMConnection::getIpToEcuName(std::string ip) +{ + for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr) + { + if (ip == itr->second.ip()) + { + return itr->first; + } + } + + return ""; +} + +void WMConnection::setAppIdToEcuName(std::string appid, std::string ecu_name) +{ + this->appid2ecuName[appid] = ecu_name; +} + +void WMConnection::setAppIdToReceivedEcuName(std::string appid) +{ + this->appid2ecuName[appid] = received_ecu_name; +} + +std::string WMConnection::getEcuName() +{ + return this->ecu_name; +} + +bool WMConnection::getEndInit() +{ + return this->end_init; +} + +void WMConnection::callOnReceivedHandler(json_object *j_out) +{ + this->onReceived(j_out); +} + +int WMConnection::initializeServer() +{ + int ret = 0; + struct sockaddr_in addr; + + SocketInfo *socketData = &this->wm_socket[this->ecu_name]; + + // Create socket + socketData->setMySocket(socket(AF_INET, SOCK_STREAM, 0)); + if (0 > socketData->mySocket()) + { + HMI_ERROR("Failed to create socket (%s)", strerror(errno)); + return -1; + } + + socketData->setConnectedSocket(socketData->mySocket()); + + // Bind socket + addr.sin_family = AF_INET; + addr.sin_port = htons(socketData->wmPort()); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + ret = bind(socketData->mySocket(), (struct sockaddr *)&addr, sizeof(addr)); + if (0 > ret) + { + HMI_ERROR("Failed to bind socket (%s)", strerror(errno)); + return -1; + } + + // Listen connection + ret = listen(socketData->mySocket(), 1); + if (0 > ret) + { + HMI_ERROR("Failed to listen connection (%s)", strerror(errno)); + return -1; + } + + // Register callback to accept connection + ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr, + socketData->mySocket(), EPOLLIN, + onIoEventAccept, this); + if (0 > ret) + { + HMI_ERROR("Failed to add I/O event accept(%s)", strerror(-ret)); + return -1; + } + + return ret; +} + +int WMConnection::initializeClient(std::string ecu_name) +{ + SocketInfo *socketData = &this->wm_socket[ecu_name]; + + if (socketData->mySocket() != -1) + { + close(socketData->mySocket()); + } + + // Create socket + int my_socket = socket(AF_INET, SOCK_STREAM, 0); + if (0 > my_socket) + { + HMI_ERROR("Failed to create socket (%s)", strerror(errno)); + return -1; + } + + socketData->setMySocket(my_socket); + + return 0; +} + +int WMConnection::connectToEcu() +{ + int cnt = 0; + + HMI_DEBUG("Start Connection"); + + if (this->wm_socket.empty()) + { + HMI_DEBUG("Connection destination is not written to connection.json"); + stopEvent(g_limit_timer_src); + stopEvent(g_sleep_timer_src); + + this->end_init = true; + this->wm_mode = Mode_Standalone; + + return 0; + } + + for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr) + { + std::string ecu_name = itr->first; + HMI_DEBUG("ECU Names %s", ecu_name.c_str()); + + if (itr->second.connectedSocket() != -1 || !itr->second.masterMode()) + { + cnt++; + HMI_DEBUG("Already Connected"); + continue; + } + + if (itr->second.masterMode()) + { + HMI_DEBUG("Try Connection"); + connectToServer(ecu_name); + } + } + + if (cnt == (int)this->wm_socket.size()) + { + HMI_DEBUG("All Connected!!"); + + stopEvent(g_sleep_timer_src); + stopEvent(g_limit_timer_src); + + this->end_init = true; + this->wm_mode = Mode_Connection; + + return 0; + } + + uint64_t sleepTime = getNextTimerTime(this->sleep); + updateTimer(g_sleep_timer_src, sleepTime); + + return 0; +} + +void WMConnection::connectionTimeLimit() +{ + HMI_DEBUG("Time Limit"); + + stopEvent(g_sleep_timer_src); + stopEvent(g_limit_timer_src); + + this->wm_socket[this->ecu_name].setConnectedSocket(-1); + this->wm_mode = Mode_Standalone; + + for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr) + { + if (itr->second.connectedSocket() != -1) + { + HMI_DEBUG("Connection Mode"); + this->wm_mode = Mode_Connection; + } + else + { + close(itr->second.mySocket()); + } + } + + if (this->wm_mode == Mode_Standalone) + { + close(this->wm_socket[this->ecu_name].mySocket()); + } + + this->end_init = true; +} + +int WMConnection::connectToServer(std::string ecu_name) +{ + int ret = 0; + struct sockaddr_in addr; + + this->initializeClient(ecu_name); + + SocketInfo *socketData = &wm_socket[ecu_name]; + + // Connect to master + addr.sin_family = AF_INET; + addr.sin_port = htons(socketData->wmPort()); + addr.sin_addr.s_addr = inet_addr(socketData->ip().c_str()); + + connect(socketData->mySocket(), (struct sockaddr *)&addr, sizeof(addr)); + + ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr, + socketData->mySocket(), EPOLLOUT, + onIoEventConnected, this); + + if (0 > ret) + { + HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret)); + return -1; + } + + return ret; +} + +int WMConnection::connectedToServer(int socket) +{ + int ret; + + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + + std::string ecu_name = getMySocketToEcuName(socket); + + ret = getpeername(socket, (struct sockaddr*)&addr, &addr_len); + + if (ret != 0) + { + HMI_DEBUG("Failed to connect %s (%s)", ecu_name.c_str(), strerror(errno)); + return -1; + } + + HMI_DEBUG("Connected to %s", ecu_name.c_str()); + + SocketInfo *socketData = &this->wm_socket[ecu_name]; + + // Store connected socket + socketData->setConnectedSocket(socket); + + return 0; +} + +int WMConnection::serverAccept(int socket) +{ + struct sockaddr_in addr; + + // Accept connection + socklen_t len = sizeof(addr); + int my_socket = this->wm_socket[this->getEcuName()].mySocket(); + int connected_socket = accept(my_socket, (struct sockaddr *)&addr, &len); + if (0 > connected_socket) + { + HMI_ERROR("Failed to accept connection (%s)", strerror(errno)); + return -1; + } + + std::string ip = inet_ntoa(addr.sin_addr); + std::string ecu_name = getIpToEcuName(ip); + + SocketInfo *socketData = &this->wm_socket[ecu_name]; + + // Store connected socket + socketData->setConnectedSocket(connected_socket); + + // Register callback to receive + int ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr, + connected_socket, EPOLLIN, + onIoEventReceive, this); + if (0 > ret) + { + HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret)); + return -1; + } + + return 0; +} + +int WMConnection::receive(json_object** j_out, int *j_cnt, int socket) +{ + char buf[1024] = {}; + int n; + + n = read(socket, buf, sizeof(buf)); + if(0 > n) + { + HMI_ERROR("Failed to receive data (%s)", strerror(errno)); + return -1; + } + + HMI_DEBUG("Received data length: %d", n); + HMI_DEBUG("Received data: %s", buf); + + // Parse received data + struct json_tokener *tokener = json_tokener_new(); + int cnt = 0; + + while (n >= tokener->char_offset) + { + j_out[cnt] = json_tokener_parse_ex(tokener, &buf[tokener->char_offset], n); + + if (nullptr == j_out[cnt]) + { + break; + } + + cnt++; + } + + *j_cnt = cnt; + json_tokener_free(tokener); + + this->received_ecu_name = this->getSocketToEcuName(socket); + HMI_DEBUG("received ecu name %s", this->received_ecu_name.c_str()); + + return 0; +} + +int WMConnection::loadTimeoutConfigFile() +{ + // Get afm application installed dir + char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR"); + if (!afm_app_install_dir) + { + HMI_ERROR("AFM_APP_INSTALL_DIR is not defined"); + } + std::string path = std::string(afm_app_install_dir) + std::string(kPathTimeoutConfigFile); + + // Load connection config file + json_object *json_obj; + int ret = jh::inputJsonFilie(path.c_str(), &json_obj); + if (0 > ret) + { + HMI_ERROR("Could not open %s, so use default timeout", path.c_str()); + this->times = kDefaultTimes; + this->sleep = kDefaultSleep; + return 0; + } + HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj)); + + int times = jh::getIntFromJson(json_obj, "times"); + this->times = (0 != times) ? times : kDefaultTimes; + + int sleep = jh::getIntFromJson(json_obj, "sleep"); + this->sleep = (0 != sleep) ? sleep : kDefaultSleep; + + // Release json_object + json_object_put(json_obj); + + return 0; +} + +int WMConnection::loadConnectionConfigFile() +{ + std::string path = std::string(kPathConnectionConfigFile); + + // Load connection config file + json_object *json_obj, *json_cfg; + int ret = jh::inputJsonFilie(path.c_str(), &json_obj); + if (0 > ret) + { + HMI_ERROR("Could not open %s, so use default mode \"slave\"", kPathConnectionConfigFile); + this->wm_socket["slave"] = SocketInfo("slave", kDefaultIpAddr, kDefaultPort, false); + return 0; + } + HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj)); + + const char* screen_name = jh::getStringFromJson(json_obj, "screen_name"); + this->mode = (nullptr != screen_name) ? screen_name : "slave"; + + int wm_port = jh::getIntFromJson(json_obj, "wm_port"); + + this->wm_socket[screen_name] = SocketInfo(screen_name, "", wm_port, true); + + // Check + HMI_DEBUG("screen_name:%s wm_port:%d", screen_name, wm_port); + + if (!json_object_object_get_ex(json_obj, "connections", &json_cfg)) + { + HMI_ERROR("connection.json Parse Error!!"); + return 0; + } + + int len = json_object_array_length(json_cfg); + + for (int i = 0; i < len; i++) + { + json_object *json_conn = json_object_array_get_idx(json_cfg, i); + + std::string screen_name = jh::getStringFromJson(json_conn, "screen_name"); + std::string ip = jh::getStringFromJson(json_conn, "ip"); + int wm_port = jh::getIntFromJson(json_conn, "wm_port"); + bool master_mode = jh::getBoolFromJson(json_conn, "master_mode"); + + this->wm_socket[screen_name] = SocketInfo(screen_name, ip, wm_port, master_mode); + + HMI_DEBUG("screen_name:%s ip:%s port:%d server_mode:%s", screen_name.c_str(), + ip.c_str(), wm_port, (master_mode ? "true" : "false")); + } + + // Release json_object + json_object_put(json_obj); + + return 0; +} + +uint64_t WMConnection::getNextTimerTime(uint64_t msec) +{ + struct timespec ts; + + if (clock_gettime(CLOCK_BOOTTIME, &ts) != 0) + { + HMI_ERROR("Could't set time (clock_gettime() returns with error"); + return -1; + } + + uint64_t timer_nsec = ((ts.tv_sec * 1000000000ULL) + (ts.tv_nsec) + (msec * 1000000)); + + if (!timer_nsec) + { + HMI_ERROR("Second is 0"); + return -1; + } + + return timer_nsec / 1000; +} + +} // namespace wm diff --git a/src/wm_connection.hpp b/src/wm_connection.hpp new file mode 100644 index 0000000..91f870e --- /dev/null +++ b/src/wm_connection.hpp @@ -0,0 +1,117 @@ +/* + * Insert Copyright if needed. + */ + +#ifndef WM_CONNECTION_HPP +#define WM_CONNECTION_HPP + +#include <functional> +#include <unordered_map> + +struct json_object; + +namespace wm +{ + +class SocketInfo +{ + public: + SocketInfo() {}; + SocketInfo(std::string screen_name, std::string ip, int wm_port, bool master_mode) : _screen_name(screen_name), + _ip(ip), _wm_port(wm_port), _master_mode(master_mode){} + std::string screenName() const { return _screen_name; } + std::string ip() const { return _ip; } + int wmPort() const { return _wm_port; } + bool masterMode() const { return _master_mode; } + int mySocket() const { return _my_socket; } + int connectedSocket() const { return _connected_socket; } + void setMySocket(int socket) { this->_my_socket = socket; } + void setConnectedSocket(int socket) { this->_connected_socket = socket; } + + private: + std::string _screen_name; + std::string _ip; + int _wm_port; + bool _master_mode; + int _my_socket = -1; + int _connected_socket = -1; +}; + +class WMConnection +{ + public: + WMConnection(); + ~WMConnection() = default; + + using ReceivedHandler = std::function<void(json_object* j_out)>; + + enum ModeType + { + Mode_Standalone = 0, + Mode_Connection, + }; + + int initialize(); + void registerCallback(ReceivedHandler on_received); + int sendRequest(char const *req, char const *appid, + char const *drawing_name, char const *drawing_area); + bool isRemoteArea(const char* area); + bool isConnecting(std::string ecu_name); + bool isConnectionMode(); + std::string parseMasterArea(const char* area); + bool isSyncDrawingForRemote(const char* role); + void startSyncDrawForRemote(const char* role); + void finishSyncDrawForRemote(const char* role); + int getMySocket(); + int getConnectedSocket(); + void setConnectedSocket(int connected_socket); + std::string getAreaToEcuName(const char* area); + std::string getSocketToEcuName(int socket); + std::string getMySocketToEcuName(int socket); + std::string getAppIdToEcuName(std::string appid); + std::string getIpToEcuName(std::string ip); + std::string getEcuName(); + bool getEndInit(); + void setAppIdToEcuName(std::string appid, std::string ecu_name); + void setAppIdToReceivedEcuName(std::string appid); + void callOnReceivedHandler(json_object *j_out); + int connectToEcu(); + int connectToServer(std::string ecu_name); + int connectedToServer(int socket); + void connectionTimeLimit(); + + int serverAccept(int socket); + int receive(json_object** j_out, int *j_cnt, int socket); + + private: + std::string mode; + std::string received_ecu_name; + ReceivedHandler onReceived; + std::string syndDrawingAppId; + + std::string ecu_name; + std::string received_ecu; + + uint64_t times; + uint64_t sleep; + + bool end_init; + ModeType wm_mode; + + std::unordered_map<std::string, SocketInfo> wm_socket; + std::unordered_map<std::string, std::string> appid2ecuName; + + int initializeServer(); + int initializeClient(std::string ecu_name); + int loadTimeoutConfigFile(); + int loadConnectionConfigFile(); + + int send(json_object* j_in, std::string ecu_name); + + uint64_t getNextTimerTime(uint64_t msec); +}; + +} // namespace wm + +#endif // WM_CONNECTION_HPP + diff --git a/src/wm_layer.cpp b/src/wm_layer.cpp index 4eceb43..e1454f8 100644 --- a/src/wm_layer.cpp +++ b/src/wm_layer.cpp @@ -66,6 +66,12 @@ void LayerState::removeLayer(unsigned layer) this->render_order.erase(fwd_itr, this->render_order.end()); } +bool LayerState::hasLayer(unsigned layer) +{ + auto itr = std::find(this->render_order.begin(), this->render_order.end(), layer); + return (itr != this->render_order.end()) ? true : false; +} + void LayerState::attachAppToArea(const string& app, const string& area) { this->area2appid[area] = app; @@ -96,6 +102,7 @@ WMLayer::WMLayer(json_object* j, unsigned wm_layer_id) : tmp_state(), state(), w this->role_list = jh::getStringFromJson(j, "role"); this->id_begin = static_cast<unsigned>(jh::getIntFromJson(j, "id_range_begin")); this->id_end = static_cast<unsigned>(jh::getIntFromJson(j, "id_range_end")); + this->screen = jh::getIntFromJson(j, "screen"); // screen is not defined in layers.json, screen is set to 0 if (name.empty()) { @@ -183,6 +190,11 @@ void WMLayer::removeLayerFromState(unsigned layer) this->tmp_state.removeLayer(layer); } +bool WMLayer::hasLayerFromState(unsigned layer) +{ + this->tmp_state.hasLayer(layer); +} + void WMLayer::attachAppToArea(const string& app, const string& area) { this->tmp_state.attachAppToArea(app, area); @@ -250,7 +262,7 @@ void WMLayer::undo() void WMLayer::dump() { DUMP("===== wm layer status ====="); - DUMP("Layer :%s", this->name.c_str()); + DUMP("Layer :%s on screen %d", this->name.c_str(), this->screen); DUMP(" [Current]"); this->state.dump(); DUMP(" [To be]"); diff --git a/src/wm_layer.hpp b/src/wm_layer.hpp index 97cf8a8..7da432c 100644 --- a/src/wm_layer.hpp +++ b/src/wm_layer.hpp @@ -38,6 +38,7 @@ class LayerState const std::vector<unsigned> getIviIdList(); void addLayer(unsigned layer); void removeLayer(unsigned layer); + bool hasLayer(unsigned layer); void attachAppToArea(const std::string& app, const std::string& area); // Debug @@ -59,6 +60,7 @@ class WMLayer unsigned idBegin() { return this->id_begin; } unsigned idEnd() { return this->id_end; } unsigned getWMLayerID() { return this->wm_layer_id; } + unsigned getScreenID() { return this->screen; } const std::string& layerName(); void appendArea(const std::string& area); LayerState& getLayerState() { return tmp_state; } @@ -69,6 +71,7 @@ class WMLayer // Manipulation void addLayerToState(unsigned layer); void removeLayerFromState(unsigned layer); + bool hasLayerFromState(unsigned layer); void attachAppToArea(const std::string& app, const std::string& area); std::string attachedApp(const std::string& area); void update(); @@ -88,6 +91,7 @@ class WMLayer std::string role_list; std::vector<std::string> area_list; std::vector<unsigned> id_list; + unsigned screen; unsigned id_begin; unsigned id_end; }; diff --git a/src/wm_layer_control.cpp b/src/wm_layer_control.cpp index c5c7913..8086fd3 100644 --- a/src/wm_layer_control.cpp +++ b/src/wm_layer_control.cpp @@ -1,6 +1,5 @@ /* * Copyright (c) 2017 TOYOTA MOTOR CORPORATION - * Copyright (c) 2018 Konsulko Group * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,10 +21,22 @@ #include "request.hpp" #include "json_helper.hpp" -#define LC_AREA_FILE "areas.json" -#define LC_LAYER_SETTING_FILE "layers.json" +#define LC_AREA_PATH "/etc/areas.json" +#define LC_LAYER_SETTING_PATH "/etc/layers.json" +#define LC_WESTON_SETTING_PATH "/etc/weston.json" #define LC_DEFAULT_AREA "fullscreen" #define BACK_GROUND_LAYER "BackGroundLayer" +#define REMOTE_LAYER "Remote" +#define REMOTE_LAYER_RSE1 "RemoteRSE1" +#define REMOTE_LAYER_RSE2 "RemoteRSE2" +#define REMOTE_LAYER_HUD "RemoteHUD" +#define REMOTE_LAYER_HUD_UL "RemoteHUDUpperLeft" +#define AREA_NAME_RSE1 "rse1.normal.full" +#define AREA_NAME_RSE2 "rse2.normal.full" +#define AREA_NAME_HUD "hud.normal.full" +#define AREA_NAME_HUD_UL "hud.upper.left" +#define defaultWestonTimes 60000 +#define defaultWestonSleep 50 using std::string; using std::vector; @@ -57,15 +68,19 @@ static void layerCallback_static(t_ilm_layer layer, g_lc_ctxt->dispatchLayerPropChangeEvent(layer, layer_prop, mask); } -LayerControl::LayerControl(const std::string& root) +LayerControl::LayerControl(const std::string& root, const std::string& ecu_name) { - string area_path(get_file_path(LC_AREA_FILE, root.c_str())); - string layer_path(get_file_path(LC_LAYER_SETTING_FILE, root.c_str())); + string area_path = root + LC_AREA_PATH; + string layer_path= root + LC_LAYER_SETTING_PATH; + string weston_path = root + LC_WESTON_SETTING_PATH; + + this->loadWestonSetting(weston_path); + // load layers.setting.json WMError ret = this->loadLayerSetting(layer_path); assert(ret == WMError::SUCCESS); // load areas.json - ret = this->loadAreaDb(area_path); + ret = this->loadAreasConfigFile(area_path, ecu_name); assert(ret == WMError::SUCCESS); } @@ -74,21 +89,37 @@ WMError LayerControl::init(const LayerControlCallbacks& cb) HMI_DEBUG("Initialize of ilm library and display"); t_ilm_uint num = 0; t_ilm_uint *ids; - int cnt = 0; - ilmErrorTypes rc = ilm_init(); + ilmErrorTypes rc; + struct timespec startTs, endTs; + + if (clock_gettime(CLOCK_BOOTTIME, &startTs) != 0) + { + HMI_ERROR("Could't set time (clock_gettime() returns with error"); + goto lc_init_error; + } + + endTs = startTs; - while (rc != ILM_SUCCESS) + while ((startTs.tv_sec + (this->times / 1000)) > endTs.tv_sec) { - cnt++; - if (20 <= cnt) + rc = ilm_init(); + + if (rc == ILM_SUCCESS) { - HMI_ERROR("Could not connect to compositor"); - goto lc_init_error; + HMI_DEBUG("Weston Connected"); + break; } + HMI_ERROR("Wait to start weston ..."); - sleep(1); - rc = ilm_init(); + usleep(this->sleep * 1000); + + if (clock_gettime(CLOCK_BOOTTIME, &endTs) != 0) + { + HMI_ERROR("Could't set time (clock_gettime() returns with error"); + goto lc_init_error; + } } + if(rc != ILM_SUCCESS) goto lc_init_error; // Get current screen setting @@ -99,12 +130,16 @@ WMError LayerControl::init(const LayerControlCallbacks& cb) for(unsigned i = 0; i < num; i++) { HMI_INFO("get screen: %d", ids[i]); + ilmScreenProperties prop; + rc = ilm_getPropertiesOfScreen(ids[i], &prop); + + if(rc != ILM_SUCCESS) goto lc_init_error; + this->wm_screens.emplace_back(Screen(ids[i], prop.screenWidth, prop.screenHeight)); } + // Currently, 0 is only available this->screenID = ids[0]; - rc = ilm_getPropertiesOfScreen(this->screenID, &this->screen_prop); - if(rc != ILM_SUCCESS) goto lc_init_error; // Register Callback to Window Manager and from ILM @@ -134,7 +169,22 @@ void LayerControl::createNewLayer(unsigned id) this->renderLayers(); } -unsigned LayerControl::getNewLayerID(const string& role) +void LayerControl::createNewRemoteLayer(unsigned id) +{ + HMI_INFO("create new ID :%d (For remote layer)", id); + struct rect rct = {640, 720, 0, 0}; + ilm_layerCreateWithDimension(&id, rct.w, rct.h); + //ilm_layerSetSourceRectangle(id, rct.x, rct.y, rct.w, rct.h); + ilm_layerSetDestinationRectangle(id, this->offset_x, this->offset_y, rct.w, rct.h); + ilm_layerSetOpacity(id, 1.0); + ilm_layerSetVisibility(id, ILM_FALSE); + ilm_commitChanges(); + auto wm_layer = getWMLayer(id); + wm_layer->addLayerToState(id); + this->renderLayers(); +} + +unsigned LayerControl::getNewLayerID(const string& role, string* layer_name) { unsigned ret = 0; for(const auto& l: this->wm_layers) @@ -142,6 +192,7 @@ unsigned LayerControl::getNewLayerID(const string& role) ret = l->getNewLayerID(role); if(ret != 0) { + *layer_name = l->layerName(); unsigned wmlid = l->getWMLayerID(); this->lid2wmlid[ret] = wmlid; break; @@ -179,6 +230,10 @@ void LayerControl::setupArea(const rectangle& base_rct, double scaling) this->offset_x = base_rct.left(); this->offset_y = base_rct.top(); + // TODO: set all screen + this->wm_screens[0].setScale(scaling); + this->wm_screens[0].setOffset(offset_x, offset_y); + for (auto &i : this->area2size) { i.second.x = static_cast<int>(scaling * i.second.x + 0.5); @@ -193,7 +248,7 @@ void LayerControl::setupArea(const rectangle& base_rct, double scaling) Screen LayerControl::getScreenInfo() { - return Screen(this->screen_prop.screenWidth, this->screen_prop.screenHeight); + return wm_screens[0]; } double LayerControl::scale() @@ -201,55 +256,69 @@ double LayerControl::scale() return this->scaling; } +WMError LayerControl::updateLayer(LayerState& layer_state) +{ + return WMError::SUCCESS; +} + WMError LayerControl::renderLayers() { HMI_INFO("Commit change"); WMError rc = WMError::SUCCESS; - // Check the number of layers - vector<unsigned> ivi_l_ids; - for(auto& l : this->wm_layers) + // Create render order for each screen and set render order + for(const auto& screen : this->wm_screens) { - auto state = l->getLayerState(); - HMI_DEBUG("layer %s", l->layerName().c_str()); - for(const auto& id : state.getIviIdList()) + unsigned size_ids = 0; + for(const auto& wm_l : this->wm_layers) { - HMI_DEBUG("Add %d", id); - ivi_l_ids.push_back(id); + if(wm_l->getScreenID() == screen.id()) + { + for(const auto& id : wm_l->getLayerState().getIviIdList()) + { + ++size_ids; + } + } + } + t_ilm_layer* id_array = new t_ilm_layer[size_ids]; + if(id_array == nullptr) + { + HMI_WARNING("short memory"); + this->undoUpdate(); + return WMError::FAIL; + } + int idx = 0; + for(const auto& wm_l : this->wm_layers) + { + if(wm_l->getScreenID() == screen.id()) + { + for(const auto& id : wm_l->getLayerState().getIviIdList()) + { + id_array[idx] = id; + ++idx; + } + } } - } - - // Create render order - t_ilm_layer* id_array = new t_ilm_layer[ivi_l_ids.size()]; - if(id_array == nullptr) - { - HMI_WARNING("short memory"); - this->undoUpdate(); - return WMError::FAIL; - } - int count = 0; - for(const auto& i : ivi_l_ids) - { - id_array[count] = i; - ++count; - } - // Display - ilmErrorTypes ret = ilm_displaySetRenderOrder(this->screenID, id_array, ivi_l_ids.size()); - if(ret != ILM_SUCCESS) - { - this->undoUpdate(); - rc = WMError::FAIL; - } - else - { - for(auto& l : this->wm_layers) + // Send to display + ilmErrorTypes ret = ilm_displaySetRenderOrder(screen.id(), id_array, size_ids); + if(ret != ILM_SUCCESS) { - l->update(); + this->undoUpdate(); + return WMError::FAIL; } + else + { + for(auto& l : this->wm_layers) + { + if(l->getScreenID() == screen.id()) { + l->update(); + } + } + } + ilm_commitChanges(); + delete id_array; } - ilm_commitChanges(); - delete id_array; return rc; } @@ -276,9 +345,34 @@ void LayerControl::undoUpdate() } } +int LayerControl::loadWestonSetting(const string &path) +{ + HMI_DEBUG("loading Weston(Conpositor Time Out) Setting from %s", path.c_str()); + + json_object *json_obj; + + int ret = jh::inputJsonFilie(path.c_str(), &json_obj); + if (0 > ret) + { + HMI_ERROR("Could not open %s, so use default", path.c_str()); + this->times = defaultWestonTimes; + this->sleep = defaultWestonSleep; + return 0; + } + HMI_INFO("json_obj dump:%s", json_object_get_string(json_obj)); + + long times = jh::getIntFromJson(json_obj, "times"); + this->times = (0 != times) ? times : defaultWestonTimes; + + long sleep = jh::getIntFromJson(json_obj, "sleep"); + this->sleep = (0 != sleep) ? sleep : defaultWestonSleep; + + return 0; +} + WMError LayerControl::loadLayerSetting(const string &path) { - HMI_DEBUG("loading WMLayer(Application Containers) Setting from %s", path.c_str()); + HMI_DEBUG("loading WMLayer(Application Containers) Setting from %s", path); json_object *json_obj, *json_cfg; int ret = jh::inputJsonFilie(path.c_str(), &json_obj); @@ -310,9 +404,9 @@ WMError LayerControl::loadLayerSetting(const string &path) return WMError::SUCCESS; } -WMError LayerControl::loadAreaDb(const std::string& path) +WMError LayerControl::loadAreasConfigFile(const std::string& path, const std::string& ecu_name) { - // Load area.db + // Load areas config file json_object *json_obj; int ret = jh::inputJsonFilie(path.c_str(), &json_obj); if (0 > ret) @@ -322,54 +416,115 @@ WMError LayerControl::loadAreaDb(const std::string& path) } HMI_INFO("json_obj dump:%s", json_object_get_string(json_obj)); - // Perse areas + // Parse ecus json_object *json_cfg; - if (!json_object_object_get_ex(json_obj, "areas", &json_cfg)) + if (!json_object_object_get_ex(json_obj, "ecus", &json_cfg)) { HMI_ERROR("Parse Error!!"); return WMError::FAIL; } - int len = json_object_array_length(json_cfg); - HMI_DEBUG("json_cfg len:%d", len); + int num_ecu = json_object_array_length(json_cfg); + HMI_DEBUG("json_cfg(ecus) len:%d", num_ecu); - const char *area; - for (int i = 0; i < len; i++) + const char* c_ecu_name; + json_object *json_ecu; + for (int i = 0; i < num_ecu; i++) { - json_object *json_tmp = json_object_array_get_idx(json_cfg, i); - HMI_DEBUG("> json_tmp dump:%s", json_object_get_string(json_tmp)); + json_ecu= json_object_array_get_idx(json_cfg, i); - area = jh::getStringFromJson(json_tmp, "name"); - if (nullptr == area) + c_ecu_name = jh::getStringFromJson(json_ecu, "name"); + if (nullptr == c_ecu_name) { HMI_ERROR("Parse Error!!"); return WMError::FAIL; } - HMI_DEBUG("> area:%s", area); - json_object *json_rect; - if (!json_object_object_get_ex(json_tmp, "rect", &json_rect)) + if (ecu_name == string(c_ecu_name)) { - HMI_ERROR("Parse Error!!"); - return WMError::FAIL; + break; } - HMI_DEBUG("> json_rect dump:%s", json_object_get_string(json_rect)); + else + { + json_ecu = nullptr; + } + } - struct rect area_size; - area_size.x = jh::getIntFromJson(json_rect, "x"); - area_size.y = jh::getIntFromJson(json_rect, "y"); - area_size.w = jh::getIntFromJson(json_rect, "w"); - area_size.h = jh::getIntFromJson(json_rect, "h"); + if (!json_ecu) + { + HMI_ERROR("Areas for ecu:%s is NOT exist!!", ecu_name.c_str()); + return WMError::FAIL; + } - this->area2size[area] = area_size; + // Parse screens + if (!json_object_object_get_ex(json_ecu, "screens", &json_cfg)) + { + HMI_ERROR("Parse Error!!"); + return WMError::FAIL; } - // Check - for (const auto& itr : this->area2size) + int num_screen = json_object_array_length(json_cfg); + HMI_DEBUG("json_cfg(screens) len:%d", num_screen); + + json_object *json_screen; + for (int i = 0; i < num_screen; i++) { - HMI_DEBUG("area:%s x:%d y:%d w:%d h:%d", - itr.first.c_str(), itr.second.x, itr.second.y, - itr.second.w, itr.second.h); + int screen_id; + json_screen = json_object_array_get_idx(json_cfg, i); + HMI_INFO("json_cfg dump:%s", json_object_get_string(json_cfg)); + + // TODO: Currently only one display is connected to a ECU. + + screen_id = jh::getIntFromJson(json_screen, "id"); // screen_id is not used currently + + // Parse areas + json_object *json_tmp; + if (!json_object_object_get_ex(json_screen, "areas", &json_tmp)) + { + HMI_ERROR("Parse Error!!"); + return WMError::FAIL; + } + + int num_area = json_object_array_length(json_tmp); + HMI_DEBUG("json_tmp(areas) len:%d", num_area); + + const char *area; + for (int j = 0; j < num_area; j++) + { + json_object *json_area = json_object_array_get_idx(json_tmp, j); + + area = jh::getStringFromJson(json_area, "name"); + if (nullptr == area) + { + HMI_ERROR("Parse Error!!"); + return WMError::FAIL; + } + HMI_DEBUG("> area:%s", area); + + json_object *json_rect; + if (!json_object_object_get_ex(json_area, "rect", &json_rect)) + { + HMI_ERROR("Parse Error!!"); + return WMError::FAIL; + } + + struct rect area_size; + area_size.x = jh::getIntFromJson(json_rect, "x"); + area_size.y = jh::getIntFromJson(json_rect, "y"); + area_size.w = jh::getIntFromJson(json_rect, "w"); + area_size.h = jh::getIntFromJson(json_rect, "h"); + HMI_INFO("%d, %d, %d, %d, ", area_size.x, area_size.y, area_size.w, area_size.h); + + this->area2size[area] = area_size; + } + + // Check + for (const auto& itr : this->area2size) + { + HMI_DEBUG("area:%s x:%d y:%d w:%d h:%d", + itr.first.c_str(), itr.second.x, itr.second.y, + itr.second.w, itr.second.h); + } } // Release json_object @@ -380,7 +535,9 @@ WMError LayerControl::loadAreaDb(const std::string& path) WMError LayerControl::layoutChange(const WMAction& action) { - if (action.visible == TaskVisible::INVISIBLE) + if ((action.visible == TaskVisible::INVISIBLE) || + (action.visible == TaskVisible::REQ_REMOTE_VISIBLE) || + (action.visible == TaskVisible::REQ_REMOTE_INVISIBLE)) { // Visibility is not change -> no redraw is required return WMError::SUCCESS; @@ -394,26 +551,22 @@ WMError LayerControl::layoutChange(const WMAction& action) unsigned surface = action.client->surfaceID(); auto rect = this->getAreaSize(action.area); - HMI_SEQ_INFO(action.req_num, "Set layout %d, %d, %d, %d",rect.x, rect.y, rect.w, rect.h); + HMI_DEBUG("Set layout %d, %d, %d, %d",rect.x, rect.y, rect.w, rect.h); + // TO BE FIXED: // Sometimes, ivi_wm_surface_size signal doesn't reach window manager, - // then, Window Manager set set source size = 0. - if(!action.client->isSourceSizeSet()) - { - ilmSurfaceProperties sp; - ilm_getPropertiesOfSurface(surface, &sp); - if((sp.origSourceHeight != sp.sourceHeight) || (sp.origSourceWidth != sp.sourceWidth)) - { - HMI_SEQ_NOTICE(action.req_num, "set source size w:%d h%d", sp.origSourceWidth, sp.origSourceHeight); - ilm_surfaceSetSourceRectangle(surface, 0, 0, sp.origSourceWidth, sp.origSourceHeight); - ilm_commitChanges(); - action.client->setSurfaceSizeCorrectly(); - } + // then, Window Manager can't set source size. + // This fixes it but it takes about 200ns(on R-Car M3) wastefully + ilmSurfaceProperties sp; + ilm_getPropertiesOfSurface(surface, &sp); + if(sp.origSourceHeight != sp.sourceHeight) { + HMI_SEQ_NOTICE(action.req_num, "WORK AROUND: set source size w:%d h%d", sp.origSourceWidth, sp.origSourceHeight); + ilm_surfaceSetSourceRectangle(surface, 0, 0, sp.origSourceWidth, sp.origSourceHeight); + ilm_commitChanges(); } ilm_surfaceSetDestinationRectangle(surface, rect.x, rect.y, rect.w, rect.h); ilm_commitChanges(); - action.client->setArea(action.area); for(auto &wm_layer: this->wm_layers) { // Store the state who is assigned to the area @@ -439,15 +592,30 @@ WMError LayerControl::visibilityChange(const WMAction& action) return WMError::NOT_REGISTERED; } - if (action.visible == TaskVisible::VISIBLE) + if (action.visible == TaskVisible::VISIBLE) { ret = this->makeVisible(action.client); } - else if (action.visible == TaskVisible::INVISIBLE) + else if (action.visible == TaskVisible::INVISIBLE) { ret = this->makeInvisible(action.client); } - ilm_commitChanges(); + else if (action.visible == TaskVisible::REMOTE_VISIBLE) + { + this->moveRemote(action.client->layerID(), action.area); + ret = this->makeVisible(action.client); + } + else if (action.visible == TaskVisible::REMOTE_INVISIBLE) + { + this->moveLocal(action.client->layerID()); + ret = this->makeInvisible(action.client); + } + else // TaskVisible::REQ_REMOTE_VISIBLE || TaskVisible::REQ_REMOTE_INVISIBLE + { + // Visibility is not change + ret = WMError::SUCCESS; + } + return ret; } @@ -519,6 +687,7 @@ void LayerControl::dispatchCreateEvent(ilmObjectType object, unsigned id, bool c return; } this->cb.surfaceCreated(sp.creatorPid, id); + ilm_surfaceSetSourceRectangle(id, 0, 0, sp.origSourceWidth, sp.origSourceHeight); ilm_surfaceAddNotification(id, surfaceCallback_static); ilm_surfaceSetVisibility(id, ILM_TRUE); ilm_surfaceSetType(id, ILM_SURFACETYPE_DESKTOP); @@ -684,4 +853,73 @@ bool LayerControl::moveForeGround(const shared_ptr<WMClient> client) return ret; } +bool LayerControl::moveRemote(unsigned layer, const std::string& area) +{ + bool ret = false; + std::string remote_layer; + + if (area == AREA_NAME_RSE1) + remote_layer = REMOTE_LAYER_RSE1; + else if (area == AREA_NAME_RSE2) + remote_layer = REMOTE_LAYER_RSE2; + else if (area == AREA_NAME_HUD) + remote_layer = REMOTE_LAYER_HUD; + else if (area == AREA_NAME_HUD_UL) + remote_layer = REMOTE_LAYER_HUD_UL; + else + remote_layer = REMOTE_LAYER; + + auto remote = this->getWMLayer(remote_layer); + + if(remote != nullptr) + { + ret = true; + if(remote->hasLayerID(layer)) + { + HMI_DEBUG("Already moved layer %d", layer); + remote->dump(); + return ret; + } + remote->addLayerToState(layer); + auto wm_layer = this->getWMLayer(layer); + wm_layer->removeLayerFromState(layer); + wm_layer->dump(); + remote->dump(); + ret = true; + } + + return ret; +} + +bool LayerControl::moveLocal(unsigned layer) +{ + bool ret = false; + + auto remote = this->getWMLayer(REMOTE_LAYER); + if(remote != nullptr) + { + remote->removeLayerFromState(layer); + auto wm_layer = this->getWMLayer(layer); + wm_layer->addLayerToState(layer); + wm_layer->dump(); + remote->dump(); + ret = true; + } + + return ret; +} + +bool LayerControl::hasRemoteLayer(unsigned layer) +{ + bool ret = false; + + auto remote = this->getWMLayer(REMOTE_LAYER); + if(remote != nullptr) + { + ret = remote->hasLayerFromState(layer); + } + + return ret; +} + } // namespace wm diff --git a/src/wm_layer_control.hpp b/src/wm_layer_control.hpp index 68acd66..6eb7a76 100644 --- a/src/wm_layer_control.hpp +++ b/src/wm_layer_control.hpp @@ -27,14 +27,24 @@ namespace wm { class Screen { public: - Screen(unsigned w, unsigned h) : _width(w), _height(h){} - unsigned width() { return _width; } - unsigned height() { return _height; } + Screen(unsigned id, unsigned w, unsigned h) : _screen_id(id), _width(w), _height(h){} + unsigned width() const { return _width; } + unsigned height() const { return _height; } + unsigned id() const { return _screen_id; } + unsigned scale() const { return _scale; } + int offsetX() const { return _offset_x; } + int offsetY() const { return _offset_y; } + void setScale(double scl) { this->_scale = scl; } + void setOffset(int x, int y) { this->_offset_x = x; this->_offset_y = y; } private: + unsigned _screen_id; unsigned _width; unsigned _height; unsigned _pysical_width = 0; unsigned _pysical_height = 0; + int _offset_x = 0; + int _offset_y = 0; + double _scale = 1.0; }; class LayerControlCallbacks { @@ -60,18 +70,21 @@ class WMClient; class LayerControl { public: - explicit LayerControl(const std::string& root); + explicit LayerControl(const std::string& root, const std::string& ecu_name); ~LayerControl() = default; WMError init(const LayerControlCallbacks& cb); void createNewLayer(unsigned id); - unsigned getNewLayerID(const std::string& role); + void createNewRemoteLayer(unsigned id); + unsigned getNewLayerID(const std::string& role, std::string* layer_name); std::shared_ptr<WMLayer> getWMLayer(unsigned layer); std::shared_ptr<WMLayer> getWMLayer(std::string layer_name); struct rect getAreaSize(const std::string& area); void setupArea(const rectangle& base_rct, double scaling); Screen getScreenInfo(); double scale(); + WMError updateLayer(LayerState& layer_state); WMError renderLayers(); + // WMError renderLayersRemote(); WMError setXDGSurfaceOriginSize(unsigned surface); void undoUpdate(); WMError layoutChange(const WMAction& action); @@ -87,23 +100,32 @@ class LayerControl void dispatchSurfacePropChangeEvent(unsigned id, struct ilmSurfaceProperties*, t_ilm_notification_mask); void dispatchLayerPropChangeEvent(unsigned id, struct ilmLayerProperties*, t_ilm_notification_mask); + bool hasRemoteLayer(unsigned layer); + private: WMError makeVisible(const std::shared_ptr<WMClient> client); WMError makeInvisible(const std::shared_ptr<WMClient> client); bool moveForeGround(const std::shared_ptr<WMClient> client); bool moveBackGround(const std::shared_ptr<WMClient> client); + bool moveRemote(unsigned layer, const std::string& area); + bool moveLocal(unsigned layer); + int loadWestonSetting(const std::string &path); WMError loadLayerSetting(const std::string& path); - WMError loadAreaDb(const std::string& path); + WMError loadAreasConfigFile(const std::string& path, const std::string& ecu_name); std::vector<std::shared_ptr<WMLayer>> wm_layers; + std::vector<Screen> wm_screens; std::unordered_map<unsigned, unsigned> lid2wmlid; std::unordered_map<std::string, struct rect> area2size; unsigned screenID; - struct ilmScreenProperties screen_prop; + double scaling; int offset_x; int offset_y; LayerControlCallbacks cb; + + long times; + long sleep; }; -} // namespace wm
\ No newline at end of file +} // namespace wm |