summaryrefslogtreecommitdiffstats
path: root/Src/Network/IndustrialStack_MNS.h
blob: 69085ac7d6c6b261a4f23b6bf4811f0a47759748 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/*
 * Video On Demand Samples
 *
 * Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. KG
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * You may also obtain this software under a propriety license from Microchip.
 * Please contact Microchip for further information.
 *
 */

/*----------------------------------------------------------*/
/*! \file
 *  \brief  This file contains the CIndustrialStack class (NetService part).
 */
/*----------------------------------------------------------*/

#ifndef INDUSTRIAL_STACK_MNS_H
#define INDUSTRIAL_STACK_MNS_H

#include <assert.h>
#include "IndustrialStack_Types.h"
#include "IndustrialStack_LLD.h"
#include "mns_types_cfg.h"
#include "mnsl.h"

#define MNSW_TESTPATTERN ((uint32_t)0xA1B2C3D4)

class IISNetServiceWrapperCB
{
public:
    virtual void OnReceivedMostMessage(CISMostMsg *rcvMessage) = 0;
    virtual void OnSyncStateChanged(bool isSynced) = 0;
    virtual void OnControlReadEnd() = 0;
};

class CISNetServiceWrapper : public CIndustrialStackLldCB
{
public:
    const uint32_t testPattern;
    bool inicWriteError;
    Mns_Lld_Api_t *pMnsInterface;
    void *pMnsInst; 
    CTransceiver *icm_inst_ptr;
    CTransceiver *rcm_inst_ptr;
    CTransceiver *mcm_inst_ptr;
private:
    CMnsl mnsl;
    Mns_Lld_Callbacks_t pLldCb;
    bool isSynced;
    IISNetServiceWrapperCB *wrapperCB;
    CIndustrialStackLld *lld;

public:    
    CISNetServiceWrapper(uint8_t deviceApi, int controlRxHandle, int controlTxHandle);
    virtual ~CISNetServiceWrapper();
    void ServiceMns();
    void AddListener(IISNetServiceWrapperCB *rcvListener);
    
    bool SendMostMessage(CISMostMsg *sndMessage);
    void Unsynchronize();
    
public:
    //Will be called from LLD, do not call directly
    virtual void OnReadThreadEnd(CIndustrialStackLld *lld);
    //All this functions will be called by the C wrappers, do not call them directly
    void OnCtrlTxTransmit( Mns_Lld_TxMsg_t *msg_ptr);
    void OnMnslEvent( Mnsl_Event_t event_code );
    void OnMessage( Msg_MostTel_t *pRx, CTransceiver *pTr );
};

#endif //INDUSTRIAL_STACK_MNS_H
id='n509' href='#n509'>509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705
/*
 * 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 <unistd.h>
#include <algorithm>
#include <mutex>
#include <json.h>
#include "window_manager.hpp"
#include "json_helper.hpp"
#include "wayland_ivi_wm.hpp"

extern "C"
{
#include <afb/afb-binding.h>
#include <systemd/sd-event.h>
}

typedef struct WMClientCtxt
{
    std::string name;
    std::string role;
    WMClientCtxt(const char *appName, const char* appRole)
    {
        name = appName;
        role = appRole;
    }
} WMClientCtxt;

struct afb_instance
{
    std::unique_ptr<wl::display> display;
    wm::WindowManager wmgr;

    afb_instance() : display{new wl::display}, wmgr{this->display.get()} {}

    int init();
};

struct afb_instance *g_afb_instance;
std::mutex binding_m;

int afb_instance::init()
{
    return this->wmgr.init();
}

int display_event_callback(sd_event_source *evs, int /*fd*/, uint32_t events,
                           void * /*data*/)
{
    if ((events & EPOLLHUP) != 0)
    {
        HMI_ERROR("The compositor hung up, dying now.");
        delete g_afb_instance;
        g_afb_instance = nullptr;
        goto error;
    }

    if ((events & EPOLLIN) != 0u)
    {
        {
            g_afb_instance->wmgr.display->read_events();
            g_afb_instance->wmgr.set_pending_events();
        }
        {
            // We want do dispatch pending wayland events from within
            // the API context
            afb_service_call("windowmanager", "ping", json_object_new_object(),
                            [](void *c, int st, json_object *j) {
                            },
                            nullptr);
        }
    }

    return 0;

error:
    sd_event_source_unref(evs);
    if (getenv("WINMAN_EXIT_ON_HANGUP") != nullptr)
    {
        exit(1);
    }
    return -1;
}

int _binding_init()
{
    HMI_NOTICE("WinMan ver. %s", WINMAN_VERSION_STRING);

    if (g_afb_instance != nullptr)
    {
        HMI_ERROR("Wayland context already initialized?");
        return 0;
    }

    if (getenv("XDG_RUNTIME_DIR") == nullptr)
    {
        HMI_ERROR("Environment variable XDG_RUNTIME_DIR not set");
        goto error;
    }

    {
        // wait until wayland compositor starts up.
        int cnt = 0;
        g_afb_instance = new afb_instance;
        while (!g_afb_instance->display->ok())
        {
            cnt++;
            if (20 <= cnt)
            {
                HMI_ERROR("Could not connect to compositor");
                goto error;
            }
            HMI_ERROR("Wait to start weston ...");
            sleep(1);
            delete g_afb_instance;
            g_afb_instance = new afb_instance;
        }
    }

    if (g_afb_instance->init() == -1)
    {
        HMI_ERROR("Could not connect to compositor");
        goto error;
    }

    {
        int ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
                                  g_afb_instance->display->get_fd(), EPOLLIN,
                                  display_event_callback, g_afb_instance);
        if (ret < 0)
        {
            HMI_ERROR("Could not initialize afb_instance event handler: %d", -ret);
            goto error;
        }
    }

    atexit([] { delete g_afb_instance; });

    return 0;

error:
    delete g_afb_instance;
    g_afb_instance = nullptr;
    return -1;
}

int binding_init() noexcept
{
    try
    {
        return _binding_init();
    }
    catch (std::exception &e)
    {
        HMI_ERROR("Uncaught exception in binding_init(): %s", e.what());
    }
    return -1;
}

static void cbRemoveClientCtxt(void *data)
{
    WMClientCtxt *ctxt = (WMClientCtxt *)data;
    if (ctxt == nullptr)
    {
        return;
    }
    HMI_DEBUG("remove app %s", ctxt->name.c_str());

    // Policy Manager does not know this app was killed,
    // so notify it by deactivate request.
    g_afb_instance->wmgr.api_deactivate_surface(
        ctxt->name.c_str(), ctxt->role.c_str(),
        [](const char *) {});

    g_afb_instance->wmgr.removeClient(ctxt->name);
    delete ctxt;
}

static void createSecurityContext(afb_req req, const char* appid, const char* role)
{
    WMClientCtxt *ctxt = (WMClientCtxt *)afb_req_context_get(req);
    if (!ctxt)
    {
        // Create Security Context at first time
        const char *new_role = g_afb_instance->wmgr.convertRoleOldToNew(role);
        WMClientCtxt *ctxt = new WMClientCtxt(appid, new_role);
        HMI_DEBUG("create session for %s", ctxt->name.c_str());
        afb_req_session_set_LOA(req, 1);
        afb_req_context_set(req, ctxt, cbRemoveClientCtxt);
    }
}

void windowmanager_requestsurface(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);
    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {
        const char *a_drawing_name = afb_req_value(req, "drawing_name");
        if (!a_drawing_name)
        {
            afb_req_fail(req, "failed", "Need char const* argument drawing_name");
            return;
        }

        char *appid = afb_req_get_application_id(req);
        if(appid)
        {
            auto ret = g_afb_instance->wmgr.api_request_surface(
                appid, a_drawing_name);
            if (ret.is_err())
            {
                afb_req_fail(req, "failed", ret.unwrap_err());
            }
            else
            {
                createSecurityContext(req, appid, a_drawing_name);
                afb_req_success(req, json_object_new_int(ret.unwrap()), "success");
            }
            free(appid);
        }
        else
        {
            afb_req_fail(req, "failed", nullptr);
        }
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurface: %s", e.what());
        return;
    }
}

void windowmanager_requestsurfacexdg(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);
    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {
        json_object *jreq = afb_req_json(req);

        json_object *j_drawing_name = nullptr;
        if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
        {
            afb_req_fail(req, "failed", "Need char const* argument drawing_name");
            return;
        }
        char const *a_drawing_name = json_object_get_string(j_drawing_name);

        json_object *j_ivi_id = nullptr;
        if (!json_object_object_get_ex(jreq, "ivi_id", &j_ivi_id))
        {
            afb_req_fail(req, "failed", "Need char const* argument ivi_id");
            return;
        }
        char const *a_ivi_id = json_object_get_string(j_ivi_id);
        char *appid = afb_req_get_application_id(req);
        if(appid)
        {
            auto ret = g_afb_instance->wmgr.api_request_surface(
                appid, a_drawing_name, a_ivi_id);

            if (ret != nullptr)
            {
                afb_req_fail(req, "failed", ret);
            }
            else
            {
                createSecurityContext(req, appid, a_drawing_name);
                afb_req_success(req, NULL, "success");
            }
            free(appid);
        }
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
        return;
    }
}

void windowmanager_activatewindow(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);
    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {
        const char *a_drawing_name = afb_req_value(req, "drawing_name");
        if (!a_drawing_name)
        {
            afb_req_fail(req, "failed", "Need char const* argument drawing_name");
            return;
        }

        const char *a_drawing_area = afb_req_value(req, "drawing_area");
        if (!a_drawing_area)
        {
            afb_req_fail(req, "failed", "Need char const* argument drawing_area");
            return;
        }

        char* appid = afb_req_get_application_id(req);
        if(appid)
        {
            g_afb_instance->wmgr.api_activate_surface(
                appid, a_drawing_name, a_drawing_area,
                [&req](const char *errmsg) {
                    if (errmsg != nullptr)
                    {
                        HMI_ERROR(errmsg);
                        afb_req_fail(req, "failed", errmsg);
                        return;
                    }
                    afb_req_success(req, NULL, "success");
                });
            free(appid);
        }
    }
    catch (std::exception &e)
    {
        HMI_WARNING("failed: Uncaught exception while calling activatesurface: %s", e.what());
        g_afb_instance->wmgr.exceptionProcessForTransition();
        return;
    }
}

void windowmanager_deactivatewindow(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);
    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {
        const char *a_drawing_name = afb_req_value(req, "drawing_name");
        if (!a_drawing_name)
        {
            afb_req_fail(req, "failed", "Need char const* argument drawing_name");
            return;
        }

        char* appid = afb_req_get_application_id(req);
        if(appid)
        {
            g_afb_instance->wmgr.api_deactivate_surface(
                appid, a_drawing_name,
                [&req](const char *errmsg) {
                    if (errmsg != nullptr)
                    {
                        HMI_ERROR(errmsg);
                        afb_req_fail(req, "failed", errmsg);
                        return;
                    }
                    afb_req_success(req, NULL, "success");
                });
            free(appid);
        }
    }
    catch (std::exception &e)
    {
        HMI_WARNING("failed: Uncaught exception while calling deactivatesurface: %s", e.what());
        g_afb_instance->wmgr.exceptionProcessForTransition();
        return;
    }
}

void windowmanager_enddraw(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);
    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {
        const char *a_drawing_name = afb_req_value(req, "drawing_name");
        if (!a_drawing_name)
        {
            afb_req_fail(req, "failed", "Need char const* argument drawing_name");
            return;
        }
        afb_req_success(req, NULL, "success");

        char* appid = afb_req_get_application_id(req);
        if(appid)
        {
            g_afb_instance->wmgr.api_enddraw(appid, a_drawing_name);
            free(appid);
        }
    }
    catch (std::exception &e)
    {
        HMI_WARNING("failed: Uncaught exception while calling enddraw: %s", e.what());
        g_afb_instance->wmgr.exceptionProcessForTransition();
        return;
    }
}

void windowmanager_getdisplayinfo_thunk(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);
    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {
        auto ret = g_afb_instance->wmgr.api_get_display_info();
        if (ret.is_err())
        {
            afb_req_fail(req, "failed", ret.unwrap_err());
            return;
        }

        afb_req_success(req, ret.unwrap(), "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling getdisplayinfo: %s", e.what());
        return;
    }
}

void windowmanager_getareainfo_thunk(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);
    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {
        json_object *jreq = afb_req_json(req);

        json_object *j_drawing_name = nullptr;
        if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
        {
            afb_req_fail(req, "failed", "Need char const* argument drawing_name");
            return;
        }
        char const *a_drawing_name = json_object_get_string(j_drawing_name);

        auto ret = g_afb_instance->wmgr.api_get_area_info(a_drawing_name);
        if (ret.is_err())
        {
            afb_req_fail(req, "failed", ret.unwrap_err());
            return;
        }

        afb_req_success(req, ret.unwrap(), "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling getareainfo: %s", e.what());
        return;
    }
}

void windowmanager_wm_subscribe(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);
    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {
        json_object *jreq = afb_req_json(req);
        json_object *j = nullptr;
        if (!json_object_object_get_ex(jreq, "event", &j))
        {
            afb_req_fail(req, "failed", "Need char const* argument event");
            return;
        }
        int event_type = json_object_get_int(j);
        const char *event_name = g_afb_instance->wmgr.kListEventName[event_type];
        struct afb_event event = g_afb_instance->wmgr.map_afb_event[event_name];
        int ret = afb_req_subscribe(req, event);
        if (ret)
        {
            afb_req_fail(req, "failed", "Error: afb_req_subscribe()");
            return;
        }
        afb_req_success(req, NULL, "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling wm_subscribe: %s", e.what());
        return;
    }
}

void windowmanager_list_drawing_names(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);
    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {

        nlohmann::json j = g_afb_instance->wmgr.id_alloc.name2id;
        auto ret = wm::Ok(json_tokener_parse(j.dump().c_str()));
        if (ret.is_err())
        {
            afb_req_fail(req, "failed", ret.unwrap_err());
            return;
        }

        afb_req_success(req, ret.unwrap(), "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling list_drawing_names: %s", e.what());
        return;
    }
}

void windowmanager_ping(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);
    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {

        g_afb_instance->wmgr.api_ping();

        afb_req_success(req, NULL, "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling ping: %s", e.what());
        return;
    }
}

void windowmanager_debug_status(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);
    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {

        json_object *jr = json_object_new_object();
        json_object_object_add(jr, "surfaces",
                               to_json(g_afb_instance->wmgr.controller->sprops));
        json_object_object_add(jr, "layers", to_json(g_afb_instance->wmgr.controller->lprops));

        afb_req_success(req, jr, "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_status: %s", e.what());
        return;
    }
}

void windowmanager_debug_layers(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);
    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {
        auto ret = wm::Ok(json_tokener_parse(g_afb_instance->wmgr.layers.to_json().dump().c_str()));

        afb_req_success(req, ret, "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_layers: %s", e.what());
        return;
    }
}

void windowmanager_debug_surfaces(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);
    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {

        auto ret = wm::Ok(to_json(g_afb_instance->wmgr.controller->sprops));
        if (ret.is_err())
        {
            afb_req_fail(req, "failed", ret.unwrap_err());
            return;
        }

        afb_req_success(req, ret.unwrap(), "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_surfaces: %s", e.what());
        return;
    }
}

void windowmanager_debug_terminate(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);
    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {

        if (getenv("WINMAN_DEBUG_TERMINATE") != nullptr)
        {
            raise(SIGKILL); // afb-daemon kills it's pgroup using TERM, which
                            // doesn't play well with perf
        }

        afb_req_success(req, NULL, "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_terminate: %s", e.what());
        return;
    }
}

const struct afb_verb_v2 windowmanager_verbs[] = {
    {"requestSurface", windowmanager_requestsurface, nullptr, nullptr, AFB_SESSION_NONE},
    {"requestSurfaceXDG", windowmanager_requestsurfacexdg, nullptr, nullptr, AFB_SESSION_NONE},
    {"activateWindow", windowmanager_activatewindow, nullptr, nullptr, AFB_SESSION_NONE},
    {"deactivateWindow", windowmanager_deactivatewindow, nullptr, nullptr, AFB_SESSION_NONE},
    {"endDraw", windowmanager_enddraw, nullptr, nullptr, AFB_SESSION_NONE},
    {"getDisplayInfo", windowmanager_getdisplayinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
    {"getAreaInfo", windowmanager_getareainfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
    {"wm_subscribe", windowmanager_wm_subscribe, nullptr, nullptr, AFB_SESSION_NONE},
    {"list_drawing_names", windowmanager_list_drawing_names, nullptr, nullptr, AFB_SESSION_NONE},
    {"ping", windowmanager_ping, nullptr, nullptr, AFB_SESSION_NONE},
    {"debug_status", windowmanager_debug_status, nullptr, nullptr, AFB_SESSION_NONE},
    {"debug_layers", windowmanager_debug_layers, nullptr, nullptr, AFB_SESSION_NONE},
    {"debug_surfaces", windowmanager_debug_surfaces, nullptr, nullptr, AFB_SESSION_NONE},
    {"debug_terminate", windowmanager_debug_terminate, nullptr, nullptr, AFB_SESSION_NONE},
    {}};

extern "C" const struct afb_binding_v2 afbBindingV2 = {
    "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, nullptr, 0};