diff options
author | Yuta Doi <yuta-d@witz-inc.co.jp> | 2018-04-27 19:01:36 +0900 |
---|---|---|
committer | Yuta Doi <yuta-d@witz-inc.co.jp> | 2018-04-27 19:01:36 +0900 |
commit | 55be85ed4bdfea6fc037d781b8cd8f58487718d1 (patch) | |
tree | 279a88e26c74aee58f11e2a5d20348569ce34667 /src | |
parent | d50188f726b15a0ae2777bf2d91ee88836feeac5 (diff) |
Add PolicyManager, related classes and some config files
- PolicyManager
Decide next layout by using occured event and current state
based on policy table.
This PolicyManger is reference and the OEMs can replace it.
- LayoutManager
Change the current layout to the layout
which decided by PolicyManager.
NOTE:
The functions of this class had been included in App class.
The part of function of this class remain there yet.
- LowCanClient
Receive the CAN signal from low level CAN service.
- app.db
Define the applications name and its role.
This file will be deleted
when the names and roles can be given by other module.
- layout.cb
Define the layouts and areas which are included by the layout.
- role.db
Define the roles of the applications.
Change-Id: I2f84bdf5e68355e022f516cee9a1db88efe58825
Signed-off-by: Yuta Doi <yuta-d@witz-inc.co.jp>
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 24 | ||||
-rw-r--r-- | src/app.cpp | 902 | ||||
-rw-r--r-- | src/app.hpp | 48 | ||||
-rw-r--r-- | src/db/app.db | 68 | ||||
-rw-r--r-- | src/json_helper.cpp | 54 | ||||
-rw-r--r-- | src/json_helper.hpp | 7 | ||||
-rw-r--r-- | src/layout.cpp | 17 | ||||
-rw-r--r-- | src/layout.hpp | 42 | ||||
-rw-r--r-- | src/layout_manager/db/layout.db | 158 | ||||
-rw-r--r-- | src/layout_manager/layout.cpp | 570 | ||||
-rw-r--r-- | src/layout_manager/layout.hpp | 84 | ||||
-rw-r--r-- | src/low_can_client.cpp | 193 | ||||
-rw-r--r-- | src/low_can_client.hpp | 72 | ||||
-rw-r--r-- | src/main.cpp | 79 | ||||
-rw-r--r-- | src/policy_manager/CMakeLists.txt | 65 | ||||
-rw-r--r-- | src/policy_manager/db/role.db | 44 | ||||
-rw-r--r-- | src/policy_manager/policy_manager.cpp | 497 | ||||
-rw-r--r-- | src/policy_manager/policy_manager.hpp | 67 | ||||
-rw-r--r-- | src/policy_manager/zipc/category.db | 32 | ||||
-rw-r--r-- | src/policy_manager/zipc/dummy_stm.c | 212 | ||||
-rw-r--r-- | src/policy_manager/zipc/dummy_stm.h | 127 |
21 files changed, 2917 insertions, 445 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cc3efc3..a632b9c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,14 +25,17 @@ set(CMAKE_SHARED_MODULE_PREFIX "") set(TARGETS_WM windowmanager-service) +# Set use STM name +set(USE_STM_NAME zipc) + add_library(${TARGETS_WM} MODULE main.cpp wayland_ivi_wm.cpp wayland_ivi_wm.hpp util.cpp util.hpp - layout.cpp - layout.hpp + layout_manager/layout.cpp + layout_manager/layout.hpp ${IVI_CON_PROTO} json_helper.cpp json_helper.hpp @@ -43,20 +46,28 @@ add_library(${TARGETS_WM} MODULE controller_hooks.hpp config.cpp config.hpp - policy.hpp) + low_can_client.cpp + low_can_client.hpp +) target_include_directories(${TARGETS_WM} PRIVATE ${AFB_INCLUDE_DIRS} ${SD_INCLUDE_DIRS} ../include - ../src) + ../src + ../src/layout_manager + ../src/${PLUGIN_PM} + ../src/${PLUGIN_PM}/${USE_STM_NAME} +) target_link_libraries(${TARGETS_WM} PRIVATE ${AFB_LIBRARIES} ${WLC_LIBRARIES} - ${SD_LIBRARIES}) + ${SD_LIBRARIES} + ${PLUGIN_PM} +) target_compile_definitions(${TARGETS_WM} PRIVATE @@ -116,6 +127,9 @@ add_custom_command(TARGET ${TARGETS_WM} POST_BUILD 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 ${PROJECT_SOURCE_DIR}/layers.json ${PROJECT_BINARY_DIR}/package/root/etc + COMMAND cp -f ${PROJECT_SOURCE_DIR}/src/layout_manager/db/layout.db ${PROJECT_BINARY_DIR}/package/root/etc + COMMAND cp -f ${PROJECT_SOURCE_DIR}/src/${PLUGIN_PM}/db/role.db ${PROJECT_BINARY_DIR}/package/root/etc + COMMAND cp -f ${PROJECT_SOURCE_DIR}/src/db/app.db ${PROJECT_BINARY_DIR}/package/root/etc ) add_custom_target(package DEPENDS ${PROJECT_BINARY_DIR}/package/root diff --git a/src/app.cpp b/src/app.cpp index 937da6a..20f5b56 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -34,6 +34,7 @@ #include <json.hpp> #include <regex> #include <thread> +#include <string> namespace wm { @@ -130,6 +131,17 @@ int App::init() { return -1; } +#if 1 // @@@@@ + // Load app.db + this->loadAppDb(); +#endif + + // Initialize PolicyManager + this->pm_.initialize(); + + // Initialize LayoutManager + this->lm_.initialize(); + // Make afb event for (int i=Event_Val_Min; i<=Event_Val_Max; i++) { map_afb_event[kListEventName[i]] = afb_daemon_make_event(kListEventName[i]); @@ -245,328 +257,177 @@ int App::init_layers() { return 0; } -void App::surface_set_layout(int surface_id, optional<int> sub_surface_id) { - if (!this->controller->surface_exists(surface_id)) { - HMI_ERROR("wm", "Surface %d does not exist", surface_id); - return; - } - - auto o_layer_id = this->layers.get_layer_id(surface_id); - - if (!o_layer_id) { - HMI_ERROR("wm", "Surface %d is not associated with any layer!", surface_id); - return; - } - - uint32_t layer_id = *o_layer_id; - - auto const &layer = this->layers.get_layer(layer_id); - auto rect = layer.value().rect; - auto &s = this->controller->surfaces[surface_id]; - - int x = rect.x; - int y = rect.y; - int w = rect.w; - int h = rect.h; - - // less-than-0 values refer to MAX + 1 - $VALUE - // e.g. MAX is either screen width or height - if (w < 0) { - w = this->controller->output_size.w + 1 + w; - } - if (h < 0) { - h = this->controller->output_size.h + 1 + h; - } - - if (sub_surface_id) { - if (o_layer_id != this->layers.get_layer_id(*sub_surface_id)) { - HMI_ERROR("wm", - "surface_set_layout: layers of surfaces (%d and %d) don't match!", - surface_id, *sub_surface_id); - return; - } - - int x_off = 0; - int y_off = 0; - - // split along major axis - if (w > h) { - w /= 2; - x_off = w; - } else { - h /= 2; - y_off = h; - } - - auto &ss = this->controller->surfaces[*sub_surface_id]; - - HMI_DEBUG("wm", "surface_set_layout for sub surface %u on layer %u", - *sub_surface_id, layer_id); - - // set destination to the display rectangle - ss->set_destination_rectangle(x + x_off, y + y_off, w, h); - - this->area_info[*sub_surface_id].x = x; - this->area_info[*sub_surface_id].y = y; - this->area_info[*sub_surface_id].w = w; - this->area_info[*sub_surface_id].h = h; - } - - HMI_DEBUG("wm", "surface_set_layout for surface %u on layer %u", surface_id, - layer_id); - - // set destination to the display rectangle - s->set_destination_rectangle(x, y, w, h); - - // update area information - this->area_info[surface_id].x = x; - this->area_info[surface_id].y = y; - this->area_info[surface_id].w = w; - this->area_info[surface_id].h = h; - - HMI_DEBUG("wm", "Surface %u now on layer %u with rect { %d, %d, %d, %d }", - surface_id, layer_id, x, y, w, h); -} - void App::layout_commit() { this->controller->commit_changes(); this->display->flush(); } -void App::api_activate_surface(char const *drawing_name, char const *drawing_area, const reply_func &reply) { - ST(); - - auto const &surface_id = this->lookup_id(drawing_name); - - if (!surface_id) { - reply("Surface does not exist"); - return; - } - - if (!this->controller->surface_exists(*surface_id)) { - reply("Surface does not exist in controller!"); - return; - } - - auto layer_id = this->layers.get_layer_id(*surface_id); - - if (!layer_id) { - reply("Surface is not on any layer!"); - return; - } - - auto o_state = *this->layers.get_layout_state(*surface_id); - - if (o_state == nullptr) { - reply("Could not find layer for surface"); - return; - } - - HMI_DEBUG("wm", "surface %d is detected", *surface_id); - reply(nullptr); - - struct LayoutState &state = *o_state; - - // disable layers that are above our current layer - for (auto const &l : this->layers.mapping) { - if (l.second.layer_id <= *layer_id) { - continue; - } - - bool flush = false; - if (l.second.state.main != -1) { - this->deactivate(l.second.state.main); - l.second.state.main = -1; - flush = true; - } - - if (l.second.state.sub != -1) { - this->deactivate(l.second.state.sub); - l.second.state.sub = -1; - flush = true; - } - - if (flush) { - this->layout_commit(); - } - } - - auto layer = this->layers.get_layer(*layer_id); - - if (state.main == -1) { - this->try_layout( - state, LayoutState{*surface_id}, [&] (LayoutState const &nl) { - HMI_DEBUG("wm", "Layout: %s", kNameLayoutNormal); - this->surface_set_layout(*surface_id); - state = nl; - - // Commit for configuraton - this->layout_commit(); - - std::string str_area = std::string(kNameLayoutNormal) + "." + std::string(kNameAreaFull); - compositor::rect area_rect = this->area_info[*surface_id]; - this->emit_syncdraw(drawing_name, str_area.c_str(), - area_rect.x, area_rect.y, area_rect.w, area_rect.h); - this->enqueue_flushdraw(state.main); - }); - } else { - if (0 == strcmp(drawing_name, "HomeScreen")) { - this->try_layout( - state, LayoutState{*surface_id}, [&] (LayoutState const &nl) { - HMI_DEBUG("wm", "Layout: %s", kNameLayoutNormal); - std::string str_area = std::string(kNameLayoutNormal) + "." + std::string(kNameAreaFull); - compositor::rect area_rect = this->area_info[*surface_id]; - this->emit_syncdraw(drawing_name, str_area.c_str(), - area_rect.x, area_rect.y, area_rect.w, area_rect.h); - this->enqueue_flushdraw(state.main); - }); - } else { - bool can_split = this->can_split(state, *surface_id); - - if (can_split) { - this->try_layout( - state, - LayoutState{state.main, *surface_id}, - [&] (LayoutState const &nl) { - HMI_DEBUG("wm", "Layout: %s", kNameLayoutSplit); - std::string main = - std::move(*this->lookup_name(state.main)); - - this->surface_set_layout(state.main, surface_id); - if (state.sub != *surface_id) { - if (state.sub != -1) { - this->deactivate(state.sub); - } - } - state = nl; - - // Commit for configuration and visibility(0) - this->layout_commit(); - - std::string str_area_main = std::string(kNameLayoutSplit) + "." + std::string(kNameAreaMain); - std::string str_area_sub = std::string(kNameLayoutSplit) + "." + std::string(kNameAreaSub); - compositor::rect area_rect_main = this->area_info[state.main]; - compositor::rect area_rect_sub = this->area_info[*surface_id]; - this->emit_syncdraw(main.c_str(), str_area_main.c_str(), - area_rect_main.x, area_rect_main.y, - area_rect_main.w, area_rect_main.h); - this->emit_syncdraw(drawing_name, str_area_sub.c_str(), - area_rect_sub.x, area_rect_sub.y, - area_rect_sub.w, area_rect_sub.h); - this->enqueue_flushdraw(state.main); - this->enqueue_flushdraw(state.sub); - }); - } else { - this->try_layout( - state, LayoutState{*surface_id}, [&] (LayoutState const &nl) { - HMI_DEBUG("wm", "Layout: %s", kNameLayoutNormal); - - this->surface_set_layout(*surface_id); - if (state.main != *surface_id) { - this->deactivate(state.main); - } - if (state.sub != -1) { - if (state.sub != *surface_id) { - this->deactivate(state.sub); - } - } - state = nl; - - // Commit for configuraton and visibility(0) - this->layout_commit(); - - std::string str_area = std::string(kNameLayoutNormal) + "." + std::string(kNameAreaFull); - compositor::rect area_rect = this->area_info[*surface_id]; - this->emit_syncdraw(drawing_name, str_area.c_str(), - area_rect.x, area_rect.y, area_rect.w, area_rect.h); - this->enqueue_flushdraw(state.main); - }); - } - } - } -} - -void App::api_deactivate_surface(char const *drawing_name, const reply_func &reply) { - ST(); - auto const &surface_id = this->lookup_id(drawing_name); - - if (!surface_id) { - reply ("Surface does not exist"); - return; - } - - if (*surface_id == this->layers.main_surface) { - reply("Cannot deactivate main_surface"); - return; - } - - auto o_state = *this->layers.get_layout_state(*surface_id); - - if (o_state == nullptr) { - reply("Could not find layer for surface"); - return; - } - - struct LayoutState &state = *o_state; - - if (state.main == -1) { - reply("No surface active"); - return; - } - - // Check against main_surface, main_surface_name is the configuration item. - if (*surface_id == this->layers.main_surface) { - HMI_DEBUG("wm", "Refusing to deactivate main_surface %d", *surface_id); - reply(nullptr); - return; - } - if((state.main == *surface_id) && (state.sub == *surface_id)){ - reply("Surface is not active"); - return; - } - reply(nullptr); - - if (state.main == *surface_id) { - if (state.sub != -1) { - this->try_layout( - state, LayoutState{state.sub, -1}, [&] (LayoutState const &nl) { - std::string sub = std::move(*this->lookup_name(state.sub)); - - this->deactivate(*surface_id); - this->surface_set_layout(state.sub); - state = nl; - - this->layout_commit(); - std::string str_area = std::string(kNameLayoutNormal) + "." + std::string(kNameAreaFull); - compositor::rect area_rect = this->area_info[state.sub]; - this->emit_syncdraw(sub.c_str(), str_area.c_str(), - area_rect.x, area_rect.y, area_rect.w, area_rect.h); - this->enqueue_flushdraw(state.sub); - }); - } else { - this->try_layout(state, LayoutState{-1, -1}, [&] (LayoutState const &nl) { - this->deactivate(*surface_id); - state = nl; - this->layout_commit(); - }); - } - } else if (state.sub == *surface_id) { - this->try_layout( - state, LayoutState{state.main, -1}, [&] (LayoutState const &nl) { - std::string main = std::move(*this->lookup_name(state.main)); - - this->deactivate(*surface_id); - this->surface_set_layout(state.main); - state = nl; - - this->layout_commit(); - std::string str_area = std::string(kNameLayoutNormal) + "." + std::string(kNameAreaFull); - compositor::rect area_rect = this->area_info[state.main]; - this->emit_syncdraw(main.c_str(), str_area.c_str(), - area_rect.x, area_rect.y, area_rect.w, area_rect.h); - this->enqueue_flushdraw(state.main); - }); - } +void App::allocateWindowResource(char const *event, char const *drawing_name, + char const *drawing_area, char const *role, + const reply_func &reply) { + const char* new_role = nullptr; + const char* new_area = nullptr; + + if (0 == strcmp("activate", event)) { + // TODO: + // This process will be removed + // because the applications will specify role instead of drawing_name + { + if ((nullptr == role) || (0 == strcmp("", role))) { + HMI_DEBUG("wm", "Role is not specified, so get by using app name"); + new_role = this->app2role_[drawing_name].c_str(); + } + else { + new_role = role; + } + HMI_DEBUG("wm", "drawing_name:%s, new_role: %s", drawing_name, new_role); + } + + // TODO: + // This process will be removed + // because the area "normal.full" and "normalfull" will be prohibited + { + if (nullptr == drawing_area) { + new_area = "normal"; + } + else if (0 == strcmp("normal.full", drawing_area)) { + new_area = "normal"; + } + else if (0 == strcmp("homescreen", new_role)) { + // Now homescreen specifies "normalfull" + new_area = "full"; + } + else { + new_area = "normal"; + } + HMI_DEBUG("wm", "drawing_area:%s, new_area: %s", drawing_area, new_area); + } + } + else if (0 == strcmp("deactivate", event)) { + // TODO: + // This process will be removed + // because the applications will specify role instead of drawing_name + { + if ((nullptr == role) || (0 == strcmp("", role))) { + HMI_DEBUG("wm", "Role is not specified, so get by using app name"); + new_role = this->app2role_[drawing_name].c_str(); + } + else { + new_role = role; + } + HMI_DEBUG("wm", "drawing_name:%s, new_role: %s", drawing_name, new_role); + } + new_area = ""; + } + + // TODO: + // Check role + + // TODO: + // If event is "activate" and area is not specifid, + // get default value by using role + + // Check Policy + json_object* json_in = json_object_new_object(); + json_object* json_out = json_object_new_object(); + json_object_object_add(json_in, "event", json_object_new_string(event)); + + if (nullptr != new_role) { + json_object_object_add(json_in, "role", json_object_new_string(new_role)); + } + if (nullptr != new_area) { + json_object_object_add(json_in, "area", json_object_new_string(new_area)); + } + + int ret = this->pm_.checkPolicy(json_in, &json_out); + if (0 > ret) { + reply("Error checkPolicy()"); + return; + } + else { + HMI_DEBUG("wm", "result: %s", json_object_get_string(json_out)); + } + + // Release json_object + json_object_put(json_in); + + // Cat state + json_object* json_car; + if (!json_object_object_get_ex(json_out, "car", &json_car)) { + reply("Not found key \"car\""); + return; + } + + json_bool is_changed; + is_changed = jh::getBoolFromJson(json_car, "is_changed"); + if (is_changed) { + // Update car state + std::string car_state = jh::getStringFromJson(json_car, "state"); + HMI_DEBUG("wm", "car_state: %s", car_state.c_str()); + + // Emit car event + if ("car_stop" == car_state) { + this->emitCarStop(); + } + else if ("car_run" == car_state) { + this->emitCarRun(); + } + else { + reply("Unknown car state"); + return; + } + } + + // Lamp state + json_object* json_lamp; + if (!json_object_object_get_ex(json_out, "lamp", &json_lamp)) { + reply("Not found key \"lamp\""); + return; + } + + is_changed = jh::getBoolFromJson(json_lamp, "is_changed"); + if (is_changed) { + // Update car state + std::string lamp_state = jh::getStringFromJson(json_lamp, "state"); + HMI_DEBUG("wm", "lamp_state: %s", lamp_state.c_str()); + + // Emit lamp event + if ("lamp_off" == lamp_state) { + this->emitHeadlampOff(); + } + else if ("lamp_on" == lamp_state) { + this->emitHeadlampOn(); + } + else { + reply("Unknown lamp state"); + return; + } + } + + // Get category + const char* category = nullptr; + std::string str_category; + if (nullptr != new_role) { + str_category = this->pm_.roleToCategory(new_role); + category = str_category.c_str(); + HMI_DEBUG("wm", "role:%s category:%s", new_role, category); + } + + // Update layout + if (this->lm_.updateLayout(json_out, new_role, category)) { + HMI_DEBUG("wm", "Layer is changed!!"); + + // Allocate surface + this->allocateSurface(); + } + else { + HMI_DEBUG("wm", "All layer is NOT changed!!"); + } + + // Release json_object + json_object_put(json_out); + + return; } void App::enqueue_flushdraw(int surface_id) { @@ -603,6 +464,15 @@ void App::api_enddraw(char const *drawing_name) { void App::api_ping() { this->dispatch_pending_events(); } +void App::send_event(char const *evname){ + HMI_DEBUG("wm", "%s: %s", __func__, evname); + + int ret = afb_event_push(this->map_afb_event[evname], nullptr); + if (ret != 0) { + HMI_DEBUG("wm", "afb_event_push failed: %m"); + } +} + void App::send_event(char const *evname, char const *label){ HMI_DEBUG("wm", "%s: %s(%s)", __func__, evname, label); @@ -671,7 +541,9 @@ void App::surface_removed(uint32_t surface_id) { } else { auto drawing_name = this->lookup_name(surface_id); if (drawing_name) { - this->api_deactivate_surface(drawing_name->c_str(), [](const char*){}); + this->allocateWindowResource("deactivate", drawing_name->c_str(), + nullptr, nullptr, + [](const char*){}); } } @@ -705,6 +577,26 @@ void App::emit_invisible(char const *label) { void App::emit_visible(char const *label) { return emit_visible(label, true); } +void App::emitHeadlampOff() { + // Send HeadlampOff event for all application + this->send_event(kListEventName[Event_HeadlampOff]); +} + +void App::emitHeadlampOn() { + // Send HeadlampOn event for all application + this->send_event(kListEventName[Event_HeadlampOn]); +} + +void App::emitCarStop() { + // Send CarStop event for all application + this->send_event(kListEventName[Event_CarStop]); +} + +void App::emitCarRun() { + // Send CarRun event for all application + this->send_event(kListEventName[Event_CarRun]); +} + result<int> App::api_request_surface(char const *drawing_name) { auto lid = this->layers.get_layer_id(std::string(drawing_name)); if (!lid) { @@ -731,6 +623,20 @@ result<int> App::api_request_surface(char const *drawing_name) { HMI_DEBUG("wm", "Set main_surface id to %u", id); } +#if 0 // @@@@@ + // TODO: + // This process will be implemented in SystemManager + { + // Generate app id + auto id = int(this->app_id_alloc_.generate_id(drawing_name)); + this->appname2appid_[drawing_name] = id; + } +#endif + + // Set map of (role, surface_id) + std::string role = this->app2role_[std::string(drawing_name)]; + this->role2surfaceid_[role] = id; + return Ok<int>(id); } @@ -910,56 +816,24 @@ void App::deactivate(int id) { } } -void App::deactivate_main_surface() { - this->layers.main_surface = -1; - this->api_deactivate_surface(this->layers.main_surface_name.c_str(), [](const char*){}); -} - -bool App::can_split(struct LayoutState const &state, int new_id) { - if (state.main != -1 && state.main != new_id) { - auto new_id_layer = this->layers.get_layer_id(new_id).value(); - auto current_id_layer = this->layers.get_layer_id(state.main).value(); - - // surfaces are on separate layers, don't bother. - if (new_id_layer != current_id_layer) { - return false; - } - - std::string const &new_id_str = this->lookup_name(new_id).value(); - std::string const &cur_id_str = this->lookup_name(state.main).value(); - - auto const &layer = this->layers.get_layer(new_id_layer); - - HMI_DEBUG("wm", "layer info name: %s", layer->name.c_str()); - - if (layer->layouts.empty()) { - return false; - } - - for (auto i = layer->layouts.cbegin(); i != layer->layouts.cend(); i++) { - HMI_DEBUG("wm", "%d main_match '%s'", new_id_layer, i->main_match.c_str()); - auto rem = std::regex(i->main_match); - if (std::regex_match(cur_id_str, rem)) { - // build the second one only if the first already matched - HMI_DEBUG("wm", "%d sub_match '%s'", new_id_layer, i->sub_match.c_str()); - auto res = std::regex(i->sub_match); - if (std::regex_match(new_id_str, res)) { - HMI_DEBUG("wm", "layout matched!"); - return true; - } - } - } - } +void App::deactivate(std::string role) { + std::string app = this->roleToApp(role); + auto const &id = this->lookup_id(app.c_str()); + if (!id) { + HMI_ERROR("wm", "Surface does not exist"); + return; + } + HMI_DEBUG("wm", "Deactivate role:%s (app:%s)", + role.c_str(), app.c_str()); - return false; + this->deactivate(*id); } -void App::try_layout(struct LayoutState & /*state*/, - struct LayoutState const &new_layout, - std::function<void(LayoutState const &nl)> apply) { - if (this->policy.layout_is_valid(new_layout)) { - apply(new_layout); - } +void App::deactivate_main_surface() { + this->layers.main_surface = -1; + this->allocateWindowResource("deactivate", this->layers.main_surface_name.c_str(), + nullptr, nullptr, + [](const char*){}); } /** @@ -982,4 +856,302 @@ void controller_hooks::surface_destination_rectangle(uint32_t /*surface_id*/, uint32_t /*w*/, uint32_t /*h*/) {} +int App::allocateSurface() { + HMI_DEBUG("wm", "Call"); + + // Get current/previous layers + LayoutManager::TypeLayers crr_layers = this->lm_.getCurrentLayers(); + LayoutManager::TypeLayers prv_layers = this->lm_.getPreviousLayers(); + + // Update resource of all layers + for (auto itr_layers = crr_layers.begin(); + itr_layers != crr_layers.end(); ++itr_layers) { + // Get layer + std::string layer = itr_layers->first; + HMI_DEBUG("wm", "Update resource in %s layer", layer.c_str()); + + // If layout is changed, update resouce + if (this->lm_.isLayoutChanged(layer.c_str())) { + // Get current/previous layout + LayoutManager::TypeLayouts crr_layout = itr_layers->second; + LayoutManager::TypeLayouts prv_layout = prv_layers[layer]; + + // Get current/previous layout name + std::string crr_layout_name = crr_layout.begin()->first; + std::string prv_layout_name = prv_layout.begin()->first; + HMI_DEBUG("wm", "layout name crr:%s prv:%s", + crr_layout_name.c_str(), prv_layout_name.c_str()); + + // Get current/previous ares + LayoutManager::TypeAreas crr_areas = crr_layout[crr_layout_name]; + LayoutManager::TypeAreas prv_areas = prv_layout[prv_layout_name]; + + // Create previous displayed role list + std::string prv_area_name; + std::vector<std::string> prv_role_list; + for (auto itr_areas = prv_areas.begin(); + itr_areas != prv_areas.end(); ++itr_areas) { + prv_area_name = itr_areas->first; + prv_role_list.push_back(prv_areas[prv_area_name]["role"]); + HMI_DEBUG("wm", "previous displayed role:%s", + prv_areas[prv_area_name]["role"].c_str()); + } + + // Allocate surface for each area + std::string crr_area_name; + std::string crr_role_name; + LayoutManager::TypeRolCtg crr_rol_ctg; + for (auto itr_areas = crr_areas.begin(); + itr_areas != crr_areas.end(); ++itr_areas) { + crr_area_name = itr_areas->first; + crr_rol_ctg = itr_areas->second; + + // Get role of current area + if ("category" == crr_rol_ctg.begin()->first) { + // If current area have category + // Get category name + std::string crr_ctg = crr_rol_ctg.begin()->second; + + // Serch relevant role fron previous displayed role list + for (auto itr_role = prv_role_list.begin(); + itr_role != prv_role_list.end(); ++itr_role) { + std::string prv_ctg = this->pm_.roleToCategory((*itr_role).c_str()); + if (crr_ctg == prv_ctg) { + // First discovered role is set to current role + crr_role_name = *itr_role; + + // Delete used role for other areas + // which have same category + prv_role_list.erase(itr_role); + + break; + } + } + } + else { + crr_role_name = itr_areas->second["role"]; + } + HMI_DEBUG("wm", "Allocate surface for area:%s role:%s", + crr_area_name.c_str(), crr_role_name.c_str()); + + // Deactivate non-displayed role + std::string prv_role_name; + if (crr_layout_name == prv_layout_name) { + HMI_DEBUG("wm", "Current layout is same with previous"); + + // Deactivate previous role in same area + // if it is different with current + prv_role_name = prv_areas[crr_area_name]["role"]; + if (crr_role_name != prv_role_name) { + this->deactivate(prv_role_name); + } + } + else { + HMI_DEBUG("wm", "Current layout is different with previous"); + + if ("none" != prv_layout_name) { + // Deactivate previous role in all area in previous layout + // if it is different with current role + for(auto itr = prv_areas.begin(); itr != prv_areas.end(); ++itr) { + prv_role_name = itr->second["role"].c_str(); + if (crr_role_name != prv_role_name) { + this->deactivate(prv_role_name); + } + } + } + } + + // Set surface for displayed role + if ("none" != crr_layout_name) { + // If current layout is not "none", + // set surface for current role + this->setSurfaceSize(crr_role_name.c_str(), crr_area_name.c_str()); + + // TODO: + // This API is workaround. + // Resource manager should manage each resource infomations + // according to architecture document. + this->lm_.updateArea(layer.c_str(), crr_role_name.c_str(), crr_area_name.c_str()); + } + } + } + } + return 0; +} + +void App::setSurfaceSize(const char* role, const char* area) { + HMI_DEBUG("wm", "role:%s area:%s", role, area); + + // Get size of current area + compositor::rect size = this->lm_.getAreaSize(area); + + // Set destination to the display rectangle + int surface_id = this->role2surfaceid_[role]; + auto &s = this->controller->surfaces[surface_id]; + s->set_destination_rectangle(size.x, size.y, size.w, size.h); + this->layout_commit(); + + // Update area information + this->area_info[surface_id].x = size.x; + this->area_info[surface_id].y = size.y; + this->area_info[surface_id].w = size.w; + this->area_info[surface_id].h = size.h; + HMI_DEBUG("wm", "Surface rect { %d, %d, %d, %d }", + size.x, size.y, size.w, size.h); + + // Emit syncDraw event + const char* app = this->roleToApp(role).c_str(); + this->emit_syncdraw(app, area, + size.x, size.y, size.w, size.h); + + // Enqueue flushDraw event + this->enqueue_flushdraw(surface_id); +} + +std::string App::roleToApp(std::string role) { + HMI_DEBUG("wm", "Call"); + + for (auto itr = this->app2role_.begin(); + itr != this->app2role_.end(); itr++) { + if (role == itr->second) { + return itr->first; + } + } + return std::string("none"); +} + +extern const char* kDefaultAppDb; +int App::loadAppDb() { + HMI_DEBUG("wm", "Call"); + + // Get afm application installed dir + char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR"); + HMI_DEBUG("wm", "afm_app_install_dir:%s", afm_app_install_dir); + + std::string file_name; + if (!afm_app_install_dir) { + HMI_ERROR("wm", "AFM_APP_INSTALL_DIR is not defined"); + } + else { + file_name = std::string(afm_app_install_dir) + std::string("/etc/app.db"); + } + + // Load app.db + HMI_DEBUG("wm", "file_name:%s", file_name.c_str()); + json_object* json_obj = json_object_from_file(file_name.c_str()); + if (nullptr == json_obj) { + HMI_ERROR("wm", "Could not open app.db, so use default role information"); + json_obj = json_tokener_parse(kDefaultAppDb); + } + HMI_DEBUG("wm", "json_obj dump:%s", json_object_get_string(json_obj)); + + // Perse apps + HMI_DEBUG("wm", "Perse apps"); + json_object* json_cfg; + if (!json_object_object_get_ex(json_obj, "apps", &json_cfg)) { + HMI_ERROR("wm", "Parse Error!!"); + return -1; + } + + int len = json_object_array_length(json_cfg); + HMI_DEBUG("wm", "json_cfg len:%d", len); + HMI_DEBUG("wm", "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); + HMI_DEBUG("wm", "> json_tmp dump:%s", json_object_get_string(json_tmp)); + + const char* app = jh::getStringFromJson(json_tmp, "name"); + if (nullptr == app) { + HMI_ERROR("wm", "Parse Error!!"); + return -1; + } + HMI_DEBUG("wm", "> app:%s", app); + + const char* role = jh::getStringFromJson(json_tmp, "role"); + if (nullptr == role) { + HMI_ERROR("wm", "Parse Error!!"); + return -1; + } + HMI_DEBUG("wm", "> role:%s", role); + + this->app2role_[app] = std::string(role); + } + + // Check + for(auto itr = this->app2role_.begin(); + itr != this->app2role_.end(); ++itr) { + HMI_DEBUG("wm", "app:%s role:%s", + itr->first.c_str(), itr->second.c_str()); + } + + // Release json_object + json_object_put(json_obj); + + return 0; +} + + +const char* kDefaultAppDb = "{ \ + \"apps\": [ \ + { \ + \"name\": \"HomeScreen\", \ + \"role\": \"homescreen\" \ + }, \ + { \ + \"name\": \"Music\", \ + \"role\": \"music\" \ + }, \ + { \ + \"name\": \"MediaPlayer\", \ + \"role\": \"music\" \ + }, \ + { \ + \"name\": \"Video\", \ + \"role\": \"video\" \ + }, \ + { \ + \"name\": \"VideoPlayer\", \ + \"role\": \"video\" \ + }, \ + { \ + \"name\": \"WebBrowser\", \ + \"role\": \"browser\" \ + }, \ + { \ + \"name\": \"Radio\", \ + \"role\": \"radio\" \ + }, \ + { \ + \"name\": \"Phone\", \ + \"role\": \"phone\" \ + }, \ + { \ + \"name\": \"Navigation\", \ + \"role\": \"map\" \ + }, \ + { \ + \"name\": \"HVAC\", \ + \"role\": \"hvac\" \ + }, \ + { \ + \"name\": \"Settings\", \ + \"role\": \"settings\" \ + }, \ + { \ + \"name\": \"Dashboard\", \ + \"role\": \"dashboard\" \ + }, \ + { \ + \"name\": \"POI\", \ + \"role\": \"poi\" \ + }, \ + { \ + \"name\": \"Mixer\", \ + \"role\": \"mixer\" \ + } \ + ] \ +}"; + + } // namespace wm diff --git a/src/app.hpp b/src/app.hpp index d1393c0..9ab1280 100644 --- a/src/app.hpp +++ b/src/app.hpp @@ -31,6 +31,7 @@ #include "policy.hpp" #include "result.hpp" #include "wayland_ivi_wm.hpp" +#include "policy_manager.hpp" #include "hmi-debug.h" namespace wl { @@ -144,7 +145,13 @@ struct App { Event_SyncDraw, Event_FlushDraw, - Event_Val_Max = Event_FlushDraw, + Event_HeadlampOff, + Event_HeadlampOn, + + Event_CarStop, + Event_CarRun, + + Event_Val_Max = Event_CarRun, }; const std::vector<const char *> kListEventName{ @@ -153,7 +160,11 @@ struct App { "visible", "invisible", "syncdraw", - "flushdraw" + "flushdraw", + "headlamp_off", + "headlamp_on", + "car_stop", + "car_run", }; struct controller_hooks chooks; @@ -203,12 +214,14 @@ struct App { result<int> api_request_surface(char const *drawing_name); char const *api_request_surface(char const *drawing_name, char const *ivi_id); - void api_activate_surface(char const *drawing_name, char const *drawing_area, const reply_func &reply); - void api_deactivate_surface(char const *drawing_name, const reply_func &reply); + void allocateWindowResource(char const *event, char const *drawing_name, + char const *role, char const *drawing_area, + const reply_func &reply); void api_enddraw(char const *drawing_name); result<json_object *> api_get_display_info(); result<json_object *> api_get_area_info(char const *drawing_name); void api_ping(); + void send_event(char const *evname); void send_event(char const *evname, char const *label); void send_event(char const *evname, char const *label, char const *area, int x, int y, int w, int h); @@ -217,6 +230,23 @@ struct App { void surface_removed(uint32_t surface_id); private: +#if 1 // @@@@@ + PolicyManager pm_; + LayoutManager lm_; + std::unordered_map<std::string, int> role2surfaceid_; + std::unordered_map<std::string, std::string> app2role_; + std::unordered_map<int, int> appid2role_; + + int allocateSurface(); + void setSurfaceSize(const char* role, const char* area); + std::string roleToApp(std::string role); + int loadAppDb(); + +#if 0 + struct id_allocator app_id_alloc_; + std::unordered_map<std::string, int> appname2appid_; +#endif +#endif optional<int> lookup_id(char const *name); optional<std::string> lookup_name(int id); @@ -227,7 +257,6 @@ private: int init_layers(); - void surface_set_layout(int surface_id, optional<int> sub_surface_id = nullopt); void layout_commit(); // TMC WM Events to clients @@ -238,15 +267,16 @@ private: void emit_visible(char const *label, bool is_visible); void emit_invisible(char const *label); void emit_visible(char const *label); + void emitHeadlampOff(); + void emitHeadlampOn(); + void emitCarStop(); + void emitCarRun(); void activate(int id); void deactivate(int id); + void deactivate(std::string role); void deactivate_main_surface(); - bool can_split(struct LayoutState const &state, int new_id); - void try_layout(struct LayoutState &state, - struct LayoutState const &new_layout, - std::function<void(LayoutState const &nl)> apply); }; } // namespace wm diff --git a/src/db/app.db b/src/db/app.db new file mode 100644 index 0000000..32155ac --- /dev/null +++ b/src/db/app.db @@ -0,0 +1,68 @@ +{ + "apps": [ + { + "name": "HomeScreen", + "role": "homescreen" + }, + { + "name": "Music", + "role": "music" + }, + { + "name": "MediaPlayer", + "role": "music" + }, + { + "name": "Video", + "role": "video" + }, + { + "name": "VideoPlayer", + "role": "video" + }, + { + "name": "WebBrowser", + "role": "browser" + }, + { + "name": "Radio", + "role": "radio" + }, + { + "name": "Phone", + "role": "phone" + }, + { + "name": "Navigation", + "role": "map" + }, + { + "name": "HVAC", + "role": "hvac" + }, + { + "name": "Settings", + "role": "settings" + }, + { + "name": "Dashboard", + "role": "dashboard" + }, + { + "name": "POI", + "role": "poi" + }, + { + "name": "Mixer", + "role": "mixer" + }, + { + "name": "Splitable1", + "role": "splitable1" + }, + { + "name": "Splitable2", + "role": "splitable2" + } + ] +}
\ No newline at end of file diff --git a/src/json_helper.cpp b/src/json_helper.cpp index 193a187..ac3d2b0 100644 --- a/src/json_helper.cpp +++ b/src/json_helper.cpp @@ -14,9 +14,12 @@ * limitations under the License. */ -#include "json_helper.hpp" +#include <json-c/json.h> #include <json.h> +#include "json_helper.hpp" +#include "hmi-debug.h" + json_object *to_json(compositor::surface_properties const &s) { // auto j = json::object({ @@ -100,3 +103,52 @@ json_object *to_json(std::vector<uint32_t> const &v) { } return a; } + +namespace jh { + +const char* getStringFromJson(json_object* obj, const char* key) { + if ((nullptr == obj) || (nullptr == key)) { + HMI_ERROR("wm:jh", "Argument is nullptr!!!"); + return nullptr; + } + + json_object* tmp; + if (!json_object_object_get_ex(obj, key, &tmp)) { + HMI_DEBUG("wm:jh", "Not found key \"%s\"", key); + return nullptr; + } + + return json_object_get_string(tmp); +} + +int getIntFromJson(json_object* obj, const char* key) { + if ((nullptr == obj) || (nullptr == key)) { + HMI_ERROR("wm", "Argument is nullptr!!!"); + return 0; + } + + json_object* tmp; + if (!json_object_object_get_ex(obj, key, &tmp)) { + HMI_DEBUG("wm", "Not found key \"%s\"", key); + return 0; + } + + return json_object_get_int(tmp); +} + +json_bool getBoolFromJson(json_object* obj, const char* key) { + if ((nullptr == obj) || (nullptr == key)) { + HMI_ERROR("wm", "Argument is nullptr!!!"); + return 0; + } + + json_object* tmp; + if (!json_object_object_get_ex(obj, key, &tmp)) { + HMI_DEBUG("wm", "Not found key \"%s\"", key); + return 0; + } + + return json_object_get_boolean(tmp); +} + +} // namespace jh diff --git a/src/json_helper.hpp b/src/json_helper.hpp index 78e03f7..c2087cf 100644 --- a/src/json_helper.hpp +++ b/src/json_helper.hpp @@ -19,12 +19,19 @@ #include "result.hpp" #include "wayland_ivi_wm.hpp" +#include <json-c/json.h> #include <json.hpp> + struct json_object; json_object *to_json(compositor::screen const *s); json_object *to_json(compositor::controller::props_map const &s); 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); +json_bool getBoolFromJson(json_object* obj, const char* key); +} // namespace jh #endif // TMCAGLWM_JSON_HELPER_HPP diff --git a/src/layout.cpp b/src/layout.cpp deleted file mode 100644 index fbf2baa..0000000 --- a/src/layout.cpp +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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 "layout.hpp" diff --git a/src/layout.hpp b/src/layout.hpp deleted file mode 100644 index d5fd00c..0000000 --- a/src/layout.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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_LAYOUT_HPP -#define TMCAGLWM_LAYOUT_HPP - -#include <cstdint> -#include <string> - -#include "result.hpp" - -namespace wm { - -struct LayoutState { - int main{-1}; - int sub{-1}; - - bool operator==(const LayoutState &b) const { - return main == b.main && sub == b.sub; - } - - bool operator!=(const LayoutState &b) const { - return !(*this == b); - } -}; - -} // namespace wm - -#endif // TMCAGLWM_LAYOUT_HPP diff --git a/src/layout_manager/db/layout.db b/src/layout_manager/db/layout.db new file mode 100644 index 0000000..c7cefd8 --- /dev/null +++ b/src/layout_manager/db/layout.db @@ -0,0 +1,158 @@ +{ + "layouts": [ + { + "name": "pu", + "layer": "on_screen", + "areas": [ + { + "name": "pop_up", + "role": "incomming_call" + } + ] + }, + { + "name": "sa", + "layer": "on_screen", + "areas": [ + { + "name": "system_alert", + "role": "system_alert" + } + ] + }, + { + "name": "m1", + "layer": "apps", + "areas": [ + { + "name": "normal", + "role": "map" + } + ] + }, + { + "name": "m2", + "layer": "apps", + "areas": [ + { + "name": "split.main", + "role": "map" + }, + { + "name": "split.sub", + "category": "splitable" + } + ] + }, + { + "name": "mf", + "layer": "apps", + "areas": [ + { + "name": "full", + "role": "map" + } + ] + }, + { + "name": "s1", + "layer": "apps", + "areas": [ + { + "name": "normal", + "category": "splitable" + } + ] + }, + { + "name": "s2", + "layer": "apps", + "areas": [ + { + "name": "split.main", + "category": "splitable" + }, + { + "name": "split.sub", + "category": "splitable" + } + ] + }, + { + "name": "g", + "layer": "apps", + "areas": [ + { + "name": "normal", + "category": "general" + } + ] + }, + { + "name": "hs", + "layer": "homescreen", + "areas": [ + { + "name": "full", + "role": "homescreen" + } + ] + } + ], + "areas": [ + { + "name": "normal", + "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": "full", + "rect": { + "x": 0, + "y": 0, + "w": 1080, + "h": 1920 + } + }, + { + "name": "pop_up", + "rect": { + "x": 0, + "y": 640, + "w": 1080, + "h": 640 + } + }, + { + "name": "system_alert", + "rect": { + "x": 0, + "y": 640, + "w": 1080, + "h": 640 + } + } + ] +} diff --git a/src/layout_manager/layout.cpp b/src/layout_manager/layout.cpp new file mode 100644 index 0000000..dc73cbf --- /dev/null +++ b/src/layout_manager/layout.cpp @@ -0,0 +1,570 @@ +/* + * 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 <json-c/json.h> +#include "layout.hpp" +#include "json_helper.hpp" +#include "hmi-debug.h" + + +LayoutManager::LayoutManager() { + HMI_DEBUG("wm:lm", "Call"); +} + +int LayoutManager::initialize() { + HMI_DEBUG("wm:lm", "Call"); + + int ret = 0; + + // Load layout.db + ret = this->loadLayoutDb(); + if (0 > ret) { + HMI_ERROR("wm:lm", "Load layout.db Error!!"); + return ret; + } + + TypeLayouts layout; + TypeAreas area; + TypeRolCtg rol_ctg; + + rol_ctg["none"] = "none"; + area["none"] = rol_ctg; + layout["none"] = area; + + this->prv_layers_["on_screen"] = layout; + this->prv_layers_["apps"] = layout; + this->prv_layers_["homescreen"] = layout; + + this->crr_layers_["on_screen"] = layout; + this->crr_layers_["apps"] = layout; + this->crr_layers_["homescreen"] = layout; + + this->prv_layers_car_stop_["on_screen"] = layout; + this->prv_layers_car_stop_["apps"] = layout; + this->prv_layers_car_stop_["homescreen"] = layout; + + return ret; +} + +bool LayoutManager::updateLayout(json_object* obj, + const char* new_role, const char* category) { + HMI_DEBUG("wm:lm", "Call"); + + bool ret = false; + + // Check car state change + json_object* json_car; + if (!json_object_object_get_ex(obj, "car", &json_car)) { + HMI_ERROR("wm:lm", "Parse Error!!"); + return -1; + } + + json_bool is_car_state_changed; + std::string car_state = ""; + is_car_state_changed = jh::getBoolFromJson(json_car, "is_changed"); + if (is_car_state_changed) { + // If car state is changed, get car state + car_state = jh::getStringFromJson(json_car, "state"); + } + + // Update layout of all layers + json_object* json_layers; + if (!json_object_object_get_ex(obj, "layers", &json_layers)) { + HMI_ERROR("wm:lm", "Parse Error!!"); + return -1; + } + + int len = json_object_array_length(json_layers); + HMI_DEBUG("wm:lm", "json_layers len:%d", len); + HMI_DEBUG("wm:lm", "json_layers dump:%s", json_object_get_string(json_layers)); + + for (int i=0; i<len; i++) { + json_object* json_tmp = json_object_array_get_idx(json_layers, i); + + // Get layer name and json_object + const char* layer; + json_object* json_layer; + json_object_object_foreach(json_tmp, key, val) { + layer = key; + json_layer = val; + HMI_DEBUG("wm:lm", "Update %s layer state", layer); + } + + // Store previous state + this->prv_layers_[layer] = this->crr_layers_[layer]; + std::string prv_layout_name = this->prv_layers_[layer].begin()->first; + + // If car state is changed car_stop -> car_run, + // store current state for state of car stop + if ((is_car_state_changed) && ("car_run" == car_state)) { + HMI_DEBUG("wm:lm", "Store current state for state of car stop"); + this->prv_layers_car_stop_[layer] = this->crr_layers_[layer]; + } + + json_object* json_is_changed; + if (!json_object_object_get_ex(json_layer, "is_changed", &json_is_changed)) { + HMI_ERROR("wm:lm", "Not found key \"is_changed\""); + return false; + } + + // If layer state is changed + if (json_object_get_boolean(json_is_changed)) { + // Set layout changed flag + this->is_layout_changed_[layer] = true; + + json_object* json_state; + if (!json_object_object_get_ex(json_layer, "state", &json_state)) { + HMI_ERROR("wm:lm", "Not found key \"state\""); + return false; + } + + const char* crr_layout_name = json_object_get_string(json_state); + HMI_DEBUG("wm:lm", "crr state: %s", crr_layout_name); + + TypeLayouts crr_layout; + if ((is_car_state_changed) && ("car_stop" == car_state)) { + // If car state is changed car_run -> car_stop, + // restore state of car stop + HMI_DEBUG("wm:lm", "Restore state of car stop"); + crr_layout = this->prv_layers_car_stop_[layer]; + } + else if ("none" == std::string(crr_layout_name)) { + // If current layout is "none", + // current areas is set with "none" + TypeAreas area; + TypeRolCtg rol_ctg; + rol_ctg["none"] = "none"; + area["none"] = rol_ctg; + crr_layout["none"] = area; + } + else { + if (std::string(crr_layout_name) == prv_layout_name) { + // If previous layout is same with current, + // previous areas are copied to current + crr_layout[crr_layout_name] = this->prv_layers_[layer][crr_layout_name]; + } + else { + // If previous layout is NOT same with current, + // current areas is set with default value + crr_layout[crr_layout_name] = this->layout_define_[crr_layout_name]; + } + + if (is_car_state_changed) { + // Updating role is not necessary + // because new_role is not specified when car state is changed + } + else { + // Get new_area for new role + std::string new_area = this->getAreaName(this->layout_define_[crr_layout_name], + new_role, category); + + // Update role in new area + TypeRolCtg crr_role; + crr_role["role"] = std::string(new_role); + crr_layout[crr_layout_name][new_area] = crr_role; + } + } + + // Update layer state + this->crr_layers_[layer] = crr_layout; + + // Check + for (auto itr_layout = this->crr_layers_[layer].begin(); + itr_layout != this->crr_layers_[layer].end(); ++itr_layout) { + for (auto itr_area = itr_layout->second.begin(); + itr_area != itr_layout->second.end(); ++itr_area) { + for (auto itr_role = itr_area->second.begin(); + itr_role != itr_area->second.end(); ++itr_role) { + HMI_DEBUG("wm:lm", "layout:%s, area:%s, rol_ctg:%s, name:%s", + itr_layout->first.c_str(), itr_area->first.c_str(), + itr_role->first.c_str(), itr_role->second.c_str()); + } + } + } + + ret = true; + } + else { + // Clear layout changed flag + this->is_layout_changed_[layer] = false; + } + } + return ret; +} + +// TODO: This API is for workaround, so this will be removed +void LayoutManager::updateArea(const char* layer, const char* role, const char* area) { + this->crr_layers_[layer].begin()->second[area]["role"] = std::string(role); +} + +LayoutManager::TypeLayers LayoutManager::getCurrentLayers() { + return this->crr_layers_; +} + +LayoutManager::TypeLayers LayoutManager::getPreviousLayers() { + return this->prv_layers_; +} + +compositor::rect LayoutManager::getAreaSize(const char* area) { + return this->area2size_[area]; +} + +std::string LayoutManager::getAreaName(TypeAreas areas, const char* role, const char* category) { + for (auto itr_area = areas.begin(); itr_area != areas.end(); ++itr_area) { + std::string area_name = itr_area->first; + TypeRolCtg rol_ctg = itr_area->second; + + if ("role" == rol_ctg.begin()->first) { + if (std::string(role) == rol_ctg.begin()->second) { + return area_name; + } + } + else if ("category" == rol_ctg.begin()->first) { + if (std::string(category) == rol_ctg.begin()->second) { + return area_name; + } + } + else { + return std::string("none"); + } + } + return std::string("none"); +} + + +bool LayoutManager::isLayoutChanged(const char* layer) { + return this->is_layout_changed_[layer]; +} + +extern const char* kDefaultLayoutDb; +int LayoutManager::loadLayoutDb() { + HMI_DEBUG("wm:lm", "Call"); + + // Get afm application installed dir + char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR"); + HMI_DEBUG("wm:lm", "afm_app_install_dir:%s", afm_app_install_dir); + + std::string file_name; + if (!afm_app_install_dir) { + HMI_ERROR("wm:lm", "AFM_APP_INSTALL_DIR is not defined"); + } + else { + file_name = std::string(afm_app_install_dir) + std::string("/etc/layout.db"); + } + + // Load layout.db + HMI_DEBUG("wm:lm", "file_name:%s", file_name.c_str()); + json_object* json_obj = json_object_from_file(file_name.c_str()); + if (nullptr == json_obj) { + HMI_ERROR("wm:lm", "Could not open layout.db, so use default role information"); + json_obj = json_tokener_parse(kDefaultLayoutDb); + } + HMI_DEBUG("wm:lm", "json_obj dump:%s", json_object_get_string(json_obj)); + + // Perse layouts + HMI_DEBUG("wm:lm", "Perse layouts"); + json_object* json_cfg; + if (!json_object_object_get_ex(json_obj, "layouts", &json_cfg)) { + HMI_ERROR("wm:lm", "Parse Error!!"); + return -1; + } + + int len = json_object_array_length(json_cfg); + HMI_DEBUG("wm:lm", "json_cfg len:%d", len); + HMI_DEBUG("wm:lm", "json_cfg dump:%s", json_object_get_string(json_cfg)); + + const char* layout; + const char* role; + const char* category; + for (int i=0; i<len; i++) { + json_object* json_tmp = json_object_array_get_idx(json_cfg, i); + + layout = jh::getStringFromJson(json_tmp, "name"); + if (nullptr == layout) { + HMI_ERROR("wm:lm", "Parse Error!!"); + return -1; + } + HMI_DEBUG("wm:lm", "> layout:%s", layout); + + json_object* json_area_array; + if (!json_object_object_get_ex(json_tmp, "areas", &json_area_array)) { + HMI_ERROR("wm:lm", "Parse Error!!"); + return -1; + } + + int len_area = json_object_array_length(json_area_array); + HMI_DEBUG("wm:lm", "json_area_array len:%d", len_area); + HMI_DEBUG("wm:lm", "json_area_array dump:%s", json_object_get_string(json_area_array)); + + TypeAreas areas; + for (int j=0; j<len_area; j++) { + json_object* json_area = json_object_array_get_idx(json_area_array, j); + + const char* area = jh::getStringFromJson(json_area, "name"); + if (nullptr == area) { + HMI_ERROR("wm:lm", "Parse Error!!"); + return -1; + } + HMI_DEBUG("wm:lm", ">> area:%s", area); + + TypeRolCtg rol_ctg_name; + role = jh::getStringFromJson(json_area, "role"); + if (nullptr == role) { + category = jh::getStringFromJson(json_area, "category"); + if (nullptr == category) { + HMI_ERROR("wm:lm", "Parse Error!!"); + return -1; + } + rol_ctg_name["category"] = std::string(category); + HMI_DEBUG("wm:lm", ">>> category:%s", category); + } + else { + rol_ctg_name["role"] = std::string(role); + HMI_DEBUG("wm:lm", ">>> role:%s", role); + } + + areas[area] = rol_ctg_name; + } + + this->layout_define_[layout] = areas; + } + + // Check + for(auto itr_layout = this->layout_define_.begin(); + itr_layout != this->layout_define_.end(); ++itr_layout) { + for (auto itr_area = itr_layout->second.begin(); + itr_area != itr_layout->second.end(); ++itr_area) { + for (auto itr_role = itr_area->second.begin(); + itr_role != itr_area->second.end(); ++itr_role) { + HMI_DEBUG("wm:lm", "layout:%s, area:%s, rol_ctg:%s, name:%s", + itr_layout->first.c_str(), itr_area->first.c_str(), + itr_role->first.c_str(), itr_role->second.c_str()); + } + } + } + + // Perse areas + HMI_DEBUG("wm:lm", "Perse areas"); + if (!json_object_object_get_ex(json_obj, "areas", &json_cfg)) { + HMI_ERROR("wm:lm", "Parse Error!!"); + return -1; + } + + len = json_object_array_length(json_cfg); + HMI_DEBUG("wm:lm", "json_cfg len:%d", len); + HMI_DEBUG("wm:lm", "json_cfg dump:%s", json_object_get_string(json_cfg)); + + const char* area; + for (int i=0; i<len; i++) { + json_object* json_tmp = json_object_array_get_idx(json_cfg, i); + HMI_DEBUG("wm:lm", "> json_tmp dump:%s", json_object_get_string(json_tmp)); + + area = jh::getStringFromJson(json_tmp, "name"); + if (nullptr == area) { + HMI_ERROR("wm:lm", "Parse Error!!"); + return -1; + } + HMI_DEBUG("wm:lm", "> area:%s", area); + + json_object* json_rect; + if (!json_object_object_get_ex(json_tmp, "rect", &json_rect)) { + HMI_ERROR("wm:lm", "Parse Error!!"); + return -1; + } + HMI_DEBUG("wm:lm", "> json_rect dump:%s", json_object_get_string(json_rect)); + + compositor::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"); + + this->area2size_[area] = area_size; + } + + // Check + for(auto itr = this->area2size_.begin(); + itr != this->area2size_.end(); ++itr) { + HMI_DEBUG("wm:lm", "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 + json_object_put(json_obj); + + return 0; +} + +const char* kDefaultLayoutDb = "{ \ + \"layouts\": [ \ + { \ + \"name\": \"pu\", \ + \"layer\": \"on_screen\", \ + \"areas\": [ \ + { \ + \"name\": \"pop_up\", \ + \"role\": \"incomming_call\" \ + } \ + ] \ + }, \ + { \ + \"name\": \"sa\", \ + \"layer\": \"on_screen\", \ + \"areas\": [ \ + { \ + \"name\": \"system_alert\", \ + \"role\": \"system_alert\" \ + } \ + ] \ + }, \ + { \ + \"name\": \"m1\", \ + \"layer\": \"apps\", \ + \"areas\": [ \ + { \ + \"name\": \"normal\", \ + \"role\": \"map\" \ + } \ + ] \ + }, \ + { \ + \"name\": \"m2\", \ + \"layer\": \"apps\", \ + \"areas\": [ \ + { \ + \"name\": \"split.main\", \ + \"role\": \"map\" \ + }, \ + { \ + \"name\": \"split.sub\", \ + \"category\": \"hvac\" \ + } \ + ] \ + }, \ + { \ + \"name\": \"mf\", \ + \"layer\": \"apps\", \ + \"areas\": [ \ + { \ + \"name\": \"full\", \ + \"role\": \"map\" \ + } \ + ] \ + }, \ + { \ + \"name\": \"s1\", \ + \"layer\": \"apps\", \ + \"areas\": [ \ + { \ + \"name\": \"normal\", \ + \"category\": \"splitable\" \ + } \ + ] \ + }, \ + { \ + \"name\": \"s2\", \ + \"layer\": \"apps\", \ + \"areas\": [ \ + { \ + \"name\": \"split.main\", \ + \"category\": \"splitable\" \ + }, \ + { \ + \"name\": \"split.sub\", \ + \"category\": \"splitable\" \ + } \ + ] \ + }, \ + { \ + \"name\": \"g\", \ + \"layer\": \"apps\", \ + \"areas\": [ \ + { \ + \"name\": \"normal\", \ + \"category\": \"general\" \ + } \ + ] \ + }, \ + { \ + \"name\": \"hs\", \ + \"layer\": \"homescreen\", \ + \"areas\": [ \ + { \ + \"name\": \"full\", \ + \"role\": \"homescreen\" \ + } \ + ] \ + } \ + ], \ + \"areas\": [ \ + { \ + \"name\": \"normal\", \ + \"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\": \"full\", \ + \"rect\": { \ + \"x\": 0, \ + \"y\": 0, \ + \"w\": 1080, \ + \"h\": 1920 \ + } \ + }, \ + { \ + \"name\": \"pop_up\", \ + \"rect\": { \ + \"x\": 0, \ + \"y\": 640, \ + \"w\": 1080, \ + \"h\": 640 \ + } \ + }, \ + { \ + \"name\": \"system_alert\", \ + \"rect\": { \ + \"x\": 0, \ + \"y\": 640, \ + \"w\": 1080, \ + \"h\": 640 \ + } \ + } \ + ] \ +}"; diff --git a/src/layout_manager/layout.hpp b/src/layout_manager/layout.hpp new file mode 100644 index 0000000..bfa4a6c --- /dev/null +++ b/src/layout_manager/layout.hpp @@ -0,0 +1,84 @@ +/* + * 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_LAYOUT_HPP +#define TMCAGLWM_LAYOUT_HPP + +#include <cstdint> +#include <string> +#include <map> +#include "result.hpp" +#include "wayland_ivi_wm.hpp" + +namespace wm { + +struct LayoutState { + int main{-1}; + int sub{-1}; + + bool operator==(const LayoutState &b) const { + return main == b.main && sub == b.sub; + } + + bool operator!=(const LayoutState &b) const { + return !(*this == b); + } +}; + +} // namespace wm + +class LayoutManager { +public: + explicit LayoutManager(); + ~LayoutManager() = default; + + typedef std::unordered_map<std::string, std::string> TypeRolCtg; + typedef std::unordered_map<std::string, TypeRolCtg> TypeAreas; + typedef std::unordered_map<std::string, TypeAreas> TypeLayouts; + typedef std::unordered_map<std::string, TypeLayouts> TypeLayers; + + int initialize(); + bool updateLayout(json_object* obj, const char* new_role, const char* new_area); + TypeLayers getCurrentLayers(); + TypeLayers getPreviousLayers(); + compositor::rect getAreaSize(const char* area); + bool isLayoutChanged(const char* layer); + + void updateArea(const char* layer, const char* role, const char* area); + +private: + // Disable copy and move + LayoutManager(LayoutManager const &) = delete; + LayoutManager &operator=(LayoutManager const &) = delete; + LayoutManager(LayoutManager &&) = delete; + LayoutManager &operator=(LayoutManager &&) = delete; + + TypeLayouts layout_define_; + std::unordered_map<std::string, compositor::rect> area2size_; + + TypeLayers crr_layers_, prv_layers_; + TypeLayers prv_layers_car_stop_; + + std::unordered_map<std::string, bool> is_layout_changed_; + + std::string getAreaName(TypeAreas area, const char* role, const char* category); + int loadLayoutDb(); + std::string role2App(std::string role, void* ptr); +}; + + + +#endif // TMCAGLWM_LAYOUT_HPP diff --git a/src/low_can_client.cpp b/src/low_can_client.cpp new file mode 100644 index 0000000..23a39e2 --- /dev/null +++ b/src/low_can_client.cpp @@ -0,0 +1,193 @@ +/* + * 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 "json_helper.hpp" +#include "low_can_client.hpp" +#include "hmi-debug.h" + +extern "C" { +#include <afb/afb-binding.h> +} + + +namespace wm { + +LowCanClient::LowCanClient() : + vehicle_speed_(0), + trans_gear_pos_(0), + park_brake_status_(TRUE), + headlamp_status_(FALSE), + prv_car_state_("car_stop"), + crr_car_state_("car_stop"), + prv_lamp_state_("lamp_off"), + crr_lamp_state_("lamp_off"), + is_changed_car_state_(false), + is_changed_lamp_state_(false) +{ + HMI_DEBUG("wm:lcc", "Call"); +} + +void LowCanClient::initialize() { + HMI_DEBUG("wm:lcc", "Call"); + + int ret; + + // Require API "low-can" + ret = afb_daemon_require_api_v2("low-can", 1); + if (0 > ret) { + HMI_INFO("wm:lcc", "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" } + for (int i=0; i<this->kNumEvent_; i++) { + json_object *json_obj = json_object_new_object(); + json_object_object_add(json_obj, "event", json_object_new_string(this->kEventName_[i])); + HMI_DEBUG("wm:lcc", "subscribe message:%s", json_object_get_string(json_obj)); + + json_object *json_result = json_object_new_object(); + ret = afb_service_call_sync("low-can", "subscribe", json_obj, &json_result); + if (0 > ret) { + HMI_INFO("wm:lcc", "Could not subscribe to \"low-can\" :%d", ret); + return; + } + HMI_DEBUG("wm:lcc", "subscribe result:%s", json_object_get_string(json_result)); + } + + return; +} + +void LowCanClient::analyzeCanSignal(struct json_object *object) { + HMI_DEBUG("wm:lcc", "object:%s", json_object_get_string(object)); + + const char* name = jh::getStringFromJson(object, "name"); + HMI_DEBUG("wm:lcc", "CAN signal name:%s", name); + + if (strstr(name, "vehicle.speed")) { + HMI_DEBUG("wm:lcc", "Receive vehicle speed"); + // Update vehicle speed + int speed = jh::getIntFromJson(object, "value"); + if (this->vehicle_speed_ != speed) { + this->vehicle_speed_ = speed; + HMI_DEBUG("wm:lcc", "Update vehicle speed:%d", this->vehicle_speed_); + } + } + else if (strstr(name, "transmission_gear_position")) { + HMI_DEBUG("wm:lcc", "Receive transmission gear position"); + // Update transmission gear position + int gear_pos = jh::getIntFromJson(object, "value"); + if (this->trans_gear_pos_ != gear_pos) { + this->trans_gear_pos_ = gear_pos; + HMI_DEBUG("wm:lcc", "Update transmission gear position:%d", this->trans_gear_pos_); + } + } + else if (strstr(name, "parking_brake_status")) { + HMI_DEBUG("wm:lcc", "Receive parking brake status"); + // Update parking gear status + json_bool park_brake = jh::getBoolFromJson(object, "value"); + if (this->park_brake_status_ != park_brake) { + this->park_brake_status_ = park_brake; + HMI_DEBUG("wm:lcc", "Update parking brake status:%d", this->park_brake_status_); + } + } + else if (strstr(name, "headlamp_status")) { + HMI_DEBUG("wm:lcc", "Receive headlamp status"); + // Update headlamp status + json_bool headlamp = jh::getBoolFromJson(object, "value"); + if (this->headlamp_status_ != headlamp) { + this->headlamp_status_ = headlamp; + HMI_DEBUG("wm:lcc", "Update headlamp status:%d", this->headlamp_status_); + } + } + + // Update car state + if ((0 == this->vehicle_speed_) || (true == this->park_brake_status_)) { + this->crr_car_state_ = "car_stop"; + } + else { + this->crr_car_state_ = "car_run"; + } + HMI_DEBUG("wm:lcc", "Current car state:%s", this->crr_car_state_.c_str()); + + // Update lamp state + if (true == this->headlamp_status_) { + this->crr_lamp_state_ = "lamp_on"; + } + else { + this->crr_lamp_state_ = "lamp_off"; + } + HMI_DEBUG("wm:lcc", "Current lamp state:%s", this->crr_lamp_state_.c_str()); + + // If car state is changed, + // backup current state for previous state and set flag + if (this->prv_car_state_ != this->crr_car_state_) { + HMI_DEBUG("wm:lcc", "Car state is changed: %s -> %s", + this->prv_car_state_.c_str(), this->crr_car_state_.c_str()); + this->prv_car_state_ = this->crr_car_state_; + this->is_changed_car_state_ = true; + } + + // If lamp state is changed, + // backup current state for previous state and set flag + if (this->prv_lamp_state_ != this->crr_lamp_state_) { + HMI_DEBUG("wm:lcc", "Lamp state is changed: %s -> %s", + this->prv_lamp_state_.c_str(), this->crr_lamp_state_.c_str()); + this->prv_lamp_state_ = this->crr_lamp_state_; + this->is_changed_lamp_state_ = true; + } +} + +bool LowCanClient::isChangedCarState() { + HMI_DEBUG("wm:lcc", "Call"); + + // Return changed flag + return this->is_changed_car_state_; +} + +bool LowCanClient::isChangedLampState() { + HMI_DEBUG("wm:lcc", "Call"); + + // Return changed flag + return this->is_changed_lamp_state_; +} + +const char* LowCanClient::getCurrentCarState() { + HMI_DEBUG("wm:lcc", "Call"); + + // Clear changed flag + this->is_changed_car_state_ = false; + + // Return current car state + return this->crr_car_state_.c_str(); +} + +const char* LowCanClient::getCurrentLampState() { + HMI_DEBUG("wm:lcc", "Call"); + + // Clear changed flag + this->is_changed_lamp_state_ = false; + + // Return current lamp state + return this->crr_lamp_state_.c_str(); +} + + +} // namespace wm diff --git a/src/low_can_client.hpp b/src/low_can_client.hpp new file mode 100644 index 0000000..5119c23 --- /dev/null +++ b/src/low_can_client.hpp @@ -0,0 +1,72 @@ +/* + * 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 <vector> +#include <json-c/json.h> + + +namespace wm { + +class LowCanClient { + +public: + explicit LowCanClient(); + ~LowCanClient() = default; + + void initialize(); + void analyzeCanSignal(struct json_object *object); + bool isChangedCarState(); + bool isChangedLampState(); + const char* getCurrentCarState(); + const char* getCurrentLampState(); + +private: + // Disable copy and move + LowCanClient(LowCanClient const &) = delete; + LowCanClient &operator=(LowCanClient const &) = delete; + LowCanClient(LowCanClient &&) = delete; + LowCanClient &operator=(LowCanClient &&) = delete; + + const int kNumEvent_ = 4; + const std::vector<const char*> kEventName_{ + "vehicle.speed", + "transmission_gear_position", + "headlamp_status", + "parking_brake_status" + }; + + int vehicle_speed_; + int trans_gear_pos_; + json_bool park_brake_status_; + json_bool headlamp_status_; + + std::string prv_car_state_; + std::string crr_car_state_; + std::string prv_lamp_state_; + std::string crr_lamp_state_; + + bool is_changed_car_state_; + bool is_changed_lamp_state_; +}; + +} // namespace wm + + +#endif // TMCAGLWM_LOW_CAN_CLIENT_HPP diff --git a/src/main.cpp b/src/main.cpp index 2f813a3..067a006 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,6 +24,7 @@ #include "json_helper.hpp" #include "util.hpp" #include "wayland_ivi_wm.hpp" +#include "low_can_client.hpp" extern "C" { #include <afb/afb-binding.h> @@ -39,9 +40,10 @@ typedef struct wmClientCtxt{ struct afb_instance { std::unique_ptr<wl::display> display; + wm::LowCanClient lcc_; wm::App app; - afb_instance() : display{new wl::display}, app{this->display.get()} {} + afb_instance() : display{new wl::display}, lcc_{}, app{this->display.get()} {} int init(); }; @@ -50,6 +52,10 @@ struct afb_instance *g_afb_instance; std::mutex binding_m; int afb_instance::init() { + // Initialize LowCanClient class + this->lcc_.initialize(); + + // Initialize App class return this->app.init(); } @@ -298,8 +304,14 @@ void windowmanager_activatesurface(afb_req req) noexcept { return; } - g_afb_instance->app.api_activate_surface(a_drawing_name, a_drawing_area, - [&req](const char* errmsg){ + const char* a_role = afb_req_value(req, "role"); + if(!a_role){ + a_role = ""; + } + + g_afb_instance->app.allocateWindowResource("activate", a_drawing_name, + a_drawing_area, a_role, + [&req](const char* errmsg){ if (errmsg != nullptr) { HMI_ERROR("wm", errmsg); afb_req_fail(req, "failed", errmsg); @@ -332,8 +344,14 @@ void windowmanager_deactivatesurface(afb_req req) noexcept { return; } - g_afb_instance->app.api_deactivate_surface(a_drawing_name, - [&req](const char* errmsg){ + const char* a_role = afb_req_value(req, "role"); + if(!a_role){ + a_role = ""; + } + + g_afb_instance->app.allocateWindowResource("deactivate", a_drawing_name, + nullptr, a_role, + [&req](const char* errmsg){ if (errmsg != nullptr) { HMI_ERROR("wm", errmsg); afb_req_fail(req, "failed", errmsg); @@ -452,6 +470,12 @@ void windowmanager_wm_subscribe(afb_req req) noexcept { return; } int event_type = json_object_get_int(j); + if ((wm::App::Event_Val_Min > event_type) + || (wm::App::Event_Val_Max < event_type)) { + afb_req_fail(req, "failed", "Invalid EventType"); + return; + } + const char *event_name = g_afb_instance->app.kListEventName[event_type]; struct afb_event event = g_afb_instance->app.map_afb_event[event_name]; int ret = afb_req_subscribe(req, event); @@ -635,5 +659,48 @@ const struct afb_verb_v2 windowmanager_verbs[] = { {} }; +void on_event(const char *event, struct json_object *object){ + HMI_DEBUG("wm", "event:%s", event); + + // If receive low can signal + if (strstr(event, "low-can")) { + // Analyze low can signal + g_afb_instance->lcc_.analyzeCanSignal(object); + + if (g_afb_instance->lcc_.isChangedCarState()) { + // If car state is changed + HMI_DEBUG("wm", "Car state is changed"); + + // Get car state + const char* car_state = g_afb_instance->lcc_.getCurrentCarState(); + + // Allocate window resource + g_afb_instance->app.allocateWindowResource(car_state, nullptr, + nullptr, nullptr, + [](const char* errmsg){ + if (errmsg != nullptr) { + HMI_ERROR("wm", errmsg); + } + }); + } + else if (g_afb_instance->lcc_.isChangedLampState()) { + // If lamp state is changed + HMI_DEBUG("wm", "Lamp state is changed"); + + // Get lamp state + const char* lamp_state = g_afb_instance->lcc_.getCurrentLampState(); + + // Allocate window resource + g_afb_instance->app.allocateWindowResource(lamp_state, nullptr, + nullptr, nullptr, + [](const char* errmsg){ + if (errmsg != nullptr) { + HMI_ERROR("wm", errmsg); + } + }); + } + } +} + extern "C" const struct afb_binding_v2 afbBindingV2 = { - "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, nullptr, 0}; + "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, on_event, 0}; diff --git a/src/policy_manager/CMakeLists.txt b/src/policy_manager/CMakeLists.txt new file mode 100644 index 0000000..ca31e5f --- /dev/null +++ b/src/policy_manager/CMakeLists.txt @@ -0,0 +1,65 @@ +# +# 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(FindPkgConfig) + +# We do not want a prefix for our module +set(CMAKE_SHARED_MODULE_PREFIX "") + +set(TARGETS_PM lib${PLUGIN_PM}) + +# Set use STM name +set(USE_STM_NAME zipc) + +add_library(${TARGETS_PM} MODULE + policy_manager.cpp + policy_manager.hpp + ${USE_STM_NAME}/dummy_stm.c +) + +target_include_directories(${TARGETS_PM} + PRIVATE + ../../include + ../ + ./ + ./${USE_STM_NAME} +) + +target_compile_definitions(${TARGETS_PM} + PRIVATE + _GNU_SOURCE +) + +target_compile_options(${TARGETS_PM} + PRIVATE + -Wall -Wextra -Wno-unused-parameter -Wno-comment) + +set_target_properties(${TARGETS_PM} + PROPERTIES + CXX_EXTENSIONS OFF + CXX_STANDARD 14 + CXX_STANDARD_REQUIRED ON + + C_EXTENSIONS OFF + C_STANDARD 99 + C_STANDARD_REQUIRED ON +) + +install( + TARGETS ${TARGET_PM} + DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT "runtime" +) diff --git a/src/policy_manager/db/role.db b/src/policy_manager/db/role.db new file mode 100644 index 0000000..2807fde --- /dev/null +++ b/src/policy_manager/db/role.db @@ -0,0 +1,44 @@ +{ + "roles":[ + { + "category": "homescreen", + "role": "homescreen", + "area": "full", + }, + { + "category": "map", + "role": "map", + "area": "full | normal | split.main", + }, + { + "category": "general", + "role": "poi | music | video | browser | sdl | settings | mixer | radio | hvac | dashboard | debug", + "area": "normal", + }, + { + "category": "phone", + "role": "phone", + "area": "normal", + }, + { + "category": "splitable", + "role": "splitable1 | splitable2", + "area": "normal | split.main | split.sub", + }, + { + "category": "popup", + "role": "popup", + "area": "on_screen", + }, + { + "category": "system_alert", + "role": "system_alert", + "area": "on_screen", + }, + { + "category": "tbt", + "role": "tbt", + "area": "hud", + } + ] +}
\ No newline at end of file diff --git a/src/policy_manager/policy_manager.cpp b/src/policy_manager/policy_manager.cpp new file mode 100644 index 0000000..61d1d7c --- /dev/null +++ b/src/policy_manager/policy_manager.cpp @@ -0,0 +1,497 @@ +/* + * 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 <fstream> +#include <sstream> +#include <istream> +#include <json-c/json.h> +#include "policy_manager.hpp" +#include "dummy_stm.h" +#include "hmi-debug.h" + + +namespace { + +static const char* kEventName[] = { + "activate", + "deactivate", + "car_stop", + "car_run", + "timer_expired", + "lamp_off", + "lamp_on" +}; + +static const int kEventNo[] = { + STM_EVT_NO_ACTIVATE, + STM_EVT_NO_DEACTIVATE, + STM_EVT_NO_CAR_STOP, + STM_EVT_NO_CAR_RUN, + STM_EVT_NO_TIMER_EXPIRED, + STM_EVT_NO_LAMP_OFF, + STM_EVT_NO_LAMP_ON +}; + +static const char* kCategoryName[] = { + "homescreen", + "map", + "general", + "splitable", + "popup", + "system_alert" +}; + +static const int kCategoryNo[] = { + STM_CTG_NO_HOMESCREEN, + STM_CTG_NO_MAP, + STM_CTG_NO_GENERAL, + STM_CTG_NO_SPLITABLE, + STM_CTG_NO_POPUP, + STM_CTG_NO_SYSTEM_ALERT +}; + +static const char* kAreaName[] = { + "full", + "normal", + "split.main", + "split.sub", + "onscreen" +}; + +static const int kAreaNo[] = { + STM_ARA_NO_FULL, + STM_ARA_NO_NORMAL, + STM_ARA_NO_SPLIT_MAIN, + STM_ARA_NO_SPLIT_SUB, + STM_ARA_NO_ON_SCREEN +}; + +// String for state +const char* gStmCarStateNo2Name[] = { + "car_stop", + "car_run" +}; + +const char* gStmLampStateNo2Name[] = { + "lamp_off", + "lamp_on" +}; + +const char* gStmLayoutNo2Name[] = { + "none", + "pu", + "sa", + "m1", + "m2", + "mf", + "s1", + "s2", + "g", + "hs", +}; + +} // namespace + +PolicyManager::PolicyManager() : + eventname2no_(), + categoryname2no_(), + areaname2no_(), + role2category_(), + category2role_(), + role2defaultarea_(), + current_state_() +{ + HMI_DEBUG("wm:pm", "Call"); +} + +int PolicyManager::initialize() { + HMI_DEBUG("wm:pm", "Call"); + + int ret = 0; + + // Create convert map + for (unsigned int i=0; i<(sizeof(kEventNo)/sizeof(int)); i++) { + HMI_DEBUG("wm:pm", "event name:%s no:%d", kEventName[i], kEventNo[i]); + this->eventname2no_[kEventName[i]] = kEventNo[i]; + } + + for (unsigned int i=0; i<(sizeof(kCategoryNo)/sizeof(int)); i++) { + HMI_DEBUG("wm:pm", "category name:%s no:%d", kCategoryName[i], kCategoryNo[i]); + this->categoryname2no_[kCategoryName[i]] = kCategoryNo[i]; + } + + for (unsigned int i=0; i<(sizeof(kAreaNo)/sizeof(int)); i++) { + HMI_DEBUG("wm:pm", "area name:%s no:%d", kAreaName[i], kAreaNo[i]); + this->areaname2no_[kAreaName[i]] = kAreaNo[i]; + } + + // Load role.db + ret = loadRoleDb(); + if (0 > ret) { + HMI_ERROR("wm:pm", "Load role.db Error!!"); + return ret; + } + + // TODO: + // Initialize StateTransitioner + // stmInitialize(); + + return ret; +} + +int PolicyManager::checkPolicy(json_object* json_in, json_object** json_out) { + HMI_DEBUG("wm:pm", "Call"); + + // Check arguments + if ((nullptr == json_in) || (nullptr == json_out)) { + HMI_ERROR("wm:pm", "Argument is NULL!!"); + return -1; + } + + // Get event from json_object + const char* event = getStringFromJson(json_in, "event"); + int event_no = 0; + if (nullptr != event) { + // Convert name to number + event_no = this->eventname2no_[event]; + HMI_DEBUG("wm:pm", "event(%s:%d)", event, event_no); + } + + // Get role from json_object + const char* role = getStringFromJson(json_in, "role"); + int category_no = 0; + if (nullptr != role) { + HMI_DEBUG("wm:pm", "role(%s)", role); + + // Convert role to category + const char* category = this->role2category_[role].c_str(); + if (0 == strcmp("", category)) { + HMI_ERROR("wm:pm", "Error!!"); + return -1; + } + HMI_DEBUG("wm:pm", "category(%s)", category); + + // Convert name to number + category_no = categoryname2no_[category]; + HMI_DEBUG("wm:pm", "role(%s), category(%s:%d)", role, category, category_no); + } + + // Get areat from json_object + const char* area = getStringFromJson(json_in, "area"); + int area_no = 0; + if (nullptr != area) { + // Convert name to number + area_no = areaname2no_[area]; + HMI_DEBUG("wm:pm", "area(%s:%d)", area, area_no); + } + + // Transition state + HMI_DEBUG("wm:pm", "set event:0x%x", (event_no | category_no | area_no)); + int ret = stmTransitionState((event_no | category_no | area_no), + &(this->current_state_)); + if (0 > ret) { + HMI_ERROR("wm:pm", "Error!!"); + return -1; + } + + // Create result + // { + // "car": { + // "is_changed": <bool>, + // "state": <const char*> + // }, + HMI_DEBUG("wm", "@@@@@ car state (is_changed:%d state:%d:%s)", + this->current_state_.car.is_changed, + this->current_state_.car.state, + gStmCarStateNo2Name[this->current_state_.car.state]); + this->addStateToJson("car", + this->current_state_.car.is_changed, + gStmCarStateNo2Name[this->current_state_.car.state], + json_out); + + // "lamp": { + // "is_changed": <bool>, + // "state": <const char*> + // }, + HMI_DEBUG("wm", "@@@@@ lamp state (is_changed:%d state:%d:%s)", + this->current_state_.lamp.is_changed, + this->current_state_.lamp.state, + gStmLampStateNo2Name[this->current_state_.lamp.state]); + this->addStateToJson("lamp", + this->current_state_.lamp.is_changed, + gStmLampStateNo2Name[this->current_state_.lamp.state], + json_out); + + // "layers": [ + // { + // "on_screen": { + // "is_changed": <bool>, + // "state": <const char*> + // } + // }, + json_object* json_layer = json_object_new_array(); + json_object* json_tmp = json_object_new_object(); + this->addStateToJson("on_screen", + this->current_state_.layer.on_screen.is_changed, + gStmLayoutNo2Name[this->current_state_.layer.on_screen.state], + &json_tmp); + json_object_array_add(json_layer, json_tmp); + + // { + // "apps": { + // "is_changed": <bool>, + // "state": <const char*> + // } + // }, + json_tmp = json_object_new_object(); + this->addStateToJson("apps", + this->current_state_.layer.apps.is_changed, + gStmLayoutNo2Name[this->current_state_.layer.apps.state], + &json_tmp); + json_object_array_add(json_layer, json_tmp); + + // { + // "homescreen": { + // "is_changed": <bool>, + // "state": <const char*> + // } + // }, + // ] + // } + json_tmp = json_object_new_object(); + this->addStateToJson("homescreen", + this->current_state_.layer.homescreen.is_changed, + gStmLayoutNo2Name[this->current_state_.layer.homescreen.state], + &json_tmp); + json_object_array_add(json_layer, json_tmp); + + // Add json array of layer + json_object_object_add(*json_out, "layers", json_layer); + + HMI_DEBUG("wm:pm", "json_out.dump:%s", json_object_get_string(*json_out)); + + return 0; +} + +std::string PolicyManager::roleToCategory(const char* role) { + return this->role2category_[role]; +} + +extern const char* kDefaultRoleDb; +int PolicyManager::loadRoleDb() { + HMI_DEBUG("wm:pm", "Call"); + + std::string file_name; + + // Get afm application installed dir + char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR"); + HMI_DEBUG("wm:pm", "afm_app_install_dir:%s", afm_app_install_dir); + + if (!afm_app_install_dir) { + HMI_ERROR("wm:pm", "AFM_APP_INSTALL_DIR is not defined"); + } + else { + file_name = std::string(afm_app_install_dir) + std::string("/etc/role.db"); + } + + // Load role.db + HMI_DEBUG("wm:pm", "file_name:%s", file_name.c_str()); + json_object* json_obj = json_object_from_file(file_name.c_str()); + if (nullptr == json_obj) { + HMI_ERROR("wm:pm", "Could not open role.db, so use default role information"); + json_obj = json_tokener_parse(kDefaultRoleDb); + } + HMI_DEBUG("wm:pm", "json_obj dump:%s", json_object_get_string(json_obj)); + + json_object* json_roles; + if (!json_object_object_get_ex(json_obj, "roles", &json_roles)) { + HMI_ERROR("wm:pm", "Parse Error!!"); + return -1; + } + + int len = json_object_array_length(json_roles); + HMI_DEBUG("wm:pm", "json_cfg len:%d", len); + HMI_DEBUG("wm:pm", "json_cfg dump:%s", json_object_get_string(json_roles)); + + json_object* json_tmp; + const char* category; + const char* roles; + const char* areas; + for (int i=0; i<len; i++) { + json_tmp = json_object_array_get_idx(json_roles, i); + + category = this->getStringFromJson(json_tmp, "category"); + roles = this->getStringFromJson(json_tmp, "role"); + areas = this->getStringFromJson(json_tmp, "area"); + + if ((nullptr == category) || (nullptr == roles) || (nullptr == areas)) { + HMI_ERROR("wm:pm", "Parse Error!!"); + return -1; + } + + // Parse roles by '|' + std::vector<std::string> vct_roles; + vct_roles = this->parseString(std::string(roles), '|'); + + // Parse areas by '|' + std::vector<std::string> vct_areas; + vct_areas = this->parseString(std::string(areas), '|'); + + // Set role, category, default area + for (auto itr = vct_roles.begin(); itr != vct_roles.end(); ++itr) { + // Delete space from role and area name + std::string role = this->deleteSpace(*itr); + std::string area = this->deleteSpace(vct_areas[0]); + + this->role2category_[role] = std::string(category); + this->role2defaultarea_[role] = area; + } + + this->category2role_[std::string(category)] = std::string(roles); + } + + // Check + HMI_DEBUG("wm:pm", "Check role2category_"); + for (auto& x:this->role2category_){ + HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str()); + } + + HMI_DEBUG("wm:pm", "Check role2defaultarea_"); + for (auto& x:this->role2defaultarea_){ + HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str()); + } + + HMI_DEBUG("wm:pm", "Check category2role_"); + for (auto& x:this->category2role_){ + HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str()); + } + + return 0; +} + +const char* PolicyManager::getStringFromJson(json_object* obj, const char* key) { + if ((nullptr == obj) || (nullptr == key)) { + HMI_ERROR("wm:pm", "Argument is nullptr!!!"); + return nullptr; + } + + json_object* tmp; + if (!json_object_object_get_ex(obj, key, &tmp)) { + HMI_DEBUG("wm:pm", "Not found key \"%s\"", key); + return nullptr; + } + + return json_object_get_string(tmp); +} + +int PolicyManager::getIntFromJson(json_object* obj, const char* key) { + if ((nullptr == obj) || (nullptr == key)) { + HMI_ERROR("wm:pm", "Argument is nullptr!!!"); + return 0; + } + + json_object* tmp; + if (!json_object_object_get_ex(obj, key, &tmp)) { + HMI_DEBUG("wm:pm", "Not found key \"%s\"", key); + return 0; + } + + return json_object_get_int(tmp); +} + +void PolicyManager::addStateToJson( + const char* key, int is_changed, const char* state, json_object** json_out) { + if ((nullptr == key) || (nullptr == state) || (nullptr == json_out)) { + HMI_ERROR("wm:pm", "Argument is nullptr!!!"); + return; + } + + json_object* json_obj = json_object_new_object(); + json_object_object_add(json_obj, "is_changed", json_object_new_boolean(is_changed)); + if (is_changed) { + HMI_DEBUG("wm:pm", "%s: state changed (%s)", key, state); + json_object_object_add(json_obj, "state", json_object_new_string(state)); + } + json_object_object_add(*json_out, key, json_obj); +} + +std::vector<std::string> PolicyManager::parseString(std::string str, char delimiter) { + // 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()) { + vct.push_back(buf); + } + } + return vct; +} + +std::string PolicyManager::deleteSpace(std::string str) { + std::string ret = str; + size_t pos; + while ((pos = ret.find_first_of(" ")) != std::string::npos) { + ret.erase(pos, 1); + } + return ret; +} + +const char* kDefaultRoleDb = "{ \ + \"roles\":[ \ + { \ + \"category\": \"homescreen\", \ + \"role\": \"homescreen\", \ + \"area\": \"full\", \ + }, \ + { \ + \"category\": \"map\", \ + \"role\": \"map\", \ + \"area\": \"full | normal | split.main\", \ + }, \ + { \ + \"category\": \"general\", \ + \"role\": \"poi | music | video | browser | sdl | settings | mixer | radio | hvac | dashboard | debug\", \ + \"area\": \"normal\", \ + }, \ + { \ + \"category\": \"phone\", \ + \"role\": \"phone\", \ + \"area\": \"normal\", \ + }, \ + { \ + \"category\": \"splitable\", \ + \"role\": \"splitable1 | splitable2\", \ + \"area\": \"normal | split.main | split.sub\", \ + }, \ + { \ + \"category\": \"popup\", \ + \"role\": \"popup\", \ + \"area\": \"on_screen\", \ + }, \ + { \ + \"category\": \"system_alert\", \ + \"role\": \"system_alert\", \ + \"area\": \"on_screen\", \ + }, \ + { \ + \"category\": \"tbt\", \ + \"role\": \"tbt\", \ + \"area\": \"hud\", \ + } \ + ] \ +}"; diff --git a/src/policy_manager/policy_manager.hpp b/src/policy_manager/policy_manager.hpp new file mode 100644 index 0000000..500120c --- /dev/null +++ b/src/policy_manager/policy_manager.hpp @@ -0,0 +1,67 @@ +/* + * 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. + */ + +#ifndef TMCAGLWM_POLICY_MANAGER_HPP +#define TMCAGLWM_POLICY_MANAGER_HPP + + +#include <unordered_map> +#include <vector> + +//namespace stm { +extern "C" { +#include "dummy_stm.h" +} +//} // namespace stm + +class PolicyManager { + +public: + explicit PolicyManager(); + ~PolicyManager() = default; + + int initialize(); + int checkPolicy(json_object* json_in, json_object** json_out); + std::string roleToCategory(const char* role); +private: + // Disable copy and move + PolicyManager(PolicyManager const &) = delete; + PolicyManager &operator=(PolicyManager const &) = delete; + PolicyManager(PolicyManager &&) = delete; + PolicyManager &operator=(PolicyManager &&) = delete; + + // Convert map + std::unordered_map<std::string, int> eventname2no_; + std::unordered_map<std::string, int> categoryname2no_; + std::unordered_map<std::string, int> areaname2no_; + + std::unordered_map<std::string, std::string> role2category_; + std::unordered_map<std::string, std::string> category2role_; + std::unordered_map<std::string, std::string> role2defaultarea_; + + stm_state_t current_state_; + + // Load role.db + int loadRoleDb(); + + const char* getStringFromJson(json_object* obj, const char* key); + int getIntFromJson(json_object* obj, const char* key); + void addStateToJson(const char* key, int is_changed, const char* state, json_object** json_out); + std::vector<std::string> parseString(std::string str, char delimiter); + std::string deleteSpace(std::string str); +}; + +#endif // TMCAGLWM_POLICY_MANAGER_HPP diff --git a/src/policy_manager/zipc/category.db b/src/policy_manager/zipc/category.db new file mode 100644 index 0000000..4867260 --- /dev/null +++ b/src/policy_manager/zipc/category.db @@ -0,0 +1,32 @@ +{ + "categories":[ + { + "name": "homescreen", + "role": "homescreen" + }, + { + "name": "map", + "role": "map" + }, + { + "name": "general", + "role": "poi | music | radio | video | browser | sdl | phone | settings | mixer | hvac | dashboard | fallback" + }, + { + "name": "pop_up", + "role": "incoming_call" + }, + { + "name": "system_alert", + "role": "system_alert" + }, + { + "name": "tbt", + "role": "tbt" + }, + { + "name": "splitable", + "role": "test_splitable1 | test_splitable2" + } + ] +} diff --git a/src/policy_manager/zipc/dummy_stm.c b/src/policy_manager/zipc/dummy_stm.c new file mode 100644 index 0000000..3c9cba2 --- /dev/null +++ b/src/policy_manager/zipc/dummy_stm.c @@ -0,0 +1,212 @@ + +#include <string.h> +#include "dummy_stm.h" + +stm_state_t g_crr_state = {0}; +stm_state_t g_prv_state = {0}; +int g_prv_apps_state_car_stop = 0; + +int stmTransitionState(int event, stm_state_t* state) { + int event_no, category_no, area_no; + int apps_state, car_state, lamp_state; + + event_no = event & STM_MSK_EVT_NO; + category_no = event & STM_MSK_CTG_NO; + area_no = event & STM_MSK_ARA_NO; + + // Backup previous state + g_prv_state = g_crr_state; + + // Get previous state + apps_state = g_prv_state.layer.apps.state; + car_state = g_prv_state.car.state; + lamp_state = g_prv_state.lamp.state; + + // Clear current state + memset(&g_crr_state, 0, sizeof(g_crr_state)); + + switch (event_no) { + case STM_EVT_NO_ACTIVATE: + switch (category_no) { + case STM_CTG_NO_HOMESCREEN: + // Apps layer + g_crr_state.layer.apps.state = gStmLayoutNoNone; + g_crr_state.layer.apps.is_changed = STM_TRUE; + + // Homescreen layer + g_crr_state.layer.homescreen.state = gStmLayoutNoHs; + g_crr_state.layer.homescreen.is_changed = STM_TRUE; + break; + case STM_CTG_NO_MAP: + switch (area_no) { + case STM_ARA_NO_FULL: + // Apps layer + switch (apps_state) { + case gStmLayoutNoMf: + // nop + break; + default: + g_crr_state.layer.apps.state = gStmLayoutNoMf; + g_crr_state.layer.apps.is_changed = STM_TRUE; + break; + } + break; + case STM_ARA_NO_NORMAL: + // Apps layer + switch (apps_state) { + case gStmLayoutNoM1: + // nop + break; + case gStmLayoutNoS1: + g_crr_state.layer.apps.state = gStmLayoutNoM2; + g_crr_state.layer.apps.is_changed = STM_TRUE; + break; + default: + g_crr_state.layer.apps.state = gStmLayoutNoM1; + g_crr_state.layer.apps.is_changed = STM_TRUE; + } + break; + case STM_ARA_NO_SPLIT_MAIN: + // Apps layer + switch (apps_state) { + case gStmLayoutNoS1: + case gStmLayoutNoS2: + g_crr_state.layer.apps.state = gStmLayoutNoS2; + g_crr_state.layer.apps.is_changed = STM_TRUE; + break; + default: + // nop + break; + } + break; + } + break; + case STM_CTG_NO_GENERAL: + switch (area_no) { + case STM_ARA_NO_NORMAL: + // Apps layer + switch (apps_state) { + case gStmLayoutNoMf: + // nop + break; + default: + g_crr_state.layer.apps.state = gStmLayoutNoG; + g_crr_state.layer.apps.is_changed = STM_TRUE; + break; + } + break; + default: + // nop + break; + } + break; + case STM_CTG_NO_SPLITABLE: + switch (area_no) { + case STM_ARA_NO_NORMAL: + // Apps layer + switch (apps_state) { + case gStmLayoutNoMf: + // nop + break; + case gStmLayoutNoS1: + g_crr_state.layer.apps.state = gStmLayoutNoS2; + g_crr_state.layer.apps.is_changed = STM_TRUE; + break; + default: + g_crr_state.layer.apps.state = gStmLayoutNoS1; + g_crr_state.layer.apps.is_changed = STM_TRUE; + break; + } + break; + case STM_ARA_NO_SPLIT_MAIN: + // Apps layer + switch (apps_state) { + case gStmLayoutNoS1: + g_crr_state.layer.apps.state = gStmLayoutNoS2; + g_crr_state.layer.apps.is_changed = STM_TRUE; + break; + case gStmLayoutNoS2: + g_crr_state.layer.apps.state = gStmLayoutNoS2; + g_crr_state.layer.apps.is_changed = STM_TRUE; + break; + default: + // nop + break; + } + break; + case STM_ARA_NO_SPLIT_SUB: + // Apps layer + switch (apps_state) { + case gStmLayoutNoM1: + g_crr_state.layer.apps.state = gStmLayoutNoM2; + g_crr_state.layer.apps.is_changed = STM_TRUE; + break; + case gStmLayoutNoM2: + g_crr_state.layer.apps.state = gStmLayoutNoM2; + g_crr_state.layer.apps.is_changed = STM_TRUE; + break; + case gStmLayoutNoS1: + g_crr_state.layer.apps.state = gStmLayoutNoS2; + g_crr_state.layer.apps.is_changed = STM_TRUE; + break; + case gStmLayoutNoS2: + g_crr_state.layer.apps.state = gStmLayoutNoS2; + g_crr_state.layer.apps.is_changed = STM_TRUE; + break; + default: + // nop + break; + } + break; + default: + // nop + break; + } + break; + default: + // nop + break; + } + break; + case STM_EVT_NO_CAR_STOP: + if (gStmCarStateNoStop != car_state) { + g_crr_state.layer.apps.state = g_prv_apps_state_car_stop; + g_crr_state.layer.apps.is_changed = STM_TRUE; + + g_crr_state.car.state = gStmCarStateNoStop; + g_crr_state.car.is_changed = STM_TRUE; + } + break; + case STM_EVT_NO_CAR_RUN: + if (gStmCarStateNoRun != car_state) { + g_prv_apps_state_car_stop = apps_state; + g_crr_state.layer.apps.state = gStmLayoutNoM1; + g_crr_state.layer.apps.is_changed = STM_TRUE; + + g_crr_state.car.state = gStmCarStateNoRun; + g_crr_state.car.is_changed = STM_TRUE; + } + break; + case STM_EVT_NO_LAMP_OFF: + if (gStmLampStateNoOff != lamp_state) { + g_crr_state.lamp.state = gStmLampStateNoOff; + g_crr_state.lamp.is_changed = STM_TRUE; + } + break; + case STM_EVT_NO_LAMP_ON: + if (gStmLampStateNoOn != lamp_state) { + g_crr_state.lamp.state = gStmLampStateNoOn; + g_crr_state.lamp.is_changed = STM_TRUE; + } + break; + default: + // nop + break; + } + + // Copy current state for return + memcpy(state, &g_crr_state, sizeof(g_crr_state)); + + return 0; +} + diff --git a/src/policy_manager/zipc/dummy_stm.h b/src/policy_manager/zipc/dummy_stm.h new file mode 100644 index 0000000..18af99b --- /dev/null +++ b/src/policy_manager/zipc/dummy_stm.h @@ -0,0 +1,127 @@ +/* + * 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. + */ + +#ifndef TMCAGLWM_DUMMY_STM_HPP +#define TMCAGLWM_DUMMY_STM_HPP + +// TODO: This file should be existed in STM + +// +#define STM_TRUE 1 +#define STM_FALSE 0 + +// Event number +#define STM_EVT_NO_ACTIVATE 0x01 +#define STM_EVT_NO_DEACTIVATE 0x02 +#define STM_EVT_NO_CAR_STOP 0x03 +#define STM_EVT_NO_CAR_RUN 0x04 +#define STM_EVT_NO_TIMER_EXPIRED 0x05 +#define STM_EVT_NO_LAMP_OFF 0x06 +#define STM_EVT_NO_LAMP_ON 0x07 + +// Category number +#define STM_CTG_NO_HOMESCREEN 0x0100 +#define STM_CTG_NO_MAP 0x0200 +#define STM_CTG_NO_GENERAL 0x0300 +#define STM_CTG_NO_SPLITABLE 0x0400 +#define STM_CTG_NO_POPUP 0x0500 +#define STM_CTG_NO_SYSTEM_ALERT 0x0600 + +// Area number +#define STM_ARA_NO_FULL 0x010000 +#define STM_ARA_NO_NORMAL 0x020000 +#define STM_ARA_NO_SPLIT_MAIN 0x030000 +#define STM_ARA_NO_SPLIT_SUB 0x040000 +#define STM_ARA_NO_ON_SCREEN 0x050000 + +// Mask +#define STM_MSK_EVT_NO 0x0000FF +#define STM_MSK_CTG_NO 0x00FF00 +#define STM_MSK_ARA_NO 0xFF0000 + +// Enum for state +enum stm_car_state_ { + gStmCarStateNoStop = 0, + gStmCarStateNoRun +}; + +enum stm_lamp_state_ { + gStmLampStateNoOff = 0, + gStmLampStateNoOn +}; + +enum stm_layout_ { + gStmLayoutNoNone = 0, + gStmLayoutNoPu, + gStmLayoutNoSa, + gStmLayoutNoM1, + gStmLayoutNoM2, + gStmLayoutNoMf, + gStmLayoutNoS1, + gStmLayoutNoS2, + gStmLayoutNoG, + gStmLayoutNoHs +}; + + +#if 0 +// String for state +const char* gStmCarStateNo2Name[] { + "car_stop", + "car_run" +}; + +const char* gStmLampStateNo2Name[] { + "lamp_off", + "lamp_on" +}; + +const char* gStmLayoutNo2Name[] { + "none", + "pu", + "sa", + "m1", + "m2", + "mf", + "s1", + "s2", + "g", + "hs", +}; +#endif + +typedef struct stm_base_state_ { + int is_changed; + int state; +} stm_base_state; + +typedef struct stm_layer_state_ { + stm_base_state on_screen; + stm_base_state apps; + stm_base_state homescreen; +} stm_layer_state; + +// Struct for state +typedef struct { + stm_base_state car; + stm_base_state lamp; + stm_layer_state layer; +} stm_state_t; + +int stmTransitionState(int event_no, stm_state_t* state); + + +#endif // TMCAGLWM_DUMMY_STM_HPP |