diff options
author | zheng_wenlong <wenlong_zheng@nexty-ele.com> | 2018-10-30 14:36:16 +0900 |
---|---|---|
committer | zheng_wenlong <wenlong_zheng@nexty-ele.com> | 2018-10-30 14:36:16 +0900 |
commit | de492ca32c0cc4eb7e090ba33945eb75a21cc14a (patch) | |
tree | c81e48f9fa7199afa87a25781599ed6d963989b1 | |
parent | 3ae8e9b6a7947b91409b112e1a699385627c5945 (diff) |
add source for ces2019
108 files changed, 9540 insertions, 16213 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index e1cb0db..7cf640f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,8 +26,6 @@ set(PACKAGE_VERSION "${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}.${PACKAGE find_package(PkgConfig REQUIRED) include(GNUInstallDirs) -pkg_check_modules(WLC wayland-client>=1.11.0 REQUIRED) - macro(wlproto var_basename proto_xml_basename) if("${WLSCAN}" STREQUAL "") find_program(WLSCAN NAMES wayland-scanner) @@ -59,22 +57,6 @@ macro(wlproto var_basename proto_xml_basename) include_directories(${CMAKE_CURRENT_BINARY_DIR}) endmacro() -# Should modernize the following somehow... -set(ENABLE_DEBUG_OUTPUT OFF CACHE BOOL "Enable debug logging") -if(ENABLE_DEBUG_OUTPUT) - add_definitions(-DDEBUG_OUTPUT) -else() - remove_definitions(-DDEBUG_OUTPUT) -endif() - -# Should modernize the following somehow... -set(ENABLE_SCOPE_TRACING OFF CACHE BOOL "Enable scope enter/leave messages for certain parts of the code.") -if(ENABLE_SCOPE_TRACING) - add_definitions(-DSCOPE_TRACING) -else() - remove_definitions(-DSCOPE_TRACING) -endif() - set(SANITIZER_MODE "none" CACHE STRING "Build using a specific sanitizer (e.g. 'address', 'thread', 'leak', 'undefined'), depends on compiler; default none") set(LINK_LIBCXX OFF CACHE BOOL "Link against LLVMs libc++") @@ -2,3 +2,13 @@ This is a WindowManager implementation for the AGL Project. =========================================================== See http://docs.automotivelinux.org/docs/apis_services/en/dev/ + +**NOTE** +This Window Manager is master (meter cluster) mode by default. +If use slave (IVI) mode, please execute sclipt `change_to_slave_mode.sh` on target as follows: +``` +$ scp ./change_to_slave_mode.sh root@<target_ip_addr>:~ +$ ssh root@<target_ip_addr> +# sync +# ./change_to_slave_mode.sh +``` diff --git a/change_to_slave_mode.sh b/change_to_slave_mode.sh new file mode 100755 index 0000000..32a70ee --- /dev/null +++ b/change_to_slave_mode.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +sed -i.orig -e 's/\"mode\": \"master\"/\"mode\": \"slave\"/' /var/local/lib/afm/applications/windowmanager-service-2017/0.1/etc/connection.json + + diff --git a/client/README b/client/README deleted file mode 100644 index 95ab875..0000000 --- a/client/README +++ /dev/null @@ -1,39 +0,0 @@ -= Example Application for TMC AGL WindowManager Client Lib -This is a example QML application that uses clients of the TMC WindowManager. - -== Dependencies -* Qt5 + QtQuick (QML) with ivi-shell support - -== Build instructions -Inside of an SDK environment run: - ----------------- -qmake -make ----------------- - -* The binary should be installed somewhere in $PATH - -== Usage -Run this application like follows: - ----------------- -qmlWindowManagerSampleApp $width $height $appLabel $colorName ----------------- - -.Note -**************** -Depending on your environment you will need to set the following -environment variable to instruct Qt to use the ivi-shell integration: -`QT_WAYLAND_SHELL_INTEGRATION=ivi-shell` -**************** - -Starts the application with a surface the size $width x $height -the Surface will request the label "$appLabel" and set its surface -color "$colorName" e.g. red. - -Note, that although the application sets an initial window size, the -window manager will send events to the application that instruct it to -set the proper, requested size for the layout. - -// vim:set tw=72 ft=asciidoc: diff --git a/client/communication.cpp b/client/communication.cpp deleted file mode 100644 index 1acfdca..0000000 --- a/client/communication.cpp +++ /dev/null @@ -1,86 +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 "communication.h" - -#include <QGuiApplication> -#include <QDebug> - -communication::communication(QObject *parent) : QObject(parent) -{ - this->quit = false; -} - -communication::~communication() -{ -} - -void communication::setWidth(const unsigned int &w) -{ - this->width = w; - emit widthChanged(); -} - -void communication::setHeight(const unsigned int &h) -{ - this->height = h; - emit heightChanged(); -} - -void communication::setColor(const QString &c) -{ - this->color = c; - emit colorChanged(); -} - -void communication::setAppName(const QString &a) -{ - this->appName = a; - emit appNameChanged(); -} - -void communication::setQuit(const bool &q) -{ - this->quit = q; - emit quitChanged(); - if(q) - exit(EXIT_SUCCESS); -} - -unsigned int communication::getWidth() const -{ - return this->width; -} - -unsigned int communication::getHeight() const -{ - return this->height; -} - -QString communication::getColor() const -{ - return this->color; -} - -QString communication::getAppName() const -{ - return this->appName; -} - -bool communication::getQuit() const -{ - return this->quit; -} diff --git a/client/communication.h b/client/communication.h deleted file mode 100644 index fd3072f..0000000 --- a/client/communication.h +++ /dev/null @@ -1,64 +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 COMMUNICATION_H -#define COMMUNICATION_H - -#include <QObject> - -class communication : public QObject -{ - Q_OBJECT - - Q_PROPERTY(unsigned int width WRITE setWidth READ getWidth NOTIFY widthChanged) - Q_PROPERTY(unsigned int height WRITE setHeight READ getHeight NOTIFY heightChanged) - Q_PROPERTY(QString color READ getColor WRITE setColor NOTIFY colorChanged) - Q_PROPERTY(QString appName READ getAppName WRITE setAppName NOTIFY appNameChanged) - Q_PROPERTY(bool quit READ getQuit WRITE setQuit NOTIFY quitChanged) - -public: - explicit communication(QObject *parent = 0); - virtual ~communication(); - -public slots: - void setWidth(const unsigned int &); - void setHeight(const unsigned int &); - void setColor(const QString&); - void setAppName(const QString&); - void setQuit(const bool&); - - unsigned int getWidth() const; - unsigned int getHeight() const; - QString getColor() const; - QString getAppName() const; - bool getQuit() const; - -signals: - void widthChanged(); - void heightChanged(); - void colorChanged(); - void appNameChanged(); - void quitChanged(); - -private: - unsigned int width; - unsigned int height; - QString color; - QString appName; - bool quit; -}; - -#endif // COMMUNICATION_H diff --git a/client/extra/WindowManagerSampleApp.qml b/client/extra/WindowManagerSampleApp.qml deleted file mode 100644 index 0945af9..0000000 --- a/client/extra/WindowManagerSampleApp.qml +++ /dev/null @@ -1,47 +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. - */ - -import QtQuick 2.2 -import QtQuick.Window 2.1 -import QtQuick.Layouts 1.1 - -Window { - id: screen - width: COMM.width - height: COMM.height - color: COMM.color - flags: Qt.FramelessWindowHint - title: COMM.appName - opacity: 0.99 - visible: true - - Timer { - id: quitTimer - interval: 2000 - repeat: false - triggeredOnStart: false - onTriggered: COMM.quit = true - } - - Text { - id: textArea - color: "black" - font.bold: true - font.pointSize: 90 - anchors.centerIn: parent - text: COMM.appName - } -} diff --git a/client/extra/WindowManagerSampleApp.qml.sample2 b/client/extra/WindowManagerSampleApp.qml.sample2 deleted file mode 100644 index 1ffc071..0000000 --- a/client/extra/WindowManagerSampleApp.qml.sample2 +++ /dev/null @@ -1,52 +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. - */ - -import QtQuick 2.2 -import QtQuick.Window 2.1 -import QtQuick.Layouts 1.1 - -Window { - id: screen - width: COMM.width - height: COMM.height - color: COMM.color - flags: Qt.FramelessWindowHint - title: COMM.appName - opacity: 0.99 - visible: true - signal created - - Timer { - id: quitTimer - interval: 2000 - repeat: false - triggeredOnStart: false - onTriggered: COMM.quit = true - } - - Text { - id: textArea - color: "black" - font.bold: true - font.pointSize: 90 - anchors.centerIn: parent - text: COMM.appName - } - onFrameSwapped: { - created() - } - -} diff --git a/client/main.cpp b/client/main.cpp deleted file mode 100644 index 3dc2e42..0000000 --- a/client/main.cpp +++ /dev/null @@ -1,99 +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 <QDebug> -#include <QDir> -#include <QGuiApplication> -#include <QQmlApplicationEngine> -#include <QQmlContext> -#include <QQuickView> -#include <QQuickWindow> -#include "communication.h" - -#include "qlibwindowmanager.h" - -int main(int argc, char *argv[]) { - QGuiApplication app(argc, argv); - - qDebug() << QCoreApplication::arguments(); - - if (QCoreApplication::arguments().count() < 5) { - qWarning() << "Wrong parameters specified for the application. " - "Please restart with correct parameters:" - "width, height, name, color [port] [token]:\n\n" - "/usr/bin/WindowManagerSampleApp/" - "qmlWindowManagerSampleApp width height name color\n"; - exit(EXIT_FAILURE); - } - - QString label = QCoreApplication::arguments().at(3); - - QLibWindowmanager* qwm = new QLibWindowmanager(); - - QString token = "wm"; - int port = 1700; - if(QCoreApplication::arguments().count() == 7){ - bool ok; - port = QCoreApplication::arguments().at(5).toInt(&ok); - if(ok == false){ - port = 1700; - } - else{ - token = QCoreApplication::arguments().at(6); - } - } - const char* ctoken = token.toLatin1().data(); - if (qwm->init(port, ctoken) != 0) { - exit(EXIT_FAILURE); - } - - if (qwm->requestSurface( - QCoreApplication::arguments().at(3).toLatin1().data()) != 0) { - exit(EXIT_FAILURE); - } - - qwm->set_event_handler(QLibWindowmanager::Event_SyncDraw, [qwm](char const *label) { - fprintf(stderr, "Surface %s got syncDraw!\n", label); - qwm->endDraw(label); - }); - qwm->set_event_handler(QLibWindowmanager::Event_Active, [](char const *label) { - fprintf(stderr, "Surface %s got activated!\n", label); - }); - qwm->set_event_handler(QLibWindowmanager::Event_Visible, [](char const *label) { - fprintf(stderr, "Surface %s got visible!\n", label); - }); - qwm->set_event_handler(QLibWindowmanager::Event_FlushDraw, [](char const *label) { - fprintf(stderr, "Surface %s got flushDraw!\n", label); - }); - - communication comm; - comm.setWidth(QCoreApplication::arguments().at(1).toUInt()); - comm.setHeight(QCoreApplication::arguments().at(2).toUInt()); - comm.setAppName(label); - comm.setColor(QCoreApplication::arguments().at(4)); - - QQmlApplicationEngine engine; - engine.rootContext()->setContextProperty("COMM", &comm); - - engine.load( - QUrl(QStringLiteral("qrc:/extra/WindowManagerSampleApp.qml"))); - QObject *root = engine.rootObjects().first(); - QQuickWindow *window = qobject_cast<QQuickWindow *>(root); - QObject::connect(root, SIGNAL(frameSwapped()), qwm, SLOT(slotActivateSurface())); - - return app.exec(); -} diff --git a/client/main.cpp.sample2 b/client/main.cpp.sample2 deleted file mode 100644 index 5d9cc44..0000000 --- a/client/main.cpp.sample2 +++ /dev/null @@ -1,92 +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 <QDebug> -#include <QDir> -#include <QGuiApplication> -#include <QQmlApplicationEngine> -#include <QQmlContext> -#include <QQuickView> -#include <QQuickWindow> -#include "communication.h" - -#include "qlibwindowmanager.h" - -int main(int argc, char *argv[]) { - QGuiApplication app(argc, argv); - - qDebug() << QCoreApplication::arguments(); - - if (QCoreApplication::arguments().count() < 5) { - qWarning() << "Wrong parameters specified for the application. " - "Please restart with correct parameters:" - "width, height, name, color [port] [token]:\n\n" - "/usr/bin/WindowManagerSampleApp/" - "qmlWindowManagerSampleApp width height name color\n"; - exit(EXIT_FAILURE); - } - - QString label = QCoreApplication::arguments().at(3); - - QLibWindowmanager* qwm = new QLibWindowmanager(); - - QString token = "wm"; - int port = 1700; - if(QCoreApplication::arguments().count() == 7){ - bool ok; - port = QCoreApplication::arguments().at(5).toInt(&ok); - if(ok == false){ - port = 1700; - } - else{ - token = QCoreApplication::arguments().at(6); - } - } - const char* ctoken = token.toLatin1().data(); - if (qwm->init(port, ctoken) != 0) { - exit(EXIT_FAILURE); - } - - if (qwm->requestSurface( - QCoreApplication::arguments().at(3).toLatin1().data()) != 0) { - exit(EXIT_FAILURE); - } - - qwm->set_event_handler(QLibWindowmanager::Event_SyncDraw, [qwm](char const *label) { - //qwm->endDraw(label); - fprintf(stderr, "Surface %s got syncDraw!\n", label); - }); - qwm->set_event_handler(QLibWindowmanager::Event_Active, [](char const *label) { - fprintf(stderr, "Surface %s got activated!\n", label); - }); - - communication comm; - comm.setWidth(QCoreApplication::arguments().at(1).toUInt()); - comm.setHeight(QCoreApplication::arguments().at(2).toUInt()); - comm.setAppName(label); - comm.setColor(QCoreApplication::arguments().at(4)); - - QQmlApplicationEngine engine; - engine.rootContext()->setContextProperty("COMM", &comm); - - engine.load( - QUrl(QStringLiteral("qrc:/extra/WindowManagerSampleApp.qml"))); - QObject *root = engine.rootObjects().first(); - QObject::connect(root, SIGNAL(created()), qwm, SLOT(slotActivateSurface())); - - return app.exec(); -} diff --git a/client/qlibwindowmanager.cpp b/client/qlibwindowmanager.cpp deleted file mode 100644 index e69f0ac..0000000 --- a/client/qlibwindowmanager.cpp +++ /dev/null @@ -1,56 +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 "qlibwindowmanager.h" -#include <unistd.h> - -int QLibWindowmanager::init(int port, char const *token) { - return this->wm->init(port, token); -} - -int QLibWindowmanager::requestSurface(const char *label) { - applabel = label; - return this->wm->requestSurface(label); -} - -int QLibWindowmanager::activateSurface(const char *label) { - return this->wm->activateSurface(label); -} - -int QLibWindowmanager::deactivateSurface(const char *label) { - return this->wm->deactivateSurface(label); -} - -int QLibWindowmanager::endDraw(const char *label) { return this->wm->endDraw(label); } - -void QLibWindowmanager::set_event_handler(enum QEventType et, - std::function<void(char const *label)> f) { - LibWindowmanager::EventType wet = (LibWindowmanager::EventType)et; - return this->wm->set_event_handler(wet, std::move(f)); -} - -void QLibWindowmanager::slotActivateSurface(){ - qDebug("%s",__FUNCTION__); - this->activateSurface(applabel.c_str()); -} - -QLibWindowmanager::QLibWindowmanager(QObject *parent) - :QObject(parent) -{ - wm = new LibWindowmanager(); -} - -QLibWindowmanager::~QLibWindowmanager() { } diff --git a/client/qlibwindowmanager.h b/client/qlibwindowmanager.h deleted file mode 100644 index ed86a65..0000000 --- a/client/qlibwindowmanager.h +++ /dev/null @@ -1,69 +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 QLIBWINDOWMANAGER_H -#define QLIBWINDOWMANAGER_H -#include <libwindowmanager.h> -#include <functional> - #include <QObject> - #include <QUrl> - #include <QVariant> - #include <string> - #include <vector> - -class QLibWindowmanager : public QObject{ -Q_OBJECT -public: - explicit QLibWindowmanager(QObject *parent = nullptr); - ~QLibWindowmanager(); - - QLibWindowmanager(const QLibWindowmanager &) = delete; - QLibWindowmanager &operator=(const QLibWindowmanager &) = delete; - -public: - using handler_fun = std::function<void(const char *)>; - - enum QEventType { - Event_Active = 1, - Event_Inactive, - - Event_Visible, - Event_Invisible, - - Event_SyncDraw, - Event_FlushDraw, - }; - - static QLibWindowmanager &instance(); - - int init(int port, char const *token); - - // WM API - int requestSurface(const char *label); - int activateSurface(const char *label); - int deactivateSurface(const char *label); - int endDraw(const char *label); - void set_event_handler(enum QEventType et, handler_fun f); - -public slots: - void slotActivateSurface(); - -private: - LibWindowmanager* wm; - std::string applabel; - std::vector<int> surfaceIDs; -}; -#endif // LIBWINDOWMANAGER_H diff --git a/client/qmlWindowManagerSampleApp.pro b/client/qmlWindowManagerSampleApp.pro deleted file mode 100644 index 3064d57..0000000 --- a/client/qmlWindowManagerSampleApp.pro +++ /dev/null @@ -1,20 +0,0 @@ -TEMPLATE = app -QT += qml quick -CONFIG += c++11 - -HEADERS += communication.h qlibwindowmanager.h - -SOURCES += main.cpp \ - communication.cpp qlibwindowmanager.cpp -RESOURCES += sample.qrc - -INCLUDEPATH += $$[QT_SYSROOT]/usr/include/afb - -LIBS += -lwindowmanager -#LIBS += -lsystemd -LIBS += -lafbwsc -#LIBS += -ljson-c - -target.path = /usr/bin/WindowManagerSampleApp - -INSTALLS += target diff --git a/client/sample.qrc b/client/sample.qrc deleted file mode 100644 index be79eb6..0000000 --- a/client/sample.qrc +++ /dev/null @@ -1,5 +0,0 @@ -<RCC> - <qresource prefix="/"> - <file>extra/WindowManagerSampleApp.qml</file> - </qresource> -</RCC> diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..de4ac34 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,9 @@ +#!/bin/bash +cd build +source /opt/agl-sdk/6.0.0-aarch64/environment-setup-aarch64-agl-linux +make package +scp package/windowmanager-service-2017.wgt root@192.168.200.45:~ +ssh root@192.168.200.45 afm-util remove windowmanager-service-2017@0.1 +ssh root@192.168.200.45 afm-util install windowmanager-service-2017.wgt +ssh root@192.168.200.45 sync +ssh root@192.168.200.45 reboot diff --git a/include/hmi-debug.h b/include/hmi-debug.h deleted file mode 100644 index 697ac80..0000000 --- a/include/hmi-debug.h +++ /dev/null @@ -1,117 +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 __HMI_DEBUG_H__ -#define __HMI_DEBUG_H__ - -#include <time.h> -#include <stdio.h> -#include <stdarg.h> -#include <string.h> -#include <stdlib.h> - -enum LOG_LEVEL{ - LOG_LEVEL_NONE = 0, - LOG_LEVEL_ERROR, - LOG_LEVEL_WARNING, - LOG_LEVEL_NOTICE, - LOG_LEVEL_INFO, - LOG_LEVEL_DEBUG, - LOG_LEVEL_MAX = LOG_LEVEL_DEBUG -}; - -#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) - -#define HMI_ERROR(prefix, args,...) _HMI_LOG(LOG_LEVEL_ERROR, __FILENAME__, __FUNCTION__, __LINE__, prefix, args, ##__VA_ARGS__) -#define HMI_WARNING(prefix, args,...) _HMI_LOG(LOG_LEVEL_WARNING, __FILENAME__, __FUNCTION__,__LINE__, prefix, args,##__VA_ARGS__) -#define HMI_NOTICE(prefix, args,...) _HMI_LOG(LOG_LEVEL_NOTICE, __FILENAME__, __FUNCTION__,__LINE__, prefix, args,##__VA_ARGS__) -#define HMI_INFO(prefix, args,...) _HMI_LOG(LOG_LEVEL_INFO, __FILENAME__, __FUNCTION__,__LINE__, prefix, args,##__VA_ARGS__) -#define HMI_DEBUG(prefix, args,...) _HMI_LOG(LOG_LEVEL_DEBUG, __FILENAME__, __FUNCTION__,__LINE__, prefix, args,##__VA_ARGS__) - -#define HMI_SEQ_ERROR(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_ERROR, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__) -#define HMI_SEQ_WARNING(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_WARNING, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__) -#define HMI_SEQ_NOTICE(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_NOTICE, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__) -#define HMI_SEQ_INFO(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_INFO, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__) -#define HMI_SEQ_DEBUG(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_DEBUG, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__) - -#define DUMP(args, ...) _DUMP(LOG_LEVEL_DEBUG, args, ##__VA_ARGS__) - -static char ERROR_FLAG[6][20] = {"NONE", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG"}; - -static void _HMI_LOG(enum LOG_LEVEL level, const char* file, const char* func, const int line, const char* prefix, const char* log, ...) -{ - const int log_level = (getenv("USE_HMI_DEBUG") == NULL)?LOG_LEVEL_ERROR:atoi(getenv("USE_HMI_DEBUG")); - if(log_level < level) - { - return; - } - - char *message; - struct timespec tp; - unsigned int time; - - clock_gettime(CLOCK_REALTIME, &tp); - time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); - - va_list args; - va_start(args, log); - if (log == NULL || vasprintf(&message, log, args) < 0) - message = NULL; - fprintf(stderr, "[%10.3f] [%s %s] [%s, %s(), Line:%d] >>> %s \n", time / 1000.0, prefix, ERROR_FLAG[level], file, func, line, message); - va_end(args); - free(message); -} - -static void _HMI_SEQ_LOG(enum LOG_LEVEL level, const char* file, const char* func, const int line, unsigned seq_num, const char* log, ...){ - const int log_level = (getenv("USE_HMI_DEBUG") == NULL) ? LOG_LEVEL_ERROR:atoi(getenv("USE_HMI_DEBUG")); - if(log_level < level) - { - return; - } - - char *message; - struct timespec tp; - unsigned int time; - - clock_gettime(CLOCK_REALTIME, &tp); - time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); - - va_list args; - va_start(args, log); - if (log == NULL || vasprintf(&message, log, args) < 0) - message = NULL; - fprintf(stderr, "[%10.3f] [wm %s] [%s, %s(), Line:%d] >>> req %d: %s \n", time / 1000.0, ERROR_FLAG[level], file, func, line, seq_num, message); - va_end(args); - free(message); -} - -static void _DUMP(enum LOG_LEVEL level, const char *log, ...) -{ - const int log_level = (getenv("USE_HMI_DEBUG") == NULL) ? LOG_LEVEL_ERROR : atoi(getenv("USE_HMI_DEBUG")); - if (log_level < level) - { - return; - } - char *message; - va_list args; - va_start(args, log); - if (log == NULL || vasprintf(&message, log, args) < 0) - message = NULL; - fprintf(stderr, "%s \n", message); - va_end(args); - free(message); -} -#endif //__HMI_DEBUG_H__
\ No newline at end of file diff --git a/include/json.hpp b/include/json.hpp deleted file mode 100644 index 6dfc183..0000000 --- a/include/json.hpp +++ /dev/null @@ -1,13003 +0,0 @@ -/* - __ _____ _____ _____ - __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 2.1.1 -|_____|_____|_____|_|___| https://github.com/nlohmann/json - -Licensed under the MIT License <http://opensource.org/licenses/MIT>. -Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#ifndef NLOHMANN_JSON_HPP -#define NLOHMANN_JSON_HPP - -#include <algorithm> // all_of, copy, fill, find, for_each, none_of, remove, reverse, transform -#include <array> // array -#include <cassert> // assert -#include <cctype> // isdigit -#include <ciso646> // and, not, or -#include <cmath> // isfinite, labs, ldexp, signbit -#include <cstddef> // nullptr_t, ptrdiff_t, size_t -#include <cstdint> // int64_t, uint64_t -#include <cstdlib> // abort, strtod, strtof, strtold, strtoul, strtoll, strtoull -#include <cstring> // strlen -#include <forward_list> // forward_list -#include <functional> // function, hash, less -#include <initializer_list> // initializer_list -#include <iomanip> // setw -#include <iostream> // istream, ostream -#include <iterator> // advance, begin, back_inserter, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator -#include <limits> // numeric_limits -#include <locale> // locale -#include <map> // map -#include <memory> // addressof, allocator, allocator_traits, unique_ptr -#include <numeric> // accumulate -#include <sstream> // stringstream -#include <stdexcept> // domain_error, invalid_argument, out_of_range -#include <string> // getline, stoi, string, to_string -#include <type_traits> // add_pointer, conditional, decay, enable_if, false_type, integral_constant, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_default_constructible, is_enum, is_floating_point, is_integral, is_nothrow_move_assignable, is_nothrow_move_constructible, is_pointer, is_reference, is_same, is_scalar, is_signed, remove_const, remove_cv, remove_pointer, remove_reference, true_type, underlying_type -#include <utility> // declval, forward, make_pair, move, pair, swap -#include <vector> // vector - -// exclude unsupported compilers -#if defined(__clang__) - #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 - #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" - #endif -#elif defined(__GNUC__) - #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 - #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" - #endif -#endif - -// disable float-equal warnings on GCC/clang -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - -// disable documentation warnings on clang -#if defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdocumentation" -#endif - -// allow for portable deprecation warnings -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #define JSON_DEPRECATED __attribute__((deprecated)) -#elif defined(_MSC_VER) - #define JSON_DEPRECATED __declspec(deprecated) -#else - #define JSON_DEPRECATED -#endif - -// allow to disable exceptions -#if not defined(JSON_NOEXCEPTION) || defined(__EXCEPTIONS) - #define JSON_THROW(exception) throw exception - #define JSON_TRY try - #define JSON_CATCH(exception) catch(exception) -#else - #define JSON_THROW(exception) std::abort() - #define JSON_TRY if(true) - #define JSON_CATCH(exception) if(false) -#endif - -/*! -@brief namespace for Niels Lohmann -@see https://github.com/nlohmann -@since version 1.0.0 -*/ -namespace nlohmann -{ - -/*! -@brief unnamed namespace with internal helper functions - -This namespace collects some functions that could not be defined inside the -@ref basic_json class. - -@since version 2.1.0 -*/ -namespace detail -{ -/////////////////////////// -// JSON type enumeration // -/////////////////////////// - -/*! -@brief the JSON type enumeration - -This enumeration collects the different JSON types. It is internally used to -distinguish the stored values, and the functions @ref basic_json::is_null(), -@ref basic_json::is_object(), @ref basic_json::is_array(), -@ref basic_json::is_string(), @ref basic_json::is_boolean(), -@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), -@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), -@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and -@ref basic_json::is_structured() rely on it. - -@note There are three enumeration entries (number_integer, number_unsigned, and -number_float), because the library distinguishes these three types for numbers: -@ref basic_json::number_unsigned_t is used for unsigned integers, -@ref basic_json::number_integer_t is used for signed integers, and -@ref basic_json::number_float_t is used for floating-point numbers or to -approximate integers which do not fit in the limits of their respective type. - -@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON -value with the default value for a given type - -@since version 1.0.0 -*/ -enum class value_t : uint8_t -{ - null, ///< null value - object, ///< object (unordered set of name/value pairs) - array, ///< array (ordered collection of values) - string, ///< string value - boolean, ///< boolean value - number_integer, ///< number value (signed integer) - number_unsigned, ///< number value (unsigned integer) - number_float, ///< number value (floating-point) - discarded ///< discarded by the the parser callback function -}; - -/*! -@brief comparison operator for JSON types - -Returns an ordering that is similar to Python: -- order: null < boolean < number < object < array < string -- furthermore, each type is not smaller than itself - -@since version 1.0.0 -*/ -inline bool operator<(const value_t lhs, const value_t rhs) noexcept -{ - static constexpr std::array<uint8_t, 8> order = {{ - 0, // null - 3, // object - 4, // array - 5, // string - 1, // boolean - 2, // integer - 2, // unsigned - 2, // float - } - }; - - // discarded values are not comparable - if (lhs == value_t::discarded or rhs == value_t::discarded) - { - return false; - } - - return order[static_cast<std::size_t>(lhs)] < - order[static_cast<std::size_t>(rhs)]; -} - - -///////////// -// helpers // -///////////// - -// alias templates to reduce boilerplate -template<bool B, typename T = void> -using enable_if_t = typename std::enable_if<B, T>::type; - -template<typename T> -using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type; - -// taken from http://stackoverflow.com/a/26936864/266378 -template<typename T> -using is_unscoped_enum = - std::integral_constant<bool, std::is_convertible<T, int>::value and - std::is_enum<T>::value>; - -/* -Implementation of two C++17 constructs: conjunction, negation. This is needed -to avoid evaluating all the traits in a condition - -For example: not std::is_same<void, T>::value and has_value_type<T>::value -will not compile when T = void (on MSVC at least). Whereas -conjunction<negation<std::is_same<void, T>>, has_value_type<T>>::value will -stop evaluating if negation<...>::value == false - -Please note that those constructs must be used with caution, since symbols can -become very long quickly (which can slow down compilation and cause MSVC -internal compiler errors). Only use it when you have to (see example ahead). -*/ -template<class...> struct conjunction : std::true_type {}; -template<class B1> struct conjunction<B1> : B1 {}; -template<class B1, class... Bn> -struct conjunction<B1, Bn...> : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {}; - -template<class B> struct negation : std::integral_constant < bool, !B::value > {}; - -// dispatch utility (taken from ranges-v3) -template<unsigned N> struct priority_tag : priority_tag < N - 1 > {}; -template<> struct priority_tag<0> {}; - - -////////////////// -// constructors // -////////////////// - -template<value_t> struct external_constructor; - -template<> -struct external_constructor<value_t::boolean> -{ - template<typename BasicJsonType> - static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept - { - j.m_type = value_t::boolean; - j.m_value = b; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor<value_t::string> -{ - template<typename BasicJsonType> - static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) - { - j.m_type = value_t::string; - j.m_value = s; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor<value_t::number_float> -{ - template<typename BasicJsonType> - static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept - { - // replace infinity and NAN by null - if (not std::isfinite(val)) - { - j = BasicJsonType{}; - } - else - { - j.m_type = value_t::number_float; - j.m_value = val; - } - j.assert_invariant(); - } -}; - -template<> -struct external_constructor<value_t::number_unsigned> -{ - template<typename BasicJsonType> - static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept - { - j.m_type = value_t::number_unsigned; - j.m_value = val; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor<value_t::number_integer> -{ - template<typename BasicJsonType> - static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept - { - j.m_type = value_t::number_integer; - j.m_value = val; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor<value_t::array> -{ - template<typename BasicJsonType> - static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) - { - j.m_type = value_t::array; - j.m_value = arr; - j.assert_invariant(); - } - - template<typename BasicJsonType, typename CompatibleArrayType, - enable_if_t<not std::is_same<CompatibleArrayType, - typename BasicJsonType::array_t>::value, - int> = 0> - static void construct(BasicJsonType& j, const CompatibleArrayType& arr) - { - using std::begin; - using std::end; - j.m_type = value_t::array; - j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr)); - j.assert_invariant(); - } -}; - -template<> -struct external_constructor<value_t::object> -{ - template<typename BasicJsonType> - static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) - { - j.m_type = value_t::object; - j.m_value = obj; - j.assert_invariant(); - } - - template<typename BasicJsonType, typename CompatibleObjectType, - enable_if_t<not std::is_same<CompatibleObjectType, - typename BasicJsonType::object_t>::value, - int> = 0> - static void construct(BasicJsonType& j, const CompatibleObjectType& obj) - { - using std::begin; - using std::end; - - j.m_type = value_t::object; - j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj)); - j.assert_invariant(); - } -}; - - -//////////////////////// -// has_/is_ functions // -//////////////////////// - -/*! -@brief Helper to determine whether there's a key_type for T. - -This helper is used to tell associative containers apart from other containers -such as sequence containers. For instance, `std::map` passes the test as it -contains a `mapped_type`, whereas `std::vector` fails the test. - -@sa http://stackoverflow.com/a/7728728/266378 -@since version 1.0.0, overworked in version 2.0.6 -*/ -#define NLOHMANN_JSON_HAS_HELPER(type) \ - template<typename T> struct has_##type { \ - private: \ - template<typename U, typename = typename U::type> \ - static int detect(U &&); \ - static void detect(...); \ - public: \ - static constexpr bool value = \ - std::is_integral<decltype(detect(std::declval<T>()))>::value; \ - } - -NLOHMANN_JSON_HAS_HELPER(mapped_type); -NLOHMANN_JSON_HAS_HELPER(key_type); -NLOHMANN_JSON_HAS_HELPER(value_type); -NLOHMANN_JSON_HAS_HELPER(iterator); - -#undef NLOHMANN_JSON_HAS_HELPER - - -template<bool B, class RealType, class CompatibleObjectType> -struct is_compatible_object_type_impl : std::false_type {}; - -template<class RealType, class CompatibleObjectType> -struct is_compatible_object_type_impl<true, RealType, CompatibleObjectType> -{ - static constexpr auto value = - std::is_constructible<typename RealType::key_type, - typename CompatibleObjectType::key_type>::value and - std::is_constructible<typename RealType::mapped_type, - typename CompatibleObjectType::mapped_type>::value; -}; - -template<class BasicJsonType, class CompatibleObjectType> -struct is_compatible_object_type -{ - static auto constexpr value = is_compatible_object_type_impl < - conjunction<negation<std::is_same<void, CompatibleObjectType>>, - has_mapped_type<CompatibleObjectType>, - has_key_type<CompatibleObjectType>>::value, - typename BasicJsonType::object_t, CompatibleObjectType >::value; -}; - -template<typename BasicJsonType, typename T> -struct is_basic_json_nested_type -{ - static auto constexpr value = std::is_same<T, typename BasicJsonType::iterator>::value or - std::is_same<T, typename BasicJsonType::const_iterator>::value or - std::is_same<T, typename BasicJsonType::reverse_iterator>::value or - std::is_same<T, typename BasicJsonType::const_reverse_iterator>::value or - std::is_same<T, typename BasicJsonType::json_pointer>::value; -}; - -template<class BasicJsonType, class CompatibleArrayType> -struct is_compatible_array_type -{ - static auto constexpr value = - conjunction<negation<std::is_same<void, CompatibleArrayType>>, - negation<is_compatible_object_type< - BasicJsonType, CompatibleArrayType>>, - negation<std::is_constructible<typename BasicJsonType::string_t, - CompatibleArrayType>>, - negation<is_basic_json_nested_type<BasicJsonType, CompatibleArrayType>>, - has_value_type<CompatibleArrayType>, - has_iterator<CompatibleArrayType>>::value; -}; - -template<bool, typename, typename> -struct is_compatible_integer_type_impl : std::false_type {}; - -template<typename RealIntegerType, typename CompatibleNumberIntegerType> -struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIntegerType> -{ - // is there an assert somewhere on overflows? - using RealLimits = std::numeric_limits<RealIntegerType>; - using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>; - - static constexpr auto value = - std::is_constructible<RealIntegerType, - CompatibleNumberIntegerType>::value and - CompatibleLimits::is_integer and - RealLimits::is_signed == CompatibleLimits::is_signed; -}; - -template<typename RealIntegerType, typename CompatibleNumberIntegerType> -struct is_compatible_integer_type -{ - static constexpr auto value = - is_compatible_integer_type_impl < - std::is_integral<CompatibleNumberIntegerType>::value and - not std::is_same<bool, CompatibleNumberIntegerType>::value, - RealIntegerType, CompatibleNumberIntegerType > ::value; -}; - - -// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists -template<typename BasicJsonType, typename T> -struct has_from_json -{ - private: - // also check the return type of from_json - template<typename U, typename = enable_if_t<std::is_same<void, decltype(uncvref_t<U>::from_json( - std::declval<BasicJsonType>(), std::declval<T&>()))>::value>> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral<decltype( - detect(std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; -}; - -// This trait checks if JSONSerializer<T>::from_json(json const&) exists -// this overload is used for non-default-constructible user-defined-types -template<typename BasicJsonType, typename T> -struct has_non_default_from_json -{ - private: - template < - typename U, - typename = enable_if_t<std::is_same< - T, decltype(uncvref_t<U>::from_json(std::declval<BasicJsonType>()))>::value >> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral<decltype(detect( - std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; -}; - -// This trait checks if BasicJsonType::json_serializer<T>::to_json exists -template<typename BasicJsonType, typename T> -struct has_to_json -{ - private: - template<typename U, typename = decltype(uncvref_t<U>::to_json( - std::declval<BasicJsonType&>(), std::declval<T>()))> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral<decltype(detect( - std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; -}; - - -///////////// -// to_json // -///////////// - -template<typename BasicJsonType, typename T, enable_if_t< - std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0> -void to_json(BasicJsonType& j, T b) noexcept -{ - external_constructor<value_t::boolean>::construct(j, b); -} - -template<typename BasicJsonType, typename CompatibleString, - enable_if_t<std::is_constructible<typename BasicJsonType::string_t, - CompatibleString>::value, int> = 0> -void to_json(BasicJsonType& j, const CompatibleString& s) -{ - external_constructor<value_t::string>::construct(j, s); -} - -template<typename BasicJsonType, typename FloatType, - enable_if_t<std::is_floating_point<FloatType>::value, int> = 0> -void to_json(BasicJsonType& j, FloatType val) noexcept -{ - external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val)); -} - -template < - typename BasicJsonType, typename CompatibleNumberUnsignedType, - enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, - CompatibleNumberUnsignedType>::value, int> = 0 > -void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept -{ - external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val)); -} - -template < - typename BasicJsonType, typename CompatibleNumberIntegerType, - enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, - CompatibleNumberIntegerType>::value, int> = 0 > -void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept -{ - external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val)); -} - -template<typename BasicJsonType, typename UnscopedEnumType, - enable_if_t<is_unscoped_enum<UnscopedEnumType>::value, int> = 0> -void to_json(BasicJsonType& j, UnscopedEnumType e) noexcept -{ - external_constructor<value_t::number_integer>::construct(j, e); -} - -template < - typename BasicJsonType, typename CompatibleArrayType, - enable_if_t < - is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value or - std::is_same<typename BasicJsonType::array_t, CompatibleArrayType>::value, - int > = 0 > -void to_json(BasicJsonType& j, const CompatibleArrayType& arr) -{ - external_constructor<value_t::array>::construct(j, arr); -} - -template < - typename BasicJsonType, typename CompatibleObjectType, - enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value, - int> = 0 > -void to_json(BasicJsonType& j, const CompatibleObjectType& arr) -{ - external_constructor<value_t::object>::construct(j, arr); -} - - -/////////////// -// from_json // -/////////////// - -// overloads for basic_json template parameters -template<typename BasicJsonType, typename ArithmeticType, - enable_if_t<std::is_arithmetic<ArithmeticType>::value and - not std::is_same<ArithmeticType, - typename BasicJsonType::boolean_t>::value, - int> = 0> -void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) -{ - switch (static_cast<value_t>(j)) - { - case value_t::number_unsigned: - { - val = static_cast<ArithmeticType>( - *j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>()); - break; - } - case value_t::number_integer: - { - val = static_cast<ArithmeticType>( - *j.template get_ptr<const typename BasicJsonType::number_integer_t*>()); - break; - } - case value_t::number_float: - { - val = static_cast<ArithmeticType>( - *j.template get_ptr<const typename BasicJsonType::number_float_t*>()); - break; - } - default: - { - JSON_THROW( - std::domain_error("type must be number, but is " + j.type_name())); - } - } -} - -template<typename BasicJsonType> -void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) -{ - if (not j.is_boolean()) - { - JSON_THROW(std::domain_error("type must be boolean, but is " + j.type_name())); - } - b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>(); -} - -template<typename BasicJsonType> -void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) -{ - if (not j.is_string()) - { - JSON_THROW(std::domain_error("type must be string, but is " + j.type_name())); - } - s = *j.template get_ptr<const typename BasicJsonType::string_t*>(); -} - -template<typename BasicJsonType> -void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) -{ - get_arithmetic_value(j, val); -} - -template<typename BasicJsonType> -void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) -{ - get_arithmetic_value(j, val); -} - -template<typename BasicJsonType> -void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) -{ - get_arithmetic_value(j, val); -} - -template<typename BasicJsonType, typename UnscopedEnumType, - enable_if_t<is_unscoped_enum<UnscopedEnumType>::value, int> = 0> -void from_json(const BasicJsonType& j, UnscopedEnumType& e) -{ - typename std::underlying_type<UnscopedEnumType>::type val; - get_arithmetic_value(j, val); - e = static_cast<UnscopedEnumType>(val); -} - -template<typename BasicJsonType> -void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) -{ - if (not j.is_array()) - { - JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); - } - arr = *j.template get_ptr<const typename BasicJsonType::array_t*>(); -} - -// forward_list doesn't have an insert method -template<typename BasicJsonType, typename T, typename Allocator> -void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l) -{ - // do not perform the check when user wants to retrieve jsons - // (except when it's null.. ?) - if (j.is_null()) - { - JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); - } - if (not std::is_same<T, BasicJsonType>::value) - { - if (not j.is_array()) - { - JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); - } - } - for (auto it = j.rbegin(), end = j.rend(); it != end; ++it) - { - l.push_front(it->template get<T>()); - } -} - -template<typename BasicJsonType, typename CompatibleArrayType> -void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0>) -{ - using std::begin; - using std::end; - - std::transform(j.begin(), j.end(), - std::inserter(arr, end(arr)), [](const BasicJsonType & i) - { - // get<BasicJsonType>() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get<typename CompatibleArrayType::value_type>(); - }); -} - -template<typename BasicJsonType, typename CompatibleArrayType> -auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1>) --> decltype( - arr.reserve(std::declval<typename CompatibleArrayType::size_type>()), - void()) -{ - using std::begin; - using std::end; - - arr.reserve(j.size()); - std::transform( - j.begin(), j.end(), std::inserter(arr, end(arr)), [](const BasicJsonType & i) - { - // get<BasicJsonType>() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get<typename CompatibleArrayType::value_type>(); - }); -} - -template<typename BasicJsonType, typename CompatibleArrayType, - enable_if_t<is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and - not std::is_same<typename BasicJsonType::array_t, CompatibleArrayType>::value, int> = 0> -void from_json(const BasicJsonType& j, CompatibleArrayType& arr) -{ - if (j.is_null()) - { - JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); - } - - // when T == BasicJsonType, do not check if value_t is correct - if (not std::is_same<typename CompatibleArrayType::value_type, BasicJsonType>::value) - { - if (not j.is_array()) - { - JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); - } - } - from_json_array_impl(j, arr, priority_tag<1> {}); -} - -template<typename BasicJsonType, typename CompatibleObjectType, - enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value, int> = 0> -void from_json(const BasicJsonType& j, CompatibleObjectType& obj) -{ - if (not j.is_object()) - { - JSON_THROW(std::domain_error("type must be object, but is " + j.type_name())); - } - - auto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>(); - using std::begin; - using std::end; - // we could avoid the assignment, but this might require a for loop, which - // might be less efficient than the container constructor for some - // containers (would it?) - obj = CompatibleObjectType(begin(*inner_object), end(*inner_object)); -} - -// overload for arithmetic types, not chosen for basic_json template arguments -// (BooleanType, etc..); note: Is it really necessary to provide explicit -// overloads for boolean_t etc. in case of a custom BooleanType which is not -// an arithmetic type? -template<typename BasicJsonType, typename ArithmeticType, - enable_if_t < - std::is_arithmetic<ArithmeticType>::value and - not std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value and - not std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value and - not std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value and - not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value, - int> = 0> -void from_json(const BasicJsonType& j, ArithmeticType& val) -{ - switch (static_cast<value_t>(j)) - { - case value_t::number_unsigned: - { - val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>()); - break; - } - case value_t::number_integer: - { - val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>()); - break; - } - case value_t::number_float: - { - val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>()); - break; - } - case value_t::boolean: - { - val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>()); - break; - } - default: - { - JSON_THROW(std::domain_error("type must be number, but is " + j.type_name())); - } - } -} - -struct to_json_fn -{ - private: - template<typename BasicJsonType, typename T> - auto call(BasicJsonType& j, T&& val, priority_tag<1>) const noexcept(noexcept(to_json(j, std::forward<T>(val)))) - -> decltype(to_json(j, std::forward<T>(val)), void()) - { - return to_json(j, std::forward<T>(val)); - } - - template<typename BasicJsonType, typename T> - void call(BasicJsonType&, T&&, priority_tag<0>) const noexcept - { - static_assert(sizeof(BasicJsonType) == 0, - "could not find to_json() method in T's namespace"); - } - - public: - template<typename BasicJsonType, typename T> - void operator()(BasicJsonType& j, T&& val) const - noexcept(noexcept(std::declval<to_json_fn>().call(j, std::forward<T>(val), priority_tag<1> {}))) - { - return call(j, std::forward<T>(val), priority_tag<1> {}); - } -}; - -struct from_json_fn -{ - private: - template<typename BasicJsonType, typename T> - auto call(const BasicJsonType& j, T& val, priority_tag<1>) const - noexcept(noexcept(from_json(j, val))) - -> decltype(from_json(j, val), void()) - { - return from_json(j, val); - } - - template<typename BasicJsonType, typename T> - void call(const BasicJsonType&, T&, priority_tag<0>) const noexcept - { - static_assert(sizeof(BasicJsonType) == 0, - "could not find from_json() method in T's namespace"); - } - - public: - template<typename BasicJsonType, typename T> - void operator()(const BasicJsonType& j, T& val) const - noexcept(noexcept(std::declval<from_json_fn>().call(j, val, priority_tag<1> {}))) - { - return call(j, val, priority_tag<1> {}); - } -}; - -// taken from ranges-v3 -template<typename T> -struct static_const -{ - static constexpr T value{}; -}; - -template<typename T> -constexpr T static_const<T>::value; -} // namespace detail - - -/// namespace to hold default `to_json` / `from_json` functions -namespace -{ -constexpr const auto& to_json = detail::static_const<detail::to_json_fn>::value; -constexpr const auto& from_json = detail::static_const<detail::from_json_fn>::value; -} - - -/*! -@brief default JSONSerializer template argument - -This serializer ignores the template arguments and uses ADL -([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl)) -for serialization. -*/ -template<typename = void, typename = void> -struct adl_serializer -{ - /*! - @brief convert a JSON value to any value type - - This function is usually called by the `get()` function of the - @ref basic_json class (either explicit or via conversion operators). - - @param[in] j JSON value to read from - @param[in,out] val value to write to - */ - template<typename BasicJsonType, typename ValueType> - static void from_json(BasicJsonType&& j, ValueType& val) noexcept( - noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val))) - { - ::nlohmann::from_json(std::forward<BasicJsonType>(j), val); - } - - /*! - @brief convert any value type to a JSON value - - This function is usually called by the constructors of the @ref basic_json - class. - - @param[in,out] j JSON value to write to - @param[in] val value to read from - */ - template<typename BasicJsonType, typename ValueType> - static void to_json(BasicJsonType& j, ValueType&& val) noexcept( - noexcept(::nlohmann::to_json(j, std::forward<ValueType>(val)))) - { - ::nlohmann::to_json(j, std::forward<ValueType>(val)); - } -}; - - -/*! -@brief a class to store JSON values - -@tparam ObjectType type for JSON objects (`std::map` by default; will be used -in @ref object_t) -@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used -in @ref array_t) -@tparam StringType type for JSON strings and object keys (`std::string` by -default; will be used in @ref string_t) -@tparam BooleanType type for JSON booleans (`bool` by default; will be used -in @ref boolean_t) -@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by -default; will be used in @ref number_integer_t) -@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c -`uint64_t` by default; will be used in @ref number_unsigned_t) -@tparam NumberFloatType type for JSON floating-point numbers (`double` by -default; will be used in @ref number_float_t) -@tparam AllocatorType type of the allocator to use (`std::allocator` by -default) -@tparam JSONSerializer the serializer to resolve internal calls to `to_json()` -and `from_json()` (@ref adl_serializer by default) - -@requirement The class satisfies the following concept requirements: -- Basic - - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible): - JSON values can be default constructed. The result will be a JSON null - value. - - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): - A JSON value can be constructed from an rvalue argument. - - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): - A JSON value can be copy-constructed from an lvalue expression. - - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): - A JSON value van be assigned from an rvalue argument. - - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): - A JSON value can be copy-assigned from an lvalue expression. - - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible): - JSON values can be destructed. -- Layout - - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType): - JSON values have - [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout): - All non-static data members are private and standard layout types, the - class has no virtual functions or (virtual) base classes. -- Library-wide - - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable): - JSON values can be compared with `==`, see @ref - operator==(const_reference,const_reference). - - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable): - JSON values can be compared with `<`, see @ref - operator<(const_reference,const_reference). - - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable): - Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of - other compatible types, using unqualified function call @ref swap(). - - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer): - JSON values can be compared against `std::nullptr_t` objects which are used - to model the `null` value. -- Container - - [Container](http://en.cppreference.com/w/cpp/concept/Container): - JSON values can be used like STL containers and provide iterator access. - - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer); - JSON values can be used like STL containers and provide reverse iterator - access. - -@invariant The member variables @a m_value and @a m_type have the following -relationship: -- If `m_type == value_t::object`, then `m_value.object != nullptr`. -- If `m_type == value_t::array`, then `m_value.array != nullptr`. -- If `m_type == value_t::string`, then `m_value.string != nullptr`. -The invariants are checked by member function assert_invariant(). - -@internal -@note ObjectType trick from http://stackoverflow.com/a/9860911 -@endinternal - -@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange -Format](http://rfc7159.net/rfc7159) - -@since version 1.0.0 - -@nosubgrouping -*/ -template < - template<typename U, typename V, typename... Args> class ObjectType = std::map, - template<typename U, typename... Args> class ArrayType = std::vector, - class StringType = std::string, - class BooleanType = bool, - class NumberIntegerType = std::int64_t, - class NumberUnsignedType = std::uint64_t, - class NumberFloatType = double, - template<typename U> class AllocatorType = std::allocator, - template<typename T, typename SFINAE = void> class JSONSerializer = adl_serializer - > -class basic_json -{ - private: - template<detail::value_t> friend struct detail::external_constructor; - /// workaround type for MSVC - using basic_json_t = basic_json<ObjectType, ArrayType, StringType, - BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, - AllocatorType, JSONSerializer>; - - public: - using value_t = detail::value_t; - // forward declarations - template<typename U> class iter_impl; - template<typename Base> class json_reverse_iterator; - class json_pointer; - template<typename T, typename SFINAE> - using json_serializer = JSONSerializer<T, SFINAE>; - - ///////////////////// - // container types // - ///////////////////// - - /// @name container types - /// The canonic container types to use @ref basic_json like any other STL - /// container. - /// @{ - - /// the type of elements in a basic_json container - using value_type = basic_json; - - /// the type of an element reference - using reference = value_type&; - /// the type of an element const reference - using const_reference = const value_type&; - - /// a type to represent differences between iterators - using difference_type = std::ptrdiff_t; - /// a type to represent container sizes - using size_type = std::size_t; - - /// the allocator type - using allocator_type = AllocatorType<basic_json>; - - /// the type of an element pointer - using pointer = typename std::allocator_traits<allocator_type>::pointer; - /// the type of an element const pointer - using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer; - - /// an iterator for a basic_json container - using iterator = iter_impl<basic_json>; - /// a const iterator for a basic_json container - using const_iterator = iter_impl<const basic_json>; - /// a reverse iterator for a basic_json container - using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>; - /// a const reverse iterator for a basic_json container - using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>; - - /// @} - - - /*! - @brief returns the allocator associated with the container - */ - static allocator_type get_allocator() - { - return allocator_type(); - } - - /*! - @brief returns version information on the library - - This function returns a JSON object with information about the library, - including the version number and information on the platform and compiler. - - @return JSON object holding version information - key | description - ----------- | --------------- - `compiler` | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version). - `copyright` | The copyright line for the library as string. - `name` | The name of the library as string. - `platform` | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`. - `url` | The URL of the project as string. - `version` | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string). - - @liveexample{The following code shows an example output of the `meta()` - function.,meta} - - @complexity Constant. - - @since 2.1.0 - */ - static basic_json meta() - { - basic_json result; - - result["copyright"] = "(C) 2013-2017 Niels Lohmann"; - result["name"] = "JSON for Modern C++"; - result["url"] = "https://github.com/nlohmann/json"; - result["version"] = - { - {"string", "2.1.1"}, - {"major", 2}, - {"minor", 1}, - {"patch", 1} - }; - -#ifdef _WIN32 - result["platform"] = "win32"; -#elif defined __linux__ - result["platform"] = "linux"; -#elif defined __APPLE__ - result["platform"] = "apple"; -#elif defined __unix__ - result["platform"] = "unix"; -#else - result["platform"] = "unknown"; -#endif - -#if defined(__clang__) - result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; -#elif defined(__ICC) || defined(__INTEL_COMPILER) - result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}}; -#elif defined(__GNUC__) || defined(__GNUG__) - result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}}; -#elif defined(__HP_cc) || defined(__HP_aCC) - result["compiler"] = "hp" -#elif defined(__IBMCPP__) - result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}}; -#elif defined(_MSC_VER) - result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}}; -#elif defined(__PGI) - result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}}; -#elif defined(__SUNPRO_CC) - result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}}; -#else - result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}}; -#endif - -#ifdef __cplusplus - result["compiler"]["c++"] = std::to_string(__cplusplus); -#else - result["compiler"]["c++"] = "unknown"; -#endif - return result; - } - - - /////////////////////////// - // JSON value data types // - /////////////////////////// - - /// @name JSON value data types - /// The data types to store a JSON value. These types are derived from - /// the template arguments passed to class @ref basic_json. - /// @{ - - /*! - @brief a type for an object - - [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: - > An object is an unordered collection of zero or more name/value pairs, - > where a name is a string and a value is a string, number, boolean, null, - > object, or array. - - To store objects in C++, a type is defined by the template parameters - described below. - - @tparam ObjectType the container to store objects (e.g., `std::map` or - `std::unordered_map`) - @tparam StringType the type of the keys or names (e.g., `std::string`). - The comparison function `std::less<StringType>` is used to order elements - inside the container. - @tparam AllocatorType the allocator to use for objects (e.g., - `std::allocator`) - - #### Default type - - With the default values for @a ObjectType (`std::map`), @a StringType - (`std::string`), and @a AllocatorType (`std::allocator`), the default - value for @a object_t is: - - @code {.cpp} - std::map< - std::string, // key_type - basic_json, // value_type - std::less<std::string>, // key_compare - std::allocator<std::pair<const std::string, basic_json>> // allocator_type - > - @endcode - - #### Behavior - - The choice of @a object_t influences the behavior of the JSON class. With - the default type, objects have the following behavior: - - - When all names are unique, objects will be interoperable in the sense - that all software implementations receiving that object will agree on - the name-value mappings. - - When the names within an object are not unique, later stored name/value - pairs overwrite previously stored name/value pairs, leaving the used - names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will - be treated as equal and both stored as `{"key": 1}`. - - Internally, name/value pairs are stored in lexicographical order of the - names. Objects will also be serialized (see @ref dump) in this order. - For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored - and serialized as `{"a": 2, "b": 1}`. - - When comparing objects, the order of the name/value pairs is irrelevant. - This makes objects interoperable in the sense that they will not be - affected by these differences. For instance, `{"b": 1, "a": 2}` and - `{"a": 2, "b": 1}` will be treated as equal. - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) specifies: - > An implementation may set limits on the maximum depth of nesting. - - In this class, the object's limit of nesting is not constraint explicitly. - However, a maximum depth of nesting may be introduced by the compiler or - runtime environment. A theoretical limit can be queried by calling the - @ref max_size function of a JSON object. - - #### Storage - - Objects are stored as pointers in a @ref basic_json type. That is, for any - access to object values, a pointer of type `object_t*` must be - dereferenced. - - @sa @ref array_t -- type for an array value - - @since version 1.0.0 - - @note The order name/value pairs are added to the object is *not* - preserved by the library. Therefore, iterating an object may return - name/value pairs in a different order than they were originally stored. In - fact, keys will be traversed in alphabetical order as `std::map` with - `std::less` is used by default. Please note this behavior conforms to [RFC - 7159](http://rfc7159.net/rfc7159), because any order implements the - specified "unordered" nature of JSON objects. - */ - using object_t = ObjectType<StringType, - basic_json, - std::less<StringType>, - AllocatorType<std::pair<const StringType, - basic_json>>>; - - /*! - @brief a type for an array - - [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: - > An array is an ordered sequence of zero or more values. - - To store objects in C++, a type is defined by the template parameters - explained below. - - @tparam ArrayType container type to store arrays (e.g., `std::vector` or - `std::list`) - @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) - - #### Default type - - With the default values for @a ArrayType (`std::vector`) and @a - AllocatorType (`std::allocator`), the default value for @a array_t is: - - @code {.cpp} - std::vector< - basic_json, // value_type - std::allocator<basic_json> // allocator_type - > - @endcode - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) specifies: - > An implementation may set limits on the maximum depth of nesting. - - In this class, the array's limit of nesting is not constraint explicitly. - However, a maximum depth of nesting may be introduced by the compiler or - runtime environment. A theoretical limit can be queried by calling the - @ref max_size function of a JSON array. - - #### Storage - - Arrays are stored as pointers in a @ref basic_json type. That is, for any - access to array values, a pointer of type `array_t*` must be dereferenced. - - @sa @ref object_t -- type for an object value - - @since version 1.0.0 - */ - using array_t = ArrayType<basic_json, AllocatorType<basic_json>>; - - /*! - @brief a type for a string - - [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: - > A string is a sequence of zero or more Unicode characters. - - To store objects in C++, a type is defined by the template parameter - described below. Unicode values are split by the JSON class into - byte-sized characters during deserialization. - - @tparam StringType the container to store strings (e.g., `std::string`). - Note this container is used for keys/names in objects, see @ref object_t. - - #### Default type - - With the default values for @a StringType (`std::string`), the default - value for @a string_t is: - - @code {.cpp} - std::string - @endcode - - #### Encoding - - Strings are stored in UTF-8 encoding. Therefore, functions like - `std::string::size()` or `std::string::length()` return the number of - bytes in the string rather than the number of characters or glyphs. - - #### String comparison - - [RFC 7159](http://rfc7159.net/rfc7159) states: - > Software implementations are typically required to test names of object - > members for equality. Implementations that transform the textual - > representation into sequences of Unicode code units and then perform the - > comparison numerically, code unit by code unit, are interoperable in the - > sense that implementations will agree in all cases on equality or - > inequality of two strings. For example, implementations that compare - > strings with escaped characters unconverted may incorrectly find that - > `"a\\b"` and `"a\u005Cb"` are not equal. - - This implementation is interoperable as it does compare strings code unit - by code unit. - - #### Storage - - String values are stored as pointers in a @ref basic_json type. That is, - for any access to string values, a pointer of type `string_t*` must be - dereferenced. - - @since version 1.0.0 - */ - using string_t = StringType; - - /*! - @brief a type for a boolean - - [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a - type which differentiates the two literals `true` and `false`. - - To store objects in C++, a type is defined by the template parameter @a - BooleanType which chooses the type to use. - - #### Default type - - With the default values for @a BooleanType (`bool`), the default value for - @a boolean_t is: - - @code {.cpp} - bool - @endcode - - #### Storage - - Boolean values are stored directly inside a @ref basic_json type. - - @since version 1.0.0 - */ - using boolean_t = BooleanType; - - /*! - @brief a type for a number (integer) - - [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: - > The representation of numbers is similar to that used in most - > programming languages. A number is represented in base 10 using decimal - > digits. It contains an integer component that may be prefixed with an - > optional minus sign, which may be followed by a fraction part and/or an - > exponent part. Leading zeros are not allowed. (...) Numeric values that - > cannot be represented in the grammar below (such as Infinity and NaN) - > are not permitted. - - This description includes both integer and floating-point numbers. - However, C++ allows more precise storage if it is known whether the number - is a signed integer, an unsigned integer or a floating-point number. - Therefore, three different types, @ref number_integer_t, @ref - number_unsigned_t and @ref number_float_t are used. - - To store integer numbers in C++, a type is defined by the template - parameter @a NumberIntegerType which chooses the type to use. - - #### Default type - - With the default values for @a NumberIntegerType (`int64_t`), the default - value for @a number_integer_t is: - - @code {.cpp} - int64_t - @endcode - - #### Default behavior - - - The restrictions about leading zeros is not enforced in C++. Instead, - leading zeros in integer literals lead to an interpretation as octal - number. Internally, the value will be stored as decimal number. For - instance, the C++ integer literal `010` will be serialized to `8`. - During deserialization, leading zeros yield an error. - - Not-a-number (NaN) values will be serialized to `null`. - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) specifies: - > An implementation may set limits on the range and precision of numbers. - - When the default type is used, the maximal integer number that can be - stored is `9223372036854775807` (INT64_MAX) and the minimal integer number - that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers - that are out of range will yield over/underflow when used in a - constructor. During deserialization, too large or small integer numbers - will be automatically be stored as @ref number_unsigned_t or @ref - number_float_t. - - [RFC 7159](http://rfc7159.net/rfc7159) further states: - > Note that when such software is used, numbers that are integers and are - > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense - > that implementations will agree exactly on their numeric values. - - As this range is a subrange of the exactly supported range [INT64_MIN, - INT64_MAX], this class's integer type is interoperable. - - #### Storage - - Integer number values are stored directly inside a @ref basic_json type. - - @sa @ref number_float_t -- type for number values (floating-point) - - @sa @ref number_unsigned_t -- type for number values (unsigned integer) - - @since version 1.0.0 - */ - using number_integer_t = NumberIntegerType; - - /*! - @brief a type for a number (unsigned) - - [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: - > The representation of numbers is similar to that used in most - > programming languages. A number is represented in base 10 using decimal - > digits. It contains an integer component that may be prefixed with an - > optional minus sign, which may be followed by a fraction part and/or an - > exponent part. Leading zeros are not allowed. (...) Numeric values that - > cannot be represented in the grammar below (such as Infinity and NaN) - > are not permitted. - - This description includes both integer and floating-point numbers. - However, C++ allows more precise storage if it is known whether the number - is a signed integer, an unsigned integer or a floating-point number. - Therefore, three different types, @ref number_integer_t, @ref - number_unsigned_t and @ref number_float_t are used. - - To store unsigned integer numbers in C++, a type is defined by the - template parameter @a NumberUnsignedType which chooses the type to use. - - #### Default type - - With the default values for @a NumberUnsignedType (`uint64_t`), the - default value for @a number_unsigned_t is: - - @code {.cpp} - uint64_t - @endcode - - #### Default behavior - - - The restrictions about leading zeros is not enforced in C++. Instead, - leading zeros in integer literals lead to an interpretation as octal - number. Internally, the value will be stored as decimal number. For - instance, the C++ integer literal `010` will be serialized to `8`. - During deserialization, leading zeros yield an error. - - Not-a-number (NaN) values will be serialized to `null`. - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) specifies: - > An implementation may set limits on the range and precision of numbers. - - When the default type is used, the maximal integer number that can be - stored is `18446744073709551615` (UINT64_MAX) and the minimal integer - number that can be stored is `0`. Integer numbers that are out of range - will yield over/underflow when used in a constructor. During - deserialization, too large or small integer numbers will be automatically - be stored as @ref number_integer_t or @ref number_float_t. - - [RFC 7159](http://rfc7159.net/rfc7159) further states: - > Note that when such software is used, numbers that are integers and are - > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense - > that implementations will agree exactly on their numeric values. - - As this range is a subrange (when considered in conjunction with the - number_integer_t type) of the exactly supported range [0, UINT64_MAX], - this class's integer type is interoperable. - - #### Storage - - Integer number values are stored directly inside a @ref basic_json type. - - @sa @ref number_float_t -- type for number values (floating-point) - @sa @ref number_integer_t -- type for number values (integer) - - @since version 2.0.0 - */ - using number_unsigned_t = NumberUnsignedType; - - /*! - @brief a type for a number (floating-point) - - [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: - > The representation of numbers is similar to that used in most - > programming languages. A number is represented in base 10 using decimal - > digits. It contains an integer component that may be prefixed with an - > optional minus sign, which may be followed by a fraction part and/or an - > exponent part. Leading zeros are not allowed. (...) Numeric values that - > cannot be represented in the grammar below (such as Infinity and NaN) - > are not permitted. - - This description includes both integer and floating-point numbers. - However, C++ allows more precise storage if it is known whether the number - is a signed integer, an unsigned integer or a floating-point number. - Therefore, three different types, @ref number_integer_t, @ref - number_unsigned_t and @ref number_float_t are used. - - To store floating-point numbers in C++, a type is defined by the template - parameter @a NumberFloatType which chooses the type to use. - - #### Default type - - With the default values for @a NumberFloatType (`double`), the default - value for @a number_float_t is: - - @code {.cpp} - double - @endcode - - #### Default behavior - - - The restrictions about leading zeros is not enforced in C++. Instead, - leading zeros in floating-point literals will be ignored. Internally, - the value will be stored as decimal number. For instance, the C++ - floating-point literal `01.2` will be serialized to `1.2`. During - deserialization, leading zeros yield an error. - - Not-a-number (NaN) values will be serialized to `null`. - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) states: - > This specification allows implementations to set limits on the range and - > precision of numbers accepted. Since software that implements IEEE - > 754-2008 binary64 (double precision) numbers is generally available and - > widely used, good interoperability can be achieved by implementations - > that expect no more precision or range than these provide, in the sense - > that implementations will approximate JSON numbers within the expected - > precision. - - This implementation does exactly follow this approach, as it uses double - precision floating-point numbers. Note values smaller than - `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` - will be stored as NaN internally and be serialized to `null`. - - #### Storage - - Floating-point number values are stored directly inside a @ref basic_json - type. - - @sa @ref number_integer_t -- type for number values (integer) - - @sa @ref number_unsigned_t -- type for number values (unsigned integer) - - @since version 1.0.0 - */ - using number_float_t = NumberFloatType; - - /// @} - - private: - - /// helper for exception-safe object creation - template<typename T, typename... Args> - static T* create(Args&& ... args) - { - AllocatorType<T> alloc; - auto deleter = [&](T * object) - { - alloc.deallocate(object, 1); - }; - std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter); - alloc.construct(object.get(), std::forward<Args>(args)...); - assert(object != nullptr); - return object.release(); - } - - //////////////////////// - // JSON value storage // - //////////////////////// - - /*! - @brief a JSON value - - The actual storage for a JSON value of the @ref basic_json class. This - union combines the different storage types for the JSON value types - defined in @ref value_t. - - JSON type | value_t type | used type - --------- | --------------- | ------------------------ - object | object | pointer to @ref object_t - array | array | pointer to @ref array_t - string | string | pointer to @ref string_t - boolean | boolean | @ref boolean_t - number | number_integer | @ref number_integer_t - number | number_unsigned | @ref number_unsigned_t - number | number_float | @ref number_float_t - null | null | *no value is stored* - - @note Variable-length types (objects, arrays, and strings) are stored as - pointers. The size of the union should not exceed 64 bits if the default - value types are used. - - @since version 1.0.0 - */ - union json_value - { - /// object (stored with pointer to save storage) - object_t* object; - /// array (stored with pointer to save storage) - array_t* array; - /// string (stored with pointer to save storage) - string_t* string; - /// boolean - boolean_t boolean; - /// number (integer) - number_integer_t number_integer; - /// number (unsigned integer) - number_unsigned_t number_unsigned; - /// number (floating-point) - number_float_t number_float; - - /// default constructor (for null values) - json_value() = default; - /// constructor for booleans - json_value(boolean_t v) noexcept : boolean(v) {} - /// constructor for numbers (integer) - json_value(number_integer_t v) noexcept : number_integer(v) {} - /// constructor for numbers (unsigned) - json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} - /// constructor for numbers (floating-point) - json_value(number_float_t v) noexcept : number_float(v) {} - /// constructor for empty values of a given type - json_value(value_t t) - { - switch (t) - { - case value_t::object: - { - object = create<object_t>(); - break; - } - - case value_t::array: - { - array = create<array_t>(); - break; - } - - case value_t::string: - { - string = create<string_t>(""); - break; - } - - case value_t::boolean: - { - boolean = boolean_t(false); - break; - } - - case value_t::number_integer: - { - number_integer = number_integer_t(0); - break; - } - - case value_t::number_unsigned: - { - number_unsigned = number_unsigned_t(0); - break; - } - - case value_t::number_float: - { - number_float = number_float_t(0.0); - break; - } - - case value_t::null: - { - break; - } - - default: - { - if (t == value_t::null) - { - JSON_THROW(std::domain_error("961c151d2e87f2686a955a9be24d316f1362bf21 2.1.1")); // LCOV_EXCL_LINE - } - break; - } - } - } - - /// constructor for strings - json_value(const string_t& value) - { - string = create<string_t>(value); - } - - /// constructor for objects - json_value(const object_t& value) - { - object = create<object_t>(value); - } - - /// constructor for arrays - json_value(const array_t& value) - { - array = create<array_t>(value); - } - }; - - /*! - @brief checks the class invariants - - This function asserts the class invariants. It needs to be called at the - end of every constructor to make sure that created objects respect the - invariant. Furthermore, it has to be called each time the type of a JSON - value is changed, because the invariant expresses a relationship between - @a m_type and @a m_value. - */ - void assert_invariant() const - { - assert(m_type != value_t::object or m_value.object != nullptr); - assert(m_type != value_t::array or m_value.array != nullptr); - assert(m_type != value_t::string or m_value.string != nullptr); - } - - public: - ////////////////////////// - // JSON parser callback // - ////////////////////////// - - /*! - @brief JSON callback events - - This enumeration lists the parser events that can trigger calling a - callback function of type @ref parser_callback_t during parsing. - - @image html callback_events.png "Example when certain parse events are triggered" - - @since version 1.0.0 - */ - enum class parse_event_t : uint8_t - { - /// the parser read `{` and started to process a JSON object - object_start, - /// the parser read `}` and finished processing a JSON object - object_end, - /// the parser read `[` and started to process a JSON array - array_start, - /// the parser read `]` and finished processing a JSON array - array_end, - /// the parser read a key of a value in an object - key, - /// the parser finished reading a JSON value - value - }; - - /*! - @brief per-element parser callback type - - With a parser callback function, the result of parsing a JSON text can be - influenced. When passed to @ref parse(std::istream&, const - parser_callback_t) or @ref parse(const CharT, const parser_callback_t), - it is called on certain events (passed as @ref parse_event_t via parameter - @a event) with a set recursion depth @a depth and context JSON value - @a parsed. The return value of the callback function is a boolean - indicating whether the element that emitted the callback shall be kept or - not. - - We distinguish six scenarios (determined by the event type) in which the - callback function can be called. The following table describes the values - of the parameters @a depth, @a event, and @a parsed. - - parameter @a event | description | parameter @a depth | parameter @a parsed - ------------------ | ----------- | ------------------ | ------------------- - parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded - parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key - parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object - parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded - parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array - parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value - - @image html callback_events.png "Example when certain parse events are triggered" - - Discarding a value (i.e., returning `false`) has different effects - depending on the context in which function was called: - - - Discarded values in structured types are skipped. That is, the parser - will behave as if the discarded value was never read. - - In case a value outside a structured type is skipped, it is replaced - with `null`. This case happens if the top-level element is skipped. - - @param[in] depth the depth of the recursion during parsing - - @param[in] event an event of type parse_event_t indicating the context in - the callback function has been called - - @param[in,out] parsed the current intermediate parse result; note that - writing to this value has no effect for parse_event_t::key events - - @return Whether the JSON value which called the function during parsing - should be kept (`true`) or not (`false`). In the latter case, it is either - skipped completely or replaced by an empty discarded object. - - @sa @ref parse(std::istream&, parser_callback_t) or - @ref parse(const CharT, const parser_callback_t) for examples - - @since version 1.0.0 - */ - using parser_callback_t = std::function<bool(int depth, - parse_event_t event, - basic_json& parsed)>; - - - ////////////////// - // constructors // - ////////////////// - - /// @name constructors and destructors - /// Constructors of class @ref basic_json, copy/move constructor, copy - /// assignment, static functions creating objects, and the destructor. - /// @{ - - /*! - @brief create an empty value with a given type - - Create an empty JSON value with a given type. The value will be default - initialized with an empty value which depends on the type: - - Value type | initial value - ----------- | ------------- - null | `null` - boolean | `false` - string | `""` - number | `0` - object | `{}` - array | `[]` - - @param[in] value_type the type of the value to create - - @complexity Constant. - - @throw std::bad_alloc if allocation for object, array, or string value - fails - - @liveexample{The following code shows the constructor for different @ref - value_t values,basic_json__value_t} - - @since version 1.0.0 - */ - basic_json(const value_t value_type) - : m_type(value_type), m_value(value_type) - { - assert_invariant(); - } - - /*! - @brief create a null object - - Create a `null` JSON value. It either takes a null pointer as parameter - (explicitly creating `null`) or no parameter (implicitly creating `null`). - The passed null pointer itself is not read -- it is only used to choose - the right constructor. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this constructor never throws - exceptions. - - @liveexample{The following code shows the constructor with and without a - null pointer parameter.,basic_json__nullptr_t} - - @since version 1.0.0 - */ - basic_json(std::nullptr_t = nullptr) noexcept - : basic_json(value_t::null) - { - assert_invariant(); - } - - /*! - @brief create a JSON value - - This is a "catch all" constructor for all compatible JSON types; that is, - types for which a `to_json()` method exsits. The constructor forwards the - parameter @a val to that method (to `json_serializer<U>::to_json` method - with `U = uncvref_t<CompatibleType>`, to be exact). - - Template type @a CompatibleType includes, but is not limited to, the - following types: - - **arrays**: @ref array_t and all kinds of compatible containers such as - `std::vector`, `std::deque`, `std::list`, `std::forward_list`, - `std::array`, `std::set`, `std::unordered_set`, `std::multiset`, and - `unordered_multiset` with a `value_type` from which a @ref basic_json - value can be constructed. - - **objects**: @ref object_t and all kinds of compatible associative - containers such as `std::map`, `std::unordered_map`, `std::multimap`, - and `std::unordered_multimap` with a `key_type` compatible to - @ref string_t and a `value_type` from which a @ref basic_json value can - be constructed. - - **strings**: @ref string_t, string literals, and all compatible string - containers can be used. - - **numbers**: @ref number_integer_t, @ref number_unsigned_t, - @ref number_float_t, and all convertible number types such as `int`, - `size_t`, `int64_t`, `float` or `double` can be used. - - **boolean**: @ref boolean_t / `bool` can be used. - - See the examples below. - - @tparam CompatibleType a type such that: - - @a CompatibleType is not derived from `std::istream`, - - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move - constructors), - - @a CompatibleType is not a @ref basic_json nested type (e.g., - @ref json_pointer, @ref iterator, etc ...) - - @ref @ref json_serializer<U> has a - `to_json(basic_json_t&, CompatibleType&&)` method - - @tparam U = `uncvref_t<CompatibleType>` - - @param[in] val the value to be forwarded - - @complexity Usually linear in the size of the passed @a val, also - depending on the implementation of the called `to_json()` - method. - - @throw what `json_serializer<U>::to_json()` throws - - @liveexample{The following code shows the constructor with several - compatible types.,basic_json__CompatibleType} - - @since version 2.1.0 - */ - template<typename CompatibleType, typename U = detail::uncvref_t<CompatibleType>, - detail::enable_if_t<not std::is_base_of<std::istream, U>::value and - not std::is_same<U, basic_json_t>::value and - not detail::is_basic_json_nested_type< - basic_json_t, U>::value and - detail::has_to_json<basic_json, U>::value, - int> = 0> - basic_json(CompatibleType && val) noexcept(noexcept(JSONSerializer<U>::to_json( - std::declval<basic_json_t&>(), std::forward<CompatibleType>(val)))) - { - JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val)); - assert_invariant(); - } - - /*! - @brief create a container (array or object) from an initializer list - - Creates a JSON value of type array or object from the passed initializer - list @a init. In case @a type_deduction is `true` (default), the type of - the JSON value to be created is deducted from the initializer list @a init - according to the following rules: - - 1. If the list is empty, an empty JSON object value `{}` is created. - 2. If the list consists of pairs whose first element is a string, a JSON - object value is created where the first elements of the pairs are - treated as keys and the second elements are as values. - 3. In all other cases, an array is created. - - The rules aim to create the best fit between a C++ initializer list and - JSON values. The rationale is as follows: - - 1. The empty initializer list is written as `{}` which is exactly an empty - JSON object. - 2. C++ has now way of describing mapped types other than to list a list of - pairs. As JSON requires that keys must be of type string, rule 2 is the - weakest constraint one can pose on initializer lists to interpret them - as an object. - 3. In all other cases, the initializer list could not be interpreted as - JSON object type, so interpreting it as JSON array type is safe. - - With the rules described above, the following JSON values cannot be - expressed by an initializer list: - - - the empty array (`[]`): use @ref array(std::initializer_list<basic_json>) - with an empty initializer list in this case - - arrays whose elements satisfy rule 2: use @ref - array(std::initializer_list<basic_json>) with the same initializer list - in this case - - @note When used without parentheses around an empty initializer list, @ref - basic_json() is called instead of this function, yielding the JSON null - value. - - @param[in] init initializer list with JSON values - - @param[in] type_deduction internal parameter; when set to `true`, the type - of the JSON value is deducted from the initializer list @a init; when set - to `false`, the type provided via @a manual_type is forced. This mode is - used by the functions @ref array(std::initializer_list<basic_json>) and - @ref object(std::initializer_list<basic_json>). - - @param[in] manual_type internal parameter; when @a type_deduction is set - to `false`, the created JSON value will use the provided type (only @ref - value_t::array and @ref value_t::object are valid); when @a type_deduction - is set to `true`, this parameter has no effect - - @throw std::domain_error if @a type_deduction is `false`, @a manual_type - is `value_t::object`, but @a init contains an element which is not a pair - whose first element is a string; example: `"cannot create object from - initializer list"` - - @complexity Linear in the size of the initializer list @a init. - - @liveexample{The example below shows how JSON values are created from - initializer lists.,basic_json__list_init_t} - - @sa @ref array(std::initializer_list<basic_json>) -- create a JSON array - value from an initializer list - @sa @ref object(std::initializer_list<basic_json>) -- create a JSON object - value from an initializer list - - @since version 1.0.0 - */ - basic_json(std::initializer_list<basic_json> init, - bool type_deduction = true, - value_t manual_type = value_t::array) - { - // check if each element is an array with two elements whose first - // element is a string - bool is_an_object = std::all_of(init.begin(), init.end(), - [](const basic_json & element) - { - return element.is_array() and element.size() == 2 and element[0].is_string(); - }); - - // adjust type if type deduction is not wanted - if (not type_deduction) - { - // if array is wanted, do not create an object though possible - if (manual_type == value_t::array) - { - is_an_object = false; - } - - // if object is wanted but impossible, throw an exception - if (manual_type == value_t::object and not is_an_object) - { - JSON_THROW(std::domain_error("cannot create object from initializer list")); - } - } - - if (is_an_object) - { - // the initializer list is a list of pairs -> create object - m_type = value_t::object; - m_value = value_t::object; - - std::for_each(init.begin(), init.end(), [this](const basic_json & element) - { - m_value.object->emplace(*(element[0].m_value.string), element[1]); - }); - } - else - { - // the initializer list describes an array -> create array - m_type = value_t::array; - m_value.array = create<array_t>(init); - } - - assert_invariant(); - } - - /*! - @brief explicitly create an array from an initializer list - - Creates a JSON array value from a given initializer list. That is, given a - list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the - initializer list is empty, the empty array `[]` is created. - - @note This function is only needed to express two edge cases that cannot - be realized with the initializer list constructor (@ref - basic_json(std::initializer_list<basic_json>, bool, value_t)). These cases - are: - 1. creating an array whose elements are all pairs whose first element is a - string -- in this case, the initializer list constructor would create an - object, taking the first elements as keys - 2. creating an empty array -- passing the empty initializer list to the - initializer list constructor yields an empty object - - @param[in] init initializer list with JSON values to create an array from - (optional) - - @return JSON array value - - @complexity Linear in the size of @a init. - - @liveexample{The following code shows an example for the `array` - function.,array} - - @sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) -- - create a JSON value from an initializer list - @sa @ref object(std::initializer_list<basic_json>) -- create a JSON object - value from an initializer list - - @since version 1.0.0 - */ - static basic_json array(std::initializer_list<basic_json> init = - std::initializer_list<basic_json>()) - { - return basic_json(init, false, value_t::array); - } - - /*! - @brief explicitly create an object from an initializer list - - Creates a JSON object value from a given initializer list. The initializer - lists elements must be pairs, and their first elements must be strings. If - the initializer list is empty, the empty object `{}` is created. - - @note This function is only added for symmetry reasons. In contrast to the - related function @ref array(std::initializer_list<basic_json>), there are - no cases which can only be expressed by this function. That is, any - initializer list @a init can also be passed to the initializer list - constructor @ref basic_json(std::initializer_list<basic_json>, bool, - value_t). - - @param[in] init initializer list to create an object from (optional) - - @return JSON object value - - @throw std::domain_error if @a init is not a pair whose first elements are - strings; thrown by - @ref basic_json(std::initializer_list<basic_json>, bool, value_t) - - @complexity Linear in the size of @a init. - - @liveexample{The following code shows an example for the `object` - function.,object} - - @sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) -- - create a JSON value from an initializer list - @sa @ref array(std::initializer_list<basic_json>) -- create a JSON array - value from an initializer list - - @since version 1.0.0 - */ - static basic_json object(std::initializer_list<basic_json> init = - std::initializer_list<basic_json>()) - { - return basic_json(init, false, value_t::object); - } - - /*! - @brief construct an array with count copies of given value - - Constructs a JSON array value by creating @a cnt copies of a passed value. - In case @a cnt is `0`, an empty array is created. As postcondition, - `std::distance(begin(),end()) == cnt` holds. - - @param[in] cnt the number of JSON copies of @a val to create - @param[in] val the JSON value to copy - - @complexity Linear in @a cnt. - - @liveexample{The following code shows examples for the @ref - basic_json(size_type\, const basic_json&) - constructor.,basic_json__size_type_basic_json} - - @since version 1.0.0 - */ - basic_json(size_type cnt, const basic_json& val) - : m_type(value_t::array) - { - m_value.array = create<array_t>(cnt, val); - assert_invariant(); - } - - /*! - @brief construct a JSON container given an iterator range - - Constructs the JSON value with the contents of the range `[first, last)`. - The semantics depends on the different types a JSON value can have: - - In case of primitive types (number, boolean, or string), @a first must - be `begin()` and @a last must be `end()`. In this case, the value is - copied. Otherwise, std::out_of_range is thrown. - - In case of structured types (array, object), the constructor behaves as - similar versions for `std::vector`. - - In case of a null type, std::domain_error is thrown. - - @tparam InputIT an input iterator type (@ref iterator or @ref - const_iterator) - - @param[in] first begin of the range to copy from (included) - @param[in] last end of the range to copy from (excluded) - - @pre Iterators @a first and @a last must be initialized. **This - precondition is enforced with an assertion.** - - @throw std::domain_error if iterators are not compatible; that is, do not - belong to the same JSON value; example: `"iterators are not compatible"` - @throw std::out_of_range if iterators are for a primitive type (number, - boolean, or string) where an out of range error can be detected easily; - example: `"iterators out of range"` - @throw std::bad_alloc if allocation for object, array, or string fails - @throw std::domain_error if called with a null value; example: `"cannot - use construct with iterators from null"` - - @complexity Linear in distance between @a first and @a last. - - @liveexample{The example below shows several ways to create JSON values by - specifying a subrange with iterators.,basic_json__InputIt_InputIt} - - @since version 1.0.0 - */ - template<class InputIT, typename std::enable_if< - std::is_same<InputIT, typename basic_json_t::iterator>::value or - std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int>::type = 0> - basic_json(InputIT first, InputIT last) - { - assert(first.m_object != nullptr); - assert(last.m_object != nullptr); - - // make sure iterator fits the current value - if (first.m_object != last.m_object) - { - JSON_THROW(std::domain_error("iterators are not compatible")); - } - - // copy type from first iterator - m_type = first.m_object->m_type; - - // check if iterator range is complete for primitive values - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - { - if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) - { - JSON_THROW(std::out_of_range("iterators out of range")); - } - break; - } - - default: - { - break; - } - } - - switch (m_type) - { - case value_t::number_integer: - { - m_value.number_integer = first.m_object->m_value.number_integer; - break; - } - - case value_t::number_unsigned: - { - m_value.number_unsigned = first.m_object->m_value.number_unsigned; - break; - } - - case value_t::number_float: - { - m_value.number_float = first.m_object->m_value.number_float; - break; - } - - case value_t::boolean: - { - m_value.boolean = first.m_object->m_value.boolean; - break; - } - - case value_t::string: - { - m_value = *first.m_object->m_value.string; - break; - } - - case value_t::object: - { - m_value.object = create<object_t>(first.m_it.object_iterator, - last.m_it.object_iterator); - break; - } - - case value_t::array: - { - m_value.array = create<array_t>(first.m_it.array_iterator, - last.m_it.array_iterator); - break; - } - - default: - { - JSON_THROW(std::domain_error("cannot use construct with iterators from " + first.m_object->type_name())); - } - } - - assert_invariant(); - } - - /*! - @brief construct a JSON value given an input stream - - @param[in,out] i stream to read a serialized JSON value from - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - - @deprecated This constructor is deprecated and will be removed in version - 3.0.0 to unify the interface of the library. Deserialization will be - done by stream operators or by calling one of the `parse` functions, - e.g. @ref parse(std::istream&, const parser_callback_t). That is, calls - like `json j(i);` for an input stream @a i need to be replaced by - `json j = json::parse(i);`. See the example below. - - @liveexample{The example below demonstrates constructing a JSON value from - a `std::stringstream` with and without callback - function.,basic_json__istream} - - @since version 2.0.0, deprecated in version 2.0.3, to be removed in - version 3.0.0 - */ - JSON_DEPRECATED - explicit basic_json(std::istream& i, const parser_callback_t cb = nullptr) - { - *this = parser(i, cb).parse(); - assert_invariant(); - } - - /////////////////////////////////////// - // other constructors and destructor // - /////////////////////////////////////// - - /*! - @brief copy constructor - - Creates a copy of a given JSON value. - - @param[in] other the JSON value to copy - - @complexity Linear in the size of @a other. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is linear. - - As postcondition, it holds: `other == basic_json(other)`. - - @throw std::bad_alloc if allocation for object, array, or string fails. - - @liveexample{The following code shows an example for the copy - constructor.,basic_json__basic_json} - - @since version 1.0.0 - */ - basic_json(const basic_json& other) - : m_type(other.m_type) - { - // check of passed value is valid - other.assert_invariant(); - - switch (m_type) - { - case value_t::object: - { - m_value = *other.m_value.object; - break; - } - - case value_t::array: - { - m_value = *other.m_value.array; - break; - } - - case value_t::string: - { - m_value = *other.m_value.string; - break; - } - - case value_t::boolean: - { - m_value = other.m_value.boolean; - break; - } - - case value_t::number_integer: - { - m_value = other.m_value.number_integer; - break; - } - - case value_t::number_unsigned: - { - m_value = other.m_value.number_unsigned; - break; - } - - case value_t::number_float: - { - m_value = other.m_value.number_float; - break; - } - - default: - { - break; - } - } - - assert_invariant(); - } - - /*! - @brief move constructor - - Move constructor. Constructs a JSON value with the contents of the given - value @a other using move semantics. It "steals" the resources from @a - other and leaves it as JSON null value. - - @param[in,out] other value to move to this object - - @post @a other is a JSON null value - - @complexity Constant. - - @liveexample{The code below shows the move constructor explicitly called - via std::move.,basic_json__moveconstructor} - - @since version 1.0.0 - */ - basic_json(basic_json&& other) noexcept - : m_type(std::move(other.m_type)), - m_value(std::move(other.m_value)) - { - // check that passed value is valid - other.assert_invariant(); - - // invalidate payload - other.m_type = value_t::null; - other.m_value = {}; - - assert_invariant(); - } - - /*! - @brief copy assignment - - Copy assignment operator. Copies a JSON value via the "copy and swap" - strategy: It is expressed in terms of the copy constructor, destructor, - and the swap() member function. - - @param[in] other value to copy from - - @complexity Linear. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is linear. - - @liveexample{The code below shows and example for the copy assignment. It - creates a copy of value `a` which is then swapped with `b`. Finally\, the - copy of `a` (which is the null value after the swap) is - destroyed.,basic_json__copyassignment} - - @since version 1.0.0 - */ - reference& operator=(basic_json other) noexcept ( - std::is_nothrow_move_constructible<value_t>::value and - std::is_nothrow_move_assignable<value_t>::value and - std::is_nothrow_move_constructible<json_value>::value and - std::is_nothrow_move_assignable<json_value>::value - ) - { - // check that passed value is valid - other.assert_invariant(); - - using std::swap; - swap(m_type, other.m_type); - swap(m_value, other.m_value); - - assert_invariant(); - return *this; - } - - /*! - @brief destructor - - Destroys the JSON value and frees all allocated memory. - - @complexity Linear. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is linear. - - All stored elements are destroyed and all memory is freed. - - @since version 1.0.0 - */ - ~basic_json() - { - assert_invariant(); - - switch (m_type) - { - case value_t::object: - { - AllocatorType<object_t> alloc; - alloc.destroy(m_value.object); - alloc.deallocate(m_value.object, 1); - break; - } - - case value_t::array: - { - AllocatorType<array_t> alloc; - alloc.destroy(m_value.array); - alloc.deallocate(m_value.array, 1); - break; - } - - case value_t::string: - { - AllocatorType<string_t> alloc; - alloc.destroy(m_value.string); - alloc.deallocate(m_value.string, 1); - break; - } - - default: - { - // all other types need no specific destructor - break; - } - } - } - - /// @} - - public: - /////////////////////// - // object inspection // - /////////////////////// - - /// @name object inspection - /// Functions to inspect the type of a JSON value. - /// @{ - - /*! - @brief serialization - - Serialization function for JSON values. The function tries to mimic - Python's `json.dumps()` function, and currently supports its @a indent - parameter. - - @param[in] indent If indent is nonnegative, then array elements and object - members will be pretty-printed with that indent level. An indent level of - `0` will only insert newlines. `-1` (the default) selects the most compact - representation. - - @return string containing the serialization of the JSON value - - @complexity Linear. - - @liveexample{The following example shows the effect of different @a indent - parameters to the result of the serialization.,dump} - - @see https://docs.python.org/2/library/json.html#json.dump - - @since version 1.0.0 - */ - string_t dump(const int indent = -1) const - { - std::stringstream ss; - - if (indent >= 0) - { - dump(ss, true, static_cast<unsigned int>(indent)); - } - else - { - dump(ss, false, 0); - } - - return ss.str(); - } - - /*! - @brief return the type of the JSON value (explicit) - - Return the type of the JSON value as a value from the @ref value_t - enumeration. - - @return the type of the JSON value - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `type()` for all JSON - types.,type} - - @since version 1.0.0 - */ - constexpr value_t type() const noexcept - { - return m_type; - } - - /*! - @brief return whether type is primitive - - This function returns true iff the JSON type is primitive (string, number, - boolean, or null). - - @return `true` if type is primitive (string, number, boolean, or null), - `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_primitive()` for all JSON - types.,is_primitive} - - @sa @ref is_structured() -- returns whether JSON value is structured - @sa @ref is_null() -- returns whether JSON value is `null` - @sa @ref is_string() -- returns whether JSON value is a string - @sa @ref is_boolean() -- returns whether JSON value is a boolean - @sa @ref is_number() -- returns whether JSON value is a number - - @since version 1.0.0 - */ - constexpr bool is_primitive() const noexcept - { - return is_null() or is_string() or is_boolean() or is_number(); - } - - /*! - @brief return whether type is structured - - This function returns true iff the JSON type is structured (array or - object). - - @return `true` if type is structured (array or object), `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_structured()` for all JSON - types.,is_structured} - - @sa @ref is_primitive() -- returns whether value is primitive - @sa @ref is_array() -- returns whether value is an array - @sa @ref is_object() -- returns whether value is an object - - @since version 1.0.0 - */ - constexpr bool is_structured() const noexcept - { - return is_array() or is_object(); - } - - /*! - @brief return whether value is null - - This function returns true iff the JSON value is null. - - @return `true` if type is null, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_null()` for all JSON - types.,is_null} - - @since version 1.0.0 - */ - constexpr bool is_null() const noexcept - { - return m_type == value_t::null; - } - - /*! - @brief return whether value is a boolean - - This function returns true iff the JSON value is a boolean. - - @return `true` if type is boolean, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_boolean()` for all JSON - types.,is_boolean} - - @since version 1.0.0 - */ - constexpr bool is_boolean() const noexcept - { - return m_type == value_t::boolean; - } - - /*! - @brief return whether value is a number - - This function returns true iff the JSON value is a number. This includes - both integer and floating-point values. - - @return `true` if type is number (regardless whether integer, unsigned - integer or floating-type), `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_number()` for all JSON - types.,is_number} - - @sa @ref is_number_integer() -- check if value is an integer or unsigned - integer number - @sa @ref is_number_unsigned() -- check if value is an unsigned integer - number - @sa @ref is_number_float() -- check if value is a floating-point number - - @since version 1.0.0 - */ - constexpr bool is_number() const noexcept - { - return is_number_integer() or is_number_float(); - } - - /*! - @brief return whether value is an integer number - - This function returns true iff the JSON value is an integer or unsigned - integer number. This excludes floating-point values. - - @return `true` if type is an integer or unsigned integer number, `false` - otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_number_integer()` for all - JSON types.,is_number_integer} - - @sa @ref is_number() -- check if value is a number - @sa @ref is_number_unsigned() -- check if value is an unsigned integer - number - @sa @ref is_number_float() -- check if value is a floating-point number - - @since version 1.0.0 - */ - constexpr bool is_number_integer() const noexcept - { - return m_type == value_t::number_integer or m_type == value_t::number_unsigned; - } - - /*! - @brief return whether value is an unsigned integer number - - This function returns true iff the JSON value is an unsigned integer - number. This excludes floating-point and (signed) integer values. - - @return `true` if type is an unsigned integer number, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_number_unsigned()` for all - JSON types.,is_number_unsigned} - - @sa @ref is_number() -- check if value is a number - @sa @ref is_number_integer() -- check if value is an integer or unsigned - integer number - @sa @ref is_number_float() -- check if value is a floating-point number - - @since version 2.0.0 - */ - constexpr bool is_number_unsigned() const noexcept - { - return m_type == value_t::number_unsigned; - } - - /*! - @brief return whether value is a floating-point number - - This function returns true iff the JSON value is a floating-point number. - This excludes integer and unsigned integer values. - - @return `true` if type is a floating-point number, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_number_float()` for all - JSON types.,is_number_float} - - @sa @ref is_number() -- check if value is number - @sa @ref is_number_integer() -- check if value is an integer number - @sa @ref is_number_unsigned() -- check if value is an unsigned integer - number - - @since version 1.0.0 - */ - constexpr bool is_number_float() const noexcept - { - return m_type == value_t::number_float; - } - - /*! - @brief return whether value is an object - - This function returns true iff the JSON value is an object. - - @return `true` if type is object, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_object()` for all JSON - types.,is_object} - - @since version 1.0.0 - */ - constexpr bool is_object() const noexcept - { - return m_type == value_t::object; - } - - /*! - @brief return whether value is an array - - This function returns true iff the JSON value is an array. - - @return `true` if type is array, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_array()` for all JSON - types.,is_array} - - @since version 1.0.0 - */ - constexpr bool is_array() const noexcept - { - return m_type == value_t::array; - } - - /*! - @brief return whether value is a string - - This function returns true iff the JSON value is a string. - - @return `true` if type is string, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_string()` for all JSON - types.,is_string} - - @since version 1.0.0 - */ - constexpr bool is_string() const noexcept - { - return m_type == value_t::string; - } - - /*! - @brief return whether value is discarded - - This function returns true iff the JSON value was discarded during parsing - with a callback function (see @ref parser_callback_t). - - @note This function will always be `false` for JSON values after parsing. - That is, discarded values can only occur during parsing, but will be - removed when inside a structured value or replaced by null in other cases. - - @return `true` if type is discarded, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_discarded()` for all JSON - types.,is_discarded} - - @since version 1.0.0 - */ - constexpr bool is_discarded() const noexcept - { - return m_type == value_t::discarded; - } - - /*! - @brief return the type of the JSON value (implicit) - - Implicitly return the type of the JSON value as a value from the @ref - value_t enumeration. - - @return the type of the JSON value - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies the @ref value_t operator for - all JSON types.,operator__value_t} - - @since version 1.0.0 - */ - constexpr operator value_t() const noexcept - { - return m_type; - } - - /// @} - - private: - ////////////////// - // value access // - ////////////////// - - /// get a boolean (explicit) - boolean_t get_impl(boolean_t* /*unused*/) const - { - if (is_boolean()) - { - return m_value.boolean; - } - - JSON_THROW(std::domain_error("type must be boolean, but is " + type_name())); - } - - /// get a pointer to the value (object) - object_t* get_impl_ptr(object_t* /*unused*/) noexcept - { - return is_object() ? m_value.object : nullptr; - } - - /// get a pointer to the value (object) - constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept - { - return is_object() ? m_value.object : nullptr; - } - - /// get a pointer to the value (array) - array_t* get_impl_ptr(array_t* /*unused*/) noexcept - { - return is_array() ? m_value.array : nullptr; - } - - /// get a pointer to the value (array) - constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept - { - return is_array() ? m_value.array : nullptr; - } - - /// get a pointer to the value (string) - string_t* get_impl_ptr(string_t* /*unused*/) noexcept - { - return is_string() ? m_value.string : nullptr; - } - - /// get a pointer to the value (string) - constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept - { - return is_string() ? m_value.string : nullptr; - } - - /// get a pointer to the value (boolean) - boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept - { - return is_boolean() ? &m_value.boolean : nullptr; - } - - /// get a pointer to the value (boolean) - constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept - { - return is_boolean() ? &m_value.boolean : nullptr; - } - - /// get a pointer to the value (integer number) - number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept - { - return is_number_integer() ? &m_value.number_integer : nullptr; - } - - /// get a pointer to the value (integer number) - constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept - { - return is_number_integer() ? &m_value.number_integer : nullptr; - } - - /// get a pointer to the value (unsigned number) - number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept - { - return is_number_unsigned() ? &m_value.number_unsigned : nullptr; - } - - /// get a pointer to the value (unsigned number) - constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept - { - return is_number_unsigned() ? &m_value.number_unsigned : nullptr; - } - - /// get a pointer to the value (floating-point number) - number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept - { - return is_number_float() ? &m_value.number_float : nullptr; - } - - /// get a pointer to the value (floating-point number) - constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept - { - return is_number_float() ? &m_value.number_float : nullptr; - } - - /*! - @brief helper function to implement get_ref() - - This funcion helps to implement get_ref() without code duplication for - const and non-const overloads - - @tparam ThisType will be deduced as `basic_json` or `const basic_json` - - @throw std::domain_error if ReferenceType does not match underlying value - type of the current JSON - */ - template<typename ReferenceType, typename ThisType> - static ReferenceType get_ref_impl(ThisType& obj) - { - // helper type - using PointerType = typename std::add_pointer<ReferenceType>::type; - - // delegate the call to get_ptr<>() - auto ptr = obj.template get_ptr<PointerType>(); - - if (ptr != nullptr) - { - return *ptr; - } - - JSON_THROW(std::domain_error("incompatible ReferenceType for get_ref, actual type is " + - obj.type_name())); - } - - public: - /// @name value access - /// Direct access to the stored value of a JSON value. - /// @{ - - /*! - @brief get special-case overload - - This overloads avoids a lot of template boilerplate, it can be seen as the - identity method - - @tparam BasicJsonType == @ref basic_json - - @return a copy of *this - - @complexity Constant. - - @since version 2.1.0 - */ - template < - typename BasicJsonType, - detail::enable_if_t<std::is_same<typename std::remove_const<BasicJsonType>::type, - basic_json_t>::value, - int> = 0 > - basic_json get() const - { - return *this; - } - - /*! - @brief get a value (explicit) - - Explicit type conversion between the JSON value and a compatible value - which is [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) - and [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). - The value is converted by calling the @ref json_serializer<ValueType> - `from_json()` method. - - The function is equivalent to executing - @code {.cpp} - ValueType ret; - JSONSerializer<ValueType>::from_json(*this, ret); - return ret; - @endcode - - This overloads is chosen if: - - @a ValueType is not @ref basic_json, - - @ref json_serializer<ValueType> has a `from_json()` method of the form - `void from_json(const @ref basic_json&, ValueType&)`, and - - @ref json_serializer<ValueType> does not have a `from_json()` method of - the form `ValueType from_json(const @ref basic_json&)` - - @tparam ValueTypeCV the provided value type - @tparam ValueType the returned value type - - @return copy of the JSON value, converted to @a ValueType - - @throw what @ref json_serializer<ValueType> `from_json()` method throws - - @liveexample{The example below shows several conversions from JSON values - to other types. There a few things to note: (1) Floating-point numbers can - be converted to integers\, (2) A JSON array can be converted to a standard - `std::vector<short>`\, (3) A JSON object can be converted to C++ - associative containers such as `std::unordered_map<std::string\, - json>`.,get__ValueType_const} - - @since version 2.1.0 - */ - template < - typename ValueTypeCV, - typename ValueType = detail::uncvref_t<ValueTypeCV>, - detail::enable_if_t < - not std::is_same<basic_json_t, ValueType>::value and - detail::has_from_json<basic_json_t, ValueType>::value and - not detail::has_non_default_from_json<basic_json_t, ValueType>::value, - int > = 0 > - ValueType get() const noexcept(noexcept( - JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>()))) - { - // we cannot static_assert on ValueTypeCV being non-const, because - // there is support for get<const basic_json_t>(), which is why we - // still need the uncvref - static_assert(not std::is_reference<ValueTypeCV>::value, - "get() cannot be used with reference types, you might want to use get_ref()"); - static_assert(std::is_default_constructible<ValueType>::value, - "types must be DefaultConstructible when used with get()"); - - ValueType ret; - JSONSerializer<ValueType>::from_json(*this, ret); - return ret; - } - - /*! - @brief get a value (explicit); special case - - Explicit type conversion between the JSON value and a compatible value - which is **not** [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) - and **not** [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). - The value is converted by calling the @ref json_serializer<ValueType> - `from_json()` method. - - The function is equivalent to executing - @code {.cpp} - return JSONSerializer<ValueTypeCV>::from_json(*this); - @endcode - - This overloads is chosen if: - - @a ValueType is not @ref basic_json and - - @ref json_serializer<ValueType> has a `from_json()` method of the form - `ValueType from_json(const @ref basic_json&)` - - @note If @ref json_serializer<ValueType> has both overloads of - `from_json()`, this one is chosen. - - @tparam ValueTypeCV the provided value type - @tparam ValueType the returned value type - - @return copy of the JSON value, converted to @a ValueType - - @throw what @ref json_serializer<ValueType> `from_json()` method throws - - @since version 2.1.0 - */ - template < - typename ValueTypeCV, - typename ValueType = detail::uncvref_t<ValueTypeCV>, - detail::enable_if_t<not std::is_same<basic_json_t, ValueType>::value and - detail::has_non_default_from_json<basic_json_t, - ValueType>::value, int> = 0 > - ValueType get() const noexcept(noexcept( - JSONSerializer<ValueTypeCV>::from_json(std::declval<const basic_json_t&>()))) - { - static_assert(not std::is_reference<ValueTypeCV>::value, - "get() cannot be used with reference types, you might want to use get_ref()"); - return JSONSerializer<ValueTypeCV>::from_json(*this); - } - - /*! - @brief get a pointer value (explicit) - - Explicit pointer access to the internally stored JSON value. No copies are - made. - - @warning The pointer becomes invalid if the underlying JSON object - changes. - - @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, - @ref number_unsigned_t, or @ref number_float_t. - - @return pointer to the internally stored JSON value if the requested - pointer type @a PointerType fits to the JSON value; `nullptr` otherwise - - @complexity Constant. - - @liveexample{The example below shows how pointers to internal values of a - JSON value can be requested. Note that no type conversions are made and a - `nullptr` is returned if the value and the requested pointer type does not - match.,get__PointerType} - - @sa @ref get_ptr() for explicit pointer-member access - - @since version 1.0.0 - */ - template<typename PointerType, typename std::enable_if< - std::is_pointer<PointerType>::value, int>::type = 0> - PointerType get() noexcept - { - // delegate the call to get_ptr - return get_ptr<PointerType>(); - } - - /*! - @brief get a pointer value (explicit) - @copydoc get() - */ - template<typename PointerType, typename std::enable_if< - std::is_pointer<PointerType>::value, int>::type = 0> - constexpr const PointerType get() const noexcept - { - // delegate the call to get_ptr - return get_ptr<PointerType>(); - } - - /*! - @brief get a pointer value (implicit) - - Implicit pointer access to the internally stored JSON value. No copies are - made. - - @warning Writing data to the pointee of the result yields an undefined - state. - - @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, - @ref number_unsigned_t, or @ref number_float_t. Enforced by a static - assertion. - - @return pointer to the internally stored JSON value if the requested - pointer type @a PointerType fits to the JSON value; `nullptr` otherwise - - @complexity Constant. - - @liveexample{The example below shows how pointers to internal values of a - JSON value can be requested. Note that no type conversions are made and a - `nullptr` is returned if the value and the requested pointer type does not - match.,get_ptr} - - @since version 1.0.0 - */ - template<typename PointerType, typename std::enable_if< - std::is_pointer<PointerType>::value, int>::type = 0> - PointerType get_ptr() noexcept - { - // get the type of the PointerType (remove pointer and const) - using pointee_t = typename std::remove_const<typename - std::remove_pointer<typename - std::remove_const<PointerType>::type>::type>::type; - // make sure the type matches the allowed types - static_assert( - std::is_same<object_t, pointee_t>::value - or std::is_same<array_t, pointee_t>::value - or std::is_same<string_t, pointee_t>::value - or std::is_same<boolean_t, pointee_t>::value - or std::is_same<number_integer_t, pointee_t>::value - or std::is_same<number_unsigned_t, pointee_t>::value - or std::is_same<number_float_t, pointee_t>::value - , "incompatible pointer type"); - - // delegate the call to get_impl_ptr<>() - return get_impl_ptr(static_cast<PointerType>(nullptr)); - } - - /*! - @brief get a pointer value (implicit) - @copydoc get_ptr() - */ - template<typename PointerType, typename std::enable_if< - std::is_pointer<PointerType>::value and - std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0> - constexpr const PointerType get_ptr() const noexcept - { - // get the type of the PointerType (remove pointer and const) - using pointee_t = typename std::remove_const<typename - std::remove_pointer<typename - std::remove_const<PointerType>::type>::type>::type; - // make sure the type matches the allowed types - static_assert( - std::is_same<object_t, pointee_t>::value - or std::is_same<array_t, pointee_t>::value - or std::is_same<string_t, pointee_t>::value - or std::is_same<boolean_t, pointee_t>::value - or std::is_same<number_integer_t, pointee_t>::value - or std::is_same<number_unsigned_t, pointee_t>::value - or std::is_same<number_float_t, pointee_t>::value - , "incompatible pointer type"); - - // delegate the call to get_impl_ptr<>() const - return get_impl_ptr(static_cast<const PointerType>(nullptr)); - } - - /*! - @brief get a reference value (implicit) - - Implicit reference access to the internally stored JSON value. No copies - are made. - - @warning Writing data to the referee of the result yields an undefined - state. - - @tparam ReferenceType reference type; must be a reference to @ref array_t, - @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or - @ref number_float_t. Enforced by static assertion. - - @return reference to the internally stored JSON value if the requested - reference type @a ReferenceType fits to the JSON value; throws - std::domain_error otherwise - - @throw std::domain_error in case passed type @a ReferenceType is - incompatible with the stored JSON value - - @complexity Constant. - - @liveexample{The example shows several calls to `get_ref()`.,get_ref} - - @since version 1.1.0 - */ - template<typename ReferenceType, typename std::enable_if< - std::is_reference<ReferenceType>::value, int>::type = 0> - ReferenceType get_ref() - { - // delegate call to get_ref_impl - return get_ref_impl<ReferenceType>(*this); - } - - /*! - @brief get a reference value (implicit) - @copydoc get_ref() - */ - template<typename ReferenceType, typename std::enable_if< - std::is_reference<ReferenceType>::value and - std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int>::type = 0> - ReferenceType get_ref() const - { - // delegate call to get_ref_impl - return get_ref_impl<ReferenceType>(*this); - } - - /*! - @brief get a value (implicit) - - Implicit type conversion between the JSON value and a compatible value. - The call is realized by calling @ref get() const. - - @tparam ValueType non-pointer type compatible to the JSON value, for - instance `int` for JSON integer numbers, `bool` for JSON booleans, or - `std::vector` types for JSON arrays. The character type of @ref string_t - as well as an initializer list of this type is excluded to avoid - ambiguities as these types implicitly convert to `std::string`. - - @return copy of the JSON value, converted to type @a ValueType - - @throw std::domain_error in case passed type @a ValueType is incompatible - to JSON, thrown by @ref get() const - - @complexity Linear in the size of the JSON value. - - @liveexample{The example below shows several conversions from JSON values - to other types. There a few things to note: (1) Floating-point numbers can - be converted to integers\, (2) A JSON array can be converted to a standard - `std::vector<short>`\, (3) A JSON object can be converted to C++ - associative containers such as `std::unordered_map<std::string\, - json>`.,operator__ValueType} - - @since version 1.0.0 - */ - template < typename ValueType, typename std::enable_if < - not std::is_pointer<ValueType>::value and - not std::is_same<ValueType, typename string_t::value_type>::value -#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 - and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value -#endif - , int >::type = 0 > - operator ValueType() const - { - // delegate the call to get<>() const - return get<ValueType>(); - } - - /// @} - - - //////////////////// - // element access // - //////////////////// - - /// @name element access - /// Access to the JSON value. - /// @{ - - /*! - @brief access specified array element with bounds checking - - Returns a reference to the element at specified location @a idx, with - bounds checking. - - @param[in] idx index of the element to access - - @return reference to the element at index @a idx - - @throw std::domain_error if the JSON value is not an array; example: - `"cannot use at() with string"` - @throw std::out_of_range if the index @a idx is out of range of the array; - that is, `idx >= size()`; example: `"array index 7 is out of range"` - - @complexity Constant. - - @liveexample{The example below shows how array elements can be read and - written using `at()`.,at__size_type} - - @since version 1.0.0 - */ - reference at(size_type idx) - { - // at only works for arrays - if (is_array()) - { - JSON_TRY - { - return m_value.array->at(idx); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); - } - } - else - { - JSON_THROW(std::domain_error("cannot use at() with " + type_name())); - } - } - - /*! - @brief access specified array element with bounds checking - - Returns a const reference to the element at specified location @a idx, - with bounds checking. - - @param[in] idx index of the element to access - - @return const reference to the element at index @a idx - - @throw std::domain_error if the JSON value is not an array; example: - `"cannot use at() with string"` - @throw std::out_of_range if the index @a idx is out of range of the array; - that is, `idx >= size()`; example: `"array index 7 is out of range"` - - @complexity Constant. - - @liveexample{The example below shows how array elements can be read using - `at()`.,at__size_type_const} - - @since version 1.0.0 - */ - const_reference at(size_type idx) const - { - // at only works for arrays - if (is_array()) - { - JSON_TRY - { - return m_value.array->at(idx); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); - } - } - else - { - JSON_THROW(std::domain_error("cannot use at() with " + type_name())); - } - } - - /*! - @brief access specified object element with bounds checking - - Returns a reference to the element at with specified key @a key, with - bounds checking. - - @param[in] key key of the element to access - - @return reference to the element at key @a key - - @throw std::domain_error if the JSON value is not an object; example: - `"cannot use at() with boolean"` - @throw std::out_of_range if the key @a key is is not stored in the object; - that is, `find(key) == end()`; example: `"key "the fast" not found"` - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read and - written using `at()`.,at__object_t_key_type} - - @sa @ref operator[](const typename object_t::key_type&) for unchecked - access by reference - @sa @ref value() for access by value with a default value - - @since version 1.0.0 - */ - reference at(const typename object_t::key_type& key) - { - // at only works for objects - if (is_object()) - { - JSON_TRY - { - return m_value.object->at(key); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(std::out_of_range("key '" + key + "' not found")); - } - } - else - { - JSON_THROW(std::domain_error("cannot use at() with " + type_name())); - } - } - - /*! - @brief access specified object element with bounds checking - - Returns a const reference to the element at with specified key @a key, - with bounds checking. - - @param[in] key key of the element to access - - @return const reference to the element at key @a key - - @throw std::domain_error if the JSON value is not an object; example: - `"cannot use at() with boolean"` - @throw std::out_of_range if the key @a key is is not stored in the object; - that is, `find(key) == end()`; example: `"key "the fast" not found"` - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read using - `at()`.,at__object_t_key_type_const} - - @sa @ref operator[](const typename object_t::key_type&) for unchecked - access by reference - @sa @ref value() for access by value with a default value - - @since version 1.0.0 - */ - const_reference at(const typename object_t::key_type& key) const - { - // at only works for objects - if (is_object()) - { - JSON_TRY - { - return m_value.object->at(key); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(std::out_of_range("key '" + key + "' not found")); - } - } - else - { - JSON_THROW(std::domain_error("cannot use at() with " + type_name())); - } - } - - /*! - @brief access specified array element - - Returns a reference to the element at specified location @a idx. - - @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), - then the array is silently filled up with `null` values to make `idx` a - valid reference to the last stored element. - - @param[in] idx index of the element to access - - @return reference to the element at index @a idx - - @throw std::domain_error if JSON is not an array or null; example: - `"cannot use operator[] with string"` - - @complexity Constant if @a idx is in the range of the array. Otherwise - linear in `idx - size()`. - - @liveexample{The example below shows how array elements can be read and - written using `[]` operator. Note the addition of `null` - values.,operatorarray__size_type} - - @since version 1.0.0 - */ - reference operator[](size_type idx) - { - // implicitly convert null value to an empty array - if (is_null()) - { - m_type = value_t::array; - m_value.array = create<array_t>(); - assert_invariant(); - } - - // operator[] only works for arrays - if (is_array()) - { - // fill up array with null values if given idx is outside range - if (idx >= m_value.array->size()) - { - m_value.array->insert(m_value.array->end(), - idx - m_value.array->size() + 1, - basic_json()); - } - - return m_value.array->operator[](idx); - } - - JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); - } - - /*! - @brief access specified array element - - Returns a const reference to the element at specified location @a idx. - - @param[in] idx index of the element to access - - @return const reference to the element at index @a idx - - @throw std::domain_error if JSON is not an array; example: `"cannot use - operator[] with null"` - - @complexity Constant. - - @liveexample{The example below shows how array elements can be read using - the `[]` operator.,operatorarray__size_type_const} - - @since version 1.0.0 - */ - const_reference operator[](size_type idx) const - { - // const operator[] only works for arrays - if (is_array()) - { - return m_value.array->operator[](idx); - } - - JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); - } - - /*! - @brief access specified object element - - Returns a reference to the element at with specified key @a key. - - @note If @a key is not found in the object, then it is silently added to - the object and filled with a `null` value to make `key` a valid reference. - In case the value was `null` before, it is converted to an object. - - @param[in] key key of the element to access - - @return reference to the element at key @a key - - @throw std::domain_error if JSON is not an object or null; example: - `"cannot use operator[] with string"` - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read and - written using the `[]` operator.,operatorarray__key_type} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value - - @since version 1.0.0 - */ - reference operator[](const typename object_t::key_type& key) - { - // implicitly convert null value to an empty object - if (is_null()) - { - m_type = value_t::object; - m_value.object = create<object_t>(); - assert_invariant(); - } - - // operator[] only works for objects - if (is_object()) - { - return m_value.object->operator[](key); - } - - JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); - } - - /*! - @brief read-only access specified object element - - Returns a const reference to the element at with specified key @a key. No - bounds checking is performed. - - @warning If the element with key @a key does not exist, the behavior is - undefined. - - @param[in] key key of the element to access - - @return const reference to the element at key @a key - - @pre The element with key @a key must exist. **This precondition is - enforced with an assertion.** - - @throw std::domain_error if JSON is not an object; example: `"cannot use - operator[] with null"` - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read using - the `[]` operator.,operatorarray__key_type_const} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value - - @since version 1.0.0 - */ - const_reference operator[](const typename object_t::key_type& key) const - { - // const operator[] only works for objects - if (is_object()) - { - assert(m_value.object->find(key) != m_value.object->end()); - return m_value.object->find(key)->second; - } - - JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); - } - - /*! - @brief access specified object element - - Returns a reference to the element at with specified key @a key. - - @note If @a key is not found in the object, then it is silently added to - the object and filled with a `null` value to make `key` a valid reference. - In case the value was `null` before, it is converted to an object. - - @param[in] key key of the element to access - - @return reference to the element at key @a key - - @throw std::domain_error if JSON is not an object or null; example: - `"cannot use operator[] with string"` - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read and - written using the `[]` operator.,operatorarray__key_type} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value - - @since version 1.0.0 - */ - template<typename T, std::size_t n> - reference operator[](T * (&key)[n]) - { - return operator[](static_cast<const T>(key)); - } - - /*! - @brief read-only access specified object element - - Returns a const reference to the element at with specified key @a key. No - bounds checking is performed. - - @warning If the element with key @a key does not exist, the behavior is - undefined. - - @note This function is required for compatibility reasons with Clang. - - @param[in] key key of the element to access - - @return const reference to the element at key @a key - - @throw std::domain_error if JSON is not an object; example: `"cannot use - operator[] with null"` - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read using - the `[]` operator.,operatorarray__key_type_const} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value - - @since version 1.0.0 - */ - template<typename T, std::size_t n> - const_reference operator[](T * (&key)[n]) const - { - return operator[](static_cast<const T>(key)); - } - - /*! - @brief access specified object element - - Returns a reference to the element at with specified key @a key. - - @note If @a key is not found in the object, then it is silently added to - the object and filled with a `null` value to make `key` a valid reference. - In case the value was `null` before, it is converted to an object. - - @param[in] key key of the element to access - - @return reference to the element at key @a key - - @throw std::domain_error if JSON is not an object or null; example: - `"cannot use operator[] with string"` - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read and - written using the `[]` operator.,operatorarray__key_type} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value - - @since version 1.1.0 - */ - template<typename T> - reference operator[](T* key) - { - // implicitly convert null to object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); - } - - // at only works for objects - if (is_object()) - { - return m_value.object->operator[](key); - } - - JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); - } - - /*! - @brief read-only access specified object element - - Returns a const reference to the element at with specified key @a key. No - bounds checking is performed. - - @warning If the element with key @a key does not exist, the behavior is - undefined. - - @param[in] key key of the element to access - - @return const reference to the element at key @a key - - @pre The element with key @a key must exist. **This precondition is - enforced with an assertion.** - - @throw std::domain_error if JSON is not an object; example: `"cannot use - operator[] with null"` - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read using - the `[]` operator.,operatorarray__key_type_const} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value - - @since version 1.1.0 - */ - template<typename T> - const_reference operator[](T* key) const - { - // at only works for objects - if (is_object()) - { - assert(m_value.object->find(key) != m_value.object->end()); - return m_value.object->find(key)->second; - } - - JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); - } - - /*! - @brief access specified object element with default value - - Returns either a copy of an object's element at the specified key @a key - or a given default value if no element with key @a key exists. - - The function is basically equivalent to executing - @code {.cpp} - try { - return at(key); - } catch(std::out_of_range) { - return default_value; - } - @endcode - - @note Unlike @ref at(const typename object_t::key_type&), this function - does not throw if the given key @a key was not found. - - @note Unlike @ref operator[](const typename object_t::key_type& key), this - function does not implicitly add an element to the position defined by @a - key. This function is furthermore also applicable to const objects. - - @param[in] key key of the element to access - @param[in] default_value the value to return if @a key is not found - - @tparam ValueType type compatible to JSON values, for instance `int` for - JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for - JSON arrays. Note the type of the expected value at @a key and the default - value @a default_value must be compatible. - - @return copy of the element at key @a key or @a default_value if @a key - is not found - - @throw std::domain_error if JSON is not an object; example: `"cannot use - value() with null"` - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be queried - with a default value.,basic_json__value} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref operator[](const typename object_t::key_type&) for unchecked - access by reference - - @since version 1.0.0 - */ - template<class ValueType, typename std::enable_if< - std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0> - ValueType value(const typename object_t::key_type& key, ValueType default_value) const - { - // at only works for objects - if (is_object()) - { - // if key is found, return value and given default value otherwise - const auto it = find(key); - if (it != end()) - { - return *it; - } - - return default_value; - } - else - { - JSON_THROW(std::domain_error("cannot use value() with " + type_name())); - } - } - - /*! - @brief overload for a default value of type const char* - @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const - */ - string_t value(const typename object_t::key_type& key, const char* default_value) const - { - return value(key, string_t(default_value)); - } - - /*! - @brief access specified object element via JSON Pointer with default value - - Returns either a copy of an object's element at the specified key @a key - or a given default value if no element with key @a key exists. - - The function is basically equivalent to executing - @code {.cpp} - try { - return at(ptr); - } catch(std::out_of_range) { - return default_value; - } - @endcode - - @note Unlike @ref at(const json_pointer&), this function does not throw - if the given key @a key was not found. - - @param[in] ptr a JSON pointer to the element to access - @param[in] default_value the value to return if @a ptr found no value - - @tparam ValueType type compatible to JSON values, for instance `int` for - JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for - JSON arrays. Note the type of the expected value at @a key and the default - value @a default_value must be compatible. - - @return copy of the element at key @a key or @a default_value if @a key - is not found - - @throw std::domain_error if JSON is not an object; example: `"cannot use - value() with null"` - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be queried - with a default value.,basic_json__value_ptr} - - @sa @ref operator[](const json_pointer&) for unchecked access by reference - - @since version 2.0.2 - */ - template<class ValueType, typename std::enable_if< - std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0> - ValueType value(const json_pointer& ptr, ValueType default_value) const - { - // at only works for objects - if (is_object()) - { - // if pointer resolves a value, return it or use default value - JSON_TRY - { - return ptr.get_checked(this); - } - JSON_CATCH (std::out_of_range&) - { - return default_value; - } - } - - JSON_THROW(std::domain_error("cannot use value() with " + type_name())); - } - - /*! - @brief overload for a default value of type const char* - @copydoc basic_json::value(const json_pointer&, ValueType) const - */ - string_t value(const json_pointer& ptr, const char* default_value) const - { - return value(ptr, string_t(default_value)); - } - - /*! - @brief access the first element - - Returns a reference to the first element in the container. For a JSON - container `c`, the expression `c.front()` is equivalent to `*c.begin()`. - - @return In case of a structured type (array or object), a reference to the - first element is returned. In case of number, string, or boolean values, a - reference to the value is returned. - - @complexity Constant. - - @pre The JSON value must not be `null` (would throw `std::out_of_range`) - or an empty array or object (undefined behavior, **guarded by - assertions**). - @post The JSON value remains unchanged. - - @throw std::out_of_range when called on `null` value - - @liveexample{The following code shows an example for `front()`.,front} - - @sa @ref back() -- access the last element - - @since version 1.0.0 - */ - reference front() - { - return *begin(); - } - - /*! - @copydoc basic_json::front() - */ - const_reference front() const - { - return *cbegin(); - } - - /*! - @brief access the last element - - Returns a reference to the last element in the container. For a JSON - container `c`, the expression `c.back()` is equivalent to - @code {.cpp} - auto tmp = c.end(); - --tmp; - return *tmp; - @endcode - - @return In case of a structured type (array or object), a reference to the - last element is returned. In case of number, string, or boolean values, a - reference to the value is returned. - - @complexity Constant. - - @pre The JSON value must not be `null` (would throw `std::out_of_range`) - or an empty array or object (undefined behavior, **guarded by - assertions**). - @post The JSON value remains unchanged. - - @throw std::out_of_range when called on `null` value. - - @liveexample{The following code shows an example for `back()`.,back} - - @sa @ref front() -- access the first element - - @since version 1.0.0 - */ - reference back() - { - auto tmp = end(); - --tmp; - return *tmp; - } - - /*! - @copydoc basic_json::back() - */ - const_reference back() const - { - auto tmp = cend(); - --tmp; - return *tmp; - } - - /*! - @brief remove element given an iterator - - Removes the element specified by iterator @a pos. The iterator @a pos must - be valid and dereferenceable. Thus the `end()` iterator (which is valid, - but is not dereferenceable) cannot be used as a value for @a pos. - - If called on a primitive type other than `null`, the resulting JSON value - will be `null`. - - @param[in] pos iterator to the element to remove - @return Iterator following the last removed element. If the iterator @a - pos refers to the last element, the `end()` iterator is returned. - - @tparam IteratorType an @ref iterator or @ref const_iterator - - @post Invalidates iterators and references at or after the point of the - erase, including the `end()` iterator. - - @throw std::domain_error if called on a `null` value; example: `"cannot - use erase() with null"` - @throw std::domain_error if called on an iterator which does not belong to - the current JSON value; example: `"iterator does not fit current value"` - @throw std::out_of_range if called on a primitive type with invalid - iterator (i.e., any iterator which is not `begin()`); example: `"iterator - out of range"` - - @complexity The complexity depends on the type: - - objects: amortized constant - - arrays: linear in distance between @a pos and the end of the container - - strings: linear in the length of the string - - other types: constant - - @liveexample{The example shows the result of `erase()` for different JSON - types.,erase__IteratorType} - - @sa @ref erase(IteratorType, IteratorType) -- removes the elements in - the given range - @sa @ref erase(const typename object_t::key_type&) -- removes the element - from an object at the given key - @sa @ref erase(const size_type) -- removes the element from an array at - the given index - - @since version 1.0.0 - */ - template<class IteratorType, typename std::enable_if< - std::is_same<IteratorType, typename basic_json_t::iterator>::value or - std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type - = 0> - IteratorType erase(IteratorType pos) - { - // make sure iterator fits the current value - if (this != pos.m_object) - { - JSON_THROW(std::domain_error("iterator does not fit current value")); - } - - IteratorType result = end(); - - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - { - if (not pos.m_it.primitive_iterator.is_begin()) - { - JSON_THROW(std::out_of_range("iterator out of range")); - } - - if (is_string()) - { - AllocatorType<string_t> alloc; - alloc.destroy(m_value.string); - alloc.deallocate(m_value.string, 1); - m_value.string = nullptr; - } - - m_type = value_t::null; - assert_invariant(); - break; - } - - case value_t::object: - { - result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); - break; - } - - case value_t::array: - { - result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); - break; - } - - default: - { - JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); - } - } - - return result; - } - - /*! - @brief remove elements given an iterator range - - Removes the element specified by the range `[first; last)`. The iterator - @a first does not need to be dereferenceable if `first == last`: erasing - an empty range is a no-op. - - If called on a primitive type other than `null`, the resulting JSON value - will be `null`. - - @param[in] first iterator to the beginning of the range to remove - @param[in] last iterator past the end of the range to remove - @return Iterator following the last removed element. If the iterator @a - second refers to the last element, the `end()` iterator is returned. - - @tparam IteratorType an @ref iterator or @ref const_iterator - - @post Invalidates iterators and references at or after the point of the - erase, including the `end()` iterator. - - @throw std::domain_error if called on a `null` value; example: `"cannot - use erase() with null"` - @throw std::domain_error if called on iterators which does not belong to - the current JSON value; example: `"iterators do not fit current value"` - @throw std::out_of_range if called on a primitive type with invalid - iterators (i.e., if `first != begin()` and `last != end()`); example: - `"iterators out of range"` - - @complexity The complexity depends on the type: - - objects: `log(size()) + std::distance(first, last)` - - arrays: linear in the distance between @a first and @a last, plus linear - in the distance between @a last and end of the container - - strings: linear in the length of the string - - other types: constant - - @liveexample{The example shows the result of `erase()` for different JSON - types.,erase__IteratorType_IteratorType} - - @sa @ref erase(IteratorType) -- removes the element at a given position - @sa @ref erase(const typename object_t::key_type&) -- removes the element - from an object at the given key - @sa @ref erase(const size_type) -- removes the element from an array at - the given index - - @since version 1.0.0 - */ - template<class IteratorType, typename std::enable_if< - std::is_same<IteratorType, typename basic_json_t::iterator>::value or - std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type - = 0> - IteratorType erase(IteratorType first, IteratorType last) - { - // make sure iterator fits the current value - if (this != first.m_object or this != last.m_object) - { - JSON_THROW(std::domain_error("iterators do not fit current value")); - } - - IteratorType result = end(); - - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - { - if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) - { - JSON_THROW(std::out_of_range("iterators out of range")); - } - - if (is_string()) - { - AllocatorType<string_t> alloc; - alloc.destroy(m_value.string); - alloc.deallocate(m_value.string, 1); - m_value.string = nullptr; - } - - m_type = value_t::null; - assert_invariant(); - break; - } - - case value_t::object: - { - result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, - last.m_it.object_iterator); - break; - } - - case value_t::array: - { - result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, - last.m_it.array_iterator); - break; - } - - default: - { - JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); - } - } - - return result; - } - - /*! - @brief remove element from a JSON object given a key - - Removes elements from a JSON object with the key value @a key. - - @param[in] key value of the elements to remove - - @return Number of elements removed. If @a ObjectType is the default - `std::map` type, the return value will always be `0` (@a key was not - found) or `1` (@a key was found). - - @post References and iterators to the erased elements are invalidated. - Other references and iterators are not affected. - - @throw std::domain_error when called on a type other than JSON object; - example: `"cannot use erase() with null"` - - @complexity `log(size()) + count(key)` - - @liveexample{The example shows the effect of `erase()`.,erase__key_type} - - @sa @ref erase(IteratorType) -- removes the element at a given position - @sa @ref erase(IteratorType, IteratorType) -- removes the elements in - the given range - @sa @ref erase(const size_type) -- removes the element from an array at - the given index - - @since version 1.0.0 - */ - size_type erase(const typename object_t::key_type& key) - { - // this erase only works for objects - if (is_object()) - { - return m_value.object->erase(key); - } - - JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); - } - - /*! - @brief remove element from a JSON array given an index - - Removes element from a JSON array at the index @a idx. - - @param[in] idx index of the element to remove - - @throw std::domain_error when called on a type other than JSON array; - example: `"cannot use erase() with null"` - @throw std::out_of_range when `idx >= size()`; example: `"array index 17 - is out of range"` - - @complexity Linear in distance between @a idx and the end of the container. - - @liveexample{The example shows the effect of `erase()`.,erase__size_type} - - @sa @ref erase(IteratorType) -- removes the element at a given position - @sa @ref erase(IteratorType, IteratorType) -- removes the elements in - the given range - @sa @ref erase(const typename object_t::key_type&) -- removes the element - from an object at the given key - - @since version 1.0.0 - */ - void erase(const size_type idx) - { - // this erase only works for arrays - if (is_array()) - { - if (idx >= size()) - { - JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); - } - - m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx)); - } - else - { - JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); - } - } - - /// @} - - - //////////// - // lookup // - //////////// - - /// @name lookup - /// @{ - - /*! - @brief find an element in a JSON object - - Finds an element in a JSON object with key equivalent to @a key. If the - element is not found or the JSON value is not an object, end() is - returned. - - @note This method always returns @ref end() when executed on a JSON type - that is not an object. - - @param[in] key key value of the element to search for - - @return Iterator to an element with key equivalent to @a key. If no such - element is found or the JSON value is not an object, past-the-end (see - @ref end()) iterator is returned. - - @complexity Logarithmic in the size of the JSON object. - - @liveexample{The example shows how `find()` is used.,find__key_type} - - @since version 1.0.0 - */ - iterator find(typename object_t::key_type key) - { - auto result = end(); - - if (is_object()) - { - result.m_it.object_iterator = m_value.object->find(key); - } - - return result; - } - - /*! - @brief find an element in a JSON object - @copydoc find(typename object_t::key_type) - */ - const_iterator find(typename object_t::key_type key) const - { - auto result = cend(); - - if (is_object()) - { - result.m_it.object_iterator = m_value.object->find(key); - } - - return result; - } - - /*! - @brief returns the number of occurrences of a key in a JSON object - - Returns the number of elements with key @a key. If ObjectType is the - default `std::map` type, the return value will always be `0` (@a key was - not found) or `1` (@a key was found). - - @note This method always returns `0` when executed on a JSON type that is - not an object. - - @param[in] key key value of the element to count - - @return Number of elements with key @a key. If the JSON value is not an - object, the return value will be `0`. - - @complexity Logarithmic in the size of the JSON object. - - @liveexample{The example shows how `count()` is used.,count} - - @since version 1.0.0 - */ - size_type count(typename object_t::key_type key) const - { - // return 0 for all nonobject types - return is_object() ? m_value.object->count(key) : 0; - } - - /// @} - - - /////////////// - // iterators // - /////////////// - - /// @name iterators - /// @{ - - /*! - @brief returns an iterator to the first element - - Returns an iterator to the first element. - - @image html range-begin-end.svg "Illustration from cppreference.com" - - @return iterator to the first element - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - @liveexample{The following code shows an example for `begin()`.,begin} - - @sa @ref cbegin() -- returns a const iterator to the beginning - @sa @ref end() -- returns an iterator to the end - @sa @ref cend() -- returns a const iterator to the end - - @since version 1.0.0 - */ - iterator begin() noexcept - { - iterator result(this); - result.set_begin(); - return result; - } - - /*! - @copydoc basic_json::cbegin() - */ - const_iterator begin() const noexcept - { - return cbegin(); - } - - /*! - @brief returns a const iterator to the first element - - Returns a const iterator to the first element. - - @image html range-begin-end.svg "Illustration from cppreference.com" - - @return const iterator to the first element - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of `const_cast<const basic_json&>(*this).begin()`. - - @liveexample{The following code shows an example for `cbegin()`.,cbegin} - - @sa @ref begin() -- returns an iterator to the beginning - @sa @ref end() -- returns an iterator to the end - @sa @ref cend() -- returns a const iterator to the end - - @since version 1.0.0 - */ - const_iterator cbegin() const noexcept - { - const_iterator result(this); - result.set_begin(); - return result; - } - - /*! - @brief returns an iterator to one past the last element - - Returns an iterator to one past the last element. - - @image html range-begin-end.svg "Illustration from cppreference.com" - - @return iterator one past the last element - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - @liveexample{The following code shows an example for `end()`.,end} - - @sa @ref cend() -- returns a const iterator to the end - @sa @ref begin() -- returns an iterator to the beginning - @sa @ref cbegin() -- returns a const iterator to the beginning - - @since version 1.0.0 - */ - iterator end() noexcept - { - iterator result(this); - result.set_end(); - return result; - } - - /*! - @copydoc basic_json::cend() - */ - const_iterator end() const noexcept - { - return cend(); - } - - /*! - @brief returns a const iterator to one past the last element - - Returns a const iterator to one past the last element. - - @image html range-begin-end.svg "Illustration from cppreference.com" - - @return const iterator one past the last element - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of `const_cast<const basic_json&>(*this).end()`. - - @liveexample{The following code shows an example for `cend()`.,cend} - - @sa @ref end() -- returns an iterator to the end - @sa @ref begin() -- returns an iterator to the beginning - @sa @ref cbegin() -- returns a const iterator to the beginning - - @since version 1.0.0 - */ - const_iterator cend() const noexcept - { - const_iterator result(this); - result.set_end(); - return result; - } - - /*! - @brief returns an iterator to the reverse-beginning - - Returns an iterator to the reverse-beginning; that is, the last element. - - @image html range-rbegin-rend.svg "Illustration from cppreference.com" - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) - requirements: - - The complexity is constant. - - Has the semantics of `reverse_iterator(end())`. - - @liveexample{The following code shows an example for `rbegin()`.,rbegin} - - @sa @ref crbegin() -- returns a const reverse iterator to the beginning - @sa @ref rend() -- returns a reverse iterator to the end - @sa @ref crend() -- returns a const reverse iterator to the end - - @since version 1.0.0 - */ - reverse_iterator rbegin() noexcept - { - return reverse_iterator(end()); - } - - /*! - @copydoc basic_json::crbegin() - */ - const_reverse_iterator rbegin() const noexcept - { - return crbegin(); - } - - /*! - @brief returns an iterator to the reverse-end - - Returns an iterator to the reverse-end; that is, one before the first - element. - - @image html range-rbegin-rend.svg "Illustration from cppreference.com" - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) - requirements: - - The complexity is constant. - - Has the semantics of `reverse_iterator(begin())`. - - @liveexample{The following code shows an example for `rend()`.,rend} - - @sa @ref crend() -- returns a const reverse iterator to the end - @sa @ref rbegin() -- returns a reverse iterator to the beginning - @sa @ref crbegin() -- returns a const reverse iterator to the beginning - - @since version 1.0.0 - */ - reverse_iterator rend() noexcept - { - return reverse_iterator(begin()); - } - - /*! - @copydoc basic_json::crend() - */ - const_reverse_iterator rend() const noexcept - { - return crend(); - } - - /*! - @brief returns a const reverse iterator to the last element - - Returns a const iterator to the reverse-beginning; that is, the last - element. - - @image html range-rbegin-rend.svg "Illustration from cppreference.com" - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) - requirements: - - The complexity is constant. - - Has the semantics of `const_cast<const basic_json&>(*this).rbegin()`. - - @liveexample{The following code shows an example for `crbegin()`.,crbegin} - - @sa @ref rbegin() -- returns a reverse iterator to the beginning - @sa @ref rend() -- returns a reverse iterator to the end - @sa @ref crend() -- returns a const reverse iterator to the end - - @since version 1.0.0 - */ - const_reverse_iterator crbegin() const noexcept - { - return const_reverse_iterator(cend()); - } - - /*! - @brief returns a const reverse iterator to one before the first - - Returns a const reverse iterator to the reverse-end; that is, one before - the first element. - - @image html range-rbegin-rend.svg "Illustration from cppreference.com" - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) - requirements: - - The complexity is constant. - - Has the semantics of `const_cast<const basic_json&>(*this).rend()`. - - @liveexample{The following code shows an example for `crend()`.,crend} - - @sa @ref rend() -- returns a reverse iterator to the end - @sa @ref rbegin() -- returns a reverse iterator to the beginning - @sa @ref crbegin() -- returns a const reverse iterator to the beginning - - @since version 1.0.0 - */ - const_reverse_iterator crend() const noexcept - { - return const_reverse_iterator(cbegin()); - } - - private: - // forward declaration - template<typename IteratorType> class iteration_proxy; - - public: - /*! - @brief wrapper to access iterator member functions in range-based for - - This function allows to access @ref iterator::key() and @ref - iterator::value() during range-based for loops. In these loops, a - reference to the JSON values is returned, so there is no access to the - underlying iterator. - - @note The name of this function is not yet final and may change in the - future. - */ - static iteration_proxy<iterator> iterator_wrapper(reference cont) - { - return iteration_proxy<iterator>(cont); - } - - /*! - @copydoc iterator_wrapper(reference) - */ - static iteration_proxy<const_iterator> iterator_wrapper(const_reference cont) - { - return iteration_proxy<const_iterator>(cont); - } - - /// @} - - - ////////////// - // capacity // - ////////////// - - /// @name capacity - /// @{ - - /*! - @brief checks whether the container is empty - - Checks if a JSON value has no elements. - - @return The return value depends on the different types and is - defined as follows: - Value type | return value - ----------- | ------------- - null | `true` - boolean | `false` - string | `false` - number | `false` - object | result of function `object_t::empty()` - array | result of function `array_t::empty()` - - @note This function does not return whether a string stored as JSON value - is empty - it returns whether the JSON container itself is empty which is - false in the case of a string. - - @complexity Constant, as long as @ref array_t and @ref object_t satisfy - the Container concept; that is, their `empty()` functions have constant - complexity. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of `begin() == end()`. - - @liveexample{The following code uses `empty()` to check if a JSON - object contains any elements.,empty} - - @sa @ref size() -- returns the number of elements - - @since version 1.0.0 - */ - bool empty() const noexcept - { - switch (m_type) - { - case value_t::null: - { - // null values are empty - return true; - } - - case value_t::array: - { - // delegate call to array_t::empty() - return m_value.array->empty(); - } - - case value_t::object: - { - // delegate call to object_t::empty() - return m_value.object->empty(); - } - - default: - { - // all other types are nonempty - return false; - } - } - } - - /*! - @brief returns the number of elements - - Returns the number of elements in a JSON value. - - @return The return value depends on the different types and is - defined as follows: - Value type | return value - ----------- | ------------- - null | `0` - boolean | `1` - string | `1` - number | `1` - object | result of function object_t::size() - array | result of function array_t::size() - - @note This function does not return the length of a string stored as JSON - value - it returns the number of elements in the JSON value which is 1 in - the case of a string. - - @complexity Constant, as long as @ref array_t and @ref object_t satisfy - the Container concept; that is, their size() functions have constant - complexity. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of `std::distance(begin(), end())`. - - @liveexample{The following code calls `size()` on the different value - types.,size} - - @sa @ref empty() -- checks whether the container is empty - @sa @ref max_size() -- returns the maximal number of elements - - @since version 1.0.0 - */ - size_type size() const noexcept - { - switch (m_type) - { - case value_t::null: - { - // null values are empty - return 0; - } - - case value_t::array: - { - // delegate call to array_t::size() - return m_value.array->size(); - } - - case value_t::object: - { - // delegate call to object_t::size() - return m_value.object->size(); - } - - default: - { - // all other types have size 1 - return 1; - } - } - } - - /*! - @brief returns the maximum possible number of elements - - Returns the maximum number of elements a JSON value is able to hold due to - system or library implementation limitations, i.e. `std::distance(begin(), - end())` for the JSON value. - - @return The return value depends on the different types and is - defined as follows: - Value type | return value - ----------- | ------------- - null | `0` (same as `size()`) - boolean | `1` (same as `size()`) - string | `1` (same as `size()`) - number | `1` (same as `size()`) - object | result of function `object_t::max_size()` - array | result of function `array_t::max_size()` - - @complexity Constant, as long as @ref array_t and @ref object_t satisfy - the Container concept; that is, their `max_size()` functions have constant - complexity. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of returning `b.size()` where `b` is the largest - possible JSON value. - - @liveexample{The following code calls `max_size()` on the different value - types. Note the output is implementation specific.,max_size} - - @sa @ref size() -- returns the number of elements - - @since version 1.0.0 - */ - size_type max_size() const noexcept - { - switch (m_type) - { - case value_t::array: - { - // delegate call to array_t::max_size() - return m_value.array->max_size(); - } - - case value_t::object: - { - // delegate call to object_t::max_size() - return m_value.object->max_size(); - } - - default: - { - // all other types have max_size() == size() - return size(); - } - } - } - - /// @} - - - /////////////// - // modifiers // - /////////////// - - /// @name modifiers - /// @{ - - /*! - @brief clears the contents - - Clears the content of a JSON value and resets it to the default value as - if @ref basic_json(value_t) would have been called: - - Value type | initial value - ----------- | ------------- - null | `null` - boolean | `false` - string | `""` - number | `0` - object | `{}` - array | `[]` - - @complexity Linear in the size of the JSON value. - - @liveexample{The example below shows the effect of `clear()` to different - JSON types.,clear} - - @since version 1.0.0 - */ - void clear() noexcept - { - switch (m_type) - { - case value_t::number_integer: - { - m_value.number_integer = 0; - break; - } - - case value_t::number_unsigned: - { - m_value.number_unsigned = 0; - break; - } - - case value_t::number_float: - { - m_value.number_float = 0.0; - break; - } - - case value_t::boolean: - { - m_value.boolean = false; - break; - } - - case value_t::string: - { - m_value.string->clear(); - break; - } - - case value_t::array: - { - m_value.array->clear(); - break; - } - - case value_t::object: - { - m_value.object->clear(); - break; - } - - default: - { - break; - } - } - } - - /*! - @brief add an object to an array - - Appends the given element @a val to the end of the JSON value. If the - function is called on a JSON null value, an empty array is created before - appending @a val. - - @param[in] val the value to add to the JSON array - - @throw std::domain_error when called on a type other than JSON array or - null; example: `"cannot use push_back() with number"` - - @complexity Amortized constant. - - @liveexample{The example shows how `push_back()` and `+=` can be used to - add elements to a JSON array. Note how the `null` value was silently - converted to a JSON array.,push_back} - - @since version 1.0.0 - */ - void push_back(basic_json&& val) - { - // push_back only works for null objects or arrays - if (not(is_null() or is_array())) - { - JSON_THROW(std::domain_error("cannot use push_back() with " + type_name())); - } - - // transform null object into an array - if (is_null()) - { - m_type = value_t::array; - m_value = value_t::array; - assert_invariant(); - } - - // add element to array (move semantics) - m_value.array->push_back(std::move(val)); - // invalidate object - val.m_type = value_t::null; - } - - /*! - @brief add an object to an array - @copydoc push_back(basic_json&&) - */ - reference operator+=(basic_json&& val) - { - push_back(std::move(val)); - return *this; - } - - /*! - @brief add an object to an array - @copydoc push_back(basic_json&&) - */ - void push_back(const basic_json& val) - { - // push_back only works for null objects or arrays - if (not(is_null() or is_array())) - { - JSON_THROW(std::domain_error("cannot use push_back() with " + type_name())); - } - - // transform null object into an array - if (is_null()) - { - m_type = value_t::array; - m_value = value_t::array; - assert_invariant(); - } - - // add element to array - m_value.array->push_back(val); - } - - /*! - @brief add an object to an array - @copydoc push_back(basic_json&&) - */ - reference operator+=(const basic_json& val) - { - push_back(val); - return *this; - } - - /*! - @brief add an object to an object - - Inserts the given element @a val to the JSON object. If the function is - called on a JSON null value, an empty object is created before inserting - @a val. - - @param[in] val the value to add to the JSON object - - @throw std::domain_error when called on a type other than JSON object or - null; example: `"cannot use push_back() with number"` - - @complexity Logarithmic in the size of the container, O(log(`size()`)). - - @liveexample{The example shows how `push_back()` and `+=` can be used to - add elements to a JSON object. Note how the `null` value was silently - converted to a JSON object.,push_back__object_t__value} - - @since version 1.0.0 - */ - void push_back(const typename object_t::value_type& val) - { - // push_back only works for null objects or objects - if (not(is_null() or is_object())) - { - JSON_THROW(std::domain_error("cannot use push_back() with " + type_name())); - } - - // transform null object into an object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); - } - - // add element to array - m_value.object->insert(val); - } - - /*! - @brief add an object to an object - @copydoc push_back(const typename object_t::value_type&) - */ - reference operator+=(const typename object_t::value_type& val) - { - push_back(val); - return *this; - } - - /*! - @brief add an object to an object - - This function allows to use `push_back` with an initializer list. In case - - 1. the current value is an object, - 2. the initializer list @a init contains only two elements, and - 3. the first element of @a init is a string, - - @a init is converted into an object element and added using - @ref push_back(const typename object_t::value_type&). Otherwise, @a init - is converted to a JSON value and added using @ref push_back(basic_json&&). - - @param init an initializer list - - @complexity Linear in the size of the initializer list @a init. - - @note This function is required to resolve an ambiguous overload error, - because pairs like `{"key", "value"}` can be both interpreted as - `object_t::value_type` or `std::initializer_list<basic_json>`, see - https://github.com/nlohmann/json/issues/235 for more information. - - @liveexample{The example shows how initializer lists are treated as - objects when possible.,push_back__initializer_list} - */ - void push_back(std::initializer_list<basic_json> init) - { - if (is_object() and init.size() == 2 and init.begin()->is_string()) - { - const string_t key = *init.begin(); - push_back(typename object_t::value_type(key, *(init.begin() + 1))); - } - else - { - push_back(basic_json(init)); - } - } - - /*! - @brief add an object to an object - @copydoc push_back(std::initializer_list<basic_json>) - */ - reference operator+=(std::initializer_list<basic_json> init) - { - push_back(init); - return *this; - } - - /*! - @brief add an object to an array - - Creates a JSON value from the passed parameters @a args to the end of the - JSON value. If the function is called on a JSON null value, an empty array - is created before appending the value created from @a args. - - @param[in] args arguments to forward to a constructor of @ref basic_json - @tparam Args compatible types to create a @ref basic_json object - - @throw std::domain_error when called on a type other than JSON array or - null; example: `"cannot use emplace_back() with number"` - - @complexity Amortized constant. - - @liveexample{The example shows how `push_back()` can be used to add - elements to a JSON array. Note how the `null` value was silently converted - to a JSON array.,emplace_back} - - @since version 2.0.8 - */ - template<class... Args> - void emplace_back(Args&& ... args) - { - // emplace_back only works for null objects or arrays - if (not(is_null() or is_array())) - { - JSON_THROW(std::domain_error("cannot use emplace_back() with " + type_name())); - } - - // transform null object into an array - if (is_null()) - { - m_type = value_t::array; - m_value = value_t::array; - assert_invariant(); - } - - // add element to array (perfect forwarding) - m_value.array->emplace_back(std::forward<Args>(args)...); - } - - /*! - @brief add an object to an object if key does not exist - - Inserts a new element into a JSON object constructed in-place with the - given @a args if there is no element with the key in the container. If the - function is called on a JSON null value, an empty object is created before - appending the value created from @a args. - - @param[in] args arguments to forward to a constructor of @ref basic_json - @tparam Args compatible types to create a @ref basic_json object - - @return a pair consisting of an iterator to the inserted element, or the - already-existing element if no insertion happened, and a bool - denoting whether the insertion took place. - - @throw std::domain_error when called on a type other than JSON object or - null; example: `"cannot use emplace() with number"` - - @complexity Logarithmic in the size of the container, O(log(`size()`)). - - @liveexample{The example shows how `emplace()` can be used to add elements - to a JSON object. Note how the `null` value was silently converted to a - JSON object. Further note how no value is added if there was already one - value stored with the same key.,emplace} - - @since version 2.0.8 - */ - template<class... Args> - std::pair<iterator, bool> emplace(Args&& ... args) - { - // emplace only works for null objects or arrays - if (not(is_null() or is_object())) - { - JSON_THROW(std::domain_error("cannot use emplace() with " + type_name())); - } - - // transform null object into an object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); - } - - // add element to array (perfect forwarding) - auto res = m_value.object->emplace(std::forward<Args>(args)...); - // create result iterator and set iterator to the result of emplace - auto it = begin(); - it.m_it.object_iterator = res.first; - - // return pair of iterator and boolean - return {it, res.second}; - } - - /*! - @brief inserts element - - Inserts element @a val before iterator @a pos. - - @param[in] pos iterator before which the content will be inserted; may be - the end() iterator - @param[in] val element to insert - @return iterator pointing to the inserted @a val. - - @throw std::domain_error if called on JSON values other than arrays; - example: `"cannot use insert() with string"` - @throw std::domain_error if @a pos is not an iterator of *this; example: - `"iterator does not fit current value"` - - @complexity Constant plus linear in the distance between @a pos and end of - the container. - - @liveexample{The example shows how `insert()` is used.,insert} - - @since version 1.0.0 - */ - iterator insert(const_iterator pos, const basic_json& val) - { - // insert only works for arrays - if (is_array()) - { - // check if iterator pos fits to this JSON value - if (pos.m_object != this) - { - JSON_THROW(std::domain_error("iterator does not fit current value")); - } - - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); - return result; - } - - JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); - } - - /*! - @brief inserts element - @copydoc insert(const_iterator, const basic_json&) - */ - iterator insert(const_iterator pos, basic_json&& val) - { - return insert(pos, val); - } - - /*! - @brief inserts elements - - Inserts @a cnt copies of @a val before iterator @a pos. - - @param[in] pos iterator before which the content will be inserted; may be - the end() iterator - @param[in] cnt number of copies of @a val to insert - @param[in] val element to insert - @return iterator pointing to the first element inserted, or @a pos if - `cnt==0` - - @throw std::domain_error if called on JSON values other than arrays; - example: `"cannot use insert() with string"` - @throw std::domain_error if @a pos is not an iterator of *this; example: - `"iterator does not fit current value"` - - @complexity Linear in @a cnt plus linear in the distance between @a pos - and end of the container. - - @liveexample{The example shows how `insert()` is used.,insert__count} - - @since version 1.0.0 - */ - iterator insert(const_iterator pos, size_type cnt, const basic_json& val) - { - // insert only works for arrays - if (is_array()) - { - // check if iterator pos fits to this JSON value - if (pos.m_object != this) - { - JSON_THROW(std::domain_error("iterator does not fit current value")); - } - - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); - return result; - } - - JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); - } - - /*! - @brief inserts elements - - Inserts elements from range `[first, last)` before iterator @a pos. - - @param[in] pos iterator before which the content will be inserted; may be - the end() iterator - @param[in] first begin of the range of elements to insert - @param[in] last end of the range of elements to insert - - @throw std::domain_error if called on JSON values other than arrays; - example: `"cannot use insert() with string"` - @throw std::domain_error if @a pos is not an iterator of *this; example: - `"iterator does not fit current value"` - @throw std::domain_error if @a first and @a last do not belong to the same - JSON value; example: `"iterators do not fit"` - @throw std::domain_error if @a first or @a last are iterators into - container for which insert is called; example: `"passed iterators may not - belong to container"` - - @return iterator pointing to the first element inserted, or @a pos if - `first==last` - - @complexity Linear in `std::distance(first, last)` plus linear in the - distance between @a pos and end of the container. - - @liveexample{The example shows how `insert()` is used.,insert__range} - - @since version 1.0.0 - */ - iterator insert(const_iterator pos, const_iterator first, const_iterator last) - { - // insert only works for arrays - if (not is_array()) - { - JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); - } - - // check if iterator pos fits to this JSON value - if (pos.m_object != this) - { - JSON_THROW(std::domain_error("iterator does not fit current value")); - } - - // check if range iterators belong to the same JSON object - if (first.m_object != last.m_object) - { - JSON_THROW(std::domain_error("iterators do not fit")); - } - - if (first.m_object == this or last.m_object == this) - { - JSON_THROW(std::domain_error("passed iterators may not belong to container")); - } - - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert( - pos.m_it.array_iterator, - first.m_it.array_iterator, - last.m_it.array_iterator); - return result; - } - - /*! - @brief inserts elements - - Inserts elements from initializer list @a ilist before iterator @a pos. - - @param[in] pos iterator before which the content will be inserted; may be - the end() iterator - @param[in] ilist initializer list to insert the values from - - @throw std::domain_error if called on JSON values other than arrays; - example: `"cannot use insert() with string"` - @throw std::domain_error if @a pos is not an iterator of *this; example: - `"iterator does not fit current value"` - - @return iterator pointing to the first element inserted, or @a pos if - `ilist` is empty - - @complexity Linear in `ilist.size()` plus linear in the distance between - @a pos and end of the container. - - @liveexample{The example shows how `insert()` is used.,insert__ilist} - - @since version 1.0.0 - */ - iterator insert(const_iterator pos, std::initializer_list<basic_json> ilist) - { - // insert only works for arrays - if (not is_array()) - { - JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); - } - - // check if iterator pos fits to this JSON value - if (pos.m_object != this) - { - JSON_THROW(std::domain_error("iterator does not fit current value")); - } - - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist); - return result; - } - - /*! - @brief exchanges the values - - Exchanges the contents of the JSON value with those of @a other. Does not - invoke any move, copy, or swap operations on individual elements. All - iterators and references remain valid. The past-the-end iterator is - invalidated. - - @param[in,out] other JSON value to exchange the contents with - - @complexity Constant. - - @liveexample{The example below shows how JSON values can be swapped with - `swap()`.,swap__reference} - - @since version 1.0.0 - */ - void swap(reference other) noexcept ( - std::is_nothrow_move_constructible<value_t>::value and - std::is_nothrow_move_assignable<value_t>::value and - std::is_nothrow_move_constructible<json_value>::value and - std::is_nothrow_move_assignable<json_value>::value - ) - { - std::swap(m_type, other.m_type); - std::swap(m_value, other.m_value); - assert_invariant(); - } - - /*! - @brief exchanges the values - - Exchanges the contents of a JSON array with those of @a other. Does not - invoke any move, copy, or swap operations on individual elements. All - iterators and references remain valid. The past-the-end iterator is - invalidated. - - @param[in,out] other array to exchange the contents with - - @throw std::domain_error when JSON value is not an array; example: - `"cannot use swap() with string"` - - @complexity Constant. - - @liveexample{The example below shows how arrays can be swapped with - `swap()`.,swap__array_t} - - @since version 1.0.0 - */ - void swap(array_t& other) - { - // swap only works for arrays - if (is_array()) - { - std::swap(*(m_value.array), other); - } - else - { - JSON_THROW(std::domain_error("cannot use swap() with " + type_name())); - } - } - - /*! - @brief exchanges the values - - Exchanges the contents of a JSON object with those of @a other. Does not - invoke any move, copy, or swap operations on individual elements. All - iterators and references remain valid. The past-the-end iterator is - invalidated. - - @param[in,out] other object to exchange the contents with - - @throw std::domain_error when JSON value is not an object; example: - `"cannot use swap() with string"` - - @complexity Constant. - - @liveexample{The example below shows how objects can be swapped with - `swap()`.,swap__object_t} - - @since version 1.0.0 - */ - void swap(object_t& other) - { - // swap only works for objects - if (is_object()) - { - std::swap(*(m_value.object), other); - } - else - { - JSON_THROW(std::domain_error("cannot use swap() with " + type_name())); - } - } - - /*! - @brief exchanges the values - - Exchanges the contents of a JSON string with those of @a other. Does not - invoke any move, copy, or swap operations on individual elements. All - iterators and references remain valid. The past-the-end iterator is - invalidated. - - @param[in,out] other string to exchange the contents with - - @throw std::domain_error when JSON value is not a string; example: `"cannot - use swap() with boolean"` - - @complexity Constant. - - @liveexample{The example below shows how strings can be swapped with - `swap()`.,swap__string_t} - - @since version 1.0.0 - */ - void swap(string_t& other) - { - // swap only works for strings - if (is_string()) - { - std::swap(*(m_value.string), other); - } - else - { - JSON_THROW(std::domain_error("cannot use swap() with " + type_name())); - } - } - - /// @} - - public: - ////////////////////////////////////////// - // lexicographical comparison operators // - ////////////////////////////////////////// - - /// @name lexicographical comparison operators - /// @{ - - /*! - @brief comparison: equal - - Compares two JSON values for equality according to the following rules: - - Two JSON values are equal if (1) they are from the same type and (2) - their stored values are the same. - - Integer and floating-point numbers are automatically converted before - comparison. Floating-point numbers are compared indirectly: two - floating-point numbers `f1` and `f2` are considered equal if neither - `f1 > f2` nor `f2 > f1` holds. - - Two JSON null values are equal. - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether the values @a lhs and @a rhs are equal - - @complexity Linear. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__equal} - - @since version 1.0.0 - */ - friend bool operator==(const_reference lhs, const_reference rhs) noexcept - { - const auto lhs_type = lhs.type(); - const auto rhs_type = rhs.type(); - - if (lhs_type == rhs_type) - { - switch (lhs_type) - { - case value_t::array: - { - return *lhs.m_value.array == *rhs.m_value.array; - } - case value_t::object: - { - return *lhs.m_value.object == *rhs.m_value.object; - } - case value_t::null: - { - return true; - } - case value_t::string: - { - return *lhs.m_value.string == *rhs.m_value.string; - } - case value_t::boolean: - { - return lhs.m_value.boolean == rhs.m_value.boolean; - } - case value_t::number_integer: - { - return lhs.m_value.number_integer == rhs.m_value.number_integer; - } - case value_t::number_unsigned: - { - return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned; - } - case value_t::number_float: - { - return lhs.m_value.number_float == rhs.m_value.number_float; - } - default: - { - return false; - } - } - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) - { - return static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) - { - return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) - { - return static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) - { - return static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned); - } - - return false; - } - - /*! - @brief comparison: equal - @copydoc operator==(const_reference, const_reference) - */ - template<typename ScalarType, typename std::enable_if< - std::is_scalar<ScalarType>::value, int>::type = 0> - friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept - { - return (lhs == basic_json(rhs)); - } - - /*! - @brief comparison: equal - @copydoc operator==(const_reference, const_reference) - */ - template<typename ScalarType, typename std::enable_if< - std::is_scalar<ScalarType>::value, int>::type = 0> - friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept - { - return (basic_json(lhs) == rhs); - } - - /*! - @brief comparison: not equal - - Compares two JSON values for inequality by calculating `not (lhs == rhs)`. - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether the values @a lhs and @a rhs are not equal - - @complexity Linear. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__notequal} - - @since version 1.0.0 - */ - friend bool operator!=(const_reference lhs, const_reference rhs) noexcept - { - return not (lhs == rhs); - } - - /*! - @brief comparison: not equal - @copydoc operator!=(const_reference, const_reference) - */ - template<typename ScalarType, typename std::enable_if< - std::is_scalar<ScalarType>::value, int>::type = 0> - friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept - { - return (lhs != basic_json(rhs)); - } - - /*! - @brief comparison: not equal - @copydoc operator!=(const_reference, const_reference) - */ - template<typename ScalarType, typename std::enable_if< - std::is_scalar<ScalarType>::value, int>::type = 0> - friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept - { - return (basic_json(lhs) != rhs); - } - - /*! - @brief comparison: less than - - Compares whether one JSON value @a lhs is less than another JSON value @a - rhs according to the following rules: - - If @a lhs and @a rhs have the same type, the values are compared using - the default `<` operator. - - Integer and floating-point numbers are automatically converted before - comparison - - In case @a lhs and @a rhs have different types, the values are ignored - and the order of the types is considered, see - @ref operator<(const value_t, const value_t). - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether @a lhs is less than @a rhs - - @complexity Linear. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__less} - - @since version 1.0.0 - */ - friend bool operator<(const_reference lhs, const_reference rhs) noexcept - { - const auto lhs_type = lhs.type(); - const auto rhs_type = rhs.type(); - - if (lhs_type == rhs_type) - { - switch (lhs_type) - { - case value_t::array: - { - return *lhs.m_value.array < *rhs.m_value.array; - } - case value_t::object: - { - return *lhs.m_value.object < *rhs.m_value.object; - } - case value_t::null: - { - return false; - } - case value_t::string: - { - return *lhs.m_value.string < *rhs.m_value.string; - } - case value_t::boolean: - { - return lhs.m_value.boolean < rhs.m_value.boolean; - } - case value_t::number_integer: - { - return lhs.m_value.number_integer < rhs.m_value.number_integer; - } - case value_t::number_unsigned: - { - return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; - } - case value_t::number_float: - { - return lhs.m_value.number_float < rhs.m_value.number_float; - } - default: - { - return false; - } - } - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) - { - return static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) - { - return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) - { - return static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_unsigned); - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_integer < static_cast<number_integer_t>(rhs.m_value.number_unsigned); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) - { - return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; - } - - // We only reach this line if we cannot compare values. In that case, - // we compare types. Note we have to call the operator explicitly, - // because MSVC has problems otherwise. - return operator<(lhs_type, rhs_type); - } - - /*! - @brief comparison: less than or equal - - Compares whether one JSON value @a lhs is less than or equal to another - JSON value by calculating `not (rhs < lhs)`. - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether @a lhs is less than or equal to @a rhs - - @complexity Linear. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__greater} - - @since version 1.0.0 - */ - friend bool operator<=(const_reference lhs, const_reference rhs) noexcept - { - return not (rhs < lhs); - } - - /*! - @brief comparison: greater than - - Compares whether one JSON value @a lhs is greater than another - JSON value by calculating `not (lhs <= rhs)`. - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether @a lhs is greater than to @a rhs - - @complexity Linear. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__lessequal} - - @since version 1.0.0 - */ - friend bool operator>(const_reference lhs, const_reference rhs) noexcept - { - return not (lhs <= rhs); - } - - /*! - @brief comparison: greater than or equal - - Compares whether one JSON value @a lhs is greater than or equal to another - JSON value by calculating `not (lhs < rhs)`. - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether @a lhs is greater than or equal to @a rhs - - @complexity Linear. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__greaterequal} - - @since version 1.0.0 - */ - friend bool operator>=(const_reference lhs, const_reference rhs) noexcept - { - return not (lhs < rhs); - } - - /// @} - - - /////////////////// - // serialization // - /////////////////// - - /// @name serialization - /// @{ - - /*! - @brief serialize to stream - - Serialize the given JSON value @a j to the output stream @a o. The JSON - value will be serialized using the @ref dump member function. The - indentation of the output can be controlled with the member variable - `width` of the output stream @a o. For instance, using the manipulator - `std::setw(4)` on @a o sets the indentation level to `4` and the - serialization result is the same as calling `dump(4)`. - - @param[in,out] o stream to serialize to - @param[in] j JSON value to serialize - - @return the stream @a o - - @complexity Linear. - - @liveexample{The example below shows the serialization with different - parameters to `width` to adjust the indentation level.,operator_serialize} - - @since version 1.0.0 - */ - friend std::ostream& operator<<(std::ostream& o, const basic_json& j) - { - // read width member and use it as indentation parameter if nonzero - const bool pretty_print = (o.width() > 0); - const auto indentation = (pretty_print ? o.width() : 0); - - // reset width to 0 for subsequent calls to this stream - o.width(0); - - // do the actual serialization - j.dump(o, pretty_print, static_cast<unsigned int>(indentation)); - - return o; - } - - /*! - @brief serialize to stream - @copydoc operator<<(std::ostream&, const basic_json&) - */ - friend std::ostream& operator>>(const basic_json& j, std::ostream& o) - { - return o << j; - } - - /// @} - - - ///////////////////// - // deserialization // - ///////////////////// - - /// @name deserialization - /// @{ - - /*! - @brief deserialize from an array - - This function reads from an array of 1-byte values. - - @pre Each element of the container has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @param[in] array array to read from - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - - @return result of the deserialization - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below demonstrates the `parse()` function reading - from an array.,parse__array__parser_callback_t} - - @since version 2.0.3 - */ - template<class T, std::size_t N> - static basic_json parse(T (&array)[N], - const parser_callback_t cb = nullptr) - { - // delegate the call to the iterator-range parse overload - return parse(std::begin(array), std::end(array), cb); - } - - /*! - @brief deserialize from string literal - - @tparam CharT character/literal type with size of 1 byte - @param[in] s string literal to read a serialized JSON value from - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - - @return result of the deserialization - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - @note String containers like `std::string` or @ref string_t can be parsed - with @ref parse(const ContiguousContainer&, const parser_callback_t) - - @liveexample{The example below demonstrates the `parse()` function with - and without callback function.,parse__string__parser_callback_t} - - @sa @ref parse(std::istream&, const parser_callback_t) for a version that - reads from an input stream - - @since version 1.0.0 (originally for @ref string_t) - */ - template<typename CharT, typename std::enable_if< - std::is_pointer<CharT>::value and - std::is_integral<typename std::remove_pointer<CharT>::type>::value and - sizeof(typename std::remove_pointer<CharT>::type) == 1, int>::type = 0> - static basic_json parse(const CharT s, - const parser_callback_t cb = nullptr) - { - return parser(reinterpret_cast<const char*>(s), cb).parse(); - } - - /*! - @brief deserialize from stream - - @param[in,out] i stream to read a serialized JSON value from - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - - @return result of the deserialization - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below demonstrates the `parse()` function with - and without callback function.,parse__istream__parser_callback_t} - - @sa @ref parse(const CharT, const parser_callback_t) for a version - that reads from a string - - @since version 1.0.0 - */ - static basic_json parse(std::istream& i, - const parser_callback_t cb = nullptr) - { - return parser(i, cb).parse(); - } - - /*! - @copydoc parse(std::istream&, const parser_callback_t) - */ - static basic_json parse(std::istream&& i, - const parser_callback_t cb = nullptr) - { - return parser(i, cb).parse(); - } - - /*! - @brief deserialize from an iterator range with contiguous storage - - This function reads from an iterator range of a container with contiguous - storage of 1-byte values. Compatible container types include - `std::vector`, `std::string`, `std::array`, `std::valarray`, and - `std::initializer_list`. Furthermore, C-style arrays can be used with - `std::begin()`/`std::end()`. User-defined containers can be used as long - as they implement random-access iterators and a contiguous storage. - - @pre The iterator range is contiguous. Violating this precondition yields - undefined behavior. **This precondition is enforced with an assertion.** - @pre Each element in the range has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @warning There is no way to enforce all preconditions at compile-time. If - the function is called with noncompliant iterators and with - assertions switched off, the behavior is undefined and will most - likely yield segmentation violation. - - @tparam IteratorType iterator of container with contiguous storage - @param[in] first begin of the range to parse (included) - @param[in] last end of the range to parse (excluded) - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - - @return result of the deserialization - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below demonstrates the `parse()` function reading - from an iterator range.,parse__iteratortype__parser_callback_t} - - @since version 2.0.3 - */ - template<class IteratorType, typename std::enable_if< - std::is_base_of< - std::random_access_iterator_tag, - typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0> - static basic_json parse(IteratorType first, IteratorType last, - const parser_callback_t cb = nullptr) - { - // assertion to check that the iterator range is indeed contiguous, - // see http://stackoverflow.com/a/35008842/266378 for more discussion - assert(std::accumulate(first, last, std::pair<bool, int>(true, 0), - [&first](std::pair<bool, int> res, decltype(*first) val) - { - res.first &= (val == *(std::next(std::addressof(*first), res.second++))); - return res; - }).first); - - // assertion to check that each element is 1 byte long - static_assert(sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1, - "each element in the iterator range must have the size of 1 byte"); - - // if iterator range is empty, create a parser with an empty string - // to generate "unexpected EOF" error message - if (std::distance(first, last) <= 0) - { - return parser("").parse(); - } - - return parser(first, last, cb).parse(); - } - - /*! - @brief deserialize from a container with contiguous storage - - This function reads from a container with contiguous storage of 1-byte - values. Compatible container types include `std::vector`, `std::string`, - `std::array`, and `std::initializer_list`. User-defined containers can be - used as long as they implement random-access iterators and a contiguous - storage. - - @pre The container storage is contiguous. Violating this precondition - yields undefined behavior. **This precondition is enforced with an - assertion.** - @pre Each element of the container has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @warning There is no way to enforce all preconditions at compile-time. If - the function is called with a noncompliant container and with - assertions switched off, the behavior is undefined and will most - likely yield segmentation violation. - - @tparam ContiguousContainer container type with contiguous storage - @param[in] c container to read from - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - - @return result of the deserialization - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below demonstrates the `parse()` function reading - from a contiguous container.,parse__contiguouscontainer__parser_callback_t} - - @since version 2.0.3 - */ - template<class ContiguousContainer, typename std::enable_if< - not std::is_pointer<ContiguousContainer>::value and - std::is_base_of< - std::random_access_iterator_tag, - typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value - , int>::type = 0> - static basic_json parse(const ContiguousContainer& c, - const parser_callback_t cb = nullptr) - { - // delegate the call to the iterator-range parse overload - return parse(std::begin(c), std::end(c), cb); - } - - /*! - @brief deserialize from stream - - Deserializes an input stream to a JSON value. - - @param[in,out] i input stream to read a serialized JSON value from - @param[in,out] j JSON value to write the deserialized input to - - @throw std::invalid_argument in case of parse errors - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below shows how a JSON value is constructed by - reading a serialization from a stream.,operator_deserialize} - - @sa parse(std::istream&, const parser_callback_t) for a variant with a - parser callback function to filter values while parsing - - @since version 1.0.0 - */ - friend std::istream& operator<<(basic_json& j, std::istream& i) - { - j = parser(i).parse(); - return i; - } - - /*! - @brief deserialize from stream - @copydoc operator<<(basic_json&, std::istream&) - */ - friend std::istream& operator>>(std::istream& i, basic_json& j) - { - j = parser(i).parse(); - return i; - } - - /// @} - - ////////////////////////////////////////// - // binary serialization/deserialization // - ////////////////////////////////////////// - - /// @name binary serialization/deserialization support - /// @{ - - private: - /*! - @note Some code in the switch cases has been copied, because otherwise - copilers would complain about implicit fallthrough and there is no - portable attribute to mute such warnings. - */ - template<typename T> - static void add_to_vector(std::vector<uint8_t>& vec, size_t bytes, const T number) - { - assert(bytes == 1 or bytes == 2 or bytes == 4 or bytes == 8); - - switch (bytes) - { - case 8: - { - vec.push_back(static_cast<uint8_t>((static_cast<uint64_t>(number) >> 070) & 0xff)); - vec.push_back(static_cast<uint8_t>((static_cast<uint64_t>(number) >> 060) & 0xff)); - vec.push_back(static_cast<uint8_t>((static_cast<uint64_t>(number) >> 050) & 0xff)); - vec.push_back(static_cast<uint8_t>((static_cast<uint64_t>(number) >> 040) & 0xff)); - vec.push_back(static_cast<uint8_t>((number >> 030) & 0xff)); - vec.push_back(static_cast<uint8_t>((number >> 020) & 0xff)); - vec.push_back(static_cast<uint8_t>((number >> 010) & 0xff)); - vec.push_back(static_cast<uint8_t>(number & 0xff)); - break; - } - - case 4: - { - vec.push_back(static_cast<uint8_t>((number >> 030) & 0xff)); - vec.push_back(static_cast<uint8_t>((number >> 020) & 0xff)); - vec.push_back(static_cast<uint8_t>((number >> 010) & 0xff)); - vec.push_back(static_cast<uint8_t>(number & 0xff)); - break; - } - - case 2: - { - vec.push_back(static_cast<uint8_t>((number >> 010) & 0xff)); - vec.push_back(static_cast<uint8_t>(number & 0xff)); - break; - } - - case 1: - { - vec.push_back(static_cast<uint8_t>(number & 0xff)); - break; - } - } - } - - /*! - @brief take sufficient bytes from a vector to fill an integer variable - - In the context of binary serialization formats, we need to read several - bytes from a byte vector and combine them to multi-byte integral data - types. - - @param[in] vec byte vector to read from - @param[in] current_index the position in the vector after which to read - - @return the next sizeof(T) bytes from @a vec, in reverse order as T - - @tparam T the integral return type - - @throw std::out_of_range if there are less than sizeof(T)+1 bytes in the - vector @a vec to read - - In the for loop, the bytes from the vector are copied in reverse order into - the return value. In the figures below, let sizeof(T)=4 and `i` be the loop - variable. - - Precondition: - - vec: | | | a | b | c | d | T: | | | | | - ^ ^ ^ ^ - current_index i ptr sizeof(T) - - Postcondition: - - vec: | | | a | b | c | d | T: | d | c | b | a | - ^ ^ ^ - | i ptr - current_index - - @sa Code adapted from <http://stackoverflow.com/a/41031865/266378>. - */ - template<typename T> - static T get_from_vector(const std::vector<uint8_t>& vec, const size_t current_index) - { - if (current_index + sizeof(T) + 1 > vec.size()) - { - JSON_THROW(std::out_of_range("cannot read " + std::to_string(sizeof(T)) + " bytes from vector")); - } - - T result; - auto* ptr = reinterpret_cast<uint8_t*>(&result); - for (size_t i = 0; i < sizeof(T); ++i) - { - *ptr++ = vec[current_index + sizeof(T) - i]; - } - return result; - } - - /*! - @brief create a MessagePack serialization of a given JSON value - - This is a straightforward implementation of the MessagePack specification. - - @param[in] j JSON value to serialize - @param[in,out] v byte vector to write the serialization to - - @sa https://github.com/msgpack/msgpack/blob/master/spec.md - */ - static void to_msgpack_internal(const basic_json& j, std::vector<uint8_t>& v) - { - switch (j.type()) - { - case value_t::null: - { - // nil - v.push_back(0xc0); - break; - } - - case value_t::boolean: - { - // true and false - v.push_back(j.m_value.boolean ? 0xc3 : 0xc2); - break; - } - - case value_t::number_integer: - { - if (j.m_value.number_integer >= 0) - { - // MessagePack does not differentiate between positive - // signed integers and unsigned integers. Therefore, we - // used the code from the value_t::number_unsigned case - // here. - if (j.m_value.number_unsigned < 128) - { - // positive fixnum - add_to_vector(v, 1, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= std::numeric_limits<uint8_t>::max()) - { - // uint 8 - v.push_back(0xcc); - add_to_vector(v, 1, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= std::numeric_limits<uint16_t>::max()) - { - // uint 16 - v.push_back(0xcd); - add_to_vector(v, 2, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= std::numeric_limits<uint32_t>::max()) - { - // uint 32 - v.push_back(0xce); - add_to_vector(v, 4, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= std::numeric_limits<uint64_t>::max()) - { - // uint 64 - v.push_back(0xcf); - add_to_vector(v, 8, j.m_value.number_unsigned); - } - } - else - { - if (j.m_value.number_integer >= -32) - { - // negative fixnum - add_to_vector(v, 1, j.m_value.number_integer); - } - else if (j.m_value.number_integer >= std::numeric_limits<int8_t>::min() and j.m_value.number_integer <= std::numeric_limits<int8_t>::max()) - { - // int 8 - v.push_back(0xd0); - add_to_vector(v, 1, j.m_value.number_integer); - } - else if (j.m_value.number_integer >= std::numeric_limits<int16_t>::min() and j.m_value.number_integer <= std::numeric_limits<int16_t>::max()) - { - // int 16 - v.push_back(0xd1); - add_to_vector(v, 2, j.m_value.number_integer); - } - else if (j.m_value.number_integer >= std::numeric_limits<int32_t>::min() and j.m_value.number_integer <= std::numeric_limits<int32_t>::max()) - { - // int 32 - v.push_back(0xd2); - add_to_vector(v, 4, j.m_value.number_integer); - } - else if (j.m_value.number_integer >= std::numeric_limits<int64_t>::min() and j.m_value.number_integer <= std::numeric_limits<int64_t>::max()) - { - // int 64 - v.push_back(0xd3); - add_to_vector(v, 8, j.m_value.number_integer); - } - } - break; - } - - case value_t::number_unsigned: - { - if (j.m_value.number_unsigned < 128) - { - // positive fixnum - add_to_vector(v, 1, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= std::numeric_limits<uint8_t>::max()) - { - // uint 8 - v.push_back(0xcc); - add_to_vector(v, 1, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= std::numeric_limits<uint16_t>::max()) - { - // uint 16 - v.push_back(0xcd); - add_to_vector(v, 2, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= std::numeric_limits<uint32_t>::max()) - { - // uint 32 - v.push_back(0xce); - add_to_vector(v, 4, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= std::numeric_limits<uint64_t>::max()) - { - // uint 64 - v.push_back(0xcf); - add_to_vector(v, 8, j.m_value.number_unsigned); - } - break; - } - - case value_t::number_float: - { - // float 64 - v.push_back(0xcb); - const auto* helper = reinterpret_cast<const uint8_t*>(&(j.m_value.number_float)); - for (size_t i = 0; i < 8; ++i) - { - v.push_back(helper[7 - i]); - } - break; - } - - case value_t::string: - { - const auto N = j.m_value.string->size(); - if (N <= 31) - { - // fixstr - v.push_back(static_cast<uint8_t>(0xa0 | N)); - } - else if (N <= 255) - { - // str 8 - v.push_back(0xd9); - add_to_vector(v, 1, N); - } - else if (N <= 65535) - { - // str 16 - v.push_back(0xda); - add_to_vector(v, 2, N); - } - else if (N <= 4294967295) - { - // str 32 - v.push_back(0xdb); - add_to_vector(v, 4, N); - } - - // append string - std::copy(j.m_value.string->begin(), j.m_value.string->end(), - std::back_inserter(v)); - break; - } - - case value_t::array: - { - const auto N = j.m_value.array->size(); - if (N <= 15) - { - // fixarray - v.push_back(static_cast<uint8_t>(0x90 | N)); - } - else if (N <= 0xffff) - { - // array 16 - v.push_back(0xdc); - add_to_vector(v, 2, N); - } - else if (N <= 0xffffffff) - { - // array 32 - v.push_back(0xdd); - add_to_vector(v, 4, N); - } - - // append each element - for (const auto& el : *j.m_value.array) - { - to_msgpack_internal(el, v); - } - break; - } - - case value_t::object: - { - const auto N = j.m_value.object->size(); - if (N <= 15) - { - // fixmap - v.push_back(static_cast<uint8_t>(0x80 | (N & 0xf))); - } - else if (N <= 65535) - { - // map 16 - v.push_back(0xde); - add_to_vector(v, 2, N); - } - else if (N <= 4294967295) - { - // map 32 - v.push_back(0xdf); - add_to_vector(v, 4, N); - } - - // append each element - for (const auto& el : *j.m_value.object) - { - to_msgpack_internal(el.first, v); - to_msgpack_internal(el.second, v); - } - break; - } - - default: - { - break; - } - } - } - - /*! - @brief create a CBOR serialization of a given JSON value - - This is a straightforward implementation of the CBOR specification. - - @param[in] j JSON value to serialize - @param[in,out] v byte vector to write the serialization to - - @sa https://tools.ietf.org/html/rfc7049 - */ - static void to_cbor_internal(const basic_json& j, std::vector<uint8_t>& v) - { - switch (j.type()) - { - case value_t::null: - { - v.push_back(0xf6); - break; - } - - case value_t::boolean: - { - v.push_back(j.m_value.boolean ? 0xf5 : 0xf4); - break; - } - - case value_t::number_integer: - { - if (j.m_value.number_integer >= 0) - { - // CBOR does not differentiate between positive signed - // integers and unsigned integers. Therefore, we used the - // code from the value_t::number_unsigned case here. - if (j.m_value.number_integer <= 0x17) - { - add_to_vector(v, 1, j.m_value.number_integer); - } - else if (j.m_value.number_integer <= std::numeric_limits<uint8_t>::max()) - { - v.push_back(0x18); - // one-byte uint8_t - add_to_vector(v, 1, j.m_value.number_integer); - } - else if (j.m_value.number_integer <= std::numeric_limits<uint16_t>::max()) - { - v.push_back(0x19); - // two-byte uint16_t - add_to_vector(v, 2, j.m_value.number_integer); - } - else if (j.m_value.number_integer <= std::numeric_limits<uint32_t>::max()) - { - v.push_back(0x1a); - // four-byte uint32_t - add_to_vector(v, 4, j.m_value.number_integer); - } - else - { - v.push_back(0x1b); - // eight-byte uint64_t - add_to_vector(v, 8, j.m_value.number_integer); - } - } - else - { - // The conversions below encode the sign in the first - // byte, and the value is converted to a positive number. - const auto positive_number = -1 - j.m_value.number_integer; - if (j.m_value.number_integer >= -24) - { - v.push_back(static_cast<uint8_t>(0x20 + positive_number)); - } - else if (positive_number <= std::numeric_limits<uint8_t>::max()) - { - // int 8 - v.push_back(0x38); - add_to_vector(v, 1, positive_number); - } - else if (positive_number <= std::numeric_limits<uint16_t>::max()) - { - // int 16 - v.push_back(0x39); - add_to_vector(v, 2, positive_number); - } - else if (positive_number <= std::numeric_limits<uint32_t>::max()) - { - // int 32 - v.push_back(0x3a); - add_to_vector(v, 4, positive_number); - } - else - { - // int 64 - v.push_back(0x3b); - add_to_vector(v, 8, positive_number); - } - } - break; - } - - case value_t::number_unsigned: - { - if (j.m_value.number_unsigned <= 0x17) - { - v.push_back(static_cast<uint8_t>(j.m_value.number_unsigned)); - } - else if (j.m_value.number_unsigned <= 0xff) - { - v.push_back(0x18); - // one-byte uint8_t - add_to_vector(v, 1, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= 0xffff) - { - v.push_back(0x19); - // two-byte uint16_t - add_to_vector(v, 2, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= 0xffffffff) - { - v.push_back(0x1a); - // four-byte uint32_t - add_to_vector(v, 4, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= 0xffffffffffffffff) - { - v.push_back(0x1b); - // eight-byte uint64_t - add_to_vector(v, 8, j.m_value.number_unsigned); - } - break; - } - - case value_t::number_float: - { - // Double-Precision Float - v.push_back(0xfb); - const auto* helper = reinterpret_cast<const uint8_t*>(&(j.m_value.number_float)); - for (size_t i = 0; i < 8; ++i) - { - v.push_back(helper[7 - i]); - } - break; - } - - case value_t::string: - { - const auto N = j.m_value.string->size(); - if (N <= 0x17) - { - v.push_back(0x60 + static_cast<uint8_t>(N)); // 1 byte for string + size - } - else if (N <= 0xff) - { - v.push_back(0x78); // one-byte uint8_t for N - add_to_vector(v, 1, N); - } - else if (N <= 0xffff) - { - v.push_back(0x79); // two-byte uint16_t for N - add_to_vector(v, 2, N); - } - else if (N <= 0xffffffff) - { - v.push_back(0x7a); // four-byte uint32_t for N - add_to_vector(v, 4, N); - } - // LCOV_EXCL_START - else if (N <= 0xffffffffffffffff) - { - v.push_back(0x7b); // eight-byte uint64_t for N - add_to_vector(v, 8, N); - } - // LCOV_EXCL_STOP - - // append string - std::copy(j.m_value.string->begin(), j.m_value.string->end(), - std::back_inserter(v)); - break; - } - - case value_t::array: - { - const auto N = j.m_value.array->size(); - if (N <= 0x17) - { - v.push_back(0x80 + static_cast<uint8_t>(N)); // 1 byte for array + size - } - else if (N <= 0xff) - { - v.push_back(0x98); // one-byte uint8_t for N - add_to_vector(v, 1, N); - } - else if (N <= 0xffff) - { - v.push_back(0x99); // two-byte uint16_t for N - add_to_vector(v, 2, N); - } - else if (N <= 0xffffffff) - { - v.push_back(0x9a); // four-byte uint32_t for N - add_to_vector(v, 4, N); - } - // LCOV_EXCL_START - else if (N <= 0xffffffffffffffff) - { - v.push_back(0x9b); // eight-byte uint64_t for N - add_to_vector(v, 8, N); - } - // LCOV_EXCL_STOP - - // append each element - for (const auto& el : *j.m_value.array) - { - to_cbor_internal(el, v); - } - break; - } - - case value_t::object: - { - const auto N = j.m_value.object->size(); - if (N <= 0x17) - { - v.push_back(0xa0 + static_cast<uint8_t>(N)); // 1 byte for object + size - } - else if (N <= 0xff) - { - v.push_back(0xb8); - add_to_vector(v, 1, N); // one-byte uint8_t for N - } - else if (N <= 0xffff) - { - v.push_back(0xb9); - add_to_vector(v, 2, N); // two-byte uint16_t for N - } - else if (N <= 0xffffffff) - { - v.push_back(0xba); - add_to_vector(v, 4, N); // four-byte uint32_t for N - } - // LCOV_EXCL_START - else if (N <= 0xffffffffffffffff) - { - v.push_back(0xbb); - add_to_vector(v, 8, N); // eight-byte uint64_t for N - } - // LCOV_EXCL_STOP - - // append each element - for (const auto& el : *j.m_value.object) - { - to_cbor_internal(el.first, v); - to_cbor_internal(el.second, v); - } - break; - } - - default: - { - break; - } - } - } - - - /* - @brief checks if given lengths do not exceed the size of a given vector - - To secure the access to the byte vector during CBOR/MessagePack - deserialization, bytes are copied from the vector into buffers. This - function checks if the number of bytes to copy (@a len) does not exceed - the size @s size of the vector. Additionally, an @a offset is given from - where to start reading the bytes. - - This function checks whether reading the bytes is safe; that is, offset is - a valid index in the vector, offset+len - - @param[in] size size of the byte vector - @param[in] len number of bytes to read - @param[in] offset offset where to start reading - - vec: x x x x x X X X X X - ^ ^ ^ - 0 offset len - - @throws out_of_range if `len > v.size()` - */ - static void check_length(const size_t size, const size_t len, const size_t offset) - { - // simple case: requested length is greater than the vector's length - if (len > size or offset > size) - { - JSON_THROW(std::out_of_range("len out of range")); - } - - // second case: adding offset would result in overflow - if ((size > (std::numeric_limits<size_t>::max() - offset))) - { - JSON_THROW(std::out_of_range("len+offset out of range")); - } - - // last case: reading past the end of the vector - if (len + offset > size) - { - JSON_THROW(std::out_of_range("len+offset out of range")); - } - } - - /*! - @brief create a JSON value from a given MessagePack vector - - @param[in] v MessagePack serialization - @param[in] idx byte index to start reading from @a v - - @return deserialized JSON value - - @throw std::invalid_argument if unsupported features from MessagePack were - used in the given vector @a v or if the input is not valid MessagePack - @throw std::out_of_range if the given vector ends prematurely - - @sa https://github.com/msgpack/msgpack/blob/master/spec.md - */ - static basic_json from_msgpack_internal(const std::vector<uint8_t>& v, size_t& idx) - { - // make sure reading 1 byte is safe - check_length(v.size(), 1, idx); - - // store and increment index - const size_t current_idx = idx++; - - if (v[current_idx] <= 0xbf) - { - if (v[current_idx] <= 0x7f) // positive fixint - { - return v[current_idx]; - } - if (v[current_idx] <= 0x8f) // fixmap - { - basic_json result = value_t::object; - const size_t len = v[current_idx] & 0x0f; - for (size_t i = 0; i < len; ++i) - { - std::string key = from_msgpack_internal(v, idx); - result[key] = from_msgpack_internal(v, idx); - } - return result; - } - else if (v[current_idx] <= 0x9f) // fixarray - { - basic_json result = value_t::array; - const size_t len = v[current_idx] & 0x0f; - for (size_t i = 0; i < len; ++i) - { - result.push_back(from_msgpack_internal(v, idx)); - } - return result; - } - else // fixstr - { - const size_t len = v[current_idx] & 0x1f; - const size_t offset = current_idx + 1; - idx += len; // skip content bytes - check_length(v.size(), len, offset); - return std::string(reinterpret_cast<const char*>(v.data()) + offset, len); - } - } - else if (v[current_idx] >= 0xe0) // negative fixint - { - return static_cast<int8_t>(v[current_idx]); - } - else - { - switch (v[current_idx]) - { - case 0xc0: // nil - { - return value_t::null; - } - - case 0xc2: // false - { - return false; - } - - case 0xc3: // true - { - return true; - } - - case 0xca: // float 32 - { - // copy bytes in reverse order into the double variable - float res; - for (size_t byte = 0; byte < sizeof(float); ++byte) - { - reinterpret_cast<uint8_t*>(&res)[sizeof(float) - byte - 1] = v.at(current_idx + 1 + byte); - } - idx += sizeof(float); // skip content bytes - return res; - } - - case 0xcb: // float 64 - { - // copy bytes in reverse order into the double variable - double res; - for (size_t byte = 0; byte < sizeof(double); ++byte) - { - reinterpret_cast<uint8_t*>(&res)[sizeof(double) - byte - 1] = v.at(current_idx + 1 + byte); - } - idx += sizeof(double); // skip content bytes - return res; - } - - case 0xcc: // uint 8 - { - idx += 1; // skip content byte - return get_from_vector<uint8_t>(v, current_idx); - } - - case 0xcd: // uint 16 - { - idx += 2; // skip 2 content bytes - return get_from_vector<uint16_t>(v, current_idx); - } - - case 0xce: // uint 32 - { - idx += 4; // skip 4 content bytes - return get_from_vector<uint32_t>(v, current_idx); - } - - case 0xcf: // uint 64 - { - idx += 8; // skip 8 content bytes - return get_from_vector<uint64_t>(v, current_idx); - } - - case 0xd0: // int 8 - { - idx += 1; // skip content byte - return get_from_vector<int8_t>(v, current_idx); - } - - case 0xd1: // int 16 - { - idx += 2; // skip 2 content bytes - return get_from_vector<int16_t>(v, current_idx); - } - - case 0xd2: // int 32 - { - idx += 4; // skip 4 content bytes - return get_from_vector<int32_t>(v, current_idx); - } - - case 0xd3: // int 64 - { - idx += 8; // skip 8 content bytes - return get_from_vector<int64_t>(v, current_idx); - } - - case 0xd9: // str 8 - { - const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx)); - const size_t offset = current_idx + 2; - idx += len + 1; // skip size byte + content bytes - check_length(v.size(), len, offset); - return std::string(reinterpret_cast<const char*>(v.data()) + offset, len); - } - - case 0xda: // str 16 - { - const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx)); - const size_t offset = current_idx + 3; - idx += len + 2; // skip 2 size bytes + content bytes - check_length(v.size(), len, offset); - return std::string(reinterpret_cast<const char*>(v.data()) + offset, len); - } - - case 0xdb: // str 32 - { - const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx)); - const size_t offset = current_idx + 5; - idx += len + 4; // skip 4 size bytes + content bytes - check_length(v.size(), len, offset); - return std::string(reinterpret_cast<const char*>(v.data()) + offset, len); - } - - case 0xdc: // array 16 - { - basic_json result = value_t::array; - const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx)); - idx += 2; // skip 2 size bytes - for (size_t i = 0; i < len; ++i) - { - result.push_back(from_msgpack_internal(v, idx)); - } - return result; - } - - case 0xdd: // array 32 - { - basic_json result = value_t::array; - const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx)); - idx += 4; // skip 4 size bytes - for (size_t i = 0; i < len; ++i) - { - result.push_back(from_msgpack_internal(v, idx)); - } - return result; - } - - case 0xde: // map 16 - { - basic_json result = value_t::object; - const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx)); - idx += 2; // skip 2 size bytes - for (size_t i = 0; i < len; ++i) - { - std::string key = from_msgpack_internal(v, idx); - result[key] = from_msgpack_internal(v, idx); - } - return result; - } - - case 0xdf: // map 32 - { - basic_json result = value_t::object; - const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx)); - idx += 4; // skip 4 size bytes - for (size_t i = 0; i < len; ++i) - { - std::string key = from_msgpack_internal(v, idx); - result[key] = from_msgpack_internal(v, idx); - } - return result; - } - - default: - { - JSON_THROW(std::invalid_argument("error parsing a msgpack @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx])))); - } - } - } - } - - /*! - @brief create a JSON value from a given CBOR vector - - @param[in] v CBOR serialization - @param[in] idx byte index to start reading from @a v - - @return deserialized JSON value - - @throw std::invalid_argument if unsupported features from CBOR were used in - the given vector @a v or if the input is not valid CBOR - @throw std::out_of_range if the given vector ends prematurely - - @sa https://tools.ietf.org/html/rfc7049 - */ - static basic_json from_cbor_internal(const std::vector<uint8_t>& v, size_t& idx) - { - // store and increment index - const size_t current_idx = idx++; - - switch (v.at(current_idx)) - { - // Integer 0x00..0x17 (0..23) - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - { - return v[current_idx]; - } - - case 0x18: // Unsigned integer (one-byte uint8_t follows) - { - idx += 1; // skip content byte - return get_from_vector<uint8_t>(v, current_idx); - } - - case 0x19: // Unsigned integer (two-byte uint16_t follows) - { - idx += 2; // skip 2 content bytes - return get_from_vector<uint16_t>(v, current_idx); - } - - case 0x1a: // Unsigned integer (four-byte uint32_t follows) - { - idx += 4; // skip 4 content bytes - return get_from_vector<uint32_t>(v, current_idx); - } - - case 0x1b: // Unsigned integer (eight-byte uint64_t follows) - { - idx += 8; // skip 8 content bytes - return get_from_vector<uint64_t>(v, current_idx); - } - - // Negative integer -1-0x00..-1-0x17 (-1..-24) - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2a: - case 0x2b: - case 0x2c: - case 0x2d: - case 0x2e: - case 0x2f: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - { - return static_cast<int8_t>(0x20 - 1 - v[current_idx]); - } - - case 0x38: // Negative integer (one-byte uint8_t follows) - { - idx += 1; // skip content byte - // must be uint8_t ! - return static_cast<number_integer_t>(-1) - get_from_vector<uint8_t>(v, current_idx); - } - - case 0x39: // Negative integer -1-n (two-byte uint16_t follows) - { - idx += 2; // skip 2 content bytes - return static_cast<number_integer_t>(-1) - get_from_vector<uint16_t>(v, current_idx); - } - - case 0x3a: // Negative integer -1-n (four-byte uint32_t follows) - { - idx += 4; // skip 4 content bytes - return static_cast<number_integer_t>(-1) - get_from_vector<uint32_t>(v, current_idx); - } - - case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows) - { - idx += 8; // skip 8 content bytes - return static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(get_from_vector<uint64_t>(v, current_idx)); - } - - // UTF-8 string (0x00..0x17 bytes follow) - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6a: - case 0x6b: - case 0x6c: - case 0x6d: - case 0x6e: - case 0x6f: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - { - const auto len = static_cast<size_t>(v[current_idx] - 0x60); - const size_t offset = current_idx + 1; - idx += len; // skip content bytes - check_length(v.size(), len, offset); - return std::string(reinterpret_cast<const char*>(v.data()) + offset, len); - } - - case 0x78: // UTF-8 string (one-byte uint8_t for n follows) - { - const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx)); - const size_t offset = current_idx + 2; - idx += len + 1; // skip size byte + content bytes - check_length(v.size(), len, offset); - return std::string(reinterpret_cast<const char*>(v.data()) + offset, len); - } - - case 0x79: // UTF-8 string (two-byte uint16_t for n follow) - { - const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx)); - const size_t offset = current_idx + 3; - idx += len + 2; // skip 2 size bytes + content bytes - check_length(v.size(), len, offset); - return std::string(reinterpret_cast<const char*>(v.data()) + offset, len); - } - - case 0x7a: // UTF-8 string (four-byte uint32_t for n follow) - { - const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx)); - const size_t offset = current_idx + 5; - idx += len + 4; // skip 4 size bytes + content bytes - check_length(v.size(), len, offset); - return std::string(reinterpret_cast<const char*>(v.data()) + offset, len); - } - - case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow) - { - const auto len = static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx)); - const size_t offset = current_idx + 9; - idx += len + 8; // skip 8 size bytes + content bytes - check_length(v.size(), len, offset); - return std::string(reinterpret_cast<const char*>(v.data()) + offset, len); - } - - case 0x7f: // UTF-8 string (indefinite length) - { - std::string result; - while (v.at(idx) != 0xff) - { - string_t s = from_cbor_internal(v, idx); - result += s; - } - // skip break byte (0xFF) - idx += 1; - return result; - } - - // array (0x00..0x17 data items follow) - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8a: - case 0x8b: - case 0x8c: - case 0x8d: - case 0x8e: - case 0x8f: - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - { - basic_json result = value_t::array; - const auto len = static_cast<size_t>(v[current_idx] - 0x80); - for (size_t i = 0; i < len; ++i) - { - result.push_back(from_cbor_internal(v, idx)); - } - return result; - } - - case 0x98: // array (one-byte uint8_t for n follows) - { - basic_json result = value_t::array; - const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx)); - idx += 1; // skip 1 size byte - for (size_t i = 0; i < len; ++i) - { - result.push_back(from_cbor_internal(v, idx)); - } - return result; - } - - case 0x99: // array (two-byte uint16_t for n follow) - { - basic_json result = value_t::array; - const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx)); - idx += 2; // skip 4 size bytes - for (size_t i = 0; i < len; ++i) - { - result.push_back(from_cbor_internal(v, idx)); - } - return result; - } - - case 0x9a: // array (four-byte uint32_t for n follow) - { - basic_json result = value_t::array; - const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx)); - idx += 4; // skip 4 size bytes - for (size_t i = 0; i < len; ++i) - { - result.push_back(from_cbor_internal(v, idx)); - } - return result; - } - - case 0x9b: // array (eight-byte uint64_t for n follow) - { - basic_json result = value_t::array; - const auto len = static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx)); - idx += 8; // skip 8 size bytes - for (size_t i = 0; i < len; ++i) - { - result.push_back(from_cbor_internal(v, idx)); - } - return result; - } - - case 0x9f: // array (indefinite length) - { - basic_json result = value_t::array; - while (v.at(idx) != 0xff) - { - result.push_back(from_cbor_internal(v, idx)); - } - // skip break byte (0xFF) - idx += 1; - return result; - } - - // map (0x00..0x17 pairs of data items follow) - case 0xa0: - case 0xa1: - case 0xa2: - case 0xa3: - case 0xa4: - case 0xa5: - case 0xa6: - case 0xa7: - case 0xa8: - case 0xa9: - case 0xaa: - case 0xab: - case 0xac: - case 0xad: - case 0xae: - case 0xaf: - case 0xb0: - case 0xb1: - case 0xb2: - case 0xb3: - case 0xb4: - case 0xb5: - case 0xb6: - case 0xb7: - { - basic_json result = value_t::object; - const auto len = static_cast<size_t>(v[current_idx] - 0xa0); - for (size_t i = 0; i < len; ++i) - { - std::string key = from_cbor_internal(v, idx); - result[key] = from_cbor_internal(v, idx); - } - return result; - } - - case 0xb8: // map (one-byte uint8_t for n follows) - { - basic_json result = value_t::object; - const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx)); - idx += 1; // skip 1 size byte - for (size_t i = 0; i < len; ++i) - { - std::string key = from_cbor_internal(v, idx); - result[key] = from_cbor_internal(v, idx); - } - return result; - } - - case 0xb9: // map (two-byte uint16_t for n follow) - { - basic_json result = value_t::object; - const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx)); - idx += 2; // skip 2 size bytes - for (size_t i = 0; i < len; ++i) - { - std::string key = from_cbor_internal(v, idx); - result[key] = from_cbor_internal(v, idx); - } - return result; - } - - case 0xba: // map (four-byte uint32_t for n follow) - { - basic_json result = value_t::object; - const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx)); - idx += 4; // skip 4 size bytes - for (size_t i = 0; i < len; ++i) - { - std::string key = from_cbor_internal(v, idx); - result[key] = from_cbor_internal(v, idx); - } - return result; - } - - case 0xbb: // map (eight-byte uint64_t for n follow) - { - basic_json result = value_t::object; - const auto len = static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx)); - idx += 8; // skip 8 size bytes - for (size_t i = 0; i < len; ++i) - { - std::string key = from_cbor_internal(v, idx); - result[key] = from_cbor_internal(v, idx); - } - return result; - } - - case 0xbf: // map (indefinite length) - { - basic_json result = value_t::object; - while (v.at(idx) != 0xff) - { - std::string key = from_cbor_internal(v, idx); - result[key] = from_cbor_internal(v, idx); - } - // skip break byte (0xFF) - idx += 1; - return result; - } - - case 0xf4: // false - { - return false; - } - - case 0xf5: // true - { - return true; - } - - case 0xf6: // null - { - return value_t::null; - } - - case 0xf9: // Half-Precision Float (two-byte IEEE 754) - { - idx += 2; // skip two content bytes - - // code from RFC 7049, Appendix D, Figure 3: - // As half-precision floating-point numbers were only added to - // IEEE 754 in 2008, today's programming platforms often still - // only have limited support for them. It is very easy to - // include at least decoding support for them even without such - // support. An example of a small decoder for half-precision - // floating-point numbers in the C language is shown in Fig. 3. - const int half = (v.at(current_idx + 1) << 8) + v.at(current_idx + 2); - const int exp = (half >> 10) & 0x1f; - const int mant = half & 0x3ff; - double val; - if (exp == 0) - { - val = std::ldexp(mant, -24); - } - else if (exp != 31) - { - val = std::ldexp(mant + 1024, exp - 25); - } - else - { - val = mant == 0 - ? std::numeric_limits<double>::infinity() - : std::numeric_limits<double>::quiet_NaN(); - } - return (half & 0x8000) != 0 ? -val : val; - } - - case 0xfa: // Single-Precision Float (four-byte IEEE 754) - { - // copy bytes in reverse order into the float variable - float res; - for (size_t byte = 0; byte < sizeof(float); ++byte) - { - reinterpret_cast<uint8_t*>(&res)[sizeof(float) - byte - 1] = v.at(current_idx + 1 + byte); - } - idx += sizeof(float); // skip content bytes - return res; - } - - case 0xfb: // Double-Precision Float (eight-byte IEEE 754) - { - // copy bytes in reverse order into the double variable - double res; - for (size_t byte = 0; byte < sizeof(double); ++byte) - { - reinterpret_cast<uint8_t*>(&res)[sizeof(double) - byte - 1] = v.at(current_idx + 1 + byte); - } - idx += sizeof(double); // skip content bytes - return res; - } - - default: // anything else (0xFF is handled inside the other types) - { - JSON_THROW(std::invalid_argument("error parsing a CBOR @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx])))); - } - } - } - - public: - /*! - @brief create a MessagePack serialization of a given JSON value - - Serializes a given JSON value @a j to a byte vector using the MessagePack - serialization format. MessagePack is a binary serialization format which - aims to be more compact than JSON itself, yet more efficient to parse. - - @param[in] j JSON value to serialize - @return MessagePack serialization as byte vector - - @complexity Linear in the size of the JSON value @a j. - - @liveexample{The example shows the serialization of a JSON value to a byte - vector in MessagePack format.,to_msgpack} - - @sa http://msgpack.org - @sa @ref from_msgpack(const std::vector<uint8_t>&, const size_t) for the - analogous deserialization - @sa @ref to_cbor(const basic_json& for the related CBOR format - - @since version 2.0.9 - */ - static std::vector<uint8_t> to_msgpack(const basic_json& j) - { - std::vector<uint8_t> result; - to_msgpack_internal(j, result); - return result; - } - - /*! - @brief create a JSON value from a byte vector in MessagePack format - - Deserializes a given byte vector @a v to a JSON value using the MessagePack - serialization format. - - @param[in] v a byte vector in MessagePack format - @param[in] start_index the index to start reading from @a v (0 by default) - @return deserialized JSON value - - @throw std::invalid_argument if unsupported features from MessagePack were - used in the given vector @a v or if the input is not valid MessagePack - @throw std::out_of_range if the given vector ends prematurely - - @complexity Linear in the size of the byte vector @a v. - - @liveexample{The example shows the deserialization of a byte vector in - MessagePack format to a JSON value.,from_msgpack} - - @sa http://msgpack.org - @sa @ref to_msgpack(const basic_json&) for the analogous serialization - @sa @ref from_cbor(const std::vector<uint8_t>&, const size_t) for the - related CBOR format - - @since version 2.0.9, parameter @a start_index since 2.1.1 - */ - static basic_json from_msgpack(const std::vector<uint8_t>& v, - const size_t start_index = 0) - { - size_t i = start_index; - return from_msgpack_internal(v, i); - } - - /*! - @brief create a MessagePack serialization of a given JSON value - - Serializes a given JSON value @a j to a byte vector using the CBOR (Concise - Binary Object Representation) serialization format. CBOR is a binary - serialization format which aims to be more compact than JSON itself, yet - more efficient to parse. - - @param[in] j JSON value to serialize - @return MessagePack serialization as byte vector - - @complexity Linear in the size of the JSON value @a j. - - @liveexample{The example shows the serialization of a JSON value to a byte - vector in CBOR format.,to_cbor} - - @sa http://cbor.io - @sa @ref from_cbor(const std::vector<uint8_t>&, const size_t) for the - analogous deserialization - @sa @ref to_msgpack(const basic_json& for the related MessagePack format - - @since version 2.0.9 - */ - static std::vector<uint8_t> to_cbor(const basic_json& j) - { - std::vector<uint8_t> result; - to_cbor_internal(j, result); - return result; - } - - /*! - @brief create a JSON value from a byte vector in CBOR format - - Deserializes a given byte vector @a v to a JSON value using the CBOR - (Concise Binary Object Representation) serialization format. - - @param[in] v a byte vector in CBOR format - @param[in] start_index the index to start reading from @a v (0 by default) - @return deserialized JSON value - - @throw std::invalid_argument if unsupported features from CBOR were used in - the given vector @a v or if the input is not valid MessagePack - @throw std::out_of_range if the given vector ends prematurely - - @complexity Linear in the size of the byte vector @a v. - - @liveexample{The example shows the deserialization of a byte vector in CBOR - format to a JSON value.,from_cbor} - - @sa http://cbor.io - @sa @ref to_cbor(const basic_json&) for the analogous serialization - @sa @ref from_msgpack(const std::vector<uint8_t>&, const size_t) for the - related MessagePack format - - @since version 2.0.9, parameter @a start_index since 2.1.1 - */ - static basic_json from_cbor(const std::vector<uint8_t>& v, - const size_t start_index = 0) - { - size_t i = start_index; - return from_cbor_internal(v, i); - } - - /// @} - - /////////////////////////// - // convenience functions // - /////////////////////////// - - /*! - @brief return the type as string - - Returns the type name as string to be used in error messages - usually to - indicate that a function was called on a wrong JSON type. - - @return basically a string representation of a the @a m_type member - - @complexity Constant. - - @liveexample{The following code exemplifies `type_name()` for all JSON - types.,type_name} - - @since version 1.0.0, public since 2.1.0 - */ - std::string type_name() const - { - { - switch (m_type) - { - case value_t::null: - return "null"; - case value_t::object: - return "object"; - case value_t::array: - return "array"; - case value_t::string: - return "string"; - case value_t::boolean: - return "boolean"; - case value_t::discarded: - return "discarded"; - default: - return "number"; - } - } - } - - private: - /*! - @brief calculates the extra space to escape a JSON string - - @param[in] s the string to escape - @return the number of characters required to escape string @a s - - @complexity Linear in the length of string @a s. - */ - static std::size_t extra_space(const string_t& s) noexcept - { - return std::accumulate(s.begin(), s.end(), size_t{}, - [](size_t res, typename string_t::value_type c) - { - switch (c) - { - case '"': - case '\\': - case '\b': - case '\f': - case '\n': - case '\r': - case '\t': - { - // from c (1 byte) to \x (2 bytes) - return res + 1; - } - - default: - { - if (c >= 0x00 and c <= 0x1f) - { - // from c (1 byte) to \uxxxx (6 bytes) - return res + 5; - } - - return res; - } - } - }); - } - - /*! - @brief escape a string - - Escape a string by replacing certain special characters by a sequence of - an escape character (backslash) and another character and other control - characters by a sequence of "\u" followed by a four-digit hex - representation. - - @param[in] s the string to escape - @return the escaped string - - @complexity Linear in the length of string @a s. - */ - static string_t escape_string(const string_t& s) - { - const auto space = extra_space(s); - if (space == 0) - { - return s; - } - - // create a result string of necessary size - string_t result(s.size() + space, '\\'); - std::size_t pos = 0; - - for (const auto& c : s) - { - switch (c) - { - // quotation mark (0x22) - case '"': - { - result[pos + 1] = '"'; - pos += 2; - break; - } - - // reverse solidus (0x5c) - case '\\': - { - // nothing to change - pos += 2; - break; - } - - // backspace (0x08) - case '\b': - { - result[pos + 1] = 'b'; - pos += 2; - break; - } - - // formfeed (0x0c) - case '\f': - { - result[pos + 1] = 'f'; - pos += 2; - break; - } - - // newline (0x0a) - case '\n': - { - result[pos + 1] = 'n'; - pos += 2; - break; - } - - // carriage return (0x0d) - case '\r': - { - result[pos + 1] = 'r'; - pos += 2; - break; - } - - // horizontal tab (0x09) - case '\t': - { - result[pos + 1] = 't'; - pos += 2; - break; - } - - default: - { - if (c >= 0x00 and c <= 0x1f) - { - // convert a number 0..15 to its hex representation - // (0..f) - static const char hexify[16] = - { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' - }; - - // print character c as \uxxxx - for (const char m : - { 'u', '0', '0', hexify[c >> 4], hexify[c & 0x0f] - }) - { - result[++pos] = m; - } - - ++pos; - } - else - { - // all other characters are added as-is - result[pos++] = c; - } - break; - } - } - } - - return result; - } - - - /*! - @brief locale-independent serialization for built-in arithmetic types - */ - struct numtostr - { - public: - template<typename NumberType> - numtostr(NumberType value) - { - x_write(value, std::is_integral<NumberType>()); - } - - const char* c_str() const - { - return m_buf.data(); - } - - private: - /// a (hopefully) large enough character buffer - std::array < char, 64 > m_buf{{}}; - - template<typename NumberType> - void x_write(NumberType x, /*is_integral=*/std::true_type) - { - // special case for "0" - if (x == 0) - { - m_buf[0] = '0'; - return; - } - - const bool is_negative = x < 0; - size_t i = 0; - - // spare 1 byte for '\0' - while (x != 0 and i < m_buf.size() - 1) - { - const auto digit = std::labs(static_cast<long>(x % 10)); - m_buf[i++] = static_cast<char>('0' + digit); - x /= 10; - } - - // make sure the number has been processed completely - assert(x == 0); - - if (is_negative) - { - // make sure there is capacity for the '-' - assert(i < m_buf.size() - 2); - m_buf[i++] = '-'; - } - - std::reverse(m_buf.begin(), m_buf.begin() + i); - } - - template<typename NumberType> - void x_write(NumberType x, /*is_integral=*/std::false_type) - { - // special case for 0.0 and -0.0 - if (x == 0) - { - size_t i = 0; - if (std::signbit(x)) - { - m_buf[i++] = '-'; - } - m_buf[i++] = '0'; - m_buf[i++] = '.'; - m_buf[i] = '0'; - return; - } - - // get number of digits for a text -> float -> text round-trip - static constexpr auto d = std::numeric_limits<NumberType>::digits10; - - // the actual conversion - const auto written_bytes = snprintf(m_buf.data(), m_buf.size(), "%.*g", d, x); - - // negative value indicates an error - assert(written_bytes > 0); - // check if buffer was large enough - assert(static_cast<size_t>(written_bytes) < m_buf.size()); - - // read information from locale - const auto loc = localeconv(); - assert(loc != nullptr); - const char thousands_sep = !loc->thousands_sep ? '\0' - : loc->thousands_sep[0]; - - const char decimal_point = !loc->decimal_point ? '\0' - : loc->decimal_point[0]; - - // erase thousands separator - if (thousands_sep != '\0') - { - const auto end = std::remove(m_buf.begin(), m_buf.begin() + written_bytes, thousands_sep); - std::fill(end, m_buf.end(), '\0'); - } - - // convert decimal point to '.' - if (decimal_point != '\0' and decimal_point != '.') - { - for (auto& c : m_buf) - { - if (c == decimal_point) - { - c = '.'; - break; - } - } - } - - // determine if need to append ".0" - size_t i = 0; - bool value_is_int_like = true; - for (i = 0; i < m_buf.size(); ++i) - { - // break when end of number is reached - if (m_buf[i] == '\0') - { - break; - } - - // check if we find non-int character - value_is_int_like = value_is_int_like and m_buf[i] != '.' and - m_buf[i] != 'e' and m_buf[i] != 'E'; - } - - if (value_is_int_like) - { - // there must be 2 bytes left for ".0" - assert((i + 2) < m_buf.size()); - // we write to the end of the number - assert(m_buf[i] == '\0'); - assert(m_buf[i - 1] != '\0'); - - // add ".0" - m_buf[i] = '.'; - m_buf[i + 1] = '0'; - - // the resulting string is properly terminated - assert(m_buf[i + 2] == '\0'); - } - } - }; - - - /*! - @brief internal implementation of the serialization function - - This function is called by the public member function dump and organizes - the serialization internally. The indentation level is propagated as - additional parameter. In case of arrays and objects, the function is - called recursively. Note that - - - strings and object keys are escaped using `escape_string()` - - integer numbers are converted implicitly via `operator<<` - - floating-point numbers are converted to a string using `"%g"` format - - @param[out] o stream to write to - @param[in] pretty_print whether the output shall be pretty-printed - @param[in] indent_step the indent level - @param[in] current_indent the current indent level (only used internally) - */ - void dump(std::ostream& o, - const bool pretty_print, - const unsigned int indent_step, - const unsigned int current_indent = 0) const - { - // variable to hold indentation for recursive calls - unsigned int new_indent = current_indent; - - switch (m_type) - { - case value_t::object: - { - if (m_value.object->empty()) - { - o << "{}"; - return; - } - - o << "{"; - - // increase indentation - if (pretty_print) - { - new_indent += indent_step; - o << "\n"; - } - - for (auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i) - { - if (i != m_value.object->cbegin()) - { - o << (pretty_print ? ",\n" : ","); - } - o << string_t(new_indent, ' ') << "\"" - << escape_string(i->first) << "\":" - << (pretty_print ? " " : ""); - i->second.dump(o, pretty_print, indent_step, new_indent); - } - - // decrease indentation - if (pretty_print) - { - new_indent -= indent_step; - o << "\n"; - } - - o << string_t(new_indent, ' ') + "}"; - return; - } - - case value_t::array: - { - if (m_value.array->empty()) - { - o << "[]"; - return; - } - - o << "["; - - // increase indentation - if (pretty_print) - { - new_indent += indent_step; - o << "\n"; - } - - for (auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i) - { - if (i != m_value.array->cbegin()) - { - o << (pretty_print ? ",\n" : ","); - } - o << string_t(new_indent, ' '); - i->dump(o, pretty_print, indent_step, new_indent); - } - - // decrease indentation - if (pretty_print) - { - new_indent -= indent_step; - o << "\n"; - } - - o << string_t(new_indent, ' ') << "]"; - return; - } - - case value_t::string: - { - o << string_t("\"") << escape_string(*m_value.string) << "\""; - return; - } - - case value_t::boolean: - { - o << (m_value.boolean ? "true" : "false"); - return; - } - - case value_t::number_integer: - { - o << numtostr(m_value.number_integer).c_str(); - return; - } - - case value_t::number_unsigned: - { - o << numtostr(m_value.number_unsigned).c_str(); - return; - } - - case value_t::number_float: - { - o << numtostr(m_value.number_float).c_str(); - return; - } - - case value_t::discarded: - { - o << "<discarded>"; - return; - } - - case value_t::null: - { - o << "null"; - return; - } - } - } - - private: - ////////////////////// - // member variables // - ////////////////////// - - /// the type of the current element - value_t m_type = value_t::null; - - /// the value of the current element - json_value m_value = {}; - - - private: - /////////////// - // iterators // - /////////////// - - /*! - @brief an iterator for primitive JSON types - - This class models an iterator for primitive JSON types (boolean, number, - string). It's only purpose is to allow the iterator/const_iterator classes - to "iterate" over primitive values. Internally, the iterator is modeled by - a `difference_type` variable. Value begin_value (`0`) models the begin, - end_value (`1`) models past the end. - */ - class primitive_iterator_t - { - public: - - difference_type get_value() const noexcept - { - return m_it; - } - /// set iterator to a defined beginning - void set_begin() noexcept - { - m_it = begin_value; - } - - /// set iterator to a defined past the end - void set_end() noexcept - { - m_it = end_value; - } - - /// return whether the iterator can be dereferenced - constexpr bool is_begin() const noexcept - { - return (m_it == begin_value); - } - - /// return whether the iterator is at end - constexpr bool is_end() const noexcept - { - return (m_it == end_value); - } - - friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it == rhs.m_it; - } - - friend constexpr bool operator!=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return !(lhs == rhs); - } - - friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it < rhs.m_it; - } - - friend constexpr bool operator<=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it <= rhs.m_it; - } - - friend constexpr bool operator>(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it > rhs.m_it; - } - - friend constexpr bool operator>=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it >= rhs.m_it; - } - - primitive_iterator_t operator+(difference_type i) - { - auto result = *this; - result += i; - return result; - } - - friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it - rhs.m_it; - } - - friend std::ostream& operator<<(std::ostream& os, primitive_iterator_t it) - { - return os << it.m_it; - } - - primitive_iterator_t& operator++() - { - ++m_it; - return *this; - } - - primitive_iterator_t operator++(int) - { - auto result = *this; - m_it++; - return result; - } - - primitive_iterator_t& operator--() - { - --m_it; - return *this; - } - - primitive_iterator_t operator--(int) - { - auto result = *this; - m_it--; - return result; - } - - primitive_iterator_t& operator+=(difference_type n) - { - m_it += n; - return *this; - } - - primitive_iterator_t& operator-=(difference_type n) - { - m_it -= n; - return *this; - } - - private: - static constexpr difference_type begin_value = 0; - static constexpr difference_type end_value = begin_value + 1; - - /// iterator as signed integer type - difference_type m_it = std::numeric_limits<std::ptrdiff_t>::denorm_min(); - }; - - /*! - @brief an iterator value - - @note This structure could easily be a union, but MSVC currently does not - allow unions members with complex constructors, see - https://github.com/nlohmann/json/pull/105. - */ - struct internal_iterator - { - /// iterator for JSON objects - typename object_t::iterator object_iterator; - /// iterator for JSON arrays - typename array_t::iterator array_iterator; - /// generic iterator for all other types - primitive_iterator_t primitive_iterator; - - /// create an uninitialized internal_iterator - internal_iterator() noexcept - : object_iterator(), array_iterator(), primitive_iterator() - {} - }; - - /// proxy class for the iterator_wrapper functions - template<typename IteratorType> - class iteration_proxy - { - private: - /// helper class for iteration - class iteration_proxy_internal - { - private: - /// the iterator - IteratorType anchor; - /// an index for arrays (used to create key names) - size_t array_index = 0; - - public: - explicit iteration_proxy_internal(IteratorType it) noexcept - : anchor(it) - {} - - /// dereference operator (needed for range-based for) - iteration_proxy_internal& operator*() - { - return *this; - } - - /// increment operator (needed for range-based for) - iteration_proxy_internal& operator++() - { - ++anchor; - ++array_index; - - return *this; - } - - /// inequality operator (needed for range-based for) - bool operator!= (const iteration_proxy_internal& o) const - { - return anchor != o.anchor; - } - - /// return key of the iterator - typename basic_json::string_t key() const - { - assert(anchor.m_object != nullptr); - - switch (anchor.m_object->type()) - { - // use integer array index as key - case value_t::array: - { - return std::to_string(array_index); - } - - // use key from the object - case value_t::object: - { - return anchor.key(); - } - - // use an empty key for all primitive types - default: - { - return ""; - } - } - } - - /// return value of the iterator - typename IteratorType::reference value() const - { - return anchor.value(); - } - }; - - /// the container to iterate - typename IteratorType::reference container; - - public: - /// construct iteration proxy from a container - explicit iteration_proxy(typename IteratorType::reference cont) - : container(cont) - {} - - /// return iterator begin (needed for range-based for) - iteration_proxy_internal begin() noexcept - { - return iteration_proxy_internal(container.begin()); - } - - /// return iterator end (needed for range-based for) - iteration_proxy_internal end() noexcept - { - return iteration_proxy_internal(container.end()); - } - }; - - public: - /*! - @brief a template for a random access iterator for the @ref basic_json class - - This class implements a both iterators (iterator and const_iterator) for the - @ref basic_json class. - - @note An iterator is called *initialized* when a pointer to a JSON value - has been set (e.g., by a constructor or a copy assignment). If the - iterator is default-constructed, it is *uninitialized* and most - methods are undefined. **The library uses assertions to detect calls - on uninitialized iterators.** - - @requirement The class satisfies the following concept requirements: - - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): - The iterator that can be moved to point (forward and backward) to any - element in constant time. - - @since version 1.0.0, simplified in version 2.0.9 - */ - template<typename U> - class iter_impl : public std::iterator<std::random_access_iterator_tag, U> - { - /// allow basic_json to access private members - friend class basic_json; - - // make sure U is basic_json or const basic_json - static_assert(std::is_same<U, basic_json>::value - or std::is_same<U, const basic_json>::value, - "iter_impl only accepts (const) basic_json"); - - public: - /// the type of the values when the iterator is dereferenced - using value_type = typename basic_json::value_type; - /// a type to represent differences between iterators - using difference_type = typename basic_json::difference_type; - /// defines a pointer to the type iterated over (value_type) - using pointer = typename std::conditional<std::is_const<U>::value, - typename basic_json::const_pointer, - typename basic_json::pointer>::type; - /// defines a reference to the type iterated over (value_type) - using reference = typename std::conditional<std::is_const<U>::value, - typename basic_json::const_reference, - typename basic_json::reference>::type; - /// the category of the iterator - using iterator_category = std::bidirectional_iterator_tag; - - /// default constructor - iter_impl() = default; - - /*! - @brief constructor for a given JSON instance - @param[in] object pointer to a JSON object for this iterator - @pre object != nullptr - @post The iterator is initialized; i.e. `m_object != nullptr`. - */ - explicit iter_impl(pointer object) noexcept - : m_object(object) - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - m_it.object_iterator = typename object_t::iterator(); - break; - } - - case basic_json::value_t::array: - { - m_it.array_iterator = typename array_t::iterator(); - break; - } - - default: - { - m_it.primitive_iterator = primitive_iterator_t(); - break; - } - } - } - - /* - Use operator `const_iterator` instead of `const_iterator(const iterator& - other) noexcept` to avoid two class definitions for @ref iterator and - @ref const_iterator. - - This function is only called if this class is an @ref iterator. If this - class is a @ref const_iterator this function is not called. - */ - operator const_iterator() const - { - const_iterator ret; - - if (m_object) - { - ret.m_object = m_object; - ret.m_it = m_it; - } - - return ret; - } - - /*! - @brief copy constructor - @param[in] other iterator to copy from - @note It is not checked whether @a other is initialized. - */ - iter_impl(const iter_impl& other) noexcept - : m_object(other.m_object), m_it(other.m_it) - {} - - /*! - @brief copy assignment - @param[in,out] other iterator to copy from - @note It is not checked whether @a other is initialized. - */ - iter_impl& operator=(iter_impl other) noexcept( - std::is_nothrow_move_constructible<pointer>::value and - std::is_nothrow_move_assignable<pointer>::value and - std::is_nothrow_move_constructible<internal_iterator>::value and - std::is_nothrow_move_assignable<internal_iterator>::value - ) - { - std::swap(m_object, other.m_object); - std::swap(m_it, other.m_it); - return *this; - } - - private: - /*! - @brief set the iterator to the first value - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - void set_begin() noexcept - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - m_it.object_iterator = m_object->m_value.object->begin(); - break; - } - - case basic_json::value_t::array: - { - m_it.array_iterator = m_object->m_value.array->begin(); - break; - } - - case basic_json::value_t::null: - { - // set to end so begin()==end() is true: null is empty - m_it.primitive_iterator.set_end(); - break; - } - - default: - { - m_it.primitive_iterator.set_begin(); - break; - } - } - } - - /*! - @brief set the iterator past the last value - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - void set_end() noexcept - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - m_it.object_iterator = m_object->m_value.object->end(); - break; - } - - case basic_json::value_t::array: - { - m_it.array_iterator = m_object->m_value.array->end(); - break; - } - - default: - { - m_it.primitive_iterator.set_end(); - break; - } - } - } - - public: - /*! - @brief return a reference to the value pointed to by the iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference operator*() const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - assert(m_it.object_iterator != m_object->m_value.object->end()); - return m_it.object_iterator->second; - } - - case basic_json::value_t::array: - { - assert(m_it.array_iterator != m_object->m_value.array->end()); - return *m_it.array_iterator; - } - - case basic_json::value_t::null: - { - JSON_THROW(std::out_of_range("cannot get value")); - } - - default: - { - if (m_it.primitive_iterator.is_begin()) - { - return *m_object; - } - - JSON_THROW(std::out_of_range("cannot get value")); - } - } - } - - /*! - @brief dereference the iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - pointer operator->() const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - assert(m_it.object_iterator != m_object->m_value.object->end()); - return &(m_it.object_iterator->second); - } - - case basic_json::value_t::array: - { - assert(m_it.array_iterator != m_object->m_value.array->end()); - return &*m_it.array_iterator; - } - - default: - { - if (m_it.primitive_iterator.is_begin()) - { - return m_object; - } - - JSON_THROW(std::out_of_range("cannot get value")); - } - } - } - - /*! - @brief post-increment (it++) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator++(int) - { - auto result = *this; - ++(*this); - return result; - } - - /*! - @brief pre-increment (++it) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator++() - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - std::advance(m_it.object_iterator, 1); - break; - } - - case basic_json::value_t::array: - { - std::advance(m_it.array_iterator, 1); - break; - } - - default: - { - ++m_it.primitive_iterator; - break; - } - } - - return *this; - } - - /*! - @brief post-decrement (it--) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator--(int) - { - auto result = *this; - --(*this); - return result; - } - - /*! - @brief pre-decrement (--it) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator--() - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - std::advance(m_it.object_iterator, -1); - break; - } - - case basic_json::value_t::array: - { - std::advance(m_it.array_iterator, -1); - break; - } - - default: - { - --m_it.primitive_iterator; - break; - } - } - - return *this; - } - - /*! - @brief comparison: equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator==(const iter_impl& other) const - { - // if objects are not the same, the comparison is undefined - if (m_object != other.m_object) - { - JSON_THROW(std::domain_error("cannot compare iterators of different containers")); - } - - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - return (m_it.object_iterator == other.m_it.object_iterator); - } - - case basic_json::value_t::array: - { - return (m_it.array_iterator == other.m_it.array_iterator); - } - - default: - { - return (m_it.primitive_iterator == other.m_it.primitive_iterator); - } - } - } - - /*! - @brief comparison: not equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator!=(const iter_impl& other) const - { - return not operator==(other); - } - - /*! - @brief comparison: smaller - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator<(const iter_impl& other) const - { - // if objects are not the same, the comparison is undefined - if (m_object != other.m_object) - { - JSON_THROW(std::domain_error("cannot compare iterators of different containers")); - } - - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - JSON_THROW(std::domain_error("cannot compare order of object iterators")); - } - - case basic_json::value_t::array: - { - return (m_it.array_iterator < other.m_it.array_iterator); - } - - default: - { - return (m_it.primitive_iterator < other.m_it.primitive_iterator); - } - } - } - - /*! - @brief comparison: less than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator<=(const iter_impl& other) const - { - return not other.operator < (*this); - } - - /*! - @brief comparison: greater than - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator>(const iter_impl& other) const - { - return not operator<=(other); - } - - /*! - @brief comparison: greater than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator>=(const iter_impl& other) const - { - return not operator<(other); - } - - /*! - @brief add to iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator+=(difference_type i) - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - JSON_THROW(std::domain_error("cannot use offsets with object iterators")); - } - - case basic_json::value_t::array: - { - std::advance(m_it.array_iterator, i); - break; - } - - default: - { - m_it.primitive_iterator += i; - break; - } - } - - return *this; - } - - /*! - @brief subtract from iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator-=(difference_type i) - { - return operator+=(-i); - } - - /*! - @brief add to iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator+(difference_type i) - { - auto result = *this; - result += i; - return result; - } - - /*! - @brief subtract from iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator-(difference_type i) - { - auto result = *this; - result -= i; - return result; - } - - /*! - @brief return difference - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - difference_type operator-(const iter_impl& other) const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - JSON_THROW(std::domain_error("cannot use offsets with object iterators")); - } - - case basic_json::value_t::array: - { - return m_it.array_iterator - other.m_it.array_iterator; - } - - default: - { - return m_it.primitive_iterator - other.m_it.primitive_iterator; - } - } - } - - /*! - @brief access to successor - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference operator[](difference_type n) const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - JSON_THROW(std::domain_error("cannot use operator[] for object iterators")); - } - - case basic_json::value_t::array: - { - return *std::next(m_it.array_iterator, n); - } - - case basic_json::value_t::null: - { - JSON_THROW(std::out_of_range("cannot get value")); - } - - default: - { - if (m_it.primitive_iterator.get_value() == -n) - { - return *m_object; - } - - JSON_THROW(std::out_of_range("cannot get value")); - } - } - } - - /*! - @brief return the key of an object iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - typename object_t::key_type key() const - { - assert(m_object != nullptr); - - if (m_object->is_object()) - { - return m_it.object_iterator->first; - } - - JSON_THROW(std::domain_error("cannot use key() for non-object iterators")); - } - - /*! - @brief return the value of an iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference value() const - { - return operator*(); - } - - private: - /// associated JSON instance - pointer m_object = nullptr; - /// the actual iterator of the associated instance - internal_iterator m_it = internal_iterator(); - }; - - /*! - @brief a template for a reverse iterator class - - @tparam Base the base iterator type to reverse. Valid types are @ref - iterator (to create @ref reverse_iterator) and @ref const_iterator (to - create @ref const_reverse_iterator). - - @requirement The class satisfies the following concept requirements: - - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): - The iterator that can be moved to point (forward and backward) to any - element in constant time. - - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): - It is possible to write to the pointed-to element (only if @a Base is - @ref iterator). - - @since version 1.0.0 - */ - template<typename Base> - class json_reverse_iterator : public std::reverse_iterator<Base> - { - public: - /// shortcut to the reverse iterator adaptor - using base_iterator = std::reverse_iterator<Base>; - /// the reference type for the pointed-to element - using reference = typename Base::reference; - - /// create reverse iterator from iterator - json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept - : base_iterator(it) - {} - - /// create reverse iterator from base class - json_reverse_iterator(const base_iterator& it) noexcept - : base_iterator(it) - {} - - /// post-increment (it++) - json_reverse_iterator operator++(int) - { - return base_iterator::operator++(1); - } - - /// pre-increment (++it) - json_reverse_iterator& operator++() - { - base_iterator::operator++(); - return *this; - } - - /// post-decrement (it--) - json_reverse_iterator operator--(int) - { - return base_iterator::operator--(1); - } - - /// pre-decrement (--it) - json_reverse_iterator& operator--() - { - base_iterator::operator--(); - return *this; - } - - /// add to iterator - json_reverse_iterator& operator+=(difference_type i) - { - base_iterator::operator+=(i); - return *this; - } - - /// add to iterator - json_reverse_iterator operator+(difference_type i) const - { - auto result = *this; - result += i; - return result; - } - - /// subtract from iterator - json_reverse_iterator operator-(difference_type i) const - { - auto result = *this; - result -= i; - return result; - } - - /// return difference - difference_type operator-(const json_reverse_iterator& other) const - { - return this->base() - other.base(); - } - - /// access to successor - reference operator[](difference_type n) const - { - return *(this->operator+(n)); - } - - /// return the key of an object iterator - typename object_t::key_type key() const - { - auto it = --this->base(); - return it.key(); - } - - /// return the value of an iterator - reference value() const - { - auto it = --this->base(); - return it.operator * (); - } - }; - - - private: - ////////////////////// - // lexer and parser // - ////////////////////// - - /*! - @brief lexical analysis - - This class organizes the lexical analysis during JSON deserialization. The - core of it is a scanner generated by [re2c](http://re2c.org) that - processes a buffer and recognizes tokens according to RFC 7159. - */ - class lexer - { - public: - /// token types for the parser - enum class token_type - { - uninitialized, ///< indicating the scanner is uninitialized - literal_true, ///< the `true` literal - literal_false, ///< the `false` literal - literal_null, ///< the `null` literal - value_string, ///< a string -- use get_string() for actual value - value_unsigned, ///< an unsigned integer -- use get_number() for actual value - value_integer, ///< a signed integer -- use get_number() for actual value - value_float, ///< an floating point number -- use get_number() for actual value - begin_array, ///< the character for array begin `[` - begin_object, ///< the character for object begin `{` - end_array, ///< the character for array end `]` - end_object, ///< the character for object end `}` - name_separator, ///< the name separator `:` - value_separator, ///< the value separator `,` - parse_error, ///< indicating a parse error - end_of_input ///< indicating the end of the input buffer - }; - - /// the char type to use in the lexer - using lexer_char_t = unsigned char; - - /// a lexer from a buffer with given length - lexer(const lexer_char_t* buff, const size_t len) noexcept - : m_content(buff) - { - assert(m_content != nullptr); - m_start = m_cursor = m_content; - m_limit = m_content + len; - } - - /// a lexer from an input stream - explicit lexer(std::istream& s) - : m_stream(&s), m_line_buffer() - { - // immediately abort if stream is erroneous - if (s.fail()) - { - JSON_THROW(std::invalid_argument("stream error")); - } - - // fill buffer - fill_line_buffer(); - - // skip UTF-8 byte-order mark - if (m_line_buffer.size() >= 3 and m_line_buffer.substr(0, 3) == "\xEF\xBB\xBF") - { - m_line_buffer[0] = ' '; - m_line_buffer[1] = ' '; - m_line_buffer[2] = ' '; - } - } - - // switch off unwanted functions (due to pointer members) - lexer() = delete; - lexer(const lexer&) = delete; - lexer operator=(const lexer&) = delete; - - /*! - @brief create a string from one or two Unicode code points - - There are two cases: (1) @a codepoint1 is in the Basic Multilingual - Plane (U+0000 through U+FFFF) and @a codepoint2 is 0, or (2) - @a codepoint1 and @a codepoint2 are a UTF-16 surrogate pair to - represent a code point above U+FFFF. - - @param[in] codepoint1 the code point (can be high surrogate) - @param[in] codepoint2 the code point (can be low surrogate or 0) - - @return string representation of the code point; the length of the - result string is between 1 and 4 characters. - - @throw std::out_of_range if code point is > 0x10ffff; example: `"code - points above 0x10FFFF are invalid"` - @throw std::invalid_argument if the low surrogate is invalid; example: - `""missing or wrong low surrogate""` - - @complexity Constant. - - @see <http://en.wikipedia.org/wiki/UTF-8#Sample_code> - */ - static string_t to_unicode(const std::size_t codepoint1, - const std::size_t codepoint2 = 0) - { - // calculate the code point from the given code points - std::size_t codepoint = codepoint1; - - // check if codepoint1 is a high surrogate - if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF) - { - // check if codepoint2 is a low surrogate - if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF) - { - codepoint = - // high surrogate occupies the most significant 22 bits - (codepoint1 << 10) - // low surrogate occupies the least significant 15 bits - + codepoint2 - // there is still the 0xD800, 0xDC00 and 0x10000 noise - // in the result so we have to subtract with: - // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 - - 0x35FDC00; - } - else - { - JSON_THROW(std::invalid_argument("missing or wrong low surrogate")); - } - } - - string_t result; - - if (codepoint < 0x80) - { - // 1-byte characters: 0xxxxxxx (ASCII) - result.append(1, static_cast<typename string_t::value_type>(codepoint)); - } - else if (codepoint <= 0x7ff) - { - // 2-byte characters: 110xxxxx 10xxxxxx - result.append(1, static_cast<typename string_t::value_type>(0xC0 | ((codepoint >> 6) & 0x1F))); - result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F))); - } - else if (codepoint <= 0xffff) - { - // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx - result.append(1, static_cast<typename string_t::value_type>(0xE0 | ((codepoint >> 12) & 0x0F))); - result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F))); - result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F))); - } - else if (codepoint <= 0x10ffff) - { - // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - result.append(1, static_cast<typename string_t::value_type>(0xF0 | ((codepoint >> 18) & 0x07))); - result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 12) & 0x3F))); - result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F))); - result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F))); - } - else - { - JSON_THROW(std::out_of_range("code points above 0x10FFFF are invalid")); - } - - return result; - } - - /// return name of values of type token_type (only used for errors) - static std::string token_type_name(const token_type t) - { - switch (t) - { - case token_type::uninitialized: - return "<uninitialized>"; - case token_type::literal_true: - return "true literal"; - case token_type::literal_false: - return "false literal"; - case token_type::literal_null: - return "null literal"; - case token_type::value_string: - return "string literal"; - case lexer::token_type::value_unsigned: - case lexer::token_type::value_integer: - case lexer::token_type::value_float: - return "number literal"; - case token_type::begin_array: - return "'['"; - case token_type::begin_object: - return "'{'"; - case token_type::end_array: - return "']'"; - case token_type::end_object: - return "'}'"; - case token_type::name_separator: - return "':'"; - case token_type::value_separator: - return "','"; - case token_type::parse_error: - return "<parse error>"; - case token_type::end_of_input: - return "end of input"; - default: - { - // catch non-enum values - return "unknown token"; // LCOV_EXCL_LINE - } - } - } - - /*! - This function implements a scanner for JSON. It is specified using - regular expressions that try to follow RFC 7159 as close as possible. - These regular expressions are then translated into a minimized - deterministic finite automaton (DFA) by the tool - [re2c](http://re2c.org). As a result, the translated code for this - function consists of a large block of code with `goto` jumps. - - @return the class of the next token read from the buffer - - @complexity Linear in the length of the input.\n - - Proposition: The loop below will always terminate for finite input.\n - - Proof (by contradiction): Assume a finite input. To loop forever, the - loop must never hit code with a `break` statement. The only code - snippets without a `break` statement are the continue statements for - whitespace and byte-order-marks. To loop forever, the input must be an - infinite sequence of whitespace or byte-order-marks. This contradicts - the assumption of finite input, q.e.d. - */ - token_type scan() - { - while (true) - { - // pointer for backtracking information - m_marker = nullptr; - - // remember the begin of the token - m_start = m_cursor; - assert(m_start != nullptr); - - - { - lexer_char_t yych; - unsigned int yyaccept = 0; - static const unsigned char yybm[] = - { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 32, 32, 0, 0, 32, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 160, 128, 0, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 0, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - }; - if ((m_limit - m_cursor) < 5) - { - fill_line_buffer(5); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yybm[0 + yych] & 32) - { - goto basic_json_parser_6; - } - if (yych <= '[') - { - if (yych <= '-') - { - if (yych <= '"') - { - if (yych <= 0x00) - { - goto basic_json_parser_2; - } - if (yych <= '!') - { - goto basic_json_parser_4; - } - goto basic_json_parser_9; - } - else - { - if (yych <= '+') - { - goto basic_json_parser_4; - } - if (yych <= ',') - { - goto basic_json_parser_10; - } - goto basic_json_parser_12; - } - } - else - { - if (yych <= '9') - { - if (yych <= '/') - { - goto basic_json_parser_4; - } - if (yych <= '0') - { - goto basic_json_parser_13; - } - goto basic_json_parser_15; - } - else - { - if (yych <= ':') - { - goto basic_json_parser_17; - } - if (yych <= 'Z') - { - goto basic_json_parser_4; - } - goto basic_json_parser_19; - } - } - } - else - { - if (yych <= 'n') - { - if (yych <= 'e') - { - if (yych == ']') - { - goto basic_json_parser_21; - } - goto basic_json_parser_4; - } - else - { - if (yych <= 'f') - { - goto basic_json_parser_23; - } - if (yych <= 'm') - { - goto basic_json_parser_4; - } - goto basic_json_parser_24; - } - } - else - { - if (yych <= 'z') - { - if (yych == 't') - { - goto basic_json_parser_25; - } - goto basic_json_parser_4; - } - else - { - if (yych <= '{') - { - goto basic_json_parser_26; - } - if (yych == '}') - { - goto basic_json_parser_28; - } - goto basic_json_parser_4; - } - } - } -basic_json_parser_2: - ++m_cursor; - { - last_token_type = token_type::end_of_input; - break; - } -basic_json_parser_4: - ++m_cursor; -basic_json_parser_5: - { - last_token_type = token_type::parse_error; - break; - } -basic_json_parser_6: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yybm[0 + yych] & 32) - { - goto basic_json_parser_6; - } - { - continue; - } -basic_json_parser_9: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych <= 0x1F) - { - goto basic_json_parser_5; - } - if (yych <= 0x7F) - { - goto basic_json_parser_31; - } - if (yych <= 0xC1) - { - goto basic_json_parser_5; - } - if (yych <= 0xF4) - { - goto basic_json_parser_31; - } - goto basic_json_parser_5; -basic_json_parser_10: - ++m_cursor; - { - last_token_type = token_type::value_separator; - break; - } -basic_json_parser_12: - yych = *++m_cursor; - if (yych <= '/') - { - goto basic_json_parser_5; - } - if (yych <= '0') - { - goto basic_json_parser_43; - } - if (yych <= '9') - { - goto basic_json_parser_45; - } - goto basic_json_parser_5; -basic_json_parser_13: - yyaccept = 1; - yych = *(m_marker = ++m_cursor); - if (yych <= '9') - { - if (yych == '.') - { - goto basic_json_parser_47; - } - if (yych >= '0') - { - goto basic_json_parser_48; - } - } - else - { - if (yych <= 'E') - { - if (yych >= 'E') - { - goto basic_json_parser_51; - } - } - else - { - if (yych == 'e') - { - goto basic_json_parser_51; - } - } - } -basic_json_parser_14: - { - last_token_type = token_type::value_unsigned; - break; - } -basic_json_parser_15: - yyaccept = 1; - m_marker = ++m_cursor; - if ((m_limit - m_cursor) < 3) - { - fill_line_buffer(3); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yybm[0 + yych] & 64) - { - goto basic_json_parser_15; - } - if (yych <= 'D') - { - if (yych == '.') - { - goto basic_json_parser_47; - } - goto basic_json_parser_14; - } - else - { - if (yych <= 'E') - { - goto basic_json_parser_51; - } - if (yych == 'e') - { - goto basic_json_parser_51; - } - goto basic_json_parser_14; - } -basic_json_parser_17: - ++m_cursor; - { - last_token_type = token_type::name_separator; - break; - } -basic_json_parser_19: - ++m_cursor; - { - last_token_type = token_type::begin_array; - break; - } -basic_json_parser_21: - ++m_cursor; - { - last_token_type = token_type::end_array; - break; - } -basic_json_parser_23: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych == 'a') - { - goto basic_json_parser_52; - } - goto basic_json_parser_5; -basic_json_parser_24: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych == 'u') - { - goto basic_json_parser_53; - } - goto basic_json_parser_5; -basic_json_parser_25: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych == 'r') - { - goto basic_json_parser_54; - } - goto basic_json_parser_5; -basic_json_parser_26: - ++m_cursor; - { - last_token_type = token_type::begin_object; - break; - } -basic_json_parser_28: - ++m_cursor; - { - last_token_type = token_type::end_object; - break; - } -basic_json_parser_30: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; -basic_json_parser_31: - if (yybm[0 + yych] & 128) - { - goto basic_json_parser_30; - } - if (yych <= 0xE0) - { - if (yych <= '\\') - { - if (yych <= 0x1F) - { - goto basic_json_parser_32; - } - if (yych <= '"') - { - goto basic_json_parser_33; - } - goto basic_json_parser_35; - } - else - { - if (yych <= 0xC1) - { - goto basic_json_parser_32; - } - if (yych <= 0xDF) - { - goto basic_json_parser_36; - } - goto basic_json_parser_37; - } - } - else - { - if (yych <= 0xEF) - { - if (yych == 0xED) - { - goto basic_json_parser_39; - } - goto basic_json_parser_38; - } - else - { - if (yych <= 0xF0) - { - goto basic_json_parser_40; - } - if (yych <= 0xF3) - { - goto basic_json_parser_41; - } - if (yych <= 0xF4) - { - goto basic_json_parser_42; - } - } - } -basic_json_parser_32: - m_cursor = m_marker; - if (yyaccept <= 1) - { - if (yyaccept == 0) - { - goto basic_json_parser_5; - } - else - { - goto basic_json_parser_14; - } - } - else - { - if (yyaccept == 2) - { - goto basic_json_parser_44; - } - else - { - goto basic_json_parser_58; - } - } -basic_json_parser_33: - ++m_cursor; - { - last_token_type = token_type::value_string; - break; - } -basic_json_parser_35: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= 'e') - { - if (yych <= '/') - { - if (yych == '"') - { - goto basic_json_parser_30; - } - if (yych <= '.') - { - goto basic_json_parser_32; - } - goto basic_json_parser_30; - } - else - { - if (yych <= '\\') - { - if (yych <= '[') - { - goto basic_json_parser_32; - } - goto basic_json_parser_30; - } - else - { - if (yych == 'b') - { - goto basic_json_parser_30; - } - goto basic_json_parser_32; - } - } - } - else - { - if (yych <= 'q') - { - if (yych <= 'f') - { - goto basic_json_parser_30; - } - if (yych == 'n') - { - goto basic_json_parser_30; - } - goto basic_json_parser_32; - } - else - { - if (yych <= 's') - { - if (yych <= 'r') - { - goto basic_json_parser_30; - } - goto basic_json_parser_32; - } - else - { - if (yych <= 't') - { - goto basic_json_parser_30; - } - if (yych <= 'u') - { - goto basic_json_parser_55; - } - goto basic_json_parser_32; - } - } - } -basic_json_parser_36: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= 0x7F) - { - goto basic_json_parser_32; - } - if (yych <= 0xBF) - { - goto basic_json_parser_30; - } - goto basic_json_parser_32; -basic_json_parser_37: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= 0x9F) - { - goto basic_json_parser_32; - } - if (yych <= 0xBF) - { - goto basic_json_parser_36; - } - goto basic_json_parser_32; -basic_json_parser_38: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= 0x7F) - { - goto basic_json_parser_32; - } - if (yych <= 0xBF) - { - goto basic_json_parser_36; - } - goto basic_json_parser_32; -basic_json_parser_39: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= 0x7F) - { - goto basic_json_parser_32; - } - if (yych <= 0x9F) - { - goto basic_json_parser_36; - } - goto basic_json_parser_32; -basic_json_parser_40: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= 0x8F) - { - goto basic_json_parser_32; - } - if (yych <= 0xBF) - { - goto basic_json_parser_38; - } - goto basic_json_parser_32; -basic_json_parser_41: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= 0x7F) - { - goto basic_json_parser_32; - } - if (yych <= 0xBF) - { - goto basic_json_parser_38; - } - goto basic_json_parser_32; -basic_json_parser_42: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= 0x7F) - { - goto basic_json_parser_32; - } - if (yych <= 0x8F) - { - goto basic_json_parser_38; - } - goto basic_json_parser_32; -basic_json_parser_43: - yyaccept = 2; - yych = *(m_marker = ++m_cursor); - if (yych <= '9') - { - if (yych == '.') - { - goto basic_json_parser_47; - } - if (yych >= '0') - { - goto basic_json_parser_48; - } - } - else - { - if (yych <= 'E') - { - if (yych >= 'E') - { - goto basic_json_parser_51; - } - } - else - { - if (yych == 'e') - { - goto basic_json_parser_51; - } - } - } -basic_json_parser_44: - { - last_token_type = token_type::value_integer; - break; - } -basic_json_parser_45: - yyaccept = 2; - m_marker = ++m_cursor; - if ((m_limit - m_cursor) < 3) - { - fill_line_buffer(3); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= '9') - { - if (yych == '.') - { - goto basic_json_parser_47; - } - if (yych <= '/') - { - goto basic_json_parser_44; - } - goto basic_json_parser_45; - } - else - { - if (yych <= 'E') - { - if (yych <= 'D') - { - goto basic_json_parser_44; - } - goto basic_json_parser_51; - } - else - { - if (yych == 'e') - { - goto basic_json_parser_51; - } - goto basic_json_parser_44; - } - } -basic_json_parser_47: - yych = *++m_cursor; - if (yych <= '/') - { - goto basic_json_parser_32; - } - if (yych <= '9') - { - goto basic_json_parser_56; - } - goto basic_json_parser_32; -basic_json_parser_48: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= '/') - { - goto basic_json_parser_50; - } - if (yych <= '9') - { - goto basic_json_parser_48; - } -basic_json_parser_50: - { - last_token_type = token_type::parse_error; - break; - } -basic_json_parser_51: - yych = *++m_cursor; - if (yych <= ',') - { - if (yych == '+') - { - goto basic_json_parser_59; - } - goto basic_json_parser_32; - } - else - { - if (yych <= '-') - { - goto basic_json_parser_59; - } - if (yych <= '/') - { - goto basic_json_parser_32; - } - if (yych <= '9') - { - goto basic_json_parser_60; - } - goto basic_json_parser_32; - } -basic_json_parser_52: - yych = *++m_cursor; - if (yych == 'l') - { - goto basic_json_parser_62; - } - goto basic_json_parser_32; -basic_json_parser_53: - yych = *++m_cursor; - if (yych == 'l') - { - goto basic_json_parser_63; - } - goto basic_json_parser_32; -basic_json_parser_54: - yych = *++m_cursor; - if (yych == 'u') - { - goto basic_json_parser_64; - } - goto basic_json_parser_32; -basic_json_parser_55: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= '@') - { - if (yych <= '/') - { - goto basic_json_parser_32; - } - if (yych <= '9') - { - goto basic_json_parser_65; - } - goto basic_json_parser_32; - } - else - { - if (yych <= 'F') - { - goto basic_json_parser_65; - } - if (yych <= '`') - { - goto basic_json_parser_32; - } - if (yych <= 'f') - { - goto basic_json_parser_65; - } - goto basic_json_parser_32; - } -basic_json_parser_56: - yyaccept = 3; - m_marker = ++m_cursor; - if ((m_limit - m_cursor) < 3) - { - fill_line_buffer(3); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= 'D') - { - if (yych <= '/') - { - goto basic_json_parser_58; - } - if (yych <= '9') - { - goto basic_json_parser_56; - } - } - else - { - if (yych <= 'E') - { - goto basic_json_parser_51; - } - if (yych == 'e') - { - goto basic_json_parser_51; - } - } -basic_json_parser_58: - { - last_token_type = token_type::value_float; - break; - } -basic_json_parser_59: - yych = *++m_cursor; - if (yych <= '/') - { - goto basic_json_parser_32; - } - if (yych >= ':') - { - goto basic_json_parser_32; - } -basic_json_parser_60: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= '/') - { - goto basic_json_parser_58; - } - if (yych <= '9') - { - goto basic_json_parser_60; - } - goto basic_json_parser_58; -basic_json_parser_62: - yych = *++m_cursor; - if (yych == 's') - { - goto basic_json_parser_66; - } - goto basic_json_parser_32; -basic_json_parser_63: - yych = *++m_cursor; - if (yych == 'l') - { - goto basic_json_parser_67; - } - goto basic_json_parser_32; -basic_json_parser_64: - yych = *++m_cursor; - if (yych == 'e') - { - goto basic_json_parser_69; - } - goto basic_json_parser_32; -basic_json_parser_65: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= '@') - { - if (yych <= '/') - { - goto basic_json_parser_32; - } - if (yych <= '9') - { - goto basic_json_parser_71; - } - goto basic_json_parser_32; - } - else - { - if (yych <= 'F') - { - goto basic_json_parser_71; - } - if (yych <= '`') - { - goto basic_json_parser_32; - } - if (yych <= 'f') - { - goto basic_json_parser_71; - } - goto basic_json_parser_32; - } -basic_json_parser_66: - yych = *++m_cursor; - if (yych == 'e') - { - goto basic_json_parser_72; - } - goto basic_json_parser_32; -basic_json_parser_67: - ++m_cursor; - { - last_token_type = token_type::literal_null; - break; - } -basic_json_parser_69: - ++m_cursor; - { - last_token_type = token_type::literal_true; - break; - } -basic_json_parser_71: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= '@') - { - if (yych <= '/') - { - goto basic_json_parser_32; - } - if (yych <= '9') - { - goto basic_json_parser_74; - } - goto basic_json_parser_32; - } - else - { - if (yych <= 'F') - { - goto basic_json_parser_74; - } - if (yych <= '`') - { - goto basic_json_parser_32; - } - if (yych <= 'f') - { - goto basic_json_parser_74; - } - goto basic_json_parser_32; - } -basic_json_parser_72: - ++m_cursor; - { - last_token_type = token_type::literal_false; - break; - } -basic_json_parser_74: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= '@') - { - if (yych <= '/') - { - goto basic_json_parser_32; - } - if (yych <= '9') - { - goto basic_json_parser_30; - } - goto basic_json_parser_32; - } - else - { - if (yych <= 'F') - { - goto basic_json_parser_30; - } - if (yych <= '`') - { - goto basic_json_parser_32; - } - if (yych <= 'f') - { - goto basic_json_parser_30; - } - goto basic_json_parser_32; - } - } - - } - - return last_token_type; - } - - /*! - @brief append data from the stream to the line buffer - - This function is called by the scan() function when the end of the - buffer (`m_limit`) is reached and the `m_cursor` pointer cannot be - incremented without leaving the limits of the line buffer. Note re2c - decides when to call this function. - - If the lexer reads from contiguous storage, there is no trailing null - byte. Therefore, this function must make sure to add these padding - null bytes. - - If the lexer reads from an input stream, this function reads the next - line of the input. - - @pre - p p p p p p u u u u u x . . . . . . - ^ ^ ^ ^ - m_content m_start | m_limit - m_cursor - - @post - u u u u u x x x x x x x . . . . . . - ^ ^ ^ - | m_cursor m_limit - m_start - m_content - */ - void fill_line_buffer(size_t n = 0) - { - // if line buffer is used, m_content points to its data - assert(m_line_buffer.empty() - or m_content == reinterpret_cast<const lexer_char_t*>(m_line_buffer.data())); - - // if line buffer is used, m_limit is set past the end of its data - assert(m_line_buffer.empty() - or m_limit == m_content + m_line_buffer.size()); - - // pointer relationships - assert(m_content <= m_start); - assert(m_start <= m_cursor); - assert(m_cursor <= m_limit); - assert(m_marker == nullptr or m_marker <= m_limit); - - // number of processed characters (p) - const auto num_processed_chars = static_cast<size_t>(m_start - m_content); - // offset for m_marker wrt. to m_start - const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start; - // number of unprocessed characters (u) - const auto offset_cursor = m_cursor - m_start; - - // no stream is used or end of file is reached - if (m_stream == nullptr or m_stream->eof()) - { - // m_start may or may not be pointing into m_line_buffer at - // this point. We trust the standard library to do the right - // thing. See http://stackoverflow.com/q/28142011/266378 - m_line_buffer.assign(m_start, m_limit); - - // append n characters to make sure that there is sufficient - // space between m_cursor and m_limit - m_line_buffer.append(1, '\x00'); - if (n > 0) - { - m_line_buffer.append(n - 1, '\x01'); - } - } - else - { - // delete processed characters from line buffer - m_line_buffer.erase(0, num_processed_chars); - // read next line from input stream - m_line_buffer_tmp.clear(); - std::getline(*m_stream, m_line_buffer_tmp, '\n'); - - // add line with newline symbol to the line buffer - m_line_buffer += m_line_buffer_tmp; - m_line_buffer.push_back('\n'); - } - - // set pointers - m_content = reinterpret_cast<const lexer_char_t*>(m_line_buffer.data()); - assert(m_content != nullptr); - m_start = m_content; - m_marker = m_start + offset_marker; - m_cursor = m_start + offset_cursor; - m_limit = m_start + m_line_buffer.size(); - } - - /// return string representation of last read token - string_t get_token_string() const - { - assert(m_start != nullptr); - return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start), - static_cast<size_t>(m_cursor - m_start)); - } - - /*! - @brief return string value for string tokens - - The function iterates the characters between the opening and closing - quotes of the string value. The complete string is the range - [m_start,m_cursor). Consequently, we iterate from m_start+1 to - m_cursor-1. - - We differentiate two cases: - - 1. Escaped characters. In this case, a new character is constructed - according to the nature of the escape. Some escapes create new - characters (e.g., `"\\n"` is replaced by `"\n"`), some are copied - as is (e.g., `"\\\\"`). Furthermore, Unicode escapes of the shape - `"\\uxxxx"` need special care. In this case, to_unicode takes care - of the construction of the values. - 2. Unescaped characters are copied as is. - - @pre `m_cursor - m_start >= 2`, meaning the length of the last token - is at least 2 bytes which is trivially true for any string (which - consists of at least two quotes). - - " c1 c2 c3 ... " - ^ ^ - m_start m_cursor - - @complexity Linear in the length of the string.\n - - Lemma: The loop body will always terminate.\n - - Proof (by contradiction): Assume the loop body does not terminate. As - the loop body does not contain another loop, one of the called - functions must never return. The called functions are `std::strtoul` - and to_unicode. Neither function can loop forever, so the loop body - will never loop forever which contradicts the assumption that the loop - body does not terminate, q.e.d.\n - - Lemma: The loop condition for the for loop is eventually false.\n - - Proof (by contradiction): Assume the loop does not terminate. Due to - the above lemma, this can only be due to a tautological loop - condition; that is, the loop condition i < m_cursor - 1 must always be - true. Let x be the change of i for any loop iteration. Then - m_start + 1 + x < m_cursor - 1 must hold to loop indefinitely. This - can be rephrased to m_cursor - m_start - 2 > x. With the - precondition, we x <= 0, meaning that the loop condition holds - indefinitely if i is always decreased. However, observe that the value - of i is strictly increasing with each iteration, as it is incremented - by 1 in the iteration expression and never decremented inside the loop - body. Hence, the loop condition will eventually be false which - contradicts the assumption that the loop condition is a tautology, - q.e.d. - - @return string value of current token without opening and closing - quotes - @throw std::out_of_range if to_unicode fails - */ - string_t get_string() const - { - assert(m_cursor - m_start >= 2); - - string_t result; - result.reserve(static_cast<size_t>(m_cursor - m_start - 2)); - - // iterate the result between the quotes - for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i) - { - // find next escape character - auto e = std::find(i, m_cursor - 1, '\\'); - if (e != i) - { - // see https://github.com/nlohmann/json/issues/365#issuecomment-262874705 - for (auto k = i; k < e; k++) - { - result.push_back(static_cast<typename string_t::value_type>(*k)); - } - i = e - 1; // -1 because of ++i - } - else - { - // processing escaped character - // read next character - ++i; - - switch (*i) - { - // the default escapes - case 't': - { - result += "\t"; - break; - } - case 'b': - { - result += "\b"; - break; - } - case 'f': - { - result += "\f"; - break; - } - case 'n': - { - result += "\n"; - break; - } - case 'r': - { - result += "\r"; - break; - } - case '\\': - { - result += "\\"; - break; - } - case '/': - { - result += "/"; - break; - } - case '"': - { - result += "\""; - break; - } - - // unicode - case 'u': - { - // get code xxxx from uxxxx - auto codepoint = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>(i + 1), - 4).c_str(), nullptr, 16); - - // check if codepoint is a high surrogate - if (codepoint >= 0xD800 and codepoint <= 0xDBFF) - { - // make sure there is a subsequent unicode - if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u') - { - JSON_THROW(std::invalid_argument("missing low surrogate")); - } - - // get code yyyy from uxxxx\uyyyy - auto codepoint2 = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer> - (i + 7), 4).c_str(), nullptr, 16); - result += to_unicode(codepoint, codepoint2); - // skip the next 10 characters (xxxx\uyyyy) - i += 10; - } - else if (codepoint >= 0xDC00 and codepoint <= 0xDFFF) - { - // we found a lone low surrogate - JSON_THROW(std::invalid_argument("missing high surrogate")); - } - else - { - // add unicode character(s) - result += to_unicode(codepoint); - // skip the next four characters (xxxx) - i += 4; - } - break; - } - } - } - } - - return result; - } - - - /*! - @brief parse string into a built-in arithmetic type as if the current - locale is POSIX. - - @note in floating-point case strtod may parse past the token's end - - this is not an error - - @note any leading blanks are not handled - */ - struct strtonum - { - public: - strtonum(const char* start, const char* end) - : m_start(start), m_end(end) - {} - - /*! - @return true iff parsed successfully as number of type T - - @param[in,out] val shall contain parsed value, or undefined value - if could not parse - */ - template<typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value>::type> - bool to(T& val) const - { - return parse(val, std::is_integral<T>()); - } - - private: - const char* const m_start = nullptr; - const char* const m_end = nullptr; - - // floating-point conversion - - // overloaded wrappers for strtod/strtof/strtold - // that will be called from parse<floating_point_t> - static void strtof(float& f, const char* str, char** endptr) - { - f = std::strtof(str, endptr); - } - - static void strtof(double& f, const char* str, char** endptr) - { - f = std::strtod(str, endptr); - } - - static void strtof(long double& f, const char* str, char** endptr) - { - f = std::strtold(str, endptr); - } - - template<typename T> - bool parse(T& value, /*is_integral=*/std::false_type) const - { - // replace decimal separator with locale-specific version, - // when necessary; data will point to either the original - // string, or buf, or tempstr containing the fixed string. - std::string tempstr; - std::array<char, 64> buf; - const size_t len = static_cast<size_t>(m_end - m_start); - - // lexer will reject empty numbers - assert(len > 0); - - // since dealing with strtod family of functions, we're - // getting the decimal point char from the C locale facilities - // instead of C++'s numpunct facet of the current std::locale - const auto loc = localeconv(); - assert(loc != nullptr); - const char decimal_point_char = (loc->decimal_point == nullptr) ? '.' : loc->decimal_point[0]; - - const char* data = m_start; - - if (decimal_point_char != '.') - { - const size_t ds_pos = static_cast<size_t>(std::find(m_start, m_end, '.') - m_start); - - if (ds_pos != len) - { - // copy the data into the local buffer or tempstr, if - // buffer is too small; replace decimal separator, and - // update data to point to the modified bytes - if ((len + 1) < buf.size()) - { - std::copy(m_start, m_end, buf.begin()); - buf[len] = 0; - buf[ds_pos] = decimal_point_char; - data = buf.data(); - } - else - { - tempstr.assign(m_start, m_end); - tempstr[ds_pos] = decimal_point_char; - data = tempstr.c_str(); - } - } - } - - char* endptr = nullptr; - value = 0; - // this calls appropriate overload depending on T - strtof(value, data, &endptr); - - // parsing was successful iff strtof parsed exactly the number - // of characters determined by the lexer (len) - const bool ok = (endptr == (data + len)); - - if (ok and (value == static_cast<T>(0.0)) and (*data == '-')) - { - // some implementations forget to negate the zero - value = -0.0; - } - - return ok; - } - - // integral conversion - - signed long long parse_integral(char** endptr, /*is_signed*/std::true_type) const - { - return std::strtoll(m_start, endptr, 10); - } - - unsigned long long parse_integral(char** endptr, /*is_signed*/std::false_type) const - { - return std::strtoull(m_start, endptr, 10); - } - - template<typename T> - bool parse(T& value, /*is_integral=*/std::true_type) const - { - char* endptr = nullptr; - errno = 0; // these are thread-local - const auto x = parse_integral(&endptr, std::is_signed<T>()); - - // called right overload? - static_assert(std::is_signed<T>() == std::is_signed<decltype(x)>(), ""); - - value = static_cast<T>(x); - - return (x == static_cast<decltype(x)>(value)) // x fits into destination T - and (x < 0) == (value < 0) // preserved sign - //and ((x != 0) or is_integral()) // strto[u]ll did nto fail - and (errno == 0) // strto[u]ll did not overflow - and (m_start < m_end) // token was not empty - and (endptr == m_end); // parsed entire token exactly - } - }; - - /*! - @brief return number value for number tokens - - This function translates the last token into the most appropriate - number type (either integer, unsigned integer or floating point), - which is passed back to the caller via the result parameter. - - integral numbers that don't fit into the the range of the respective - type are parsed as number_float_t - - floating-point values do not satisfy std::isfinite predicate - are converted to value_t::null - - throws if the entire string [m_start .. m_cursor) cannot be - interpreted as a number - - @param[out] result @ref basic_json object to receive the number. - @param[in] token the type of the number token - */ - bool get_number(basic_json& result, const token_type token) const - { - assert(m_start != nullptr); - assert(m_start < m_cursor); - assert((token == token_type::value_unsigned) or - (token == token_type::value_integer) or - (token == token_type::value_float)); - - strtonum num_converter(reinterpret_cast<const char*>(m_start), - reinterpret_cast<const char*>(m_cursor)); - - switch (token) - { - case lexer::token_type::value_unsigned: - { - number_unsigned_t val; - if (num_converter.to(val)) - { - // parsing successful - result.m_type = value_t::number_unsigned; - result.m_value = val; - return true; - } - break; - } - - case lexer::token_type::value_integer: - { - number_integer_t val; - if (num_converter.to(val)) - { - // parsing successful - result.m_type = value_t::number_integer; - result.m_value = val; - return true; - } - break; - } - - default: - { - break; - } - } - - // parse float (either explicitly or because a previous conversion - // failed) - number_float_t val; - if (num_converter.to(val)) - { - // parsing successful - result.m_type = value_t::number_float; - result.m_value = val; - - // replace infinity and NAN by null - if (not std::isfinite(result.m_value.number_float)) - { - result.m_type = value_t::null; - result.m_value = basic_json::json_value(); - } - - return true; - } - - // couldn't parse number in any format - return false; - } - - private: - /// optional input stream - std::istream* m_stream = nullptr; - /// line buffer buffer for m_stream - string_t m_line_buffer {}; - /// used for filling m_line_buffer - string_t m_line_buffer_tmp {}; - /// the buffer pointer - const lexer_char_t* m_content = nullptr; - /// pointer to the beginning of the current symbol - const lexer_char_t* m_start = nullptr; - /// pointer for backtracking information - const lexer_char_t* m_marker = nullptr; - /// pointer to the current symbol - const lexer_char_t* m_cursor = nullptr; - /// pointer to the end of the buffer - const lexer_char_t* m_limit = nullptr; - /// the last token type - token_type last_token_type = token_type::end_of_input; - }; - - /*! - @brief syntax analysis - - This class implements a recursive decent parser. - */ - class parser - { - public: - /// a parser reading from a string literal - parser(const char* buff, const parser_callback_t cb = nullptr) - : callback(cb), - m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(buff), std::strlen(buff)) - {} - - /// a parser reading from an input stream - parser(std::istream& is, const parser_callback_t cb = nullptr) - : callback(cb), m_lexer(is) - {} - - /// a parser reading from an iterator range with contiguous storage - template<class IteratorType, typename std::enable_if< - std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value - , int>::type - = 0> - parser(IteratorType first, IteratorType last, const parser_callback_t cb = nullptr) - : callback(cb), - m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(&(*first)), - static_cast<size_t>(std::distance(first, last))) - {} - - /// public parser interface - basic_json parse() - { - // read first token - get_token(); - - basic_json result = parse_internal(true); - result.assert_invariant(); - - expect(lexer::token_type::end_of_input); - - // return parser result and replace it with null in case the - // top-level value was discarded by the callback function - return result.is_discarded() ? basic_json() : std::move(result); - } - - private: - /// the actual parser - basic_json parse_internal(bool keep) - { - auto result = basic_json(value_t::discarded); - - switch (last_token) - { - case lexer::token_type::begin_object: - { - if (keep and (not callback - or ((keep = callback(depth++, parse_event_t::object_start, result)) != 0))) - { - // explicitly set result to object to cope with {} - result.m_type = value_t::object; - result.m_value = value_t::object; - } - - // read next token - get_token(); - - // closing } -> we are done - if (last_token == lexer::token_type::end_object) - { - get_token(); - if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) - { - result = basic_json(value_t::discarded); - } - return result; - } - - // no comma is expected here - unexpect(lexer::token_type::value_separator); - - // otherwise: parse key-value pairs - do - { - // ugly, but could be fixed with loop reorganization - if (last_token == lexer::token_type::value_separator) - { - get_token(); - } - - // store key - expect(lexer::token_type::value_string); - const auto key = m_lexer.get_string(); - - bool keep_tag = false; - if (keep) - { - if (callback) - { - basic_json k(key); - keep_tag = callback(depth, parse_event_t::key, k); - } - else - { - keep_tag = true; - } - } - - // parse separator (:) - get_token(); - expect(lexer::token_type::name_separator); - - // parse and add value - get_token(); - auto value = parse_internal(keep); - if (keep and keep_tag and not value.is_discarded()) - { - result[key] = std::move(value); - } - } - while (last_token == lexer::token_type::value_separator); - - // closing } - expect(lexer::token_type::end_object); - get_token(); - if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) - { - result = basic_json(value_t::discarded); - } - - return result; - } - - case lexer::token_type::begin_array: - { - if (keep and (not callback - or ((keep = callback(depth++, parse_event_t::array_start, result)) != 0))) - { - // explicitly set result to object to cope with [] - result.m_type = value_t::array; - result.m_value = value_t::array; - } - - // read next token - get_token(); - - // closing ] -> we are done - if (last_token == lexer::token_type::end_array) - { - get_token(); - if (callback and not callback(--depth, parse_event_t::array_end, result)) - { - result = basic_json(value_t::discarded); - } - return result; - } - - // no comma is expected here - unexpect(lexer::token_type::value_separator); - - // otherwise: parse values - do - { - // ugly, but could be fixed with loop reorganization - if (last_token == lexer::token_type::value_separator) - { - get_token(); - } - - // parse value - auto value = parse_internal(keep); - if (keep and not value.is_discarded()) - { - result.push_back(std::move(value)); - } - } - while (last_token == lexer::token_type::value_separator); - - // closing ] - expect(lexer::token_type::end_array); - get_token(); - if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) - { - result = basic_json(value_t::discarded); - } - - return result; - } - - case lexer::token_type::literal_null: - { - get_token(); - result.m_type = value_t::null; - break; - } - - case lexer::token_type::value_string: - { - const auto s = m_lexer.get_string(); - get_token(); - result = basic_json(s); - break; - } - - case lexer::token_type::literal_true: - { - get_token(); - result.m_type = value_t::boolean; - result.m_value = true; - break; - } - - case lexer::token_type::literal_false: - { - get_token(); - result.m_type = value_t::boolean; - result.m_value = false; - break; - } - - case lexer::token_type::value_unsigned: - case lexer::token_type::value_integer: - case lexer::token_type::value_float: - { - m_lexer.get_number(result, last_token); - get_token(); - break; - } - - default: - { - // the last token was unexpected - unexpect(last_token); - } - } - - if (keep and callback and not callback(depth, parse_event_t::value, result)) - { - result = basic_json(value_t::discarded); - } - return result; - } - - /// get next token from lexer - typename lexer::token_type get_token() - { - last_token = m_lexer.scan(); - return last_token; - } - - void expect(typename lexer::token_type t) const - { - if (t != last_token) - { - std::string error_msg = "parse error - unexpected "; - error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + - "'") : - lexer::token_type_name(last_token)); - error_msg += "; expected " + lexer::token_type_name(t); - JSON_THROW(std::invalid_argument(error_msg)); - } - } - - void unexpect(typename lexer::token_type t) const - { - if (t == last_token) - { - std::string error_msg = "parse error - unexpected "; - error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + - "'") : - lexer::token_type_name(last_token)); - JSON_THROW(std::invalid_argument(error_msg)); - } - } - - private: - /// current level of recursion - int depth = 0; - /// callback function - const parser_callback_t callback = nullptr; - /// the type of the last read token - typename lexer::token_type last_token = lexer::token_type::uninitialized; - /// the lexer - lexer m_lexer; - }; - - public: - /*! - @brief JSON Pointer - - A JSON pointer defines a string syntax for identifying a specific value - within a JSON document. It can be used with functions `at` and - `operator[]`. Furthermore, JSON pointers are the base for JSON patches. - - @sa [RFC 6901](https://tools.ietf.org/html/rfc6901) - - @since version 2.0.0 - */ - class json_pointer - { - /// allow basic_json to access private members - friend class basic_json; - - public: - /*! - @brief create JSON pointer - - Create a JSON pointer according to the syntax described in - [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). - - @param[in] s string representing the JSON pointer; if omitted, the - empty string is assumed which references the whole JSON - value - - @throw std::domain_error if reference token is nonempty and does not - begin with a slash (`/`); example: `"JSON pointer must be empty or - begin with /"` - @throw std::domain_error if a tilde (`~`) is not followed by `0` - (representing `~`) or `1` (representing `/`); example: `"escape error: - ~ must be followed with 0 or 1"` - - @liveexample{The example shows the construction several valid JSON - pointers as well as the exceptional behavior.,json_pointer} - - @since version 2.0.0 - */ - explicit json_pointer(const std::string& s = "") - : reference_tokens(split(s)) - {} - - /*! - @brief return a string representation of the JSON pointer - - @invariant For each JSON pointer `ptr`, it holds: - @code {.cpp} - ptr == json_pointer(ptr.to_string()); - @endcode - - @return a string representation of the JSON pointer - - @liveexample{The example shows the result of `to_string`., - json_pointer__to_string} - - @since version 2.0.0 - */ - std::string to_string() const noexcept - { - return std::accumulate(reference_tokens.begin(), - reference_tokens.end(), std::string{}, - [](const std::string & a, const std::string & b) - { - return a + "/" + escape(b); - }); - } - - /// @copydoc to_string() - operator std::string() const - { - return to_string(); - } - - private: - /// remove and return last reference pointer - std::string pop_back() - { - if (is_root()) - { - JSON_THROW(std::domain_error("JSON pointer has no parent")); - } - - auto last = reference_tokens.back(); - reference_tokens.pop_back(); - return last; - } - - /// return whether pointer points to the root document - bool is_root() const - { - return reference_tokens.empty(); - } - - json_pointer top() const - { - if (is_root()) - { - JSON_THROW(std::domain_error("JSON pointer has no parent")); - } - - json_pointer result = *this; - result.reference_tokens = {reference_tokens[0]}; - return result; - } - - /*! - @brief create and return a reference to the pointed to value - - @complexity Linear in the number of reference tokens. - */ - reference get_and_create(reference j) const - { - pointer result = &j; - - // in case no reference tokens exist, return a reference to the - // JSON value j which will be overwritten by a primitive value - for (const auto& reference_token : reference_tokens) - { - switch (result->m_type) - { - case value_t::null: - { - if (reference_token == "0") - { - // start a new array if reference token is 0 - result = &result->operator[](0); - } - else - { - // start a new object otherwise - result = &result->operator[](reference_token); - } - break; - } - - case value_t::object: - { - // create an entry in the object - result = &result->operator[](reference_token); - break; - } - - case value_t::array: - { - // create an entry in the array - result = &result->operator[](static_cast<size_type>(std::stoi(reference_token))); - break; - } - - /* - The following code is only reached if there exists a - reference token _and_ the current value is primitive. In - this case, we have an error situation, because primitive - values may only occur as single value; that is, with an - empty list of reference tokens. - */ - default: - { - JSON_THROW(std::domain_error("invalid value to unflatten")); - } - } - } - - return *result; - } - - /*! - @brief return a reference to the pointed to value - - @note This version does not throw if a value is not present, but tries - to create nested values instead. For instance, calling this function - with pointer `"/this/that"` on a null value is equivalent to calling - `operator[]("this").operator[]("that")` on that value, effectively - changing the null value to an object. - - @param[in] ptr a JSON value - - @return reference to the JSON value pointed to by the JSON pointer - - @complexity Linear in the length of the JSON pointer. - - @throw std::out_of_range if the JSON pointer can not be resolved - @throw std::domain_error if an array index begins with '0' - @throw std::invalid_argument if an array index was not a number - */ - reference get_unchecked(pointer ptr) const - { - for (const auto& reference_token : reference_tokens) - { - // convert null values to arrays or objects before continuing - if (ptr->m_type == value_t::null) - { - // check if reference token is a number - const bool nums = std::all_of(reference_token.begin(), - reference_token.end(), - [](const char x) - { - return std::isdigit(x); - }); - - // change value to array for numbers or "-" or to object - // otherwise - if (nums or reference_token == "-") - { - *ptr = value_t::array; - } - else - { - *ptr = value_t::object; - } - } - - switch (ptr->m_type) - { - case value_t::object: - { - // use unchecked object access - ptr = &ptr->operator[](reference_token); - break; - } - - case value_t::array: - { - // error condition (cf. RFC 6901, Sect. 4) - if (reference_token.size() > 1 and reference_token[0] == '0') - { - JSON_THROW(std::domain_error("array index must not begin with '0'")); - } - - if (reference_token == "-") - { - // explicitly treat "-" as index beyond the end - ptr = &ptr->operator[](ptr->m_value.array->size()); - } - else - { - // convert array index to number; unchecked access - ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token))); - } - break; - } - - default: - { - JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); - } - } - } - - return *ptr; - } - - reference get_checked(pointer ptr) const - { - for (const auto& reference_token : reference_tokens) - { - switch (ptr->m_type) - { - case value_t::object: - { - // note: at performs range check - ptr = &ptr->at(reference_token); - break; - } - - case value_t::array: - { - if (reference_token == "-") - { - // "-" always fails the range check - JSON_THROW(std::out_of_range("array index '-' (" + - std::to_string(ptr->m_value.array->size()) + - ") is out of range")); - } - - // error condition (cf. RFC 6901, Sect. 4) - if (reference_token.size() > 1 and reference_token[0] == '0') - { - JSON_THROW(std::domain_error("array index must not begin with '0'")); - } - - // note: at performs range check - ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token))); - break; - } - - default: - { - JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); - } - } - } - - return *ptr; - } - - /*! - @brief return a const reference to the pointed to value - - @param[in] ptr a JSON value - - @return const reference to the JSON value pointed to by the JSON - pointer - */ - const_reference get_unchecked(const_pointer ptr) const - { - for (const auto& reference_token : reference_tokens) - { - switch (ptr->m_type) - { - case value_t::object: - { - // use unchecked object access - ptr = &ptr->operator[](reference_token); - break; - } - - case value_t::array: - { - if (reference_token == "-") - { - // "-" cannot be used for const access - JSON_THROW(std::out_of_range("array index '-' (" + - std::to_string(ptr->m_value.array->size()) + - ") is out of range")); - } - - // error condition (cf. RFC 6901, Sect. 4) - if (reference_token.size() > 1 and reference_token[0] == '0') - { - JSON_THROW(std::domain_error("array index must not begin with '0'")); - } - - // use unchecked array access - ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token))); - break; - } - - default: - { - JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); - } - } - } - - return *ptr; - } - - const_reference get_checked(const_pointer ptr) const - { - for (const auto& reference_token : reference_tokens) - { - switch (ptr->m_type) - { - case value_t::object: - { - // note: at performs range check - ptr = &ptr->at(reference_token); - break; - } - - case value_t::array: - { - if (reference_token == "-") - { - // "-" always fails the range check - JSON_THROW(std::out_of_range("array index '-' (" + - std::to_string(ptr->m_value.array->size()) + - ") is out of range")); - } - - // error condition (cf. RFC 6901, Sect. 4) - if (reference_token.size() > 1 and reference_token[0] == '0') - { - JSON_THROW(std::domain_error("array index must not begin with '0'")); - } - - // note: at performs range check - ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token))); - break; - } - - default: - { - JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); - } - } - } - - return *ptr; - } - - /// split the string input to reference tokens - static std::vector<std::string> split(const std::string& reference_string) - { - std::vector<std::string> result; - - // special case: empty reference string -> no reference tokens - if (reference_string.empty()) - { - return result; - } - - // check if nonempty reference string begins with slash - if (reference_string[0] != '/') - { - JSON_THROW(std::domain_error("JSON pointer must be empty or begin with '/'")); - } - - // extract the reference tokens: - // - slash: position of the last read slash (or end of string) - // - start: position after the previous slash - for ( - // search for the first slash after the first character - size_t slash = reference_string.find_first_of('/', 1), - // set the beginning of the first reference token - start = 1; - // we can stop if start == string::npos+1 = 0 - start != 0; - // set the beginning of the next reference token - // (will eventually be 0 if slash == std::string::npos) - start = slash + 1, - // find next slash - slash = reference_string.find_first_of('/', start)) - { - // use the text between the beginning of the reference token - // (start) and the last slash (slash). - auto reference_token = reference_string.substr(start, slash - start); - - // check reference tokens are properly escaped - for (size_t pos = reference_token.find_first_of('~'); - pos != std::string::npos; - pos = reference_token.find_first_of('~', pos + 1)) - { - assert(reference_token[pos] == '~'); - - // ~ must be followed by 0 or 1 - if (pos == reference_token.size() - 1 or - (reference_token[pos + 1] != '0' and - reference_token[pos + 1] != '1')) - { - JSON_THROW(std::domain_error("escape error: '~' must be followed with '0' or '1'")); - } - } - - // finally, store the reference token - unescape(reference_token); - result.push_back(reference_token); - } - - return result; - } - - private: - /*! - @brief replace all occurrences of a substring by another string - - @param[in,out] s the string to manipulate; changed so that all - occurrences of @a f are replaced with @a t - @param[in] f the substring to replace with @a t - @param[in] t the string to replace @a f - - @pre The search string @a f must not be empty. - - @since version 2.0.0 - */ - static void replace_substring(std::string& s, - const std::string& f, - const std::string& t) - { - assert(not f.empty()); - - for ( - size_t pos = s.find(f); // find first occurrence of f - pos != std::string::npos; // make sure f was found - s.replace(pos, f.size(), t), // replace with t - pos = s.find(f, pos + t.size()) // find next occurrence of f - ); - } - - /// escape tilde and slash - static std::string escape(std::string s) - { - // escape "~"" to "~0" and "/" to "~1" - replace_substring(s, "~", "~0"); - replace_substring(s, "/", "~1"); - return s; - } - - /// unescape tilde and slash - static void unescape(std::string& s) - { - // first transform any occurrence of the sequence '~1' to '/' - replace_substring(s, "~1", "/"); - // then transform any occurrence of the sequence '~0' to '~' - replace_substring(s, "~0", "~"); - } - - /*! - @param[in] reference_string the reference string to the current value - @param[in] value the value to consider - @param[in,out] result the result object to insert values to - - @note Empty objects or arrays are flattened to `null`. - */ - static void flatten(const std::string& reference_string, - const basic_json& value, - basic_json& result) - { - switch (value.m_type) - { - case value_t::array: - { - if (value.m_value.array->empty()) - { - // flatten empty array as null - result[reference_string] = nullptr; - } - else - { - // iterate array and use index as reference string - for (size_t i = 0; i < value.m_value.array->size(); ++i) - { - flatten(reference_string + "/" + std::to_string(i), - value.m_value.array->operator[](i), result); - } - } - break; - } - - case value_t::object: - { - if (value.m_value.object->empty()) - { - // flatten empty object as null - result[reference_string] = nullptr; - } - else - { - // iterate object and use keys as reference string - for (const auto& element : *value.m_value.object) - { - flatten(reference_string + "/" + escape(element.first), - element.second, result); - } - } - break; - } - - default: - { - // add primitive value with its reference string - result[reference_string] = value; - break; - } - } - } - - /*! - @param[in] value flattened JSON - - @return unflattened JSON - */ - static basic_json unflatten(const basic_json& value) - { - if (not value.is_object()) - { - JSON_THROW(std::domain_error("only objects can be unflattened")); - } - - basic_json result; - - // iterate the JSON object values - for (const auto& element : *value.m_value.object) - { - if (not element.second.is_primitive()) - { - JSON_THROW(std::domain_error("values in object must be primitive")); - } - - // assign value to reference pointed to by JSON pointer; Note - // that if the JSON pointer is "" (i.e., points to the whole - // value), function get_and_create returns a reference to - // result itself. An assignment will then create a primitive - // value. - json_pointer(element.first).get_and_create(result) = element.second; - } - - return result; - } - - private: - friend bool operator==(json_pointer const& lhs, - json_pointer const& rhs) noexcept - { - return lhs.reference_tokens == rhs.reference_tokens; - } - - friend bool operator!=(json_pointer const& lhs, - json_pointer const& rhs) noexcept - { - return !(lhs == rhs); - } - - /// the reference tokens - std::vector<std::string> reference_tokens {}; - }; - - ////////////////////////// - // JSON Pointer support // - ////////////////////////// - - /// @name JSON Pointer functions - /// @{ - - /*! - @brief access specified element via JSON Pointer - - Uses a JSON pointer to retrieve a reference to the respective JSON value. - No bound checking is performed. Similar to @ref operator[](const typename - object_t::key_type&), `null` values are created in arrays and objects if - necessary. - - In particular: - - If the JSON pointer points to an object key that does not exist, it - is created an filled with a `null` value before a reference to it - is returned. - - If the JSON pointer points to an array index that does not exist, it - is created an filled with a `null` value before a reference to it - is returned. All indices between the current maximum and the given - index are also filled with `null`. - - The special value `-` is treated as a synonym for the index past the - end. - - @param[in] ptr a JSON pointer - - @return reference to the element pointed to by @a ptr - - @complexity Constant. - - @throw std::out_of_range if the JSON pointer can not be resolved - @throw std::domain_error if an array index begins with '0' - @throw std::invalid_argument if an array index was not a number - - @liveexample{The behavior is shown in the example.,operatorjson_pointer} - - @since version 2.0.0 - */ - reference operator[](const json_pointer& ptr) - { - return ptr.get_unchecked(this); - } - - /*! - @brief access specified element via JSON Pointer - - Uses a JSON pointer to retrieve a reference to the respective JSON value. - No bound checking is performed. The function does not change the JSON - value; no `null` values are created. In particular, the the special value - `-` yields an exception. - - @param[in] ptr JSON pointer to the desired element - - @return const reference to the element pointed to by @a ptr - - @complexity Constant. - - @throw std::out_of_range if the JSON pointer can not be resolved - @throw std::domain_error if an array index begins with '0' - @throw std::invalid_argument if an array index was not a number - - @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} - - @since version 2.0.0 - */ - const_reference operator[](const json_pointer& ptr) const - { - return ptr.get_unchecked(this); - } - - /*! - @brief access specified element via JSON Pointer - - Returns a reference to the element at with specified JSON pointer @a ptr, - with bounds checking. - - @param[in] ptr JSON pointer to the desired element - - @return reference to the element pointed to by @a ptr - - @complexity Constant. - - @throw std::out_of_range if the JSON pointer can not be resolved - @throw std::domain_error if an array index begins with '0' - @throw std::invalid_argument if an array index was not a number - - @liveexample{The behavior is shown in the example.,at_json_pointer} - - @since version 2.0.0 - */ - reference at(const json_pointer& ptr) - { - return ptr.get_checked(this); - } - - /*! - @brief access specified element via JSON Pointer - - Returns a const reference to the element at with specified JSON pointer @a - ptr, with bounds checking. - - @param[in] ptr JSON pointer to the desired element - - @return reference to the element pointed to by @a ptr - - @complexity Constant. - - @throw std::out_of_range if the JSON pointer can not be resolved - @throw std::domain_error if an array index begins with '0' - @throw std::invalid_argument if an array index was not a number - - @liveexample{The behavior is shown in the example.,at_json_pointer_const} - - @since version 2.0.0 - */ - const_reference at(const json_pointer& ptr) const - { - return ptr.get_checked(this); - } - - /*! - @brief return flattened JSON value - - The function creates a JSON object whose keys are JSON pointers (see [RFC - 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all - primitive. The original JSON value can be restored using the @ref - unflatten() function. - - @return an object that maps JSON pointers to primitive values - - @note Empty objects and arrays are flattened to `null` and will not be - reconstructed correctly by the @ref unflatten() function. - - @complexity Linear in the size the JSON value. - - @liveexample{The following code shows how a JSON object is flattened to an - object whose keys consist of JSON pointers.,flatten} - - @sa @ref unflatten() for the reverse function - - @since version 2.0.0 - */ - basic_json flatten() const - { - basic_json result(value_t::object); - json_pointer::flatten("", *this, result); - return result; - } - - /*! - @brief unflatten a previously flattened JSON value - - The function restores the arbitrary nesting of a JSON value that has been - flattened before using the @ref flatten() function. The JSON value must - meet certain constraints: - 1. The value must be an object. - 2. The keys must be JSON pointers (see - [RFC 6901](https://tools.ietf.org/html/rfc6901)) - 3. The mapped values must be primitive JSON types. - - @return the original JSON from a flattened version - - @note Empty objects and arrays are flattened by @ref flatten() to `null` - values and can not unflattened to their original type. Apart from - this example, for a JSON value `j`, the following is always true: - `j == j.flatten().unflatten()`. - - @complexity Linear in the size the JSON value. - - @liveexample{The following code shows how a flattened JSON object is - unflattened into the original nested JSON object.,unflatten} - - @sa @ref flatten() for the reverse function - - @since version 2.0.0 - */ - basic_json unflatten() const - { - return json_pointer::unflatten(*this); - } - - /// @} - - ////////////////////////// - // JSON Patch functions // - ////////////////////////// - - /// @name JSON Patch functions - /// @{ - - /*! - @brief applies a JSON patch - - [JSON Patch](http://jsonpatch.com) defines a JSON document structure for - expressing a sequence of operations to apply to a JSON) document. With - this function, a JSON Patch is applied to the current JSON value by - executing all operations from the patch. - - @param[in] json_patch JSON patch document - @return patched document - - @note The application of a patch is atomic: Either all operations succeed - and the patched document is returned or an exception is thrown. In - any case, the original value is not changed: the patch is applied - to a copy of the value. - - @throw std::out_of_range if a JSON pointer inside the patch could not - be resolved successfully in the current JSON value; example: `"key baz - not found"` - @throw invalid_argument if the JSON patch is malformed (e.g., mandatory - attributes are missing); example: `"operation add must have member path"` - - @complexity Linear in the size of the JSON value and the length of the - JSON patch. As usually only a fraction of the JSON value is affected by - the patch, the complexity can usually be neglected. - - @liveexample{The following code shows how a JSON patch is applied to a - value.,patch} - - @sa @ref diff -- create a JSON patch by comparing two JSON values - - @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) - @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901) - - @since version 2.0.0 - */ - basic_json patch(const basic_json& json_patch) const - { - // make a working copy to apply the patch to - basic_json result = *this; - - // the valid JSON Patch operations - enum class patch_operations {add, remove, replace, move, copy, test, invalid}; - - const auto get_op = [](const std::string op) - { - if (op == "add") - { - return patch_operations::add; - } - if (op == "remove") - { - return patch_operations::remove; - } - if (op == "replace") - { - return patch_operations::replace; - } - if (op == "move") - { - return patch_operations::move; - } - if (op == "copy") - { - return patch_operations::copy; - } - if (op == "test") - { - return patch_operations::test; - } - - return patch_operations::invalid; - }; - - // wrapper for "add" operation; add value at ptr - const auto operation_add = [&result](json_pointer & ptr, basic_json val) - { - // adding to the root of the target document means replacing it - if (ptr.is_root()) - { - result = val; - } - else - { - // make sure the top element of the pointer exists - json_pointer top_pointer = ptr.top(); - if (top_pointer != ptr) - { - result.at(top_pointer); - } - - // get reference to parent of JSON pointer ptr - const auto last_path = ptr.pop_back(); - basic_json& parent = result[ptr]; - - switch (parent.m_type) - { - case value_t::null: - case value_t::object: - { - // use operator[] to add value - parent[last_path] = val; - break; - } - - case value_t::array: - { - if (last_path == "-") - { - // special case: append to back - parent.push_back(val); - } - else - { - const auto idx = std::stoi(last_path); - if (static_cast<size_type>(idx) > parent.size()) - { - // avoid undefined behavior - JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); - } - else - { - // default case: insert add offset - parent.insert(parent.begin() + static_cast<difference_type>(idx), val); - } - } - break; - } - - default: - { - // if there exists a parent it cannot be primitive - assert(false); // LCOV_EXCL_LINE - } - } - } - }; - - // wrapper for "remove" operation; remove value at ptr - const auto operation_remove = [&result](json_pointer & ptr) - { - // get reference to parent of JSON pointer ptr - const auto last_path = ptr.pop_back(); - basic_json& parent = result.at(ptr); - - // remove child - if (parent.is_object()) - { - // perform range check - auto it = parent.find(last_path); - if (it != parent.end()) - { - parent.erase(it); - } - else - { - JSON_THROW(std::out_of_range("key '" + last_path + "' not found")); - } - } - else if (parent.is_array()) - { - // note erase performs range check - parent.erase(static_cast<size_type>(std::stoi(last_path))); - } - }; - - // type check - if (not json_patch.is_array()) - { - // a JSON patch must be an array of objects - JSON_THROW(std::invalid_argument("JSON patch must be an array of objects")); - } - - // iterate and apply the operations - for (const auto& val : json_patch) - { - // wrapper to get a value for an operation - const auto get_value = [&val](const std::string & op, - const std::string & member, - bool string_type) -> basic_json& - { - // find value - auto it = val.m_value.object->find(member); - - // context-sensitive error message - const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; - - // check if desired value is present - if (it == val.m_value.object->end()) - { - JSON_THROW(std::invalid_argument(error_msg + " must have member '" + member + "'")); - } - - // check if result is of type string - if (string_type and not it->second.is_string()) - { - JSON_THROW(std::invalid_argument(error_msg + " must have string member '" + member + "'")); - } - - // no error: return value - return it->second; - }; - - // type check - if (not val.is_object()) - { - JSON_THROW(std::invalid_argument("JSON patch must be an array of objects")); - } - - // collect mandatory members - const std::string op = get_value("op", "op", true); - const std::string path = get_value(op, "path", true); - json_pointer ptr(path); - - switch (get_op(op)) - { - case patch_operations::add: - { - operation_add(ptr, get_value("add", "value", false)); - break; - } - - case patch_operations::remove: - { - operation_remove(ptr); - break; - } - - case patch_operations::replace: - { - // the "path" location must exist - use at() - result.at(ptr) = get_value("replace", "value", false); - break; - } - - case patch_operations::move: - { - const std::string from_path = get_value("move", "from", true); - json_pointer from_ptr(from_path); - - // the "from" location must exist - use at() - basic_json v = result.at(from_ptr); - - // The move operation is functionally identical to a - // "remove" operation on the "from" location, followed - // immediately by an "add" operation at the target - // location with the value that was just removed. - operation_remove(from_ptr); - operation_add(ptr, v); - break; - } - - case patch_operations::copy: - { - const std::string from_path = get_value("copy", "from", true);; - const json_pointer from_ptr(from_path); - - // the "from" location must exist - use at() - result[ptr] = result.at(from_ptr); - break; - } - - case patch_operations::test: - { - bool success = false; - JSON_TRY - { - // check if "value" matches the one at "path" - // the "path" location must exist - use at() - success = (result.at(ptr) == get_value("test", "value", false)); - } - JSON_CATCH (std::out_of_range&) - { - // ignore out of range errors: success remains false - } - - // throw an exception if test fails - if (not success) - { - JSON_THROW(std::domain_error("unsuccessful: " + val.dump())); - } - - break; - } - - case patch_operations::invalid: - { - // op must be "add", "remove", "replace", "move", "copy", or - // "test" - JSON_THROW(std::invalid_argument("operation value '" + op + "' is invalid")); - } - } - } - - return result; - } - - /*! - @brief creates a diff as a JSON patch - - Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can - be changed into the value @a target by calling @ref patch function. - - @invariant For two JSON values @a source and @a target, the following code - yields always `true`: - @code {.cpp} - source.patch(diff(source, target)) == target; - @endcode - - @note Currently, only `remove`, `add`, and `replace` operations are - generated. - - @param[in] source JSON value to compare from - @param[in] target JSON value to compare against - @param[in] path helper value to create JSON pointers - - @return a JSON patch to convert the @a source to @a target - - @complexity Linear in the lengths of @a source and @a target. - - @liveexample{The following code shows how a JSON patch is created as a - diff for two JSON values.,diff} - - @sa @ref patch -- apply a JSON patch - - @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) - - @since version 2.0.0 - */ - static basic_json diff(const basic_json& source, - const basic_json& target, - const std::string& path = "") - { - // the patch - basic_json result(value_t::array); - - // if the values are the same, return empty patch - if (source == target) - { - return result; - } - - if (source.type() != target.type()) - { - // different types: replace value - result.push_back( - { - {"op", "replace"}, - {"path", path}, - {"value", target} - }); - } - else - { - switch (source.type()) - { - case value_t::array: - { - // first pass: traverse common elements - size_t i = 0; - while (i < source.size() and i < target.size()) - { - // recursive call to compare array values at index i - auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); - result.insert(result.end(), temp_diff.begin(), temp_diff.end()); - ++i; - } - - // i now reached the end of at least one array - // in a second pass, traverse the remaining elements - - // remove my remaining elements - const auto end_index = static_cast<difference_type>(result.size()); - while (i < source.size()) - { - // add operations in reverse order to avoid invalid - // indices - result.insert(result.begin() + end_index, object( - { - {"op", "remove"}, - {"path", path + "/" + std::to_string(i)} - })); - ++i; - } - - // add other remaining elements - while (i < target.size()) - { - result.push_back( - { - {"op", "add"}, - {"path", path + "/" + std::to_string(i)}, - {"value", target[i]} - }); - ++i; - } - - break; - } - - case value_t::object: - { - // first pass: traverse this object's elements - for (auto it = source.begin(); it != source.end(); ++it) - { - // escape the key name to be used in a JSON patch - const auto key = json_pointer::escape(it.key()); - - if (target.find(it.key()) != target.end()) - { - // recursive call to compare object values at key it - auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key); - result.insert(result.end(), temp_diff.begin(), temp_diff.end()); - } - else - { - // found a key that is not in o -> remove it - result.push_back(object( - { - {"op", "remove"}, - {"path", path + "/" + key} - })); - } - } - - // second pass: traverse other object's elements - for (auto it = target.begin(); it != target.end(); ++it) - { - if (source.find(it.key()) == source.end()) - { - // found a key that is not in this -> add it - const auto key = json_pointer::escape(it.key()); - result.push_back( - { - {"op", "add"}, - {"path", path + "/" + key}, - {"value", it.value()} - }); - } - } - - break; - } - - default: - { - // both primitive type: replace value - result.push_back( - { - {"op", "replace"}, - {"path", path}, - {"value", target} - }); - break; - } - } - } - - return result; - } - - /// @} -}; - -///////////// -// presets // -///////////// - -/*! -@brief default JSON class - -This type is the default specialization of the @ref basic_json class which -uses the standard template types. - -@since version 1.0.0 -*/ -using json = basic_json<>; -} // namespace nlohmann - - -/////////////////////// -// nonmember support // -/////////////////////// - -// specialization of std::swap, and std::hash -namespace std -{ -/*! -@brief exchanges the values of two JSON objects - -@since version 1.0.0 -*/ -template<> -inline void swap(nlohmann::json& j1, - nlohmann::json& j2) noexcept( - is_nothrow_move_constructible<nlohmann::json>::value and - is_nothrow_move_assignable<nlohmann::json>::value - ) -{ - j1.swap(j2); -} - -/// hash value for JSON objects -template<> -struct hash<nlohmann::json> -{ - /*! - @brief return a hash value for a JSON object - - @since version 1.0.0 - */ - std::size_t operator()(const nlohmann::json& j) const - { - // a naive hashing via the string representation - const auto& h = hash<nlohmann::json::string_t>(); - return h(j.dump()); - } -}; -} // namespace std - -/*! -@brief user-defined string literal for JSON values - -This operator implements a user-defined string literal for JSON objects. It -can be used by adding `"_json"` to a string literal and returns a JSON object -if no parse error occurred. - -@param[in] s a string representation of a JSON object -@param[in] n the length of string @a s -@return a JSON object - -@since version 1.0.0 -*/ -inline nlohmann::json operator "" _json(const char* s, std::size_t n) -{ - return nlohmann::json::parse(s, s + n); -} - -/*! -@brief user-defined string literal for JSON pointer - -This operator implements a user-defined string literal for JSON Pointers. It -can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer -object if no parse error occurred. - -@param[in] s a string representation of a JSON Pointer -@param[in] n the length of string @a s -@return a JSON pointer object - -@since version 2.0.0 -*/ -inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) -{ - return nlohmann::json::json_pointer(std::string(s, n)); -} - -// restore GCC/clang diagnostic settings -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic pop -#endif - -// clean up -#undef JSON_CATCH -#undef JSON_DEPRECATED -#undef JSON_THROW -#undef JSON_TRY - -#endif diff --git a/layers_setting.json b/layers_setting.json new file mode 100644 index 0000000..1b58a3a --- /dev/null +++ b/layers_setting.json @@ -0,0 +1,69 @@ +{ + "description": "Layer mapping", + "mappings": [ + { + "name": "BackGroundLayer", + "role" : "map|radio|music|video", + "type" : "stack", + "id_range_begin": 0, + "id_range_end": 0, + "comment": "Work Around: This is evacuation layer that not stopping event loop" + }, + { + "name": "FarHomeScreen", + "role": "", + "type": "stack", + "id_range_begin": 100, + "id_range_end": 199, + "comment": "FarHomeScreen is the part of HomeScreen. The z order of this layer is lower than NearHomeScreen" + }, + { + "name": "Apps", + "role": "music|video|browser|radio|phone|map|navigation|hvac|settings|dashboard|poi|mixer|sdl|launcher|receiver|tachometer|fallback", + "type": "tile", + "id_range_begin": 1000, + "id_range_end": 2999, + "comment": "Range of IDs that will always be placed on layer 1001" + }, + { + "name": "NearHomeScreen", + "role": "homescreen", + "type": "tile", + "id_range_begin": 3000, + "id_range_end": 3000, + "comment": "TOYOTA special software keyboard" + }, + { + "name": "Application Popup Layer", + "role": "popup*", + "type": "stack", + "id_range_begin": 4000, + "id_range_end": 4999, + "comment": "[T.B.D]This layer is for application popup layer" + }, + { + "name": "Restriction", + "role": "restriction", + "type": "stack", + "id_range_begin": 5000, + "id_range_end": 5999, + "comment": "This layer is for restriction notification. This is used by restriction role" + }, + { + "name": "OnScreen", + "role": "^on_screen*", + "type": "stack", + "id_range_begin": 6000, + "id_range_end": 6999, + "comment": "Range of IDs that will always be placed on the OnScreen layer, that gets a very high 'dummy' id of 9999" + }, + { + "name": "Remote", + "role": "tbtnavi", + "type": "stack", + "id_range_begin": 9000, + "id_range_end": 9999, + "comment": "Range of IDs that will always be placed on the OnScreen layer, that gets a very high 'dummy' id of 9999" + } + ] +} diff --git a/package/root/config.xml b/package/root/config.xml index d969b0b..e297b28 100644 --- a/package/root/config.xml +++ b/package/root/config.xml @@ -8,11 +8,14 @@ <feature name="urn:AGL:widget:required-permission"> <param name="urn:AGL:permission::public:hidden" value="required" /> <param name="urn:AGL:permission::system:run-by-default" value="required" /> + <param name="urn:AGL:permission:afm:system:runner" value="required" /> </feature> <feature name="urn:AGL:widget:provided-api"> <param name="windowmanager" value="ws" /> </feature> - <feature name="urn:AGL:widget:required-binding"> + <feature name="urn:AGL:widget:required-api"> + <param name="low-can" value="ws" /> <param name="lib/windowmanager-service.so" value="local" /> + <param name="afm-main" value="ws" /> </feature> </widget> diff --git a/policy_manager/CMakeLists.txt b/policy_manager/CMakeLists.txt index 584d311..5903340 100644 --- a/policy_manager/CMakeLists.txt +++ b/policy_manager/CMakeLists.txt @@ -19,21 +19,21 @@ pkg_check_modules(AFB REQUIRED afb-daemon) pkg_check_modules(SD REQUIRED libsystemd>=222) # Set name of STM -set(STM_DIR stub) -#set(STM_DIR zipc) +#set(STM_DIR stub) +set(STM_DIR zipc) -# Select roles.db +# Select roles.json if(zipc MATCHES ${STM_DIR}) # if trying to show split layout, change from OFF to ON - set(TRY_SPLIT_LAYOUT OFF CACHE BOOL "Enable to show split layout") + set(TRY_SPLIT_LAYOUT ON CACHE BOOL "Enable to show split layout") if(${TRY_SPLIT_LAYOUT}) - set(ROLES_DB_NAME roles.db.zipc.split) + set(ROLES_CONFIG_FILE_NAME roles.json.zipc.split) else() - set(ROLES_DB_NAME roles.db.zipc) + set(ROLES_CONFIG_FILE_NAME roles.json.zipc) endif() else() - set(ROLES_DB_NAME roles.db) + set(ROLES_CONFIG_FILE_NAME roles.json) endif() # Add STM directory @@ -45,6 +45,7 @@ add_library(${TARGETS_PM} SHARED policy_manager.cpp stm/stm.c + ../src/util.cpp ) target_include_directories(${TARGETS_PM} @@ -98,6 +99,6 @@ add_custom_command(TARGET ${TARGETS_PM} POST_BUILD COMMAND mkdir -p ${PROJECT_BINARY_DIR}/package/root/lib COMMAND cp -f ${PROJECT_BINARY_DIR}/${PLUGIN_PM}/lib${PLUGIN_PM}.so ${PROJECT_BINARY_DIR}/package/root/lib COMMAND mkdir -p ${PROJECT_BINARY_DIR}/package/root/etc - COMMAND cp -f ${PROJECT_SOURCE_DIR}/${PLUGIN_PM}/db/states.db ${PROJECT_BINARY_DIR}/package/root/etc - COMMAND cp -f ${PROJECT_SOURCE_DIR}/${PLUGIN_PM}/db/${ROLES_DB_NAME} ${PROJECT_BINARY_DIR}/package/root/etc/roles.db + COMMAND cp -f ${PROJECT_SOURCE_DIR}/${PLUGIN_PM}/config/layouts.json ${PROJECT_BINARY_DIR}/package/root/etc + COMMAND cp -f ${PROJECT_SOURCE_DIR}/${PLUGIN_PM}/config/${ROLES_CONFIG_FILE_NAME} ${PROJECT_BINARY_DIR}/package/root/etc/roles.json ) diff --git a/policy_manager/config/layouts.json b/policy_manager/config/layouts.json new file mode 100644 index 0000000..b12bce1 --- /dev/null +++ b/policy_manager/config/layouts.json @@ -0,0 +1,371 @@ +{ + "ecus": [ + { + "name": "master", + "layouts": [ + { + "name": "homescreen", + "areas": [ + { + "name": "fullscreen", + "category": "homescreen" + } + ] + }, + { + "name": "splitable.split", + "areas": [ + { + "name": "split.main", + "category": "splitable_main" + }, + { + "name": "split.sub", + "category": "splitable_sub" + } + ] + }, + { + "name": "general.normal", + "areas": [ + { + "name": "normal.full", + "category": "general" + } + ] + }, + { + "name": "software_keyboard", + "areas": [ + { + "name": "software_keyboard", + "category": "software_keyboard" + } + ] + }, + { + "name": "pop_up", + "areas": [ + { + "name": "on_screen", + "category": "pop_up" + } + ] + }, + { + "name": "system_alert", + "areas": [ + { + "name": "on_screen", + "category": "system_alert" + } + ] + }, + { + "name": "tbt", + "areas": [ + { + "name": "normal.full", + "category": "tbt" + } + ] + }, + { + "name": "remote_tbt", + "areas": [ + { + "name": "master.split.sub", + "category": "tbt" + } + ] + }, + { + "name": "meter.normal", + "areas": [ + { + "name": "normal.full", + "category": "meter" + } + ] + }, + { + "name": "meter_receiver", + "areas": [ + { + "name": "split.main", + "category": "meter" + }, + { + "name": "split.sub", + "category": "receiver" + } + ] + }, + { + "name": "meter_splitable", + "areas": [ + { + "name": "split.main", + "category": "meter" + }, + { + "name": "split.sub", + "category": "splitable_sub" + } + ] + }, + { + "name": "splitable_receiver", + "areas": [ + { + "name": "split.main", + "category": "splitable_main" + }, + { + "name": "split.sub", + "category": "receiver" + } + ] + }, + { + "name": "receiver.split", + "areas": [ + { + "name": "split.sub", + "category": "receiver" + } + ] + }, + { + "name": "debug.normal", + "areas": [ + { + "name": "normal.full", + "category": "debug" + } + ] + }, + { + "name": "debug.split.main", + "areas": [ + { + "name": "split.main", + "category": "debug" + } + ] + }, + { + "name": "debug.split.sub", + "areas": [ + { + "name": "split.sub", + "category": "debug" + } + ] + }, + { + "name": "debug.fullscreen", + "areas": [ + { + "name": "fullscreen", + "category": "debug" + } + ] + } + ] + }, + { + "name": "slave", + "layouts": [ + { + "name": "homescreen", + "areas": [ + { + "name": "fullscreen", + "category": "homescreen" + } + ] + }, + { + "name": "map.normal", + "areas": [ + { + "name": "normal.full", + "category": "map" + } + ] + }, + { + "name": "map.split", + "areas": [ + { + "name": "split.main", + "category": "map" + }, + { + "name": "split.sub", + "category": "splitable" + } + ] + }, + { + "name": "map.fullscreen", + "areas": [ + { + "name": "fullscreen", + "category": "map" + } + ] + }, + { + "name": "splitable.normal", + "areas": [ + { + "name": "normal.full", + "category": "splitable" + } + ] + }, + { + "name": "splitable.split", + "areas": [ + { + "name": "split.main", + "category": "splitable" + }, + { + "name": "split.sub", + "category": "splitable" + } + ] + }, + { + "name": "general.normal", + "areas": [ + { + "name": "normal.full", + "category": "general" + } + ] + }, + { + "name": "system.normal", + "areas": [ + { + "name": "normal.full", + "category": "system" + } + ] + }, + { + "name": "software_keyboard", + "areas": [ + { + "name": "software_keyboard", + "category": "software_keyboard" + } + ] + }, + { + "name": "restriction.normal", + "areas": [ + { + "name": "restriction.normal", + "category": "restriction" + } + ] + }, + { + "name": "restriction.split.main", + "areas": [ + { + "name": "restriction.split.main", + "category": "restriction" + } + ] + }, + { + "name": "restriction.split.sub", + "areas": [ + { + "name": "restriction.split.sub", + "category": "restriction" + } + ] + }, + { + "name": "pop_up", + "areas": [ + { + "name": "on_screen", + "category": "pop_up" + } + ] + }, + { + "name": "system_alert", + "areas": [ + { + "name": "on_screen", + "category": "system_alert" + } + ] + }, + { + "name": "tbt", + "areas": [ + { + "name": "normal.full", + "category": "tbt" + } + ] + }, + { + "name": "remote_tbt", + "areas": [ + { + "name": "master.split.sub", + "category": "tbt" + } + ] + }, + { + "name": "debug.normal", + "areas": [ + { + "name": "normal.full", + "category": "debug" + } + ] + }, + { + "name": "debug.split.main", + "areas": [ + { + "name": "split.main", + "category": "debug" + } + ] + }, + { + "name": "debug.split.sub", + "areas": [ + { + "name": "split.sub", + "category": "debug" + } + ] + }, + { + "name": "debug.fullscreen", + "areas": [ + { + "name": "fullscreen", + "category": "debug" + } + ] + } + ] + } + ] +} diff --git a/policy_manager/db/roles.db b/policy_manager/config/roles.json index 5d31aea..c657fec 100644 --- a/policy_manager/db/roles.db +++ b/policy_manager/config/roles.json @@ -35,6 +35,18 @@ "role": "system_alert", "area": "on_screen", "layer": "on_screen", + }, + { + "category": "tbt", + "role": "tbt", + "area": "normal.full | master.split.sub", + "layer": "remote", + }, + { + "category": "receiver", + "role": "receiver", + "area": "normal.full | split.main | split.sub", + "layer": "apps", } ] } diff --git a/policy_manager/db/roles.db.zipc b/policy_manager/config/roles.json.zipc index facb1d8..facb1d8 100644 --- a/policy_manager/db/roles.db.zipc +++ b/policy_manager/config/roles.json.zipc diff --git a/policy_manager/config/roles.json.zipc.split b/policy_manager/config/roles.json.zipc.split new file mode 100644 index 0000000..ba5505b --- /dev/null +++ b/policy_manager/config/roles.json.zipc.split @@ -0,0 +1,151 @@ +{ + "ecus": [ + { + "name": "master", + "roles":[ + { + "category": "homescreen", + "role": "homescreen", + "area": "fullscreen", + "layer": "homescreen", + }, + { + "category": "general", + "role": "launcher | browser | debug | fallback", + "area": "normal.full", + "description": "For split test, video and music are moved to category:splitable", + "layer": "apps", + }, + { + "category": "splitable_main", + "role": "settings | mixer | hvac | video | phone | dashboard", + "area": "split.main", + "description": "For split test, video and music are included here", + "layer": "apps", + }, + { + "category": "splitable_sub", + "role": "music | radio | poi", + "area": "split.sub", + "description": "For split test, video and music are included here", + "layer": "apps", + }, + { + "category": "software_keyboard", + "role": "software_keyboard", + "area": "software_keyboard", + "layer": "near_homescreen", + }, + { + "category": "pop_up", + "role": "on_screen | on_screen_phone | onscreen", + "area": "on_screen", + "layer": "on_screen", + }, + { + "category": "system_alert", + "role": "system_alert", + "area": "on_screen", + "layer": "on_screen", + }, + { + "category": "tbt", + "role": "tbtnavi", + "area": "master.split.sub", + "layer": "remote", + }, + { + "category": "meter", + "role": "tachometer", + "area": "split.main | normal.full", + "layer": "apps", + }, + { + "category": "receiver", + "role": "receiver", + "area": "split.sub | normal.full", + "layer": "apps", + } + ] + }, + { + "name": "slave", + "roles":[ + { + "category": "homescreen", + "role": "homescreen", + "area": "fullscreen", + "layer": "homescreen", + }, + { + "category": "map", + "role": "navigation", + "area": "normal.full | split.main | fullscreen", + "layer": "apps", + }, + { + "category": "general", + "role": "launcher | poi | browser | mixer | radio | hvac | debug | phone | fallback", + "area": "normal.full", + "description": "For split test, video and music are moved to category:splitable", + "layer": "apps", + }, + { + "category": "system", + "role": "settings | dashboard", + "area": "normal.full", + "layer": "apps", + }, + { + "category": "splitable", + "role": "video | music | sdl | eb", + "area": "normal.full | split.main | split.sub", + "description": "For split test, video and music are included here", + "layer": "apps", + }, + { + "category": "software_keyboard", + "role": "software_keyboard", + "area": "software_keyboard", + "layer": "near_homescreen", + }, + { + "category": "restriction", + "role": "restriction", + "area": "restriction.normal | restriction.split.main | restriction.split.sub", + "layer": "restriction", + }, + { + "category": "pop_up", + "role": "on_screen | on_screen_phone | onscreen", + "area": "on_screen", + "layer": "on_screen", + }, + { + "category": "system_alert", + "role": "system_alert", + "area": "on_screen", + "layer": "on_screen", + }, + { + "category": "tbt", + "role": "tbtnavi", + "area": "master.split.sub", + "layer": "remote", + }, + { + "category": "meter", + "role": "tachometer", + "area": "split.main | normal.full", + "layer": "apps", + }, + { + "category": "receiver", + "role": "receiver", + "area": "split.sub | normal.full", + "layer": "apps", + } + ] + } + ] +} diff --git a/policy_manager/db/roles.db.zipc.split b/policy_manager/db/roles.db.zipc.split deleted file mode 100644 index 73c80cf..0000000 --- a/policy_manager/db/roles.db.zipc.split +++ /dev/null @@ -1,60 +0,0 @@ -{ - "roles":[ - { - "category": "homescreen", - "role": "homescreen", - "area": "fullscreen", - "layer": "homescreen", - }, - { - "category": "map", - "role": "map", - "area": "normal.full | split.main", - "layer": "apps", - }, - { - "category": "general", - "role": "launcher | poi | browser | sdl | mixer | radio | hvac | debug | phone | fallback", - "area": "normal.full", - "description": "For split test, video and music are moved to category:splitable", - "layer": "apps", - }, - { - "category": "system", - "role": "settings | dashboard", - "area": "normal.full", - "layer": "apps", - }, - { - "category": "splitable", - "role": "video | music", - "area": "normal.full | split.main | split.sub", - "description": "For split test, video and music are included here", - "layer": "apps", - }, - { - "category": "software_keyboard", - "role": "software_keyboard", - "area": "software_keyboard", - "layer": "near_homescreen", - }, - { - "category": "restriction", - "role": "restriction", - "area": "restriction.normal | restriction.split.main | restriction.split.sub", - "layer": "restriction", - }, - { - "category": "pop_up", - "role": "on_screen | on_screen_phone", - "area": "on_screen", - "layer": "on_screen", - }, - { - "category": "system_alert", - "role": "system_alert", - "area": "on_screen", - "layer": "on_screen", - } - ] -} diff --git a/policy_manager/db/states.db b/policy_manager/db/states.db deleted file mode 100644 index 371be3b..0000000 --- a/policy_manager/db/states.db +++ /dev/null @@ -1,174 +0,0 @@ -{ - "states": [ - { - "name": "homescreen", - "areas": [ - { - "name": "fullscreen", - "category": "homescreen" - } - ] - }, - { - "name": "map.normal", - "areas": [ - { - "name": "normal.full", - "category": "map" - } - ] - }, - { - "name": "map.split", - "areas": [ - { - "name": "split.main", - "category": "map" - }, - { - "name": "split.sub", - "category": "splitable" - } - ] - }, - { - "name": "map.fullscreen", - "areas": [ - { - "name": "fullscreen", - "category": "map" - } - ] - }, - { - "name": "splitable.normal", - "areas": [ - { - "name": "normal.full", - "category": "splitable" - } - ] - }, - { - "name": "splitable.split", - "areas": [ - { - "name": "split.main", - "category": "splitable" - }, - { - "name": "split.sub", - "category": "splitable" - } - ] - }, - { - "name": "general.normal", - "areas": [ - { - "name": "normal.full", - "category": "general" - } - ] - }, - { - "name": "system.normal", - "areas": [ - { - "name": "normal.full", - "category": "system" - } - ] - }, - { - "name": "software_keyboard", - "areas": [ - { - "name": "software_keyboard", - "category": "software_keyboard" - } - ] - }, - { - "name": "restriction.normal", - "areas": [ - { - "name": "restriction.normal", - "category": "restriction" - } - ] - }, - { - "name": "restriction.split.main", - "areas": [ - { - "name": "restriction.split.main", - "category": "restriction" - } - ] - }, - { - "name": "restriction.split.sub", - "areas": [ - { - "name": "restriction.split.sub", - "category": "restriction" - } - ] - }, - { - "name": "pop_up", - "areas": [ - { - "name": "on_screen", - "category": "pop_up" - } - ] - }, - { - "name": "system_alert", - "areas": [ - { - "name": "on_screen", - "category": "system_alert" - } - ] - }, - { - "name": "debug.normal", - "areas": [ - { - "name": "normal.full", - "category": "debug" - } - ] - }, - { - "name": "debug.split.main", - "areas": [ - { - "name": "split.main", - "category": "debug" - } - ] - }, - { - "name": "debug.split.sub", - "areas": [ - { - "name": "split.sub", - "category": "debug" - } - ] - }, - { - "name": "debug.fullscreen", - "areas": [ - { - "name": "fullscreen", - "category": "debug" - } - ] - } - ] -} diff --git a/policy_manager/policy_manager.cpp b/policy_manager/policy_manager.cpp index c7bb007..05f2ccb 100644 --- a/policy_manager/policy_manager.cpp +++ b/policy_manager/policy_manager.cpp @@ -22,7 +22,7 @@ #include <algorithm> #include <json-c/json.h> #include "policy_manager.hpp" -#include "hmi-debug.h" +#include "util.hpp" extern "C" { @@ -34,6 +34,9 @@ extern "C" namespace pm { +static const char kPathRolesConfigFile[] = "/etc/roles.json"; +static const char kPathLayoutsConfigFile[] = "/etc/layouts.json"; + static const int kInvisibleRoleHistoryNum = 5; static PolicyManager *g_context; @@ -59,44 +62,56 @@ PolicyManager::PolicyManager() role2category(), category2role(), category2areas() -{} +{ + this->p_crr_state = new (StmState); + this->p_prv_state = new (StmState); +} + +PolicyManager::~PolicyManager() +{ + delete this->p_crr_state; + delete this->p_prv_state; +} -int PolicyManager::initialize() +int PolicyManager::initialize(std::string ecu_name) { int ret = 0; + // Set ECU name + this->ecu_name = ecu_name; + // Create convert map for (int i = StmEvtNoMin; i <= StmEvtNoMax; i++) { - HMI_DEBUG("wm:pm", "event name:%s no:%d", kStmEventName[i], i); + HMI_DEBUG("event name:%s no:%d", kStmEventName[i], i); this->eventname2no[kStmEventName[i]] = i; } for (int i = StmCtgNoMin; i <= StmCtgNoMax; i++) { - HMI_DEBUG("wm:pm", "category name:%s no:%d", kStmCategoryName[i], i); + HMI_DEBUG("category name:%s no:%d", kStmCategoryName[i], i); this->categoryname2no[kStmCategoryName[i]] = i; } for (int i = StmAreaNoMin; i <= StmAreaNoMax; i++) { - HMI_DEBUG("wm:pm", "area name:%s no:%d", kStmAreaName[i], i); + HMI_DEBUG("area name:%s no:%d", kStmAreaName[i], i); this->areaname2no[kStmAreaName[i]] = i; } - // Load roles.db - ret = this->loadRoleDb(); + // Load roles config + ret = this->loadRolesConfigFile(); if (0 > ret) { - HMI_ERROR("wm:pm", "Load roles.db Error!!"); + HMI_ERROR("Load roles config file Error!!"); return ret; } - // Load states.db - ret = this->loadStateDb(); + // Load layouts config + ret = this->loadLayoutsConfigFile(); if (0 > ret) { - HMI_ERROR("wm:pm", "Load states.db Error!!"); + HMI_ERROR("Load layouts config file Error!!"); return ret; } @@ -104,7 +119,7 @@ int PolicyManager::initialize() this->initializeState(); // Initialize StateTransitioner - stmInitialize(); + stmInitialize(ecu_name.c_str()); // Store instance pm::g_context = this; @@ -123,7 +138,7 @@ int PolicyManager::setInputEventData(json_object *json_in) // Check arguments if (nullptr == json_in) { - HMI_ERROR("wm:pm", "Argument is NULL!!"); + HMI_ERROR("Argument is NULL!!"); return -1; } @@ -137,17 +152,17 @@ int PolicyManager::setInputEventData(json_object *json_in) if (this->eventname2no.end() != itr) { event_no = this->eventname2no[event]; - HMI_DEBUG("wm:pm", "event(%s:%d)", event, event_no); + HMI_DEBUG("event(%s:%d)", event, event_no); } else { - HMI_ERROR("wm:pm", "Invalid event name!!"); + HMI_ERROR("Invalid event name!!"); return -1; } } else { - HMI_ERROR("wm:pm", "Event is not set!!"); + HMI_ERROR("Event is not set!!"); return -1; } @@ -157,7 +172,7 @@ int PolicyManager::setInputEventData(json_object *json_in) int category_no = StmCtgNoNone; if (nullptr != role) { - HMI_DEBUG("wm:pm", "role(%s)", role); + HMI_DEBUG("role(%s)", role); // Convert role to category auto itr = this->role2category.find(role); @@ -170,7 +185,7 @@ int PolicyManager::setInputEventData(json_object *json_in) itr = this->role2category.find("fallback"); if (this->role2category.end() != itr) { - HMI_DEBUG("wm:pm", "Role:%s is not registered in roles.db, fallback as normal app", role); + HMI_DEBUG("Role:%s is not registered in roles config file, fallback as normal app", role); category = this->role2category["fallback"]; } } @@ -179,7 +194,7 @@ int PolicyManager::setInputEventData(json_object *json_in) { // Convert name to number category_no = categoryname2no[category]; - HMI_DEBUG("wm:pm", "category(%s:%d)", category.c_str(), category_no); + HMI_DEBUG("category(%s:%d)", category.c_str(), category_no); } } if (StmCtgNoNone == category_no) @@ -205,7 +220,7 @@ int PolicyManager::setInputEventData(json_object *json_in) area = this->category2areas[category].front().c_str(); area_no = this->areaname2no[area]; } - HMI_DEBUG("wm:pm", "area(%s:%d)", area, area_no); + HMI_DEBUG("area(%s:%d)", area, area_no); } // Set event info to the queue @@ -237,25 +252,42 @@ int PolicyManager::executeStateTransition() void PolicyManager::undoState() { - HMI_DEBUG("wm:pm", "Undo State !!!"); + HMI_DEBUG("Undo State !!!"); // Undo state of STM stmUndoState(); - HMI_DEBUG("wm:pm", ">>>>>>>>>> BEFORE UNDO"); + HMI_DEBUG(">>>>>>>>>> BEFORE UNDO"); this->dumpLayerState(this->crr_layers); this->crr_layers = this->prv_layers; + this->crr_invisible_role_history = this->prv_invisible_role_history; - HMI_DEBUG("wm:pm", ">>>>>>>>>> AFTER UNDO"); + HMI_DEBUG(">>>>>>>>>> AFTER UNDO"); this->dumpLayerState(this->crr_layers); } void PolicyManager::initializeState() { + this->initializeModeState(); this->initializeLayerState(); } +void PolicyManager::initializeModeState() +{ + Mode init_car_ele; + init_car_ele.state = "none"; + init_car_ele.changed = false; + + for (int i = StmCarElementNoMin; i <= StmCarElementNoMax; i++) + { + const char *car_ele_name = kStmCarElementName[i]; + this->crr_car_elements[car_ele_name] = init_car_ele; + } + + this->prv_car_elements = this->crr_car_elements; +} + void PolicyManager::initializeLayerState() { AreaState init_area; @@ -282,7 +314,7 @@ void PolicyManager::addStateToJson(const char *name, bool changed, { if ((nullptr == name) || (nullptr == json_out)) { - HMI_ERROR("wm:pm", "Invalid argument!!!"); + HMI_ERROR("Invalid argument!!!"); return; } @@ -296,7 +328,7 @@ void PolicyManager::addStateToJson(const char *layer_name, bool changed, { if ((nullptr == layer_name) || (nullptr == json_out)) { - HMI_ERROR("wm:pm", "Invalid argument!!!"); + HMI_ERROR("Invalid argument!!!"); return; } @@ -315,47 +347,108 @@ void PolicyManager::addStateToJson(const char *layer_name, bool changed, json_object_object_add(*json_out, "areas", json_areas); } -void PolicyManager::updateState(int event_id, StmState crr_state) +void PolicyManager::updateState(int event_id) { - this->updateLayer(event_id, crr_state); + this->updateModeState(); + this->updateLayer(event_id); } -void PolicyManager::updateLayer(int event_id, StmState crr_state) +void PolicyManager::updateModeState() +{ + int car_state_no; + std::string car_state; + bool changed; + + // Store previous layers + this->prv_car_elements = this->crr_car_elements; + + // Update car elements + HMI_DEBUG(">>> CAR ELEMENTS"); + for (int car_ele_no = StmCarElementNoMin; + car_ele_no <= StmCarElementNoMax; car_ele_no++) + { + const char *car_ele_name = kStmCarElementName[car_ele_no]; + + car_state_no = this->p_crr_state->car_element[car_ele_no].state; + car_state = kStmCarElementStateNameList[car_ele_no][car_state_no]; + changed = (this->p_crr_state->car_element[car_ele_no].changed) ? true : false; + + this->crr_car_elements[car_ele_name].state = car_state; + this->crr_car_elements[car_ele_name].changed = changed; + + HMI_DEBUG(">>> >>> NAME: %s", car_ele_name); + HMI_DEBUG(">>> >>> >>> STATE:%s", car_state.c_str()); + HMI_DEBUG(">>> >>> >>> CHANGED:%s", (changed) ? "true" : "false"); + } +} + +void PolicyManager::updateLayer(int event_id) { for (int layer_no = StmLayerNoMin; layer_no <= StmLayerNoMax; layer_no++) { - HMI_DEBUG("wm:pm", ">>> LAYER:%s CHANGED:%d LAYOUT:%s", - kStmLayerName[layer_no], crr_state.layer[layer_no].changed, - kStmLayoutName[crr_state.layer[layer_no].state]); + HMI_DEBUG(">>> LAYER:%s CHANGED:%d LAYOUT:%s", + kStmLayerName[layer_no], this->p_crr_state->layer[layer_no].changed, + kStmLayoutName[this->p_crr_state->layer[layer_no].state]); } // Store previous layers this->prv_layers = this->crr_layers; + // Store previous role history + this->prv_invisible_role_history = this->crr_invisible_role_history; + // Update layers for (int layer_no = StmLayerNoMin; layer_no <= StmLayerNoMax; layer_no++) { const char *layer_name = kStmLayerName[layer_no]; + // If restriction mode is changed to mode2 on, + // store current state for state of restriction mode off + if (this->changedRestrictionModeTo2On() || + this->changedLightstatusBrakeOnToOff()) + { + HMI_DEBUG("Store current state for state of restriction mode off"); + this->prv_layers_car_stop[layer_name] = this->crr_layers[layer_name]; + } + // This layer is changed? - int changed = crr_state.layer[layer_no].changed; + int changed = this->p_crr_state->layer[layer_no].changed; if (changed) { - HMI_DEBUG("wm:pm", ">>>>>>>>>> Update layout of layer:%s", layer_name); + HMI_DEBUG(">>>>>>>>>> Update layout of layer:%s", layer_name); // Get current layout name of this layer - int crr_layout_state_no = crr_state.layer[layer_no].state; + int crr_layout_state_no = this->p_crr_state->layer[layer_no].state; std::string crr_layout_name = std::string(kStmLayoutName[crr_layout_state_no]); LayoutState crr_layout_state; - this->updateLayout(event_id, layer_no, - crr_layout_name, crr_layout_state); + changed = this->updateLayout(event_id, layer_no, + crr_layout_name, crr_layout_state); // Update current layout of this layer this->crr_layers[layer_name].layout_state = crr_layout_state; } + else + { + int category_no = STM_GET_CATEGORY_FROM_ID(event_id); + std::string req_ctg = kStmCategoryName[category_no]; + std::string req_role = this->req_role_list[event_id]; + for (const auto &ctg : this->layer2categories[layer_name]) + { + if (ctg == req_ctg) + { + // If layer is not changed and requested role is in this layer, + // push requested role to history stack + // because the application which has this role have been started + HMI_DEBUG("Add requested role to history " + "because the application which has this role have been started"); + this->pushInvisibleRoleHistory(req_ctg, req_role); + } + } + } + // Update changed flag this->crr_layers[layer_name].changed = (changed) ? true : false; } @@ -363,10 +456,10 @@ void PolicyManager::updateLayer(int event_id, StmState crr_state) // Erase role for the event_id from list this->req_role_list.erase(event_id); - HMI_DEBUG("wm:pm", ">>>>>>>>>> DUMP LAYERS (BEFORE)"); + HMI_DEBUG(">>>>>>>>>> DUMP LAYERS (BEFORE)"); this->dumpLayerState(this->prv_layers); - HMI_DEBUG("wm:pm", ">>>>>>>>>> DUMP LAYERS (AFTER)"); + HMI_DEBUG(">>>>>>>>>> DUMP LAYERS (AFTER)"); this->dumpLayerState(this->crr_layers); this->dumpInvisibleRoleHistory(); @@ -375,7 +468,7 @@ void PolicyManager::updateLayer(int event_id, StmState crr_state) int PolicyManager::updateLayout(int event_id, int layer_no, std::string crr_layout_name, LayoutState &crr_layout_state) { - int changed; + int changed = 1; int event_no = STM_GET_EVENT_FROM_ID(event_id); int category_no = STM_GET_CATEGORY_FROM_ID(event_id); @@ -392,7 +485,36 @@ int PolicyManager::updateLayout(int event_id, int layer_no, LayoutState prv_layout_state = this->prv_layers[layer_name].layout_state; std::string prv_layout_name = prv_layout_state.name; - if ((prv_layout_name == crr_layout_name) && + if (this->changedRestrictionMode2OnToOther() || + this->changedLightstatusBrakeOffToOn()) + { + // If restriction mode is changed from mode2 -> mode1, + // restore state of restriction mode off + HMI_DEBUG("Restriction mode is changed from mode2 -> mode1, so restore state of restriction mode off"); + crr_layout_state = this->prv_layers_car_stop[layer_name].layout_state; + crr_layout_name = crr_layout_state.name; + if ((prv_layout_name == crr_layout_name) && + (kStmAreaName[StmAreaNoNone] == crr_layout_name)) + { + changed = 0; + } + else + { + // If the roles which is exist in previous layout is not in current, + // push to role history + for (const auto &prv_as : prv_layout_state.area_list) + { + for (const auto &crr_as : crr_layout_state.area_list) + { + if (prv_as.role == crr_as.role) + break; + } + + this->pushInvisibleRoleHistory(prv_as.category, prv_as.role); + } + } + } + else if ((prv_layout_name == crr_layout_name) && (kStmLayoutName[StmLayoutNoNone] == crr_layout_name)) { // If previous and current layout are none @@ -405,17 +527,17 @@ int PolicyManager::updateLayout(int event_id, int layer_no, crr_layout_state = prv_layout_state; changed = 1; - HMI_DEBUG("wm:pm", "-- layout name previous:%s current:%s", + HMI_DEBUG("-- layout name previous:%s current:%s", prv_layout_name.c_str(), crr_layout_name.c_str()); if (prv_layout_name == crr_layout_name) { - HMI_DEBUG("wm:pm", "---- Previous layout is same with current"); + HMI_DEBUG("---- Previous layout is same with current"); } else { // If previous layout is NOT same with current, // current areas is set with default value - HMI_DEBUG("wm:pm", "---- Previous layout is NOT same with current"); + HMI_DEBUG("---- Previous layout is NOT same with current"); crr_layout_state.name = this->default_layouts[crr_layout_name].name; crr_layout_state.category_num = this->default_layouts[crr_layout_name].category_num; crr_layout_state.area_list = this->default_layouts[crr_layout_name].area_list; @@ -434,7 +556,7 @@ int PolicyManager::updateLayout(int event_id, int layer_no, // } // const char *ctg = kStmCategoryName[ctg_no]; - HMI_DEBUG("wm:pm", "-- Create candidate list for ctg:%s", ctg.c_str()); + HMI_DEBUG("-- Create candidate list for ctg:%s", ctg.c_str()); AreaList tmp_cand_list; int candidate_num = 0; @@ -447,7 +569,7 @@ int PolicyManager::updateLayout(int event_id, int layer_no, std::string used_role = ""; if ((ctg == req_ctg) && ("activate" == req_evt)) { - HMI_DEBUG("wm:pm", "---- Requested event is activate"); + HMI_DEBUG("---- Requested event is activate"); for (AreaState &as : crr_layout_state.area_list) { if (as.category == req_ctg) @@ -459,7 +581,7 @@ int PolicyManager::updateLayout(int event_id, int layer_no, as.role = req_role; used_role = req_role; blank_num--; - HMI_DEBUG("wm:pm", "------ Update current layout: area:%s category:%s role:%s", + HMI_DEBUG("------ Update current layout: area:%s category:%s role:%s", as.name.c_str(), as.category.c_str(), as.role.c_str()); break; } @@ -476,7 +598,7 @@ int PolicyManager::updateLayout(int event_id, int layer_no, // If there is the category // which is same with new category and not used for updating yet, // push it to list - HMI_DEBUG("wm:pm", "---- Push previous(category:%s role:%s) to candidate list", + HMI_DEBUG("---- Push previous(category:%s role:%s) to candidate list", area_state.category.c_str(), area_state.role.c_str()); tmp_cand_list.push_back(area_state); candidate_num++; @@ -488,7 +610,7 @@ int PolicyManager::updateLayout(int event_id, int layer_no, // so push requested role to candidate list if (request_for_this_layer && ("" == used_role)) { - HMI_DEBUG("wm:pm", "---- Push request(area:%s category:%s role:%s) to candidate list", + HMI_DEBUG("---- Push request(area:%s category:%s role:%s) to candidate list", req_area.c_str(), req_ctg.c_str(), req_role.c_str()); AreaState area_state; area_state.name = req_area; @@ -498,7 +620,7 @@ int PolicyManager::updateLayout(int event_id, int layer_no, candidate_num++; } - HMI_DEBUG("wm:pm", "---- blank_num:%d candidate_num:%d", blank_num, candidate_num); + HMI_DEBUG("---- blank_num:%d candidate_num:%d", blank_num, candidate_num); // Compare number of candidate/blank, // And remove role in order of the oldest as necessary @@ -514,10 +636,10 @@ int PolicyManager::updateLayout(int event_id, int layer_no, area_state.role = this->popInvisibleRoleHistory(ctg); if ("" == area_state.role) { - HMI_ERROR("wm:pm", "There is no role in history stack!!"); + HMI_ERROR("There is no role in history stack!!"); } tmp_cand_list.push_back(area_state); - HMI_DEBUG("wm:pm", "------ Add role:%s to candidate list", + HMI_DEBUG("------ Add role:%s to candidate list", area_state.role.c_str()); candidate_num++; } @@ -528,7 +650,7 @@ int PolicyManager::updateLayout(int event_id, int layer_no, while (candidate_num != blank_num) { std::string removed_role = tmp_cand_list.begin()->role; - HMI_DEBUG("wm:pm", "------ Remove the oldest role:%s from candidate list", + HMI_DEBUG("------ Remove the oldest role:%s from candidate list", removed_role.c_str()); tmp_cand_list.erase(tmp_cand_list.begin()); candidate_num--; @@ -555,14 +677,14 @@ int PolicyManager::updateLayout(int event_id, int layer_no, } // Update areas - HMI_DEBUG("wm:pm", "-- Update areas by using candidate list"); + HMI_DEBUG("-- Update areas by using candidate list"); for (AreaState &as : crr_layout_state.area_list) { - HMI_DEBUG("wm:pm", "---- Check area:%s category:%s role:%s", + HMI_DEBUG("---- Check area:%s category:%s role:%s", as.name.c_str(), as.category.c_str(), as.role.c_str()); if ("" == as.role) { - HMI_DEBUG("wm:pm", "------ Update this area with role:%s", + HMI_DEBUG("------ Update this area with role:%s", cand_list[as.category].begin()->role.c_str()); as.role = cand_list[as.category].begin()->role; cand_list[as.category].erase(cand_list[as.category].begin()); @@ -572,10 +694,35 @@ int PolicyManager::updateLayout(int event_id, int layer_no, return changed; } -void PolicyManager::createOutputInformation(StmState crr_state, json_object **json_out) +void PolicyManager::createOutputInformation(json_object **json_out) { json_object *json_tmp; + // Create car element information + // { + // "car_elements": [ + // { + // "parking_brake": { + // "changed": <bool>, + // "state": <const char*> + // }, + // ... + // }, + json_object *json_car_ele = json_object_new_array(); + const char *car_ele_name; + for (int car_ele_no = StmCarElementNoMin; + car_ele_no <= StmCarElementNoMax; car_ele_no++) + { + car_ele_name = kStmCarElementName[car_ele_no]; + json_tmp = json_object_new_object(); + this->addStateToJson(car_ele_name, + this->crr_car_elements[car_ele_name].changed, + this->crr_car_elements[car_ele_name].state, + &json_tmp); + json_object_array_add(json_car_ele, json_tmp); + } + json_object_object_add(*json_out, "car_elements", json_car_ele); + // Create layout information // // "layers": [ @@ -608,9 +755,41 @@ void PolicyManager::createOutputInformation(StmState crr_state, json_object **js json_object_object_add(*json_out, "layers", json_layer); } +void PolicyManager::controlTimerEvent() +{ + if (this->p_crr_state->car_element[StmCarElementNoRunning].changed) + { + if (StmRunningNoRun == this->p_crr_state->car_element[StmCarElementNoRunning].state) + { + // Set delay event(restriction mode on) + this->setStateTransitionProcessToSystemd(StmEvtNoRestrictionModeOn, + 3000, ""); + } + else if (StmRunningNoStop == + this->p_crr_state->car_element[StmCarElementNoRunning].state) + { + // Stop timer for restriction on event + if (this->event_source_list.find(StmEvtNoRestrictionModeOn) != + this->event_source_list.end()) + { + HMI_DEBUG("Stop timer for restriction on"); + sd_event_source *event_source = this->event_source_list[StmEvtNoRestrictionModeOn]; + int ret = sd_event_source_set_enabled(event_source, SD_EVENT_OFF); + if (0 > ret) + { + HMI_ERROR("Failed to stop timer"); + } + } + + // Set event(restriction mode off) + this->setStateTransitionProcessToSystemd(StmEvtNoRestrictionModeOff, 0, ""); + } + } +} + int PolicyManager::transitionState(sd_event_source *source, void *data) { - HMI_DEBUG("wm:pm", ">>>>>>>>>> START STATE TRANSITION"); + HMI_DEBUG(">>>>>>>>>> START STATE TRANSITION"); int event_id = *((int *)data); @@ -618,17 +797,19 @@ int PolicyManager::transitionState(sd_event_source *source, void *data) event_no = STM_GET_EVENT_FROM_ID(event_id); category_no = STM_GET_CATEGORY_FROM_ID(event_id); area_no = STM_GET_AREA_FROM_ID(event_id); - HMI_DEBUG("wm:pm", ">>>>>>>>>> EVENT:%s CATEGORY:%s AREA:%s", + HMI_DEBUG(">>>>>>>>>> EVENT:%s CATEGORY:%s AREA:%s", kStmEventName[event_no], kStmCategoryName[category_no], kStmAreaName[area_no]); + // Store current state + *(this->p_prv_state) = *(this->p_crr_state); + // Transition state - StmState crr_state; - int ret = stmTransitionState(event_id, &crr_state); + int ret = stmTransitionState(event_id, this->p_crr_state); if (0 > ret) { - HMI_ERROR("wm:pm", "Failed transition state"); + HMI_ERROR("Failed transition state"); if (nullptr != this->callback.onError) { json_object *json_out = json_object_new_object(); @@ -647,11 +828,11 @@ int PolicyManager::transitionState(sd_event_source *source, void *data) } // Update state which is managed by PolicyManager - this->updateState(event_id, crr_state); + this->updateState(event_id); // Create output information for ResourceManager json_object *json_out = json_object_new_object(); - this->createOutputInformation(crr_state, &json_out); + this->createOutputInformation(&json_out); // Notify changed state if (nullptr != this->callback.onStateTransitioned) @@ -659,6 +840,9 @@ int PolicyManager::transitionState(sd_event_source *source, void *data) this->callback.onStateTransitioned(json_out); } + // Start/Stop timer events + this->controlTimerEvent(); + // Release json_object json_object_put(json_out); @@ -674,13 +858,13 @@ int PolicyManager::transitionState(sd_event_source *source, void *data) this->event_source_list.erase(event_id); } - HMI_DEBUG("wm:pm", ">>>>>>>>>> FINISH STATE TRANSITION"); + HMI_DEBUG(">>>>>>>>>> FINISH STATE TRANSITION"); return 0; } int PolicyManager::timerEvent(sd_event_source *source, uint64_t usec, void *data) { - HMI_DEBUG("wm:pm", "Call"); + HMI_DEBUG("Call"); int ret = this->transitionState(source, data); return ret; @@ -689,7 +873,7 @@ int PolicyManager::timerEvent(sd_event_source *source, uint64_t usec, void *data int PolicyManager::setStateTransitionProcessToSystemd(int event_id, uint64_t delay_ms, std::string role) { struct sd_event_source *event_source; - HMI_DEBUG("wm:pm", "event_id:0x%x delay:%d role:%s", event_id, delay_ms, role.c_str()); + HMI_DEBUG("event_id:0x%x delay:%d role:%s", event_id, delay_ms, role.c_str()); if (0 == delay_ms) { @@ -697,7 +881,7 @@ int PolicyManager::setStateTransitionProcessToSystemd(int event_id, uint64_t del &pm::transitionStateWrapper, new int(event_id)); if (0 > ret) { - HMI_ERROR("wm:pm", "Faild to sd_event_add_defer: errno:%d", ret); + HMI_ERROR("Faild to sd_event_add_defer: errno:%d", ret); return -1; } } @@ -716,7 +900,7 @@ int PolicyManager::setStateTransitionProcessToSystemd(int event_id, uint64_t del &pm::timerEventWrapper, new int(event_id)); if (0 > ret) { - HMI_ERROR("wm:pm", "Faild to sd_event_add_time: errno:%d", ret); + HMI_ERROR("Faild to sd_event_add_time: errno:%d", ret); return -1; } } @@ -727,43 +911,136 @@ int PolicyManager::setStateTransitionProcessToSystemd(int event_id, uint64_t del return 0; } -int PolicyManager::loadRoleDb() +bool PolicyManager::changedRestrictionModeTo2On() +{ + // TODO: If possible thie process should be include in zipc stm in the future + if (this->p_crr_state->car_element[StmCarElementNoRestrictionMode].changed && + (StmRestrictionModeSttNoOn != this->p_prv_state->car_element[StmCarElementNoRestrictionMode].state) && + (StmRestrictionModeSttNoOn == this->p_crr_state->car_element[StmCarElementNoRestrictionMode].state)) + { + return true; + } + return false; +} + +bool PolicyManager::changedRestrictionMode2OnToOther() +{ + // TODO: If possible thie process should be include in zipc stm in the future + if (this->p_crr_state->car_element[StmCarElementNoRestrictionMode].changed && + (StmRestrictionModeSttNoOn == this->p_prv_state->car_element[StmCarElementNoRestrictionMode].state) && + (StmRestrictionModeSttNoOn != this->p_crr_state->car_element[StmCarElementNoRestrictionMode].state)) + { + return true; + } + return false; +} + +bool PolicyManager::changedLightstatusBrakeOffToOn() +{ + // TODO: For master + // If possible thie process should be include in zipc stm in the future + if (("master" == this->ecu_name) && + this->p_crr_state->car_element[StmCarElementNoLightstatusBrake].changed && + (StmLightstatusBrakeSttNoOff == this->p_prv_state->car_element[StmCarElementNoLightstatusBrake].state) && + (StmLightstatusBrakeSttNoOn == this->p_crr_state->car_element[StmCarElementNoLightstatusBrake].state)) + { + return true; + } + return false; +} + +bool PolicyManager::changedLightstatusBrakeOnToOff() +{ + // TODO: For master + // If possible thie process should be include in zipc stm in the future + if (("master" == this->ecu_name) && + this->p_crr_state->car_element[StmCarElementNoLightstatusBrake].changed && + (StmLightstatusBrakeSttNoOn == this->p_prv_state->car_element[StmCarElementNoLightstatusBrake].state) && + (StmLightstatusBrakeSttNoOff == this->p_crr_state->car_element[StmCarElementNoLightstatusBrake].state)) + { + return true; + } + return false; +} + +int PolicyManager::loadRolesConfigFile() { 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); + HMI_DEBUG("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"); + HMI_ERROR("AFM_APP_INSTALL_DIR is not defined"); } else { - file_name = std::string(afm_app_install_dir) + std::string("/etc/roles.db"); + file_name = std::string(afm_app_install_dir) + std::string(pm::kPathRolesConfigFile); } - // Load roles.db + // Load roles config file json_object *json_obj; int ret = this->inputJsonFilie(file_name.c_str(), &json_obj); if (0 > ret) { - HMI_ERROR("wm:pm", "Could not open roles.db, so use default role information"); - json_obj = json_tokener_parse(kDefaultRoleDb); + HMI_ERROR("Could not open %s, so use default role information", pm::kPathRolesConfigFile); + json_obj = json_tokener_parse(kDefaultRolesConfig); } - HMI_DEBUG("wm:pm", "json_obj dump:%s", json_object_get_string(json_obj)); + HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj)); + + // Parse ecus + json_object *json_cfg; + if (!json_object_object_get_ex(json_obj, "ecus", &json_cfg)) + { + HMI_ERROR("Parse Error!!"); + return -1; + } + + int num_ecu = json_object_array_length(json_cfg); + HMI_DEBUG("json_cfg(ecus) len:%d", num_ecu); + + const char* c_ecu_name; + json_object *json_ecu; + for (int i = 0; i < num_ecu; i++) + { + json_ecu= json_object_array_get_idx(json_cfg, i); + c_ecu_name = this->getStringFromJson(json_ecu, "name"); + if (nullptr == c_ecu_name) + { + HMI_ERROR("Parse Error!!"); + return -1; + } + + if (std::string(c_ecu_name) == this->ecu_name) + { + break; + } + else + { + json_ecu = nullptr; + } + } + + if (!json_ecu) + { + HMI_ERROR("Areas for ecu:%s is NOT exist!!", this->ecu_name.c_str()); + return -1; + } + + // Parse roles json_object *json_roles; - if (!json_object_object_get_ex(json_obj, "roles", &json_roles)) + if (!json_object_object_get_ex(json_ecu, "roles", &json_roles)) { - HMI_ERROR("wm:pm", "Parse Error!!"); + HMI_ERROR("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)); + HMI_DEBUG("json_cfg len:%d", len); + HMI_DEBUG("json_cfg dump:%s", json_object_get_string(json_roles)); json_object *json_tmp; const char *category; @@ -782,7 +1059,7 @@ int PolicyManager::loadRoleDb() if ((nullptr == category) || (nullptr == roles) || (nullptr == areas) || (nullptr == layer)) { - HMI_ERROR("wm:pm", "Parse Error!!"); + HMI_ERROR("Parse Error!!"); return -1; } @@ -805,95 +1082,144 @@ int PolicyManager::loadRoleDb() } // Check - HMI_DEBUG("wm:pm", "Check role2category"); + HMI_DEBUG("Check role2category"); for (const auto &x : this->role2category) { - HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str()); + HMI_DEBUG("key:%s, val:%s", x.first.c_str(), x.second.c_str()); } - HMI_DEBUG("wm:pm", "Check category2role"); + HMI_DEBUG("Check category2role"); for (const auto &x : this->category2role) { - HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str()); + HMI_DEBUG("key:%s, val:%s", x.first.c_str(), x.second.c_str()); } - HMI_DEBUG("wm:pm", "Check category2areas"); + HMI_DEBUG("Check category2areas"); for (const auto &x : this->category2areas) { for (const auto &y : x.second) { - HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), y.c_str()); + HMI_DEBUG("key:%s, val:%s", x.first.c_str(), y.c_str()); + } + } + + HMI_DEBUG("Check layer2categories"); + for (const auto &x : this->layer2categories) + { + for (const auto &y : x.second) + { + HMI_DEBUG("key:%s, val:%s", x.first.c_str(), y.c_str()); } } return 0; } -int PolicyManager::loadStateDb() +int PolicyManager::loadLayoutsConfigFile() { - HMI_DEBUG("wm:pm", "Call"); + HMI_DEBUG("Call"); // 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); + HMI_DEBUG("afm_app_install_dir:%s", afm_app_install_dir); std::string file_name; if (!afm_app_install_dir) { - HMI_ERROR("wm:pm", "AFM_APP_INSTALL_DIR is not defined"); + HMI_ERROR("AFM_APP_INSTALL_DIR is not defined"); } else { - file_name = std::string(afm_app_install_dir) + std::string("/etc/states.db"); + file_name = std::string(afm_app_install_dir) + std::string(pm::kPathLayoutsConfigFile); } - // Load states.db + // Load states config file json_object *json_obj; int ret = this->inputJsonFilie(file_name.c_str(), &json_obj); if (0 > ret) { - HMI_DEBUG("wm:pm", "Could not open states.db, so use default layout information"); - json_obj = json_tokener_parse(kDefaultStateDb); + HMI_DEBUG("Could not open %s, so use default layout information", pm::kPathLayoutsConfigFile); + json_obj = json_tokener_parse(kDefaultLayoutsConfig); } - HMI_DEBUG("wm:pm", "json_obj dump:%s", json_object_get_string(json_obj)); + HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj)); - // Perse states - HMI_DEBUG("wm:pm", "Perse states"); + // Parse ecus json_object *json_cfg; - if (!json_object_object_get_ex(json_obj, "states", &json_cfg)) + if (!json_object_object_get_ex(json_obj, "ecus", &json_cfg)) + { + HMI_ERROR("Parse Error!!"); + return -1; + } + + int num_ecu = json_object_array_length(json_cfg); + HMI_DEBUG("json_cfg(ecus) len:%d", num_ecu); + + const char* c_ecu_name; + json_object *json_ecu; + for (int i = 0; i < num_ecu; i++) + { + json_ecu= json_object_array_get_idx(json_cfg, i); + + c_ecu_name = this->getStringFromJson(json_ecu, "name"); + if (nullptr == c_ecu_name) + { + HMI_ERROR("Parse Error!!"); + return -1; + } + + if (std::string(c_ecu_name) == this->ecu_name) + { + break; + } + else + { + json_ecu = nullptr; + } + } + + if (!json_ecu) + { + HMI_ERROR("Areas for ecu:%s is NOT exist!!", this->ecu_name.c_str()); + return -1; + } + + // Perse layouts + HMI_DEBUG("Perse layouts"); + json_object *json_layouts; + if (!json_object_object_get_ex(json_ecu, "layouts", &json_layouts)) { - HMI_ERROR("wm:pm", "Parse Error!!"); + HMI_ERROR("Parse Error!!"); return -1; } - int len = json_object_array_length(json_cfg); - HMI_DEBUG("wm:pm", "json_cfg len:%d", len); - HMI_DEBUG("wm:pm", "json_cfg dump:%s", json_object_get_string(json_cfg)); + int len = json_object_array_length(json_layouts); + HMI_DEBUG("json_layouts len:%d", len); + HMI_DEBUG("json_layouts dump:%s", json_object_get_string(json_layouts)); 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); + json_object *json_tmp = json_object_array_get_idx(json_layouts, i); layout = this->getStringFromJson(json_tmp, "name"); if (nullptr == layout) { - HMI_ERROR("wm:pm", "Parse Error!!"); + HMI_ERROR("Parse Error!!"); return -1; } - HMI_DEBUG("wm:pm", "> layout:%s", layout); + HMI_DEBUG("> layout:%s", layout); json_object *json_area_array; if (!json_object_object_get_ex(json_tmp, "areas", &json_area_array)) { - HMI_ERROR("wm:pm", "Parse Error!!"); + HMI_ERROR("Parse Error!!"); return -1; } int len_area = json_object_array_length(json_area_array); - HMI_DEBUG("wm:pm", "json_area_array len:%d", len_area); - HMI_DEBUG("wm:pm", "json_area_array dump:%s", json_object_get_string(json_area_array)); + HMI_DEBUG("json_area_array len:%d", len_area); + HMI_DEBUG("json_area_array dump:%s", json_object_get_string(json_area_array)); LayoutState layout_state; AreaState area_state; @@ -913,22 +1239,22 @@ int PolicyManager::loadStateDb() const char *area = this->getStringFromJson(json_area, "name"); if (nullptr == area) { - HMI_ERROR("wm:pm", "Parse Error!!"); + HMI_ERROR("Parse Error!!"); return -1; } area_state.name = std::string(area); - HMI_DEBUG("wm:pm", ">> area:%s", area); + HMI_DEBUG(">> area:%s", area); // Get app attribute of the area category = this->getStringFromJson(json_area, "category"); if (nullptr == category) { - HMI_ERROR("wm:pm", "Parse Error!!"); + HMI_ERROR("Parse Error!!"); return -1; } area_state.category = std::string(category); category_num[category]++; - HMI_DEBUG("wm:pm", ">>> category:%s", category); + HMI_DEBUG(">>> category:%s", category); role = this->getStringFromJson(json_area, "role"); if (nullptr != role) @@ -940,7 +1266,7 @@ int PolicyManager::loadStateDb() { area_state.role = std::string(""); } - HMI_DEBUG("wm:pm", ">>> role:%s", role); + HMI_DEBUG(">>> role:%s", role); layout_state.area_list.push_back(area_state); } @@ -960,14 +1286,14 @@ int PolicyManager::loadStateDb() for (auto itr_layout = this->default_layouts.begin(); itr_layout != this->default_layouts.end(); ++itr_layout) { - HMI_DEBUG("wm:pm", ">>> layout:%s", itr_layout->first.c_str()); + HMI_DEBUG(">>> layout:%s", itr_layout->first.c_str()); for (auto itr_area = itr_layout->second.area_list.begin(); itr_area != itr_layout->second.area_list.end(); ++itr_area) { - HMI_DEBUG("wm:pm", ">>> >>> area :%s", itr_area->name.c_str()); - HMI_DEBUG("wm:pm", ">>> >>> category:%s", itr_area->category.c_str()); - HMI_DEBUG("wm:pm", ">>> >>> role :%s", itr_area->role.c_str()); + HMI_DEBUG(">>> >>> area :%s", itr_area->name.c_str()); + HMI_DEBUG(">>> >>> category:%s", itr_area->category.c_str()); + HMI_DEBUG(">>> >>> role :%s", itr_area->role.c_str()); } } @@ -979,35 +1305,35 @@ int PolicyManager::loadStateDb() void PolicyManager::pushInvisibleRoleHistory(std::string category, std::string role) { - auto i = std::remove_if(this->invisible_role_history[category].begin(), - this->invisible_role_history[category].end(), + auto i = std::remove_if(this->crr_invisible_role_history[category].begin(), + this->crr_invisible_role_history[category].end(), [role](std::string x) { return (role == x); }); - if (this->invisible_role_history[category].end() != i) + if (this->crr_invisible_role_history[category].end() != i) { - this->invisible_role_history[category].erase(i); + this->crr_invisible_role_history[category].erase(i); } - this->invisible_role_history[category].push_back(role); + this->crr_invisible_role_history[category].push_back(role); - if (pm::kInvisibleRoleHistoryNum < invisible_role_history[category].size()) + if (pm::kInvisibleRoleHistoryNum < crr_invisible_role_history[category].size()) { - this->invisible_role_history[category].erase( - this->invisible_role_history[category].begin()); + this->crr_invisible_role_history[category].erase( + this->crr_invisible_role_history[category].begin()); } } std::string PolicyManager::popInvisibleRoleHistory(std::string category) { std::string role; - if (invisible_role_history[category].empty()) + if (crr_invisible_role_history[category].empty()) { role = ""; } else { - role = this->invisible_role_history[category].back(); - this->invisible_role_history[category].pop_back(); + role = this->crr_invisible_role_history[category].back(); + this->crr_invisible_role_history[category].pop_back(); } return role; } @@ -1017,7 +1343,7 @@ const char *PolicyManager::getStringFromJson(json_object *obj, const char *key) json_object *tmp; if (!json_object_object_get_ex(obj, key, &tmp)) { - HMI_DEBUG("wm:pm", "Not found key \"%s\"", key); + HMI_DEBUG("Not found key \"%s\"", key); return nullptr; } @@ -1029,13 +1355,13 @@ int PolicyManager::inputJsonFilie(const char *file, json_object **obj) const int input_size = 128; int ret = -1; - HMI_DEBUG("wm:pm", "Input file: %s", file); + HMI_DEBUG("Input file: %s", file); // Open json file FILE *fp = fopen(file, "rb"); if (nullptr == fp) { - HMI_ERROR("wm:pm", "Could not open file"); + HMI_ERROR("Could not open file"); return ret; } @@ -1050,7 +1376,7 @@ int PolicyManager::inputJsonFilie(const char *file, json_object **obj) *obj = json_tokener_parse_ex(tokener, buffer, len); if (nullptr != *obj) { - HMI_DEBUG("wm:pm", "File input is success"); + HMI_DEBUG("File input is success"); ret = 0; break; } @@ -1058,9 +1384,9 @@ int PolicyManager::inputJsonFilie(const char *file, json_object **obj) json_error = json_tokener_get_error(tokener); if ((json_tokener_continue != json_error) || (input_size > len)) { - HMI_ERROR("wm:pm", "Failed to parse file (byte:%d err:%s)", + HMI_ERROR("Failed to parse file (byte:%d err:%s)", (input_size * block_cnt), json_tokener_error_desc(json_error)); - HMI_ERROR("wm:pm", "\n%s", buffer); + HMI_ERROR("\n%s", buffer); *obj = nullptr; break; } @@ -1078,8 +1404,8 @@ int PolicyManager::inputJsonFilie(const char *file, json_object **obj) void PolicyManager::dumpLayerState(std::unordered_map<std::string, LayerState> &layers) { - HMI_DEBUG("wm:pm", "-------------------------------------------------------------------------------------------------------"); - HMI_DEBUG("wm:pm", "|%-15s|%s|%-20s|%-20s|%-20s|%-20s|", + HMI_DEBUG("-------------------------------------------------------------------------------------------------------"); + HMI_DEBUG("|%-15s|%s|%-20s|%-20s|%-20s|%-20s|", "LAYER", "C", "LAYOUT", "AREA", "CATEGORY", "ROLE"); for (const auto &itr : layers) { @@ -1093,21 +1419,21 @@ void PolicyManager::dumpLayerState(std::unordered_map<std::string, LayerState> & if (first) { first = false; - HMI_DEBUG("wm:pm", "|%-15s|%1s|%-20s|%-20s|%-20s|%-20s|", + HMI_DEBUG("|%-15s|%1s|%-20s|%-20s|%-20s|%-20s|", layer, changed, layout, as.name.c_str(), as.category.c_str(), as.role.c_str()); } else - HMI_DEBUG("wm:pm", "|%-15s|%1s|%-20s|%-20s|%-20s|%-20s|", + HMI_DEBUG("|%-15s|%1s|%-20s|%-20s|%-20s|%-20s|", "", "", "", as.name.c_str(), as.category.c_str(), as.role.c_str()); } } - HMI_DEBUG("wm:pm", "-------------------------------------------------------------------------------------------------------"); + HMI_DEBUG("-------------------------------------------------------------------------------------------------------"); } void PolicyManager::dumpInvisibleRoleHistory() { - HMI_DEBUG("wm:pm", ">>>>>>>>>> DUMP INVISIBLE ROLE HISTORY ( category [older > newer] )"); + HMI_DEBUG(">>>>>>>>>> DUMP INVISIBLE ROLE HISTORY ( category [older > newer] )"); for (int ctg_no = StmCtgNoMin; ctg_no <= StmCtgNoMax; ctg_no++) { if (ctg_no == StmCtgNoNone) @@ -1116,11 +1442,11 @@ void PolicyManager::dumpInvisibleRoleHistory() std::string category = std::string(kStmCategoryName[ctg_no]); std::string str = category + " [ "; - for (const auto &i : this->invisible_role_history[category]) + for (const auto &i : this->crr_invisible_role_history[category]) str += (i + " > "); str += "]"; - HMI_DEBUG("wm:pm", "%s", str.c_str()); + HMI_DEBUG("%s", str.c_str()); } } @@ -1152,7 +1478,7 @@ std::string PolicyManager::deleteSpace(std::string str) return ret; } -const char *PolicyManager::kDefaultRoleDb = "{ \ +const char *PolicyManager::kDefaultRolesConfig = "{ \ \"roles\":[ \ { \ \"category\": \"homescreen\", \ @@ -1197,8 +1523,8 @@ const char *PolicyManager::kDefaultRoleDb = "{ \ ] \ }"; -const char *PolicyManager::kDefaultStateDb = "{ \ - \"states\": [ \ +const char *PolicyManager::kDefaultLayoutsConfig = "{ \ + \"layouts\": [ \ { \ \"name\": \"homescreen\", \ \"layer\": \"far_homescreen\", \ diff --git a/policy_manager/policy_manager.hpp b/policy_manager/policy_manager.hpp index 798b706..61fbf06 100644 --- a/policy_manager/policy_manager.hpp +++ b/policy_manager/policy_manager.hpp @@ -31,7 +31,7 @@ class PolicyManager { public: explicit PolicyManager(); - ~PolicyManager() = default; + ~PolicyManager(); using Handler = std::function<void(json_object *)>; @@ -41,7 +41,7 @@ class PolicyManager Handler onError; } CallbackTable; - int initialize(); + int initialize(std::string ecu_name); void registerCallback(CallbackTable callback_table); int setInputEventData(json_object *json_in); int executeStateTransition(); @@ -87,10 +87,19 @@ class PolicyManager bool changed; } LayerState; + typedef struct Mode + { + std::string state; + bool changed; + } Mode; + typedef std::vector<std::string> Areas; typedef std::vector<std::string> Categories; typedef std::vector<std::string> Roles; + StmState *p_crr_state; + StmState *p_prv_state; + // Convert map std::unordered_map<std::string, int> eventname2no; std::unordered_map<std::string, int> categoryname2no; @@ -107,27 +116,43 @@ class PolicyManager CallbackTable callback; + std::unordered_map<std::string, Mode> prv_car_elements; + std::unordered_map<std::string, Mode> crr_car_elements; + std::unordered_map<std::string, LayerState> prv_layers; std::unordered_map<std::string, LayerState> crr_layers; + std::unordered_map<std::string, LayerState> prv_layers_car_stop; + std::unordered_map<std::string, LayoutState> default_layouts; - std::map<std::string, Roles> invisible_role_history; + std::map<std::string, Roles> crr_invisible_role_history; + std::map<std::string, Roles> prv_invisible_role_history; + + std::string ecu_name; void initializeState(); + void initializeModeState(); void initializeLayerState(); - void updateState(int event_id, StmState crr_state); - void updateLayer(int event_id, StmState crr_state); + void updateState(int event_id); + void updateModeState(); + void updateLayer(int event_id); int updateLayout(int event_id, int layer_no, std::string crr_layout_name, LayoutState &crr_layout_state); - void createOutputInformation(StmState crr_state, json_object **json_out); + void createOutputInformation(json_object **json_out); + void controlTimerEvent(); int setStateTransitionProcessToSystemd(int event, uint64_t delay_ms, std::string role); void pushInvisibleRoleHistory(std::string category, std::string role); std::string popInvisibleRoleHistory(std::string category); - int loadRoleDb(); - int loadStateDb(); + bool changedRestrictionModeTo2On(); + bool changedRestrictionMode2OnToOther(); + bool changedLightstatusBrakeOffToOn(); + bool changedLightstatusBrakeOnToOff(); + + int loadRolesConfigFile(); + int loadLayoutsConfigFile(); void dumpLayerState(std::unordered_map<std::string, LayerState> &layers); void dumpInvisibleRoleHistory(); @@ -142,8 +167,8 @@ class PolicyManager std::vector<std::string> parseString(std::string str, char delimiter); std::string deleteSpace(std::string str); - static const char *kDefaultRoleDb; - static const char *kDefaultStateDb; + static const char *kDefaultRolesConfig; + static const char *kDefaultLayoutsConfig; }; #endif // TMCAGLWM_POLICY_MANAGER_HPP diff --git a/policy_manager/stm/stm.c b/policy_manager/stm/stm.c index c63a599..1c4170d 100644 --- a/policy_manager/stm/stm.c +++ b/policy_manager/stm/stm.c @@ -22,9 +22,18 @@ const char* kStmEventName[] = { "none", "activate", "deactivate", + "trans_gear_neutral", + "trans_gear_not_neutral", + "parking_brake_off", + "parking_brake_on", + "accel_pedal_off", + "accel_pedal_on", + "lamp_off", + "lamp_on", + "lightstatus_brake_off", + "lightstatus_brake_on", "restriction_mode_off", - "restriction_mode_1_on", - "restriction_mode_2_on", + "restriction_mode_on", "undo", }; @@ -34,11 +43,16 @@ const char* kStmCategoryName[] = { "map", "general", "splitable", + "splitable_main", + "splitable_sub", "pop_up", "system_alert", "restriction", "system", "software_keyboard", + "tbt", + "meter", + "receiver", "debug", }; @@ -53,6 +67,7 @@ const char* kStmAreaName[] = { "restriction.split.main", "restriction.split.sub", "software_keyboard", + "master.split.sub", }; const char* kStmLayoutName[] = { @@ -71,6 +86,13 @@ const char* kStmLayoutName[] = { "restriction.split.sub", "system.normal", "software_keyboard", + "tbt", + "remote_tbt", + "meter.normal", + "meter_receiver", + "meter_splitable", + "splitable_receiver", + "receiver.split", "debug.normal", "debug.split.main", "debug.split.sub", @@ -83,9 +105,10 @@ const char* kStmLayerName[] = { "near_homescreen", "restriction", "on_screen", + "remote", }; -const char* kStmModeName[] = { +const char* kStmCarElementName[] = { "trans_gear", "parking_brake", "accel_pedal", @@ -95,18 +118,53 @@ const char* kStmModeName[] = { "restriction_mode", }; +const char* kStmTransGearStateName[] = { + "neutral", + "not_neutral" +}; + +const char* kStmParkingBrakeStateName[] = { + "off", + "on" +}; + +const char* kStmAccelPedalStateName[] = { + "off", + "on" +}; + +const char* kStmRunningSttNo2Name[] = { + "stop", + "run" +}; + +const char* kStmLampStateName[] = { + "off", + "on" +}; + +const char* kStmLightstatusBrakeStateName[] = { + "off", + "on" +}; + const char* kStmRestrictionModeStateName[] = { "off", - "1on", - "2on", + "on", }; -const char** kStmModeStateNameList[] = { +const char** kStmCarElementStateNameList[] = { + kStmTransGearStateName, + kStmParkingBrakeStateName, + kStmAccelPedalStateName, + kStmRunningSttNo2Name, + kStmLampStateName, + kStmLightstatusBrakeStateName, kStmRestrictionModeStateName, }; -void stmInitialize() { - stmInitializeInner(); +void stmInitialize(const char *ecu_name) { + stmInitializeInner(ecu_name); } int stmTransitionState(int event, StmState* state) { diff --git a/policy_manager/stm/stm.h b/policy_manager/stm/stm.h index deebf9c..685a43b 100644 --- a/policy_manager/stm/stm.h +++ b/policy_manager/stm/stm.h @@ -37,9 +37,18 @@ enum StmEvtNo { StmEvtNoNone = 0, StmEvtNoActivate, StmEvtNoDeactivate, + StmEvtNoTransGearN, + StmEvtNoTransGearNotN, + StmEvtNoParkingBrakeOff, + StmEvtNoParkingBrakeOn, + StmEvtNoAccelPedalOff, + StmEvtNoAccelPedalOn, + StmEvtNoLampOff, + StmEvtNoLampOn, + StmEvtNoLightstatusBrakeOff, + StmEvtNoLightstatusBrakeOn, StmEvtNoRestrictionModeOff, - StmEvtNoRestrictionMode1On, - StmEvtNoRestrictionMode2On, + StmEvtNoRestrictionModeOn, StmEvtNoUndo, StmEvtNoNum, @@ -55,11 +64,16 @@ enum StmCtgNo { StmCtgNoMap, StmCtgNoGeneral, StmCtgNoSplitable, + StmCtgNoSplitableMain, + StmCtgNoSplitableSub, StmCtgNoPopUp, StmCtgNoSystemAlert, StmCtgNoRestriction, StmCtgNoSystem, StmCtgNoSoftwareKeyboard, + StmCtgNoTbt, + StmCtgNoMeter, + StmCtgNoReceiver, StmCtgNoDebug, StmCtgNoNum, @@ -80,6 +94,7 @@ enum StmAreaNo { StmAreaNoRestrictionSplitMain, StmAreaNoRestrictionSplitSub, StmAreaNoSoftwareKyeboard, + StmAreaNoMasterSplitSub, StmAreaNoNum, @@ -94,6 +109,7 @@ enum StmLayerNo { StmLayerNoNearHomescreen, StmLayerNoRestriction, StmLayerNoOnScreen, + StmLayerNoRemote, StmLayerNoNum, @@ -118,6 +134,13 @@ enum StmLayoutNo { StmLayoutNoRstSplSub, StmLayoutNoSysNml, StmLayoutNoSftKbd, + StmLayoutNoTbt, + StmLayoutNoRmtTbt, + StmLayoutNoMtrNml, + StmLayoutNoMtrRcv, + StmLayoutNoMtrSpl, + StmLayoutNoSplRcv, + StmLayoutNoRcvSpl, StmLayoutNoDbgNml, StmLayoutNoDbgSplMain, StmLayoutNoDbgSplSub, @@ -129,21 +152,56 @@ enum StmLayoutNo { StmLayoutNoMax = StmLayoutNoNum - 1, }; -// Mode kind number -enum StmModeNo { - StmModeNoRestrictionMode = 0, +// Enum for mode state +enum StmTransGearStt { + StmTransGearSttNoN = 0, + StmTransGearSttNoNotN +}; - StmModeNoNum, +enum StmParkingBrakeStt { + StmParkingBrakeSttNoOff = 0, + StmParkingBrakeSttNoOn +}; - StmModeNoMin = StmModeNoRestrictionMode, - StmModeNoMax = StmModeNoNum - 1, +enum StmAccelPedalStt { + StmAccelPedalSttNoOff = 0, + StmAccelPedalSttNoOn +}; + +enum StmCarStt { + StmRunningNoStop = 0, + StmRunningNoRun +}; + +enum StmLampStt { + StmLampSttNoOff = 0, + StmLampSttNoOn +}; + +enum StmLightstatusBrakeStt { + StmLightstatusBrakeSttNoOff = 0, + StmLightstatusBrakeSttNoOn }; -// Enum for mode state enum StmRestrictionModeSttNo { StmRestrictionModeSttNoOff = 0, - StmRestrictionModeSttNo1On, - StmRestrictionModeSttNo2On, + StmRestrictionModeSttNoOn, +}; + +// Mode kind number +enum StmCarElementNo { + StmCarElementNoTransGear = 0, + StmCarElementNoParkingBrake, + StmCarElementNoAccelPedal, + StmCarElementNoRunning, + StmCarElementNoLamp, + StmCarElementNoLightstatusBrake, + StmCarElementNoRestrictionMode, + + StmCarElementNoNum, + + StmCarElementNoMin = StmCarElementNoTransGear, + StmCarElementNoMax = StmCarElementNoNum - 1, }; // String for state @@ -152,8 +210,8 @@ extern const char* kStmCategoryName[]; extern const char* kStmAreaName[]; extern const char* kStmLayoutName[]; extern const char* kStmLayerName[]; -extern const char* kStmModeName[]; -extern const char** kStmModeStateNameList[]; +extern const char* kStmCarElementName[]; +extern const char** kStmCarElementStateNameList[]; // Struct for state typedef struct StmBaseState { @@ -162,12 +220,12 @@ typedef struct StmBaseState { } StmBaseState; typedef struct StmState { - StmBaseState mode[StmModeNoNum]; + StmBaseState car_element[StmCarElementNoNum]; StmBaseState layer[StmLayerNoNum]; } StmState; // API -void stmInitialize(); +void stmInitialize(const char *ecu_name); int stmTransitionState(int event_no, StmState* state); void stmUndoState(); diff --git a/policy_manager/stm/stub/stm_inner.c b/policy_manager/stm/stub/stm_inner.c index bd1b319..2ae2cf0 100644 --- a/policy_manager/stm/stub/stm_inner.c +++ b/policy_manager/stm/stub/stm_inner.c @@ -95,6 +95,32 @@ int stmTransitionStateInner(int event, StmState* state) { g_stm_crr_state.layer[StmLayerNoOnScreen].state = StmLayoutNoSysAlt; g_stm_crr_state.layer[StmLayerNoOnScreen].changed = STM_TRUE; } + else if (StmCtgNoTbt == category_no) + { + if (StmAreaNoMasterSplitSub == area_no) + { + g_stm_crr_state.layer[StmLayerNoApps].state = StmLayoutNoRcvSpl; + g_stm_crr_state.layer[StmLayerNoApps].changed = STM_TRUE; + + g_stm_crr_state.layer[StmLayerNoRemote].state = StmLayoutNoRmtTbt; + g_stm_crr_state.layer[StmLayerNoRemote].changed = STM_TRUE; + } + else if (StmAreaNoNormal == area_no) + { + g_stm_crr_state.layer[StmLayerNoRemote].state = StmLayoutNoTbt; + g_stm_crr_state.layer[StmLayerNoRemote].changed = STM_TRUE; + } + } + else if (StmCtgNoReceiver == category_no) + { + g_stm_crr_state.layer[StmLayerNoApps].state = StmLayoutNoRcvSpl; + g_stm_crr_state.layer[StmLayerNoApps].changed = STM_TRUE; + } + else if (StmCtgNoMeter == category_no) + { + g_stm_crr_state.layer[StmLayerNoApps].state = StmLayoutNoMtrNml; + g_stm_crr_state.layer[StmLayerNoApps].changed = STM_TRUE; + } } else if (StmEvtNoDeactivate == event_no) { @@ -138,6 +164,14 @@ int stmTransitionStateInner(int event, StmState* state) { g_stm_crr_state.layer[StmLayerNoOnScreen].changed = STM_TRUE; } } + else if (StmCtgNoTbt == category_no) + { + if (StmLayoutNoRmtTbt == g_stm_prv_state.layer[StmLayerNoRemote].state) + { + g_stm_crr_state.layer[StmLayerNoRemote].state = StmLayoutNoNone; + g_stm_crr_state.layer[StmLayerNoRemote].changed = STM_TRUE; + } + } } // Copy current state for return diff --git a/policy_manager/stm/zipc/CMakeLists.txt b/policy_manager/stm/zipc/CMakeLists.txt index de286a7..abbdc41 100644 --- a/policy_manager/stm/zipc/CMakeLists.txt +++ b/policy_manager/stm/zipc/CMakeLists.txt @@ -24,6 +24,13 @@ set(ST_DIR_NHS ${ST_DIR}/NearHomeScreen) set(ST_DIR_OS ${ST_DIR}/OnScreenlayer) set(ST_DIR_RL ${ST_DIR}/RestrictionLayer) set(ST_DIR_RM ${ST_DIR}/RestrictionMode) +set(ST_DIR_AP ${ST_DIR}/AccelPedal) +set(ST_DIR_CS ${ST_DIR}/CarState) +set(ST_DIR_LSB ${ST_DIR}/LightStatusBrake) + +set(ST_DIR_MST_AL ${ST_DIR}/master/layer/apps) +set(ST_DIR_MST_RMT ${ST_DIR}/master/layer/remote) + add_library(${TARGETS_STM} STATIC @@ -41,6 +48,16 @@ add_library(${TARGETS_STM} ${ST_DIR_RL}/ZREL_Restriction_func.c ${ST_DIR_RM}/ZREM_RestrictionMode.c ${ST_DIR_RM}/ZREM_RestrictionMode_func.c + ${ST_DIR_AP}/ZACCEL_AccelPedal.c + ${ST_DIR_AP}/ZACCEL_AccelPedalState_func.c + ${ST_DIR_CS}/ZCAR_CarState.c + ${ST_DIR_CS}/ZCAR_CarState_func.c + ${ST_DIR_LSB}/ZLIGHT_LightstatusBrake.c + ${ST_DIR_LSB}/ZLIGHT_LightstatusBrakeStatus_func.c + ./stm_master_apps.c + ./stm_master_remote.c + ${ST_DIR_MST_AL}/Zmaster_apps_apps_main.c + ${ST_DIR_MST_RMT}/Zmaster_remote_remote.c ) target_include_directories(${TARGETS_STM} @@ -53,6 +70,11 @@ target_include_directories(${TARGETS_STM} ./${ST_DIR_OS} ./${ST_DIR_RL} ./${ST_DIR_RM} + ./${ST_DIR_AP} + ./${ST_DIR_CS} + ./${ST_DIR_LSB} + ./${ST_DIR_MST_AL} + ./${ST_DIR_MST_RMT} ./${ST_DIR_CMN} ) diff --git a/policy_manager/stm/zipc/StateTransitionor/AccelPedal/ZACCEL_AccelPedal.c b/policy_manager/stm/zipc/StateTransitionor/AccelPedal/ZACCEL_AccelPedal.c new file mode 100644 index 0000000..fa692ee --- /dev/null +++ b/policy_manager/stm/zipc/StateTransitionor/AccelPedal/ZACCEL_AccelPedal.c @@ -0,0 +1,117 @@ +/************************************************************/ +/* ZACCEL_AccelPedal.c */ +/* AccelPedal State transition model source file */ +/* ZIPC Designer Version 1.2.0 */ +/************************************************************/ +#include "../ZST_include.h" + +/* State management variable */ +static uint8_t ZACCEL_AccelPedalState[ZACCEL_ACCELPEDALSTATENOMAX]; + +static void ZACCEL_AccelPedals0e1( void ); +static void ZACCEL_AccelPedals1e0( void ); +static void ZACCEL_AccelPedals0Event( void ); +static void ZACCEL_AccelPedals1Event( void ); + +/****************************************/ +/* Action function */ +/* STM : AccelPedal */ +/* State : accel_pedal_off( No 0 ) */ +/* Event : evt_accel_pedal_on( No 1 ) */ +/****************************************/ +static void ZACCEL_AccelPedals0e1( void ) +{ + ZACCEL_AccelPedalState[ZACCEL_ACCELPEDAL] = ( uint8_t )ZACCEL_ACCELPEDALS1; + stm_aps_start_activity_accel_pedal_on(); +} + +/****************************************/ +/* Action function */ +/* STM : AccelPedal */ +/* State : accel_pedal_on( No 1 ) */ +/* Event : evt_accel_pedal_off( No 0 )*/ +/****************************************/ +static void ZACCEL_AccelPedals1e0( void ) +{ + ZACCEL_AccelPedalState[ZACCEL_ACCELPEDAL] = ( uint8_t )ZACCEL_ACCELPEDALS0; + stm_aps_start_activity_accel_pedal_off(); +} + +/****************************************/ +/* Event appraisal function */ +/* STM : AccelPedal */ +/* State : accel_pedal_off( No 0 ) */ +/****************************************/ +static void ZACCEL_AccelPedals0Event( void ) +{ + /*evt_accel_pedal_on*/ + if( g_stm_event == StmEvtNoAccelPedalOn ) + { + ZACCEL_AccelPedals0e1(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } +} + +/****************************************/ +/* Event appraisal function */ +/* STM : AccelPedal */ +/* State : accel_pedal_on( No 1 ) */ +/****************************************/ +static void ZACCEL_AccelPedals1Event( void ) +{ + /*evt_accel_pedal_off*/ + if( g_stm_event == StmEvtNoAccelPedalOff ) + { + ZACCEL_AccelPedals1e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } +} + +/****************************************/ +/* Event call function */ +/* STM : AccelPedal */ +/****************************************/ +void stm_aps_event_call( void ) +{ + stm_aps_start_stm(); + switch( ZACCEL_AccelPedalState[ZACCEL_ACCELPEDAL] ) + { + case ZACCEL_ACCELPEDALS0: + ZACCEL_AccelPedals0Event(); + break; + case ZACCEL_ACCELPEDALS1: + ZACCEL_AccelPedals1Event(); + break; + default: + /*Not accessible to this else (default).*/ + break; + } +} + +/****************************************/ +/* Initial function */ +/* STM : AccelPedal */ +/****************************************/ +void stm_aps_initialize( void ) +{ + ZACCEL_AccelPedalState[ZACCEL_ACCELPEDAL] = ( uint8_t )ZACCEL_ACCELPEDALS0; + stm_aps_start_activity_accel_pedal_off(); +} + +/****************************************/ +/* Terminate function */ +/* STM : AccelPedal */ +/****************************************/ +void ZACCEL_AccelPedalTerminate( void ) +{ + ZACCEL_AccelPedalState[ZACCEL_ACCELPEDAL] = ( uint8_t )ZACCEL_ACCELPEDALTERMINATE; +} + diff --git a/policy_manager/stm/zipc/StateTransitionor/AccelPedal/ZACCEL_AccelPedal.h b/policy_manager/stm/zipc/StateTransitionor/AccelPedal/ZACCEL_AccelPedal.h new file mode 100644 index 0000000..40da956 --- /dev/null +++ b/policy_manager/stm/zipc/StateTransitionor/AccelPedal/ZACCEL_AccelPedal.h @@ -0,0 +1,41 @@ +/************************************************************/ +/* ZACCEL_AccelPedal.h */ +/* AccelPedal State transition model header file */ +/* ZIPC Designer Version 1.2.0 */ +/************************************************************/ +#ifndef ZHEADER_ZACCEL_ACCELPEDAL_H +#define ZHEADER_ZACCEL_ACCELPEDAL_H + +/*State management variable access define*/ +#define ZACCEL_ACCELPEDAL ( 0U ) +#define ZACCEL_ACCELPEDALS0 ( 0U ) +#define ZACCEL_ACCELPEDALS1 ( 1U ) +#define ZACCEL_ACCELPEDALSTATENOMAX ( 1U ) + +/*End state define*/ +#define ZACCEL_ACCELPEDALEND ( 2U ) +/*Terminate state define*/ +#define ZACCEL_ACCELPEDALTERMINATE ( ZACCEL_ACCELPEDALEND + 1U ) + +/*State no define*/ +#define ZACCEL_ACCELPEDALS0STATENO ( 0U ) +#define ZACCEL_ACCELPEDALS1STATENO ( 1U ) + +/*State serial no define*/ +#define ZACCEL_ACCELPEDALS0STATESERIALNO ( 0U ) +#define ZACCEL_ACCELPEDALS1STATESERIALNO ( 1U ) + +/*Event no define*/ +#define ZACCEL_ACCELPEDALE0EVENTNO ( 0U ) +#define ZACCEL_ACCELPEDALE1EVENTNO ( 1U ) + +/*Event serial no define*/ +#define ZACCEL_ACCELPEDALE0EVENTSERIALNO ( 0U ) +#define ZACCEL_ACCELPEDALE1EVENTSERIALNO ( 1U ) + +/*Extern function*/ +extern void stm_aps_event_call( void ); +extern void stm_aps_initialize( void ); +extern void ZACCEL_AccelPedalTerminate( void ); + +#endif diff --git a/policy_manager/stm/zipc/StateTransitionor/AccelPedal/ZACCEL_AccelPedalState_func.c b/policy_manager/stm/zipc/StateTransitionor/AccelPedal/ZACCEL_AccelPedalState_func.c new file mode 100644 index 0000000..1fd9c2a --- /dev/null +++ b/policy_manager/stm/zipc/StateTransitionor/AccelPedal/ZACCEL_AccelPedalState_func.c @@ -0,0 +1,45 @@ +/************************************************************/ +/* ZACCEL_AccelPedalState_func.c */ +/* Function and variable source file */ +/* ZIPC Designer Version 1.2.0 */ +/************************************************************/ +#include "../ZST_include.h" + +/************************************************************* + Function definition +*************************************************************/ + +/* + * @name stm_aps_start_activity_accel_pedal_off + */ +void stm_aps_start_activity_accel_pedal_off() { + g_stm_crr_state.car_element[StmCarElementNoAccelPedal].state = StmAccelPedalSttNoOff; + g_stm_crr_state.car_element[StmCarElementNoAccelPedal].changed = STM_TRUE; +} + +/* + * @name stm_aps_start_activity_accel_pedal_on + */ +void stm_aps_start_activity_accel_pedal_on() { + g_stm_crr_state.car_element[StmCarElementNoAccelPedal].state = StmAccelPedalSttNoOn; + g_stm_crr_state.car_element[StmCarElementNoAccelPedal].changed = STM_TRUE; +} + +/* + * @name stm_aps_initialize_variable + */ +void stm_aps_initialize_variable() { + g_stm_prv_state.car_element[StmCarElementNoAccelPedal].state = StmAccelPedalSttNoOff; + g_stm_prv_state.car_element[StmCarElementNoAccelPedal].changed = STM_FALSE; + + g_stm_crr_state.car_element[StmCarElementNoAccelPedal].state = StmAccelPedalSttNoOff; + g_stm_crr_state.car_element[StmCarElementNoAccelPedal].changed = STM_FALSE; +} + +/* + * @name stm_aps_start_stm + */ +void stm_aps_start_stm() { + g_stm_prv_state.car_element[StmCarElementNoAccelPedal].state = g_stm_crr_state.car_element[StmCarElementNoAccelPedal].state; + g_stm_crr_state.car_element[StmCarElementNoAccelPedal].changed = STM_FALSE; +} diff --git a/policy_manager/stm/zipc/StateTransitionor/AccelPedal/ZACCEL_AccelPedalState_func.h b/policy_manager/stm/zipc/StateTransitionor/AccelPedal/ZACCEL_AccelPedalState_func.h new file mode 100644 index 0000000..7d36cd0 --- /dev/null +++ b/policy_manager/stm/zipc/StateTransitionor/AccelPedal/ZACCEL_AccelPedalState_func.h @@ -0,0 +1,14 @@ +/************************************************************/ +/* ZACCEL_AccelPedalState_func.h */ +/* Function and variable header file */ +/* ZIPC Designer Version 1.2.0 */ +/************************************************************/ +#ifndef ZHEADER_ZACCEL_ACCELPEDALSTATE_FUNC_H +#define ZHEADER_ZACCEL_ACCELPEDALSTATE_FUNC_H + +extern void stm_aps_start_activity_accel_pedal_off(); +extern void stm_aps_start_activity_accel_pedal_on(); +extern void stm_aps_initialize_variable(); +extern void stm_aps_start_stm(); + +#endif diff --git a/policy_manager/stm/zipc/StateTransitionor/AppsLayer/ZAPL_AppsLayer.c b/policy_manager/stm/zipc/StateTransitionor/AppsLayer/ZAPL_AppsLayer.c index b6891e8..9002810 100644 --- a/policy_manager/stm/zipc/StateTransitionor/AppsLayer/ZAPL_AppsLayer.c +++ b/policy_manager/stm/zipc/StateTransitionor/AppsLayer/ZAPL_AppsLayer.c @@ -20,11 +20,11 @@ static void ZAPL_RestrictionModeOffs0e7( void ); static void ZAPL_RestrictionModeOffs0e13( void ); static void ZAPL_RestrictionModeOffs0e15( void ); static void ZAPL_RestrictionModeOffs0e18( void ); -static void ZAPL_RestrictionModeOffs1e0( void ); static void ZAPL_RestrictionModeOffs1e8( void ); +static void ZAPL_RestrictionModeOffs1e14( void ); static void ZAPL_RestrictionModeOffs2e3( void ); -static void ZAPL_RestrictionModeOffs3e2( void ); -static void ZAPL_RestrictionModeOffs4e3( void ); +static void ZAPL_RestrictionModeOffs3e16( void ); +static void ZAPL_RestrictionModeOffs4e17( void ); static void ZAPL_RestrictionModeOffs5e3( void ); static void ZAPL_RestrictionModeOffs6e6( void ); static void ZAPL_RestrictionModeOffs7e7( void ); @@ -87,7 +87,7 @@ static void ZAPL_AppsLayers0StateEntry( void ) /****************************************/ /* State start activity function */ /* STM : AppsLayer */ -/* State : restriction_mode_2_on( No 1 ) */ +/* State : restriction_mode_on( No 1 )*/ /****************************************/ static void ZAPL_AppsLayers1StateEntry( void ) { @@ -121,7 +121,7 @@ static void ZAPL_AppsLayers0e1( void ) /****************************************/ /* Action function */ /* STM : AppsLayer */ -/* State : restriction_mode_2_on( No 1 ) */ +/* State : restriction_mode_on( No 1 )*/ /* Event : stt_restriction_mode_off( No 0 ) */ /****************************************/ static void ZAPL_AppsLayers1e0( void ) @@ -229,23 +229,23 @@ static void ZAPL_RestrictionModeOffs0e18( void ) /* Action function */ /* STM : RestrictionModeOff */ /* State : map( No 1 ) */ -/* Event : ara_normal( No 0 ) */ +/* Event : ara_fullscreen( No 8 ) */ /****************************************/ -static void ZAPL_RestrictionModeOffs1e0( void ) +static void ZAPL_RestrictionModeOffs1e8( void ) { - stm_apl_start_activity_map(); + ZAPL_AppsLayerState[ZAPL_APPSLAYERS0F] = ( uint8_t )ZAPL_RESTRICTIONMODEOFFS0; + stm_apl_start_activity_none(); } /****************************************/ /* Action function */ /* STM : RestrictionModeOff */ /* State : map( No 1 ) */ -/* Event : ara_fullscreen( No 8 ) */ +/* Event : stt_prv_layer_apps_map_nml( No 14 ) */ /****************************************/ -static void ZAPL_RestrictionModeOffs1e8( void ) +static void ZAPL_RestrictionModeOffs1e14( void ) { - ZAPL_AppsLayerState[ZAPL_APPSLAYERS0F] = ( uint8_t )ZAPL_RESTRICTIONMODEOFFS0; - stm_apl_start_activity_none(); + stm_apl_start_activity_map(); } /****************************************/ @@ -263,9 +263,9 @@ static void ZAPL_RestrictionModeOffs2e3( void ) /* Action function */ /* STM : RestrictionModeOff */ /* State : map_fullscreen( No 3 ) */ -/* Event : ara_fullscreen( No 2 ) */ +/* Event : stt_prv_layer_apps_map_fll( No 16 ) */ /****************************************/ -static void ZAPL_RestrictionModeOffs3e2( void ) +static void ZAPL_RestrictionModeOffs3e16( void ) { stm_apl_start_activity_map_fullscreen(); } @@ -274,9 +274,9 @@ static void ZAPL_RestrictionModeOffs3e2( void ) /* Action function */ /* STM : RestrictionModeOff */ /* State : splitable_normal( No 4 ) */ -/* Event : ara_normal( No 3 ) */ +/* Event : stt_prv_layer_apps_spl_nml( No 17 ) */ /****************************************/ -static void ZAPL_RestrictionModeOffs4e3( void ) +static void ZAPL_RestrictionModeOffs4e17( void ) { stm_apl_start_activity_splitable_normal(); } @@ -367,10 +367,10 @@ static void ZAPL_RestrictionModeOns1e3( void ) /****************************************/ static void ZAPL_AppsLayers0Event( void ) { - /*stt_restriction_mode_2_on*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNo2On ) + /*stt_restriction_mode_on*/ + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOn ) { - stm_apl_event_restriction_mode_2_on(); + stm_apl_event_restriction_mode_on(); /*stt_map_is_activated*/ if( g_stm_map_is_activated == STM_TRUE ) { @@ -406,7 +406,7 @@ static void ZAPL_AppsLayers0Event( void ) static void ZAPL_RestrictionModeOffs0Event( void ) { /*stt_restriction_mode_off*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNoOff ) + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOff ) { /*evt_activate*/ if( g_stm_event == StmEvtNoActivate ) @@ -548,7 +548,7 @@ static void ZAPL_RestrictionModeOffs0Event( void ) static void ZAPL_RestrictionModeOffs1Event( void ) { /*stt_restriction_mode_off*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNoOff ) + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOff ) { /*evt_activate*/ if( g_stm_event == StmEvtNoActivate ) @@ -556,13 +556,8 @@ static void ZAPL_RestrictionModeOffs1Event( void ) /*ctg_map*/ if( g_stm_category == StmCtgNoMap ) { - /*ara_normal*/ - if( g_stm_area == StmAreaNoNormal ) - { - ZAPL_RestrictionModeOffs1e0(); - } /*ara_fullscreen*/ - else if( g_stm_area == StmAreaNoFullscreen ) + if( g_stm_area == StmAreaNoFullscreen ) { ZAPL_RestrictionModeOffs0e2(); } @@ -664,7 +659,7 @@ static void ZAPL_RestrictionModeOffs1Event( void ) /*stt_prv_layer_apps_map_nml*/ else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoMapNml ) { - ZAPL_RestrictionModeOffs1e0(); + ZAPL_RestrictionModeOffs1e14(); } /*stt_prv_layer_apps_map_spl*/ else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoMapSpl ) @@ -723,7 +718,7 @@ static void ZAPL_RestrictionModeOffs1Event( void ) static void ZAPL_RestrictionModeOffs2Event( void ) { /*stt_restriction_mode_off*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNoOff ) + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOff ) { /*evt_activate*/ if( g_stm_event == StmEvtNoActivate ) @@ -898,7 +893,7 @@ static void ZAPL_RestrictionModeOffs2Event( void ) static void ZAPL_RestrictionModeOffs3Event( void ) { /*stt_restriction_mode_off*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNoOff ) + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOff ) { /*evt_activate*/ if( g_stm_event == StmEvtNoActivate ) @@ -911,11 +906,6 @@ static void ZAPL_RestrictionModeOffs3Event( void ) { ZAPL_RestrictionModeOffs0e0(); } - /*ara_fullscreen*/ - else if( g_stm_area == StmAreaNoFullscreen ) - { - ZAPL_RestrictionModeOffs3e2(); - } else { /*Else and default design have not done.*/ @@ -1019,7 +1009,7 @@ static void ZAPL_RestrictionModeOffs3Event( void ) /*stt_prv_layer_apps_map_fll*/ else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoMapFll ) { - ZAPL_RestrictionModeOffs3e2(); + ZAPL_RestrictionModeOffs3e16(); } /*stt_prv_layer_apps_spl_nml*/ else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoSplNml ) @@ -1068,7 +1058,7 @@ static void ZAPL_RestrictionModeOffs3Event( void ) static void ZAPL_RestrictionModeOffs4Event( void ) { /*stt_restriction_mode_off*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNoOff ) + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOff ) { /*evt_activate*/ if( g_stm_event == StmEvtNoActivate ) @@ -1100,13 +1090,8 @@ static void ZAPL_RestrictionModeOffs4Event( void ) /*ctg_splitable*/ else if( g_stm_category == StmCtgNoSplitable ) { - /*ara_normal*/ - if( g_stm_area == StmAreaNoNormal ) - { - ZAPL_RestrictionModeOffs4e3(); - } /*ara_split_main*/ - else if( g_stm_area == StmAreaNoSplitMain ) + if( g_stm_area == StmAreaNoSplitMain ) { ZAPL_RestrictionModeOffs0e18(); } @@ -1209,7 +1194,7 @@ static void ZAPL_RestrictionModeOffs4Event( void ) /*stt_prv_layer_apps_spl_nml*/ else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoSplNml ) { - ZAPL_RestrictionModeOffs4e3(); + ZAPL_RestrictionModeOffs4e17(); } /*stt_prv_layer_apps_spl_spl*/ else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoSplSpl ) @@ -1253,7 +1238,7 @@ static void ZAPL_RestrictionModeOffs4Event( void ) static void ZAPL_RestrictionModeOffs5Event( void ) { /*stt_restriction_mode_off*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNoOff ) + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOff ) { /*evt_activate*/ if( g_stm_event == StmEvtNoActivate ) @@ -1438,7 +1423,7 @@ static void ZAPL_RestrictionModeOffs5Event( void ) static void ZAPL_RestrictionModeOffs6Event( void ) { /*stt_restriction_mode_off*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNoOff ) + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOff ) { /*evt_activate*/ if( g_stm_event == StmEvtNoActivate ) @@ -1608,7 +1593,7 @@ static void ZAPL_RestrictionModeOffs6Event( void ) static void ZAPL_RestrictionModeOffs7Event( void ) { /*stt_restriction_mode_off*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNoOff ) + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOff ) { /*evt_activate*/ if( g_stm_event == StmEvtNoActivate ) @@ -1773,12 +1758,12 @@ static void ZAPL_RestrictionModeOffs7Event( void ) /****************************************/ /* Event appraisal function */ /* STM : AppsLayer */ -/* State : restriction_mode_2_on( No 1 ) */ +/* State : restriction_mode_on( No 1 )*/ /****************************************/ static void ZAPL_AppsLayers1Event( void ) { /*stt_restriction_mode_off*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNoOff ) + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOff ) { stm_apl_event_restriction_mode_off(); ZAPL_AppsLayers1e0(); @@ -1797,8 +1782,8 @@ static void ZAPL_AppsLayers1Event( void ) /****************************************/ static void ZAPL_RestrictionModeOns0Event( void ) { - /*stt_restriction_mode_2_on*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNo2On ) + /*stt_restriction_mode_on*/ + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOn ) { /*evt_activate*/ if( g_stm_event == StmEvtNoActivate ) @@ -1862,8 +1847,8 @@ static void ZAPL_RestrictionModeOns0Event( void ) /****************************************/ static void ZAPL_RestrictionModeOns1Event( void ) { - /*stt_restriction_mode_2_on*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNo2On ) + /*stt_restriction_mode_on*/ + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOn ) { /*evt_activate*/ if( g_stm_event == StmEvtNoActivate ) diff --git a/policy_manager/stm/zipc/StateTransitionor/AppsLayer/ZAPL_Apps_func.c b/policy_manager/stm/zipc/StateTransitionor/AppsLayer/ZAPL_Apps_func.c index b42df05..d2e7075 100644 --- a/policy_manager/stm/zipc/StateTransitionor/AppsLayer/ZAPL_Apps_func.c +++ b/policy_manager/stm/zipc/StateTransitionor/AppsLayer/ZAPL_Apps_func.c @@ -92,15 +92,15 @@ void stm_apl_start_activity_system() { * @name stm_apl_event_restriction_mode_off */ void stm_apl_event_restriction_mode_off() { - g_stm_crr_state.layer[StmLayerNoApps].state = g_prv_apps_state_rest_mode_1; + g_stm_crr_state.layer[StmLayerNoApps].state = g_prv_apps_state_car_stop; g_stm_crr_state.layer[StmLayerNoApps].changed = STM_TRUE; } /* - * @name stm_apl_event_restriction_mode_2_on + * @name stm_apl_event_restriction_mode_on */ -void stm_apl_event_restriction_mode_2_on() { - g_prv_apps_state_rest_mode_1 = g_stm_prv_state.layer[StmLayerNoApps].state; +void stm_apl_event_restriction_mode_on() { + g_prv_apps_state_car_stop = g_stm_prv_state.layer[StmLayerNoApps].state; } /* diff --git a/policy_manager/stm/zipc/StateTransitionor/AppsLayer/ZAPL_Apps_func.h b/policy_manager/stm/zipc/StateTransitionor/AppsLayer/ZAPL_Apps_func.h index 6f741b5..4f74c9f 100644 --- a/policy_manager/stm/zipc/StateTransitionor/AppsLayer/ZAPL_Apps_func.h +++ b/policy_manager/stm/zipc/StateTransitionor/AppsLayer/ZAPL_Apps_func.h @@ -15,7 +15,7 @@ extern void stm_apl_start_activity_splitable_split(); extern void stm_apl_start_activity_general(); extern void stm_apl_start_activity_system(); extern void stm_apl_event_restriction_mode_off(); -extern void stm_apl_event_restriction_mode_2_on(); +extern void stm_apl_event_restriction_mode_on(); extern void stm_apl_initialize_variable(); extern void stm_apl_start_stm(); diff --git a/policy_manager/stm/zipc/StateTransitionor/CarState/ZCAR_CarState.c b/policy_manager/stm/zipc/StateTransitionor/CarState/ZCAR_CarState.c new file mode 100644 index 0000000..8e20123 --- /dev/null +++ b/policy_manager/stm/zipc/StateTransitionor/CarState/ZCAR_CarState.c @@ -0,0 +1,154 @@ +/************************************************************/ +/* ZCAR_CarState.c */ +/* CarState State transition model source file */ +/* ZIPC Designer Version 1.2.0 */ +/************************************************************/ +#include "../ZST_include.h" + +/* State management variable */ +static uint8_t ZCAR_CarStateState[ZCAR_CARSTATESTATENOMAX]; + +static void ZCAR_CarStates0e1( void ); +static void ZCAR_CarStates1e0( void ); +static void ZCAR_CarStates0Event( void ); +static void ZCAR_CarStates1Event( void ); + +/****************************************/ +/* Action function */ +/* STM : CarState */ +/* State : car_stop( No 0 ) */ +/* Event : stt_accel_pedal_on( No 1 ) */ +/****************************************/ +static void ZCAR_CarStates0e1( void ) +{ + ZCAR_CarStateState[ZCAR_CARSTATE] = ( uint8_t )ZCAR_CARSTATES1; + stm_rns_start_activity_car_run(); +} + +/****************************************/ +/* Action function */ +/* STM : CarState */ +/* State : car_run( No 1 ) */ +/* Event : stt_accel_pedal_off( No 0 )*/ +/****************************************/ +static void ZCAR_CarStates1e0( void ) +{ + ZCAR_CarStateState[ZCAR_CARSTATE] = ( uint8_t )ZCAR_CARSTATES0; + stm_rns_start_activity_car_stop(); +} + +/****************************************/ +/* Event appraisal function */ +/* STM : CarState */ +/* State : car_stop( No 0 ) */ +/****************************************/ +static void ZCAR_CarStates0Event( void ) +{ + /*stt_lightstatus_brake_off*/ + if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOff ) + { + /*stt_accel_pedal_on*/ + if( g_stm_crr_state.car_element[StmCarElementNoAccelPedal].state == StmAccelPedalSttNoOn ) + { + ZCAR_CarStates0e1(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } +} + +/****************************************/ +/* Event appraisal function */ +/* STM : CarState */ +/* State : car_run( No 1 ) */ +/****************************************/ +static void ZCAR_CarStates1Event( void ) +{ + /*stt_lightstatus_brake_off*/ + if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOff ) + { + /*stt_accel_pedal_off*/ + if( g_stm_crr_state.car_element[StmCarElementNoAccelPedal].state == StmAccelPedalSttNoOff ) + { + ZCAR_CarStates1e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*stt_lightstatus_brake_on*/ + else if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOn ) + { + /*stt_accel_pedal_off*/ + if( g_stm_crr_state.car_element[StmCarElementNoAccelPedal].state == StmAccelPedalSttNoOff ) + { + ZCAR_CarStates1e0(); + } + /*stt_accel_pedal_on*/ + else if( g_stm_crr_state.car_element[StmCarElementNoAccelPedal].state == StmAccelPedalSttNoOn ) + { + ZCAR_CarStates1e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } +} + +/****************************************/ +/* Event call function */ +/* STM : CarState */ +/****************************************/ +void stm_rns_event_call( void ) +{ + stm_rns_start_stm(); + switch( ZCAR_CarStateState[ZCAR_CARSTATE] ) + { + case ZCAR_CARSTATES0: + ZCAR_CarStates0Event(); + break; + case ZCAR_CARSTATES1: + ZCAR_CarStates1Event(); + break; + default: + /*Not accessible to this else (default).*/ + break; + } +} + +/****************************************/ +/* Initial function */ +/* STM : CarState */ +/****************************************/ +void stm_rns_initialize( void ) +{ + ZCAR_CarStateState[ZCAR_CARSTATE] = ( uint8_t )ZCAR_CARSTATES0; + stm_rns_start_activity_car_stop(); +} + +/****************************************/ +/* Terminate function */ +/* STM : CarState */ +/****************************************/ +void ZCAR_CarStateTerminate( void ) +{ + ZCAR_CarStateState[ZCAR_CARSTATE] = ( uint8_t )ZCAR_CARSTATETERMINATE; +} + diff --git a/policy_manager/stm/zipc/StateTransitionor/CarState/ZCAR_CarState.h b/policy_manager/stm/zipc/StateTransitionor/CarState/ZCAR_CarState.h new file mode 100644 index 0000000..18003a7 --- /dev/null +++ b/policy_manager/stm/zipc/StateTransitionor/CarState/ZCAR_CarState.h @@ -0,0 +1,45 @@ +/************************************************************/ +/* ZCAR_CarState.h */ +/* CarState State transition model header file */ +/* ZIPC Designer Version 1.2.0 */ +/************************************************************/ +#ifndef ZHEADER_ZCAR_CARSTATE_H +#define ZHEADER_ZCAR_CARSTATE_H + +/*State management variable access define*/ +#define ZCAR_CARSTATE ( 0U ) +#define ZCAR_CARSTATES0 ( 0U ) +#define ZCAR_CARSTATES1 ( 1U ) +#define ZCAR_CARSTATESTATENOMAX ( 1U ) + +/*End state define*/ +#define ZCAR_CARSTATEEND ( 2U ) +/*Terminate state define*/ +#define ZCAR_CARSTATETERMINATE ( ZCAR_CARSTATEEND + 1U ) + +/*State no define*/ +#define ZCAR_CARSTATES0STATENO ( 0U ) +#define ZCAR_CARSTATES1STATENO ( 1U ) + +/*State serial no define*/ +#define ZCAR_CARSTATES0STATESERIALNO ( 0U ) +#define ZCAR_CARSTATES1STATESERIALNO ( 1U ) + +/*Event no define*/ +#define ZCAR_CARSTATEE0EVENTNO ( 0U ) +#define ZCAR_CARSTATEE1EVENTNO ( 1U ) +#define ZCAR_CARSTATEE2EVENTNO ( 2U ) +#define ZCAR_CARSTATEE3EVENTNO ( 3U ) + +/*Event serial no define*/ +#define ZCAR_CARSTATEE0EVENTSERIALNO ( 0U ) +#define ZCAR_CARSTATEE1EVENTSERIALNO ( 1U ) +#define ZCAR_CARSTATEE2EVENTSERIALNO ( 2U ) +#define ZCAR_CARSTATEE3EVENTSERIALNO ( 3U ) + +/*Extern function*/ +extern void stm_rns_event_call( void ); +extern void stm_rns_initialize( void ); +extern void ZCAR_CarStateTerminate( void ); + +#endif diff --git a/policy_manager/stm/zipc/StateTransitionor/CarState/ZCAR_CarState_func.c b/policy_manager/stm/zipc/StateTransitionor/CarState/ZCAR_CarState_func.c new file mode 100644 index 0000000..d6cd5d1 --- /dev/null +++ b/policy_manager/stm/zipc/StateTransitionor/CarState/ZCAR_CarState_func.c @@ -0,0 +1,45 @@ +/************************************************************/ +/* ZCAR_CarState_func.c */ +/* Function and variable source file */ +/* ZIPC Designer Version 1.2.0 */ +/************************************************************/ +#include "../ZST_include.h" + +/************************************************************* + Function definition +*************************************************************/ + +/* + * @name stm_rns_start_activity_car_stop + */ +void stm_rns_start_activity_car_stop() { + g_stm_crr_state.car_element[StmCarElementNoRunning].state = StmRunningNoStop; + g_stm_crr_state.car_element[StmCarElementNoRunning].changed = STM_TRUE; +} + +/* + * @name stm_rns_start_activity_car_run + */ +void stm_rns_start_activity_car_run() { + g_stm_crr_state.car_element[StmCarElementNoRunning].state = StmRunningNoRun; + g_stm_crr_state.car_element[StmCarElementNoRunning].changed = STM_TRUE; +} + +/* + * @name stm_rns_initialize_variable + */ +void stm_rns_initialize_variable() { + g_stm_prv_state.car_element[StmCarElementNoRunning].state = StmRunningNoStop; + g_stm_prv_state.car_element[StmCarElementNoRunning].changed = STM_FALSE; + + g_stm_crr_state.car_element[StmCarElementNoRunning].state = StmRunningNoStop; + g_stm_crr_state.car_element[StmCarElementNoRunning].changed = STM_FALSE; +} + +/* + * @name stm_rns_start_stm + */ +void stm_rns_start_stm() { + g_stm_prv_state.car_element[StmCarElementNoRunning].state = g_stm_crr_state.car_element[StmCarElementNoRunning].state; + g_stm_crr_state.car_element[StmCarElementNoRunning].changed = STM_FALSE; +} diff --git a/policy_manager/stm/zipc/StateTransitionor/CarState/ZCAR_CarState_func.h b/policy_manager/stm/zipc/StateTransitionor/CarState/ZCAR_CarState_func.h new file mode 100644 index 0000000..8c1dc93 --- /dev/null +++ b/policy_manager/stm/zipc/StateTransitionor/CarState/ZCAR_CarState_func.h @@ -0,0 +1,14 @@ +/************************************************************/ +/* ZCAR_CarState_func.h */ +/* Function and variable header file */ +/* ZIPC Designer Version 1.2.0 */ +/************************************************************/ +#ifndef ZHEADER_ZCAR_CARSTATE_FUNC_H +#define ZHEADER_ZCAR_CARSTATE_FUNC_H + +extern void stm_rns_start_activity_car_stop(); +extern void stm_rns_start_activity_car_run(); +extern void stm_rns_initialize_variable(); +extern void stm_rns_start_stm(); + +#endif diff --git a/policy_manager/stm/zipc/StateTransitionor/HomeScreenLayer/ZHSL_HomeScreen.c b/policy_manager/stm/zipc/StateTransitionor/HomeScreenLayer/ZHSL_HomeScreen.c index a4cd474..1375c66 100644 --- a/policy_manager/stm/zipc/StateTransitionor/HomeScreenLayer/ZHSL_HomeScreen.c +++ b/policy_manager/stm/zipc/StateTransitionor/HomeScreenLayer/ZHSL_HomeScreen.c @@ -9,7 +9,6 @@ static uint8_t ZHSL_HomeScreenState[ZHSL_HOMESCREENSTATENOMAX]; static void ZHSL_HomeScreens0e0( void ); -static void ZHSL_HomeScreens1e0( void ); static void ZHSL_HomeScreens0Event( void ); static void ZHSL_HomeScreens1Event( void ); @@ -26,17 +25,6 @@ static void ZHSL_HomeScreens0e0( void ) } /****************************************/ -/* Action function */ -/* STM : HomeScreen */ -/* State : homescreen( No 1 ) */ -/* Event : ara_fullscreen( No 0 ) */ -/****************************************/ -static void ZHSL_HomeScreens1e0( void ) -{ - stm_hsl_start_activity_homescreen(); -} - -/****************************************/ /* Event appraisal function */ /* STM : HomeScreen */ /* State : none( No 0 ) */ @@ -80,34 +68,6 @@ static void ZHSL_HomeScreens0Event( void ) /****************************************/ static void ZHSL_HomeScreens1Event( void ) { - /*evt_activate*/ - if( g_stm_event == StmEvtNoActivate ) - { - /*ctg_homescreen*/ - if( g_stm_category == StmCtgNoHomescreen ) - { - /*ara_fullscreen*/ - if( g_stm_area == StmAreaNoFullscreen ) - { - ZHSL_HomeScreens1e0(); - } - else - { - /*Else and default design have not done.*/ - /*Please confirm the STM and design else and default.*/ - } - } - else - { - /*Else and default design have not done.*/ - /*Please confirm the STM and design else and default.*/ - } - } - else - { - /*Else and default design have not done.*/ - /*Please confirm the STM and design else and default.*/ - } } /****************************************/ diff --git a/policy_manager/stm/zipc/StateTransitionor/LightStatusBrake/ZLIGHT_LightstatusBrake.c b/policy_manager/stm/zipc/StateTransitionor/LightStatusBrake/ZLIGHT_LightstatusBrake.c new file mode 100644 index 0000000..8f65d32 --- /dev/null +++ b/policy_manager/stm/zipc/StateTransitionor/LightStatusBrake/ZLIGHT_LightstatusBrake.c @@ -0,0 +1,117 @@ +/************************************************************/ +/* ZLIGHT_LightstatusBrake.c */ +/* LightstatusBrake State transition model source file */ +/* ZIPC Designer Version 1.2.0 */ +/************************************************************/ +#include "../ZST_include.h" + +/* State management variable */ +static uint8_t ZLIGHT_LightstatusBrakeState[ZLIGHT_LIGHTSTATUSBRAKESTATENOMAX]; + +static void ZLIGHT_LightstatusBrakes0e1( void ); +static void ZLIGHT_LightstatusBrakes1e0( void ); +static void ZLIGHT_LightstatusBrakes0Event( void ); +static void ZLIGHT_LightstatusBrakes1Event( void ); + +/****************************************/ +/* Action function */ +/* STM : LightstatusBrake */ +/* State : lightstatus_brake_on( No 0 ) */ +/* Event : evt_lightstatus_brake_off( No 1 ) */ +/****************************************/ +static void ZLIGHT_LightstatusBrakes0e1( void ) +{ + ZLIGHT_LightstatusBrakeState[ZLIGHT_LIGHTSTATUSBRAKE] = ( uint8_t )ZLIGHT_LIGHTSTATUSBRAKES1; + stm_lbs_start_activity_lightstatus_brake_off(); +} + +/****************************************/ +/* Action function */ +/* STM : LightstatusBrake */ +/* State : lightstatus_brake_off( No 1 ) */ +/* Event : evt_lightstatus_brake_on( No 0 ) */ +/****************************************/ +static void ZLIGHT_LightstatusBrakes1e0( void ) +{ + ZLIGHT_LightstatusBrakeState[ZLIGHT_LIGHTSTATUSBRAKE] = ( uint8_t )ZLIGHT_LIGHTSTATUSBRAKES0; + stm_lbs_start_activity_lightstatus_brake_on(); +} + +/****************************************/ +/* Event appraisal function */ +/* STM : LightstatusBrake */ +/* State : lightstatus_brake_on( No 0 ) */ +/****************************************/ +static void ZLIGHT_LightstatusBrakes0Event( void ) +{ + /*evt_lightstatus_brake_off*/ + if( g_stm_event == StmEvtNoLightstatusBrakeOff ) + { + ZLIGHT_LightstatusBrakes0e1(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } +} + +/****************************************/ +/* Event appraisal function */ +/* STM : LightstatusBrake */ +/* State : lightstatus_brake_off( No 1 ) */ +/****************************************/ +static void ZLIGHT_LightstatusBrakes1Event( void ) +{ + /*evt_lightstatus_brake_on*/ + if( g_stm_event == StmEvtNoLightstatusBrakeOn ) + { + ZLIGHT_LightstatusBrakes1e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } +} + +/****************************************/ +/* Event call function */ +/* STM : LightstatusBrake */ +/****************************************/ +void stm_lbs_event_call( void ) +{ + stm_lbs_start_stm(); + switch( ZLIGHT_LightstatusBrakeState[ZLIGHT_LIGHTSTATUSBRAKE] ) + { + case ZLIGHT_LIGHTSTATUSBRAKES0: + ZLIGHT_LightstatusBrakes0Event(); + break; + case ZLIGHT_LIGHTSTATUSBRAKES1: + ZLIGHT_LightstatusBrakes1Event(); + break; + default: + /*Not accessible to this else (default).*/ + break; + } +} + +/****************************************/ +/* Initial function */ +/* STM : LightstatusBrake */ +/****************************************/ +void stm_lbs_initialize( void ) +{ + ZLIGHT_LightstatusBrakeState[ZLIGHT_LIGHTSTATUSBRAKE] = ( uint8_t )ZLIGHT_LIGHTSTATUSBRAKES0; + stm_lbs_start_activity_lightstatus_brake_on(); +} + +/****************************************/ +/* Terminate function */ +/* STM : LightstatusBrake */ +/****************************************/ +void ZLIGHT_LightstatusBrakeTerminate( void ) +{ + ZLIGHT_LightstatusBrakeState[ZLIGHT_LIGHTSTATUSBRAKE] = ( uint8_t )ZLIGHT_LIGHTSTATUSBRAKETERMINATE; +} + diff --git a/policy_manager/stm/zipc/StateTransitionor/LightStatusBrake/ZLIGHT_LightstatusBrake.h b/policy_manager/stm/zipc/StateTransitionor/LightStatusBrake/ZLIGHT_LightstatusBrake.h new file mode 100644 index 0000000..0ced0ec --- /dev/null +++ b/policy_manager/stm/zipc/StateTransitionor/LightStatusBrake/ZLIGHT_LightstatusBrake.h @@ -0,0 +1,41 @@ +/************************************************************/ +/* ZLIGHT_LightstatusBrake.h */ +/* LightstatusBrake State transition model header file */ +/* ZIPC Designer Version 1.2.0 */ +/************************************************************/ +#ifndef ZHEADER_ZLIGHT_LIGHTSTATUSBRAKE_H +#define ZHEADER_ZLIGHT_LIGHTSTATUSBRAKE_H + +/*State management variable access define*/ +#define ZLIGHT_LIGHTSTATUSBRAKE ( 0U ) +#define ZLIGHT_LIGHTSTATUSBRAKES0 ( 0U ) +#define ZLIGHT_LIGHTSTATUSBRAKES1 ( 1U ) +#define ZLIGHT_LIGHTSTATUSBRAKESTATENOMAX ( 1U ) + +/*End state define*/ +#define ZLIGHT_LIGHTSTATUSBRAKEEND ( 2U ) +/*Terminate state define*/ +#define ZLIGHT_LIGHTSTATUSBRAKETERMINATE ( ZLIGHT_LIGHTSTATUSBRAKEEND + 1U ) + +/*State no define*/ +#define ZLIGHT_LIGHTSTATUSBRAKES0STATENO ( 0U ) +#define ZLIGHT_LIGHTSTATUSBRAKES1STATENO ( 1U ) + +/*State serial no define*/ +#define ZLIGHT_LIGHTSTATUSBRAKES0STATESERIALNO ( 0U ) +#define ZLIGHT_LIGHTSTATUSBRAKES1STATESERIALNO ( 1U ) + +/*Event no define*/ +#define ZLIGHT_LIGHTSTATUSBRAKEE0EVENTNO ( 0U ) +#define ZLIGHT_LIGHTSTATUSBRAKEE1EVENTNO ( 1U ) + +/*Event serial no define*/ +#define ZLIGHT_LIGHTSTATUSBRAKEE0EVENTSERIALNO ( 0U ) +#define ZLIGHT_LIGHTSTATUSBRAKEE1EVENTSERIALNO ( 1U ) + +/*Extern function*/ +extern void stm_lbs_event_call( void ); +extern void stm_lbs_initialize( void ); +extern void ZLIGHT_LightstatusBrakeTerminate( void ); + +#endif diff --git a/policy_manager/stm/zipc/StateTransitionor/LightStatusBrake/ZLIGHT_LightstatusBrakeStatus_func.c b/policy_manager/stm/zipc/StateTransitionor/LightStatusBrake/ZLIGHT_LightstatusBrakeStatus_func.c new file mode 100644 index 0000000..70c7478 --- /dev/null +++ b/policy_manager/stm/zipc/StateTransitionor/LightStatusBrake/ZLIGHT_LightstatusBrakeStatus_func.c @@ -0,0 +1,45 @@ +/************************************************************/ +/* ZLIGHT_LightstatusBrakeStatus_func.c */ +/* Function and variable source file */ +/* ZIPC Designer Version 1.2.0 */ +/************************************************************/ +#include "../ZST_include.h" + +/************************************************************* + Function definition +*************************************************************/ + +/* + * @name stm_lbs_start_activity_lightstatus_brake_off + */ +void stm_lbs_start_activity_lightstatus_brake_off() { + g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state = StmLightstatusBrakeSttNoOff; + g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].changed = STM_TRUE; +} + +/* + * @name stm_lbs_start_activity_lightstatus_brake_on + */ +void stm_lbs_start_activity_lightstatus_brake_on() { + g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state = StmLightstatusBrakeSttNoOn; + g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].changed = STM_TRUE; +} + +/* + * @name stm_lbs_initialize_variable + */ +void stm_lbs_initialize_variable() { + g_stm_prv_state.car_element[StmCarElementNoLightstatusBrake].state = StmLightstatusBrakeSttNoOn; + g_stm_prv_state.car_element[StmCarElementNoLightstatusBrake].changed = STM_FALSE; + + g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state = StmLightstatusBrakeSttNoOn; + g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].changed = STM_FALSE; +} + +/* + * @name stm_lbs_start_stm + */ +void stm_lbs_start_stm() { + g_stm_prv_state.car_element[StmCarElementNoLightstatusBrake].state = g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state; + g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].changed = STM_FALSE; +} diff --git a/policy_manager/stm/zipc/StateTransitionor/LightStatusBrake/ZLIGHT_LightstatusBrakeStatus_func.h b/policy_manager/stm/zipc/StateTransitionor/LightStatusBrake/ZLIGHT_LightstatusBrakeStatus_func.h new file mode 100644 index 0000000..5ebd5b1 --- /dev/null +++ b/policy_manager/stm/zipc/StateTransitionor/LightStatusBrake/ZLIGHT_LightstatusBrakeStatus_func.h @@ -0,0 +1,14 @@ +/************************************************************/ +/* ZLIGHT_LightstatusBrakeStatus_func.h */ +/* Function and variable header file */ +/* ZIPC Designer Version 1.2.0 */ +/************************************************************/ +#ifndef ZHEADER_ZLIGHT_LIGHTSTATUSBRAKESTATUS_FUNC_H +#define ZHEADER_ZLIGHT_LIGHTSTATUSBRAKESTATUS_FUNC_H + +extern void stm_lbs_start_activity_lightstatus_brake_off(); +extern void stm_lbs_start_activity_lightstatus_brake_on(); +extern void stm_lbs_initialize_variable(); +extern void stm_lbs_start_stm(); + +#endif diff --git a/policy_manager/stm/zipc/StateTransitionor/NearHomeScreen/ZNHL_NearHomeScreen_func.c b/policy_manager/stm/zipc/StateTransitionor/NearHomeScreen/ZNHL_NearHomeScreen_func.c index c8ba22f..dad2484 100644 --- a/policy_manager/stm/zipc/StateTransitionor/NearHomeScreen/ZNHL_NearHomeScreen_func.c +++ b/policy_manager/stm/zipc/StateTransitionor/NearHomeScreen/ZNHL_NearHomeScreen_func.c @@ -29,15 +29,15 @@ void stm_nhl_start_activity_software_keyboard() { * @name stm_nhl_event_restriction_mode_off */ void stm_nhl_event_restriction_mode_off() { - g_stm_crr_state.layer[StmLayerNoNearHomescreen].state = g_prv_near_homescreen_state_rest_mode_1; + g_stm_crr_state.layer[StmLayerNoNearHomescreen].state = g_prv_near_homescreen_state_car_stop; g_stm_crr_state.layer[StmLayerNoNearHomescreen].changed = STM_TRUE; } /* - * @name stm_nhl_event_restriction_mode_2_on + * @name stm_nhl_event_restriction_mode_on */ void stm_nhl_event_restriction_mode_on() { - g_prv_near_homescreen_state_rest_mode_1 = g_stm_prv_state.layer[StmLayerNoNearHomescreen].state; + g_prv_near_homescreen_state_car_stop = g_stm_prv_state.layer[StmLayerNoNearHomescreen].state; } /* diff --git a/policy_manager/stm/zipc/StateTransitionor/NearHomeScreen/ZNHL_NearHomescreen.c b/policy_manager/stm/zipc/StateTransitionor/NearHomeScreen/ZNHL_NearHomescreen.c index cc3bbc7..1c024b8 100644 --- a/policy_manager/stm/zipc/StateTransitionor/NearHomeScreen/ZNHL_NearHomescreen.c +++ b/policy_manager/stm/zipc/StateTransitionor/NearHomeScreen/ZNHL_NearHomescreen.c @@ -10,8 +10,8 @@ static uint8_t ZNHL_NearHomescreenState[ZNHL_NEARHOMESCREENSTATENOMAX]; static void ZNHL_NearHomescreens0e0( void ); static void ZNHL_NearHomescreens0e3( void ); -static void ZNHL_NearHomescreens1e0( void ); static void ZNHL_NearHomescreens1e2( void ); +static void ZNHL_NearHomescreens1e4( void ); static void ZNHL_NearHomescreens0Event( void ); static void ZNHL_NearHomescreens1Event( void ); @@ -42,23 +42,23 @@ static void ZNHL_NearHomescreens0e3( void ) /* Action function */ /* STM : NearHomescreen */ /* State : software_keyboard( No 1 ) */ -/* Event : ara_software_keyboard( No 0 ) */ +/* Event : ctg_software_keyboard( No 2 ) */ /****************************************/ -static void ZNHL_NearHomescreens1e0( void ) +static void ZNHL_NearHomescreens1e2( void ) { - stm_nhl_start_activity_software_keyboard(); + ZNHL_NearHomescreenState[ZNHL_NEARHOMESCREEN] = ( uint8_t )ZNHL_NEARHOMESCREENS0; + stm_nhl_start_activity_none(); } /****************************************/ /* Action function */ /* STM : NearHomescreen */ /* State : software_keyboard( No 1 ) */ -/* Event : ctg_software_keyboard( No 2 ) */ +/* Event : stt_prv_layer_near_homescreen_sft_kbd( No 4 ) */ /****************************************/ -static void ZNHL_NearHomescreens1e2( void ) +static void ZNHL_NearHomescreens1e4( void ) { - ZNHL_NearHomescreenState[ZNHL_NEARHOMESCREEN] = ( uint8_t )ZNHL_NEARHOMESCREENS0; - stm_nhl_start_activity_none(); + stm_nhl_start_activity_software_keyboard(); } /****************************************/ @@ -123,30 +123,8 @@ static void ZNHL_NearHomescreens0Event( void ) /****************************************/ static void ZNHL_NearHomescreens1Event( void ) { - /*evt_activate*/ - if( g_stm_event == StmEvtNoActivate ) - { - /*ctg_software_keyboard*/ - if( g_stm_category == StmCtgNoSoftwareKeyboard ) - { - /*ara_software_keyboard*/ - if( g_stm_area == StmAreaNoSoftwareKyeboard ) - { - ZNHL_NearHomescreens1e0(); - } - else - { - ZNHL_NearHomescreens1e0(); - } - } - else - { - /*Else and default design have not done.*/ - /*Please confirm the STM and design else and default.*/ - } - } /*evt_deactivate*/ - else if( g_stm_event == StmEvtNoDeactivate ) + if( g_stm_event == StmEvtNoDeactivate ) { /*ctg_software_keyboard*/ if( g_stm_category == StmCtgNoSoftwareKeyboard ) @@ -170,7 +148,7 @@ static void ZNHL_NearHomescreens1Event( void ) /*stt_prv_layer_near_homescreen_sft_kbd*/ else if( g_stm_prv_state.layer[StmLayerNoNearHomescreen].state == StmLayoutNoSftKbd ) { - ZNHL_NearHomescreens1e0(); + ZNHL_NearHomescreens1e4(); } else { @@ -178,8 +156,8 @@ static void ZNHL_NearHomescreens1Event( void ) /*Please confirm the STM and design else and default.*/ } } - /*stt_restriction_mode_1_on*/ - else if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNo1On ) + /*stt_lightstatus_brake_off*/ + else if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOff ) { ZNHL_NearHomescreens1e2(); } diff --git a/policy_manager/stm/zipc/StateTransitionor/OnScreenlayer/ZOSL_OnScreen_func.c b/policy_manager/stm/zipc/StateTransitionor/OnScreenlayer/ZOSL_OnScreen_func.c index 90a6f6f..c131608 100644 --- a/policy_manager/stm/zipc/StateTransitionor/OnScreenlayer/ZOSL_OnScreen_func.c +++ b/policy_manager/stm/zipc/StateTransitionor/OnScreenlayer/ZOSL_OnScreen_func.c @@ -37,15 +37,15 @@ void stm_osl_start_activity_system_alert() { * @name stm_osl_event_restriction_mode_off */ void stm_osl_event_restriction_mode_off() { - g_stm_crr_state.layer[StmLayerNoOnScreen].state = g_prv_on_screen_state_rest_mode_1; + g_stm_crr_state.layer[StmLayerNoOnScreen].state = g_prv_on_screen_state_car_stop; g_stm_crr_state.layer[StmLayerNoOnScreen].changed = STM_TRUE; } /* - * @name stm_osl_event_restriction_mode_2_on + * @name stm_osl_event_restriction_mode_on */ -void stm_osl_event_restriction_mode_2_on() { - g_prv_on_screen_state_rest_mode_1 = g_stm_prv_state.layer[StmLayerNoOnScreen].state; +void stm_osl_event_restriction_mode_on() { + g_prv_on_screen_state_car_stop = g_stm_prv_state.layer[StmLayerNoOnScreen].state; } /* * @name stm_osl_initialize_variable diff --git a/policy_manager/stm/zipc/StateTransitionor/OnScreenlayer/ZOSL_OnScreen_func.h b/policy_manager/stm/zipc/StateTransitionor/OnScreenlayer/ZOSL_OnScreen_func.h index e85accb..3edef28 100644 --- a/policy_manager/stm/zipc/StateTransitionor/OnScreenlayer/ZOSL_OnScreen_func.h +++ b/policy_manager/stm/zipc/StateTransitionor/OnScreenlayer/ZOSL_OnScreen_func.h @@ -10,7 +10,7 @@ extern void stm_osl_start_activity_none(); extern void stm_osl_start_activity_pop_up(); extern void stm_osl_start_activity_system_alert(); extern void stm_osl_event_restriction_mode_off(); -extern void stm_osl_event_restriction_mode_2_on(); +extern void stm_osl_event_restriction_mode_on(); extern void stm_osl_initialize_variable(); extern void stm_osl_start_stm(); diff --git a/policy_manager/stm/zipc/StateTransitionor/OnScreenlayer/ZOSL_OslMain.c b/policy_manager/stm/zipc/StateTransitionor/OnScreenlayer/ZOSL_OslMain.c index 53a50e1..6b60219 100644 --- a/policy_manager/stm/zipc/StateTransitionor/OnScreenlayer/ZOSL_OslMain.c +++ b/policy_manager/stm/zipc/StateTransitionor/OnScreenlayer/ZOSL_OslMain.c @@ -18,11 +18,11 @@ static void ZOSL_OslRestOffs0e1( void ); static void ZOSL_OslRestOffs0e4( void ); static void ZOSL_OslRestOffs1e0( void ); static void ZOSL_OslRestOffs1e2( void ); -static void ZOSL_OslRestOffs2e1( void ); +static void ZOSL_OslRestOffs2e6( void ); static void ZOSL_OslRestOns0e0( void ); static void ZOSL_OslRestOns0e2( void ); -static void ZOSL_OslRestOns1e0( void ); static void ZOSL_OslRestOns1e1( void ); +static void ZOSL_OslRestOns1e3( void ); static void ZOSL_OslMains0Event( void ); static void ZOSL_OslRestOffs0Event( void ); static void ZOSL_OslRestOffs1Event( void ); @@ -58,7 +58,7 @@ static void ZOSL_OslMains0StateEntry( void ) /****************************************/ /* State start activity function */ /* STM : OslMain */ -/* State : restriction_mode_2_on( No 1 ) */ +/* State : restriction_mode_on( No 1 )*/ /****************************************/ static void ZOSL_OslMains1StateEntry( void ) { @@ -105,7 +105,7 @@ static void ZOSL_OslMains0e2( void ) /****************************************/ /* Action function */ /* STM : OslMain */ -/* State : restriction_mode_2_on( No 1 ) */ +/* State : restriction_mode_on( No 1 )*/ /* Event : stt_restriction_mode_off( No 0 ) */ /****************************************/ static void ZOSL_OslMains1e0( void ) @@ -176,9 +176,9 @@ static void ZOSL_OslRestOffs1e2( void ) /* Action function */ /* STM : OslRestOff */ /* State : system_alert( No 2 ) */ -/* Event : ara_onscreen( No 1 ) */ +/* Event : stt_prv_layer_on_screen_sys_alt( No 6 ) */ /****************************************/ -static void ZOSL_OslRestOffs2e1( void ) +static void ZOSL_OslRestOffs2e6( void ) { stm_osl_start_activity_system_alert(); } @@ -210,23 +210,23 @@ static void ZOSL_OslRestOns0e2( void ) /* Action function */ /* STM : OslRestOn */ /* State : system_alert( No 1 ) */ -/* Event : ara_onscreen( No 0 ) */ +/* Event : ctg_systemalert( No 1 ) */ /****************************************/ -static void ZOSL_OslRestOns1e0( void ) +static void ZOSL_OslRestOns1e1( void ) { - stm_osl_start_activity_system_alert(); + ZOSL_OslMainState[ZOSL_OSLMAINS1F] = ( uint8_t )ZOSL_OSLRESTONS0; + stm_osl_start_activity_none(); } /****************************************/ /* Action function */ /* STM : OslRestOn */ /* State : system_alert( No 1 ) */ -/* Event : ctg_systemalert( No 1 ) */ +/* Event : stt_prv_layer_on_screen_sys_alt( No 3 ) */ /****************************************/ -static void ZOSL_OslRestOns1e1( void ) +static void ZOSL_OslRestOns1e3( void ) { - ZOSL_OslMainState[ZOSL_OSLMAINS1F] = ( uint8_t )ZOSL_OSLRESTONS0; - stm_osl_start_activity_none(); + stm_osl_start_activity_system_alert(); } /****************************************/ @@ -236,10 +236,10 @@ static void ZOSL_OslRestOns1e1( void ) /****************************************/ static void ZOSL_OslMains0Event( void ) { - /*stt_restriction_mode_2_on*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNo2On ) + /*stt_restriction_mode_on*/ + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOn ) { - stm_rel_event_restriction_mode_2_on(); + stm_rel_event_restriction_mode_on(); /*stt_crr_layer_on_screen_pop*/ if( g_stm_crr_state.layer[StmLayerNoOnScreen].state == StmLayoutNoPopUp ) { @@ -271,7 +271,7 @@ static void ZOSL_OslMains0Event( void ) static void ZOSL_OslRestOffs0Event( void ) { /*stt_restriction_mode_off*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNoOff ) + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOff ) { /*evt_activate*/ if( g_stm_event == StmEvtNoActivate ) @@ -355,7 +355,7 @@ static void ZOSL_OslRestOffs0Event( void ) static void ZOSL_OslRestOffs1Event( void ) { /*stt_restriction_mode_off*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNoOff ) + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOff ) { /*evt_activate*/ if( g_stm_event == StmEvtNoActivate ) @@ -453,33 +453,10 @@ static void ZOSL_OslRestOffs1Event( void ) static void ZOSL_OslRestOffs2Event( void ) { /*stt_restriction_mode_off*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNoOff ) + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOff ) { - /*evt_activate*/ - if( g_stm_event == StmEvtNoActivate ) - { - /*ctg_systemalert*/ - if( g_stm_category == StmCtgNoSystemAlert ) - { - /*ara_onscreen*/ - if( g_stm_area == StmAreaNoOnScreen ) - { - ZOSL_OslRestOffs2e1(); - } - else - { - /*Else and default design have not done.*/ - /*Please confirm the STM and design else and default.*/ - } - } - else - { - /*Else and default design have not done.*/ - /*Please confirm the STM and design else and default.*/ - } - } /*evt_deactivate*/ - else if( g_stm_event == StmEvtNoDeactivate ) + if( g_stm_event == StmEvtNoDeactivate ) { /*ctg_systemalert*/ if( g_stm_category == StmCtgNoSystemAlert ) @@ -508,7 +485,7 @@ static void ZOSL_OslRestOffs2Event( void ) /*stt_prv_layer_on_screen_sys_alt*/ else if( g_stm_prv_state.layer[StmLayerNoOnScreen].state == StmLayoutNoSysAlt ) { - ZOSL_OslRestOffs2e1(); + ZOSL_OslRestOffs2e6(); } else { @@ -532,12 +509,12 @@ static void ZOSL_OslRestOffs2Event( void ) /****************************************/ /* Event appraisal function */ /* STM : OslMain */ -/* State : restriction_mode_2_on( No 1 ) */ +/* State : restriction_mode_on( No 1 )*/ /****************************************/ static void ZOSL_OslMains1Event( void ) { /*stt_restriction_mode_off*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNoOff ) + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOff ) { stm_rel_event_restriction_mode_off(); ZOSL_OslMains1e0(); @@ -556,8 +533,8 @@ static void ZOSL_OslMains1Event( void ) /****************************************/ static void ZOSL_OslRestOns0Event( void ) { - /*stt_restriction_mode_2_on*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNo2On ) + /*stt_restriction_mode_on*/ + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOn ) { /*evt_activate*/ if( g_stm_event == StmEvtNoActivate ) @@ -621,34 +598,11 @@ static void ZOSL_OslRestOns0Event( void ) /****************************************/ static void ZOSL_OslRestOns1Event( void ) { - /*stt_restriction_mode_2_on*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNo2On ) + /*stt_restriction_mode_on*/ + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOn ) { - /*evt_activate*/ - if( g_stm_event == StmEvtNoActivate ) - { - /*ctg_systemalert*/ - if( g_stm_category == StmCtgNoSystemAlert ) - { - /*ara_onscreen*/ - if( g_stm_area == StmAreaNoOnScreen ) - { - ZOSL_OslRestOns1e0(); - } - else - { - /*Else and default design have not done.*/ - /*Please confirm the STM and design else and default.*/ - } - } - else - { - /*Else and default design have not done.*/ - /*Please confirm the STM and design else and default.*/ - } - } /*evt_deactivate*/ - else if( g_stm_event == StmEvtNoDeactivate ) + if( g_stm_event == StmEvtNoDeactivate ) { /*ctg_systemalert*/ if( g_stm_category == StmCtgNoSystemAlert ) @@ -672,7 +626,7 @@ static void ZOSL_OslRestOns1Event( void ) /*stt_prv_layer_on_screen_sys_alt*/ else if( g_stm_prv_state.layer[StmLayerNoOnScreen].state == StmLayoutNoSysAlt ) { - ZOSL_OslRestOns1e0(); + ZOSL_OslRestOns1e3(); } else { diff --git a/policy_manager/stm/zipc/StateTransitionor/RestrictionLayer/ZREL_RelMain.c b/policy_manager/stm/zipc/StateTransitionor/RestrictionLayer/ZREL_RelMain.c index 6d07643..4c390ff 100644 --- a/policy_manager/stm/zipc/StateTransitionor/RestrictionLayer/ZREL_RelMain.c +++ b/policy_manager/stm/zipc/StateTransitionor/RestrictionLayer/ZREL_RelMain.c @@ -58,7 +58,7 @@ static void ZREL_RelMains0StateEntry( void ) /****************************************/ /* State start activity function */ /* STM : RelMain */ -/* State : restriction_mode_2_on( No 1 ) */ +/* State : restriction_mode_on( No 1 )*/ /****************************************/ static void ZREL_RelMains1StateEntry( void ) { @@ -77,7 +77,7 @@ static void ZREL_RelMains1StateEntry( void ) /* Action function */ /* STM : RelMain */ /* State : restriction_mode_off( No 0 ) */ -/* Event : stt_restriction_mode_2_on( No 1 ) */ +/* Event : stt_restriction_mode_on( No 1 ) */ /****************************************/ static void ZREL_RelMains0e1( void ) { @@ -89,7 +89,7 @@ static void ZREL_RelMains0e1( void ) /****************************************/ /* Action function */ /* STM : RelMain */ -/* State : restriction_mode_2_on( No 1 ) */ +/* State : restriction_mode_on( No 1 )*/ /* Event : stt_restriction_mode_off( No 0 ) */ /****************************************/ static void ZREL_RelMains1e0( void ) @@ -197,10 +197,10 @@ static void ZREL_RelRestOffs3e0( void ) /****************************************/ static void ZREL_RelMains0Event( void ) { - /*stt_restriction_mode_2_on*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNo2On ) + /*stt_restriction_mode_on*/ + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOn ) { - stm_rel_event_restriction_mode_2_on(); + stm_rel_event_restriction_mode_on(); ZREL_RelMains0e1(); } else @@ -217,54 +217,73 @@ static void ZREL_RelMains0Event( void ) /****************************************/ static void ZREL_RelRestOffs0Event( void ) { - /*stt_restriction_mode_1_on*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNo1On ) + /*stt_restriction_mode_off*/ + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOff ) { - /*stt_crr_layer_apps_changed*/ - if( g_stm_crr_state.layer[StmLayerNoApps].changed == STM_TRUE ) + /*stt_lightstatus_brake_off*/ + if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOff ) { - /*stt_crr_layer_apps_map_spl*/ - if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoMapSpl ) + /*stt_crr_layer_apps_changed*/ + if( g_stm_crr_state.layer[StmLayerNoApps].changed == STM_TRUE ) { - ZREL_RelRestOffs0e0(); - } - /*stt_crr_layer_apps_spl_nml*/ - else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplNml ) - { - ZREL_RelRestOffs0e1(); - } - /*stt_crr_layer_apps_spl_spl*/ - else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplSpl ) - { - ZREL_RelRestOffs0e1(); - } - /*stt_crr_layer_apps_gen_nml*/ - else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoGenNml ) - { - ZREL_RelRestOffs0e1(); + /*stt_crr_layer_apps_map_spl*/ + if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoMapSpl ) + { + ZREL_RelRestOffs0e0(); + } + /*stt_crr_layer_apps_spl_nml*/ + else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplNml ) + { + ZREL_RelRestOffs0e1(); + } + /*stt_crr_layer_apps_spl_spl*/ + else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplSpl ) + { + ZREL_RelRestOffs0e1(); + } + /*stt_crr_layer_apps_gen_nml*/ + else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoGenNml ) + { + ZREL_RelRestOffs0e1(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } } - else + /*evt_activate*/ + else if( g_stm_event == StmEvtNoActivate ) { - /*Else and default design have not done.*/ - /*Please confirm the STM and design else and default.*/ - } - } - /*evt_activate*/ - else if( g_stm_event == StmEvtNoActivate ) - { - /*ctg_restriction*/ - if( g_stm_category == StmCtgNoRestriction ) - { - /*ara_restriction_normal*/ - if( g_stm_area == StmAreaNoRestrictionNormal ) + /*ctg_restriction*/ + if( g_stm_category == StmCtgNoRestriction ) { - /*stt_crr_layer_apps_spl_nml*/ - if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplNml ) + /*ara_restriction_normal*/ + if( g_stm_area == StmAreaNoRestrictionNormal ) { - ZREL_RelRestOffs0e1(); + /*stt_crr_layer_apps_spl_nml*/ + if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplNml ) + { + ZREL_RelRestOffs0e1(); + } + /*stt_crr_layer_apps_map_spl*/ + else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoMapSpl ) + { + ZREL_RelRestOffs0e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ara_restriction_split_main*/ + else if( g_stm_area == StmAreaNoRestrictionSplitMain ) + { + ZREL_RelRestOffs0e8(); } - /*stt_crr_layer_apps_map_spl*/ - else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoMapSpl ) + /*ara_restriction_split_sub*/ + else if( g_stm_area == StmAreaNoRestrictionSplitSub ) { ZREL_RelRestOffs0e0(); } @@ -274,16 +293,6 @@ static void ZREL_RelRestOffs0Event( void ) /*Please confirm the STM and design else and default.*/ } } - /*ara_restriction_split_main*/ - else if( g_stm_area == StmAreaNoRestrictionSplitMain ) - { - ZREL_RelRestOffs0e8(); - } - /*ara_restriction_split_sub*/ - else if( g_stm_area == StmAreaNoRestrictionSplitSub ) - { - ZREL_RelRestOffs0e0(); - } else { /*Else and default design have not done.*/ @@ -296,17 +305,8 @@ static void ZREL_RelRestOffs0Event( void ) /*Please confirm the STM and design else and default.*/ } } - else - { - /*Else and default design have not done.*/ - /*Please confirm the STM and design else and default.*/ - } - } - /*stt_restriction_mode_off*/ - else if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNoOff ) - { /*evt_undo*/ - if( g_stm_event == StmEvtNoUndo ) + else if( g_stm_event == StmEvtNoUndo ) { /*stt_prv_layer_rst_none*/ if( g_stm_prv_state.layer[StmLayerNoRestriction].state == StmLayoutNoNone ) @@ -354,62 +354,81 @@ static void ZREL_RelRestOffs0Event( void ) /****************************************/ static void ZREL_RelRestOffs1Event( void ) { - /*stt_restriction_mode_1_on*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNo1On ) + /*stt_restriction_mode_off*/ + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOff ) { - /*stt_crr_layer_apps_changed*/ - if( g_stm_crr_state.layer[StmLayerNoApps].changed == STM_TRUE ) - { - /*stt_crr_layer_apps_map_spl*/ - if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoMapSpl ) - { - ZREL_RelRestOffs0e0(); - } - /*stt_crr_layer_apps_spl_nml*/ - else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplNml ) - { - ZREL_RelRestOffs1e1(); - } - /*stt_crr_layer_apps_spl_spl*/ - else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplSpl ) - { - ZREL_RelRestOffs1e1(); - } - /*stt_crr_layer_apps_gen_nml*/ - else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoGenNml ) - { - ZREL_RelRestOffs1e1(); - } - else - { - ZREL_RelRestOffs1e4(); - } - } - /*stt_crr_layer_hs_changed*/ - else if( g_stm_crr_state.layer[StmLayerNoHomescreen].changed == STM_TRUE ) + /*stt_lightstatus_brake_off*/ + if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOff ) { - /*stt_crr_layer_hs_hms*/ - if( g_stm_crr_state.layer[StmLayerNoHomescreen].state == StmLayoutNoHms ) + /*stt_crr_layer_apps_changed*/ + if( g_stm_crr_state.layer[StmLayerNoApps].changed == STM_TRUE ) { - ZREL_RelRestOffs1e4(); + /*stt_crr_layer_apps_map_spl*/ + if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoMapSpl ) + { + ZREL_RelRestOffs0e0(); + } + /*stt_crr_layer_apps_spl_nml*/ + else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplNml ) + { + ZREL_RelRestOffs1e1(); + } + /*stt_crr_layer_apps_spl_spl*/ + else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplSpl ) + { + ZREL_RelRestOffs1e1(); + } + /*stt_crr_layer_apps_gen_nml*/ + else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoGenNml ) + { + ZREL_RelRestOffs1e1(); + } + else + { + ZREL_RelRestOffs1e4(); + } } - else + /*stt_crr_layer_hs_changed*/ + else if( g_stm_crr_state.layer[StmLayerNoHomescreen].changed == STM_TRUE ) { - /*Else and default design have not done.*/ - /*Please confirm the STM and design else and default.*/ + /*stt_crr_layer_hs_hms*/ + if( g_stm_crr_state.layer[StmLayerNoHomescreen].state == StmLayoutNoHms ) + { + ZREL_RelRestOffs1e4(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } } - } - /*evt_activate*/ - else if( g_stm_event == StmEvtNoActivate ) - { - /*ctg_restriction*/ - if( g_stm_category == StmCtgNoRestriction ) + /*evt_activate*/ + else if( g_stm_event == StmEvtNoActivate ) { - /*ara_restriction_normal*/ - if( g_stm_area == StmAreaNoRestrictionNormal ) + /*ctg_restriction*/ + if( g_stm_category == StmCtgNoRestriction ) { - /*stt_crr_layer_apps_map_spl*/ - if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoMapSpl ) + /*ara_restriction_normal*/ + if( g_stm_area == StmAreaNoRestrictionNormal ) + { + /*stt_crr_layer_apps_map_spl*/ + if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoMapSpl ) + { + ZREL_RelRestOffs0e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ara_restriction_split_main*/ + else if( g_stm_area == StmAreaNoRestrictionSplitMain ) + { + ZREL_RelRestOffs0e8(); + } + /*ara_restriction_split_sub*/ + else if( g_stm_area == StmAreaNoRestrictionSplitSub ) { ZREL_RelRestOffs0e0(); } @@ -419,15 +438,19 @@ static void ZREL_RelRestOffs1Event( void ) /*Please confirm the STM and design else and default.*/ } } - /*ara_restriction_split_main*/ - else if( g_stm_area == StmAreaNoRestrictionSplitMain ) + /*ctg_homescreen*/ + else if( g_stm_category == StmCtgNoHomescreen ) { - ZREL_RelRestOffs0e8(); - } - /*ara_restriction_split_sub*/ - else if( g_stm_area == StmAreaNoRestrictionSplitSub ) - { - ZREL_RelRestOffs0e0(); + /*ara_fullscreen*/ + if( g_stm_area == StmAreaNoFullscreen ) + { + ZREL_RelRestOffs1e4(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } } else { @@ -435,11 +458,11 @@ static void ZREL_RelRestOffs1Event( void ) /*Please confirm the STM and design else and default.*/ } } - /*ctg_homescreen*/ - else if( g_stm_category == StmCtgNoHomescreen ) + /*evt_deactivate*/ + else if( g_stm_event == StmEvtNoDeactivate ) { - /*ara_fullscreen*/ - if( g_stm_area == StmAreaNoFullscreen ) + /*ctg_restriction*/ + if( g_stm_category == StmCtgNoRestriction ) { ZREL_RelRestOffs1e4(); } @@ -455,11 +478,11 @@ static void ZREL_RelRestOffs1Event( void ) /*Please confirm the STM and design else and default.*/ } } - /*evt_deactivate*/ - else if( g_stm_event == StmEvtNoDeactivate ) + /*stt_lightstatus_brake_on*/ + else if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOn ) { - /*ctg_restriction*/ - if( g_stm_category == StmCtgNoRestriction ) + /*stt_prv_layer_rst_not_none*/ + if( g_stm_prv_state.layer[StmLayerNoRestriction].state != StmLayoutNoNone ) { ZREL_RelRestOffs1e4(); } @@ -469,20 +492,6 @@ static void ZREL_RelRestOffs1Event( void ) /*Please confirm the STM and design else and default.*/ } } - else - { - /*Else and default design have not done.*/ - /*Please confirm the STM and design else and default.*/ - } - } - /*stt_restriction_mode_off*/ - else if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNoOff ) - { - /*stt_prv_layer_rst_not_none*/ - if( g_stm_prv_state.layer[StmLayerNoRestriction].state != StmLayoutNoNone ) - { - ZREL_RelRestOffs1e4(); - } /*evt_undo*/ else if( g_stm_event == StmEvtNoUndo ) { @@ -532,69 +541,83 @@ static void ZREL_RelRestOffs1Event( void ) /****************************************/ static void ZREL_RelRestOffs2Event( void ) { - /*stt_restriction_mode_1_on*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNo1On ) + /*stt_restriction_mode_off*/ + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOff ) { - /*stt_crr_layer_apps_changed*/ - if( g_stm_crr_state.layer[StmLayerNoApps].changed == STM_TRUE ) - { - /*stt_crr_layer_apps_map_spl*/ - if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoMapSpl ) - { - ZREL_RelRestOffs0e0(); - } - /*stt_crr_layer_apps_spl_nml*/ - else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplNml ) - { - ZREL_RelRestOffs0e1(); - } - /*stt_crr_layer_apps_spl_spl*/ - else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplSpl ) - { - ZREL_RelRestOffs0e1(); - } - /*stt_crr_layer_apps_gen_nml*/ - else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoGenNml ) - { - ZREL_RelRestOffs0e1(); - } - else - { - ZREL_RelRestOffs1e4(); - } - } - /*stt_crr_layer_hs_changed*/ - else if( g_stm_crr_state.layer[StmLayerNoHomescreen].changed == STM_TRUE ) + /*stt_lightstatus_brake_off*/ + if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOff ) { - /*stt_crr_layer_hs_hms*/ - if( g_stm_crr_state.layer[StmLayerNoHomescreen].state == StmLayoutNoHms ) + /*stt_crr_layer_apps_changed*/ + if( g_stm_crr_state.layer[StmLayerNoApps].changed == STM_TRUE ) { - ZREL_RelRestOffs1e4(); + /*stt_crr_layer_apps_map_spl*/ + if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoMapSpl ) + { + ZREL_RelRestOffs0e0(); + } + /*stt_crr_layer_apps_spl_nml*/ + else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplNml ) + { + ZREL_RelRestOffs0e1(); + } + /*stt_crr_layer_apps_spl_spl*/ + else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplSpl ) + { + ZREL_RelRestOffs0e1(); + } + /*stt_crr_layer_apps_gen_nml*/ + else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoGenNml ) + { + ZREL_RelRestOffs0e1(); + } + else + { + ZREL_RelRestOffs1e4(); + } } - else + /*stt_crr_layer_hs_changed*/ + else if( g_stm_crr_state.layer[StmLayerNoHomescreen].changed == STM_TRUE ) { - /*Else and default design have not done.*/ - /*Please confirm the STM and design else and default.*/ + /*stt_crr_layer_hs_hms*/ + if( g_stm_crr_state.layer[StmLayerNoHomescreen].state == StmLayoutNoHms ) + { + ZREL_RelRestOffs1e4(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } } - } - /*evt_activate*/ - else if( g_stm_event == StmEvtNoActivate ) - { - /*ctg_restriction*/ - if( g_stm_category == StmCtgNoRestriction ) + /*evt_activate*/ + else if( g_stm_event == StmEvtNoActivate ) { - /*ara_restriction_normal*/ - if( g_stm_area == StmAreaNoRestrictionNormal ) + /*ctg_restriction*/ + if( g_stm_category == StmCtgNoRestriction ) { - /*stt_crr_layer_apps_spl_nml*/ - if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplNml ) + /*ara_restriction_normal*/ + if( g_stm_area == StmAreaNoRestrictionNormal ) { - ZREL_RelRestOffs0e1(); + /*stt_crr_layer_apps_spl_nml*/ + if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplNml ) + { + ZREL_RelRestOffs0e1(); + } + /*stt_crr_layer_apps_map_spl*/ + else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoMapSpl ) + { + ZREL_RelRestOffs0e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } } - /*stt_crr_layer_apps_map_spl*/ - else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoMapSpl ) + /*ara_restriction_split_sub*/ + else if( g_stm_area == StmAreaNoRestrictionSplitSub ) { - ZREL_RelRestOffs0e0(); + ZREL_RelRestOffs0e1(); } else { @@ -602,10 +625,19 @@ static void ZREL_RelRestOffs2Event( void ) /*Please confirm the STM and design else and default.*/ } } - /*ara_restriction_split_sub*/ - else if( g_stm_area == StmAreaNoRestrictionSplitSub ) + /*ctg_homescreen*/ + else if( g_stm_category == StmCtgNoHomescreen ) { - ZREL_RelRestOffs0e1(); + /*ara_fullscreen*/ + if( g_stm_area == StmAreaNoFullscreen ) + { + ZREL_RelRestOffs1e4(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } } else { @@ -613,11 +645,11 @@ static void ZREL_RelRestOffs2Event( void ) /*Please confirm the STM and design else and default.*/ } } - /*ctg_homescreen*/ - else if( g_stm_category == StmCtgNoHomescreen ) + /*evt_deactivate*/ + else if( g_stm_event == StmEvtNoDeactivate ) { - /*ara_fullscreen*/ - if( g_stm_area == StmAreaNoFullscreen ) + /*ctg_restriction*/ + if( g_stm_category == StmCtgNoRestriction ) { ZREL_RelRestOffs1e4(); } @@ -633,11 +665,11 @@ static void ZREL_RelRestOffs2Event( void ) /*Please confirm the STM and design else and default.*/ } } - /*evt_deactivate*/ - else if( g_stm_event == StmEvtNoDeactivate ) + /*stt_lightstatus_brake_on*/ + else if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOn ) { - /*ctg_restriction*/ - if( g_stm_category == StmCtgNoRestriction ) + /*stt_prv_layer_rst_not_none*/ + if( g_stm_prv_state.layer[StmLayerNoRestriction].state != StmLayoutNoNone ) { ZREL_RelRestOffs1e4(); } @@ -647,20 +679,6 @@ static void ZREL_RelRestOffs2Event( void ) /*Please confirm the STM and design else and default.*/ } } - else - { - /*Else and default design have not done.*/ - /*Please confirm the STM and design else and default.*/ - } - } - /*stt_restriction_mode_off*/ - else if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNoOff ) - { - /*stt_prv_layer_rst_not_none*/ - if( g_stm_prv_state.layer[StmLayerNoRestriction].state != StmLayoutNoNone ) - { - ZREL_RelRestOffs1e4(); - } /*evt_undo*/ else if( g_stm_event == StmEvtNoUndo ) { @@ -710,62 +728,76 @@ static void ZREL_RelRestOffs2Event( void ) /****************************************/ static void ZREL_RelRestOffs3Event( void ) { - /*stt_restriction_mode_1_on*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNo1On ) + /*stt_restriction_mode_off*/ + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOff ) { - /*stt_crr_layer_apps_changed*/ - if( g_stm_crr_state.layer[StmLayerNoApps].changed == STM_TRUE ) - { - /*stt_crr_layer_apps_map_spl*/ - if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoMapSpl ) - { - ZREL_RelRestOffs3e0(); - } - /*stt_crr_layer_apps_spl_nml*/ - else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplNml ) - { - ZREL_RelRestOffs0e1(); - } - /*stt_crr_layer_apps_spl_spl*/ - else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplSpl ) - { - ZREL_RelRestOffs0e1(); - } - /*stt_crr_layer_apps_gen_nml*/ - else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoGenNml ) - { - ZREL_RelRestOffs0e1(); - } - else - { - ZREL_RelRestOffs1e4(); - } - } - /*stt_crr_layer_hs_changed*/ - else if( g_stm_crr_state.layer[StmLayerNoHomescreen].changed == STM_TRUE ) + /*stt_lightstatus_brake_off*/ + if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOff ) { - /*stt_crr_layer_hs_hms*/ - if( g_stm_crr_state.layer[StmLayerNoHomescreen].state == StmLayoutNoHms ) + /*stt_crr_layer_apps_changed*/ + if( g_stm_crr_state.layer[StmLayerNoApps].changed == STM_TRUE ) { - ZREL_RelRestOffs1e4(); + /*stt_crr_layer_apps_map_spl*/ + if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoMapSpl ) + { + ZREL_RelRestOffs3e0(); + } + /*stt_crr_layer_apps_spl_nml*/ + else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplNml ) + { + ZREL_RelRestOffs0e1(); + } + /*stt_crr_layer_apps_spl_spl*/ + else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplSpl ) + { + ZREL_RelRestOffs0e1(); + } + /*stt_crr_layer_apps_gen_nml*/ + else if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoGenNml ) + { + ZREL_RelRestOffs0e1(); + } + else + { + ZREL_RelRestOffs1e4(); + } } - else + /*stt_crr_layer_hs_changed*/ + else if( g_stm_crr_state.layer[StmLayerNoHomescreen].changed == STM_TRUE ) { - /*Else and default design have not done.*/ - /*Please confirm the STM and design else and default.*/ + /*stt_crr_layer_hs_hms*/ + if( g_stm_crr_state.layer[StmLayerNoHomescreen].state == StmLayoutNoHms ) + { + ZREL_RelRestOffs1e4(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } } - } - /*evt_activate*/ - else if( g_stm_event == StmEvtNoActivate ) - { - /*ctg_restriction*/ - if( g_stm_category == StmCtgNoRestriction ) + /*evt_activate*/ + else if( g_stm_event == StmEvtNoActivate ) { - /*ara_restriction_normal*/ - if( g_stm_area == StmAreaNoRestrictionNormal ) + /*ctg_restriction*/ + if( g_stm_category == StmCtgNoRestriction ) { - /*stt_crr_layer_apps_spl_nml*/ - if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplNml ) + /*ara_restriction_normal*/ + if( g_stm_area == StmAreaNoRestrictionNormal ) + { + /*stt_crr_layer_apps_spl_nml*/ + if( g_stm_crr_state.layer[StmLayerNoApps].state == StmLayoutNoSplNml ) + { + ZREL_RelRestOffs0e1(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ara_restriction_split_main*/ + else if( g_stm_area == StmAreaNoRestrictionSplitMain ) { ZREL_RelRestOffs0e1(); } @@ -775,10 +807,19 @@ static void ZREL_RelRestOffs3Event( void ) /*Please confirm the STM and design else and default.*/ } } - /*ara_restriction_split_main*/ - else if( g_stm_area == StmAreaNoRestrictionSplitMain ) + /*ctg_homescreen*/ + else if( g_stm_category == StmCtgNoHomescreen ) { - ZREL_RelRestOffs0e1(); + /*ara_fullscreen*/ + if( g_stm_area == StmAreaNoFullscreen ) + { + ZREL_RelRestOffs1e4(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } } else { @@ -786,11 +827,11 @@ static void ZREL_RelRestOffs3Event( void ) /*Please confirm the STM and design else and default.*/ } } - /*ctg_homescreen*/ - else if( g_stm_category == StmCtgNoHomescreen ) + /*evt_deactivate*/ + else if( g_stm_event == StmEvtNoDeactivate ) { - /*ara_fullscreen*/ - if( g_stm_area == StmAreaNoFullscreen ) + /*ctg_restriction*/ + if( g_stm_category == StmCtgNoRestriction ) { ZREL_RelRestOffs1e4(); } @@ -806,11 +847,11 @@ static void ZREL_RelRestOffs3Event( void ) /*Please confirm the STM and design else and default.*/ } } - /*evt_deactivate*/ - else if( g_stm_event == StmEvtNoDeactivate ) + /*stt_lightstatus_brake_on*/ + else if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOn ) { - /*ctg_restriction*/ - if( g_stm_category == StmCtgNoRestriction ) + /*stt_prv_layer_rst_not_none*/ + if( g_stm_prv_state.layer[StmLayerNoRestriction].state != StmLayoutNoNone ) { ZREL_RelRestOffs1e4(); } @@ -820,20 +861,6 @@ static void ZREL_RelRestOffs3Event( void ) /*Please confirm the STM and design else and default.*/ } } - else - { - /*Else and default design have not done.*/ - /*Please confirm the STM and design else and default.*/ - } - } - /*stt_restriction_mode_off*/ - else if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNoOff ) - { - /*stt_prv_layer_rst_not_none*/ - if( g_stm_prv_state.layer[StmLayerNoRestriction].state != StmLayoutNoNone ) - { - ZREL_RelRestOffs1e4(); - } /*evt_undo*/ else if( g_stm_event == StmEvtNoUndo ) { @@ -879,12 +906,12 @@ static void ZREL_RelRestOffs3Event( void ) /****************************************/ /* Event appraisal function */ /* STM : RelMain */ -/* State : restriction_mode_2_on( No 1 ) */ +/* State : restriction_mode_on( No 1 )*/ /****************************************/ static void ZREL_RelMains1Event( void ) { /*stt_restriction_mode_off*/ - if( g_stm_crr_state.mode[StmModeNoRestrictionMode].state == StmRestrictionModeSttNoOff ) + if( g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state == StmRestrictionModeSttNoOff ) { stm_rel_event_restriction_mode_off(); ZREL_RelMains1e0(); diff --git a/policy_manager/stm/zipc/StateTransitionor/RestrictionLayer/ZREL_Restriction_func.c b/policy_manager/stm/zipc/StateTransitionor/RestrictionLayer/ZREL_Restriction_func.c index 5195f98..a1aa213 100644 --- a/policy_manager/stm/zipc/StateTransitionor/RestrictionLayer/ZREL_Restriction_func.c +++ b/policy_manager/stm/zipc/StateTransitionor/RestrictionLayer/ZREL_Restriction_func.c @@ -45,15 +45,15 @@ void stm_rel_start_activity_restriction_split_sub() { * @name stm_rel_event_restriction_mode_off */ void stm_rel_event_restriction_mode_off() { - g_stm_crr_state.layer[StmLayerNoRestriction].state = g_prv_restriction_state_rest_mode_1; + g_stm_crr_state.layer[StmLayerNoRestriction].state = g_prv_restriction_state_car_stop; g_stm_crr_state.layer[StmLayerNoRestriction].changed = STM_TRUE; } /* - * @name stm_rel_event_restriction_mode_2_on + * @name stm_rel_event_restriction_mode_on */ -void stm_rel_event_restriction_mode_2_on() { - g_prv_restriction_state_rest_mode_1 = g_stm_prv_state.layer[StmLayerNoRestriction].state; +void stm_rel_event_restriction_mode_on() { + g_prv_restriction_state_car_stop = g_stm_prv_state.layer[StmLayerNoRestriction].state; } /* diff --git a/policy_manager/stm/zipc/StateTransitionor/RestrictionLayer/ZREL_Restriction_func.h b/policy_manager/stm/zipc/StateTransitionor/RestrictionLayer/ZREL_Restriction_func.h index 5cd9b7d..3763820 100644 --- a/policy_manager/stm/zipc/StateTransitionor/RestrictionLayer/ZREL_Restriction_func.h +++ b/policy_manager/stm/zipc/StateTransitionor/RestrictionLayer/ZREL_Restriction_func.h @@ -11,7 +11,7 @@ extern void stm_rel_start_activity_restriction_normal(); extern void stm_rel_start_activity_restriction_split_main(); extern void stm_rel_start_activity_restriction_split_sub(); extern void stm_rel_event_restriction_mode_off(); -extern void stm_rel_event_restriction_mode_2_on(); +extern void stm_rel_event_restriction_mode_on(); extern void stm_rel_initialize_variable(); extern void stm_rel_start_stm(); diff --git a/policy_manager/stm/zipc/StateTransitionor/RestrictionMode/ZREM_RestrictionMode.c b/policy_manager/stm/zipc/StateTransitionor/RestrictionMode/ZREM_RestrictionMode.c index 7fe5700..2ba6a87 100644 --- a/policy_manager/stm/zipc/StateTransitionor/RestrictionMode/ZREM_RestrictionMode.c +++ b/policy_manager/stm/zipc/StateTransitionor/RestrictionMode/ZREM_RestrictionMode.c @@ -9,88 +9,45 @@ static uint8_t ZREM_RestrictionModeState[ZREM_RESTRICTIONMODESTATENOMAX]; static void ZREM_RestrictionModes0e1( void ); -static void ZREM_RestrictionModes0e2( void ); static void ZREM_RestrictionModes1e0( void ); static void ZREM_RestrictionModes0Event( void ); static void ZREM_RestrictionModes1Event( void ); -static void ZREM_RestrictionModes2Event( void ); /****************************************/ /* Action function */ /* STM : RestrictionMode */ -/* State : restriction_mode_off( No 0 ) */ -/* Event : evt_restriction_mode_1_on( No 1 ) */ +/* State : restriction_mode_on( No 0 )*/ +/* Event : evt_restriction_mode_off( No 1 ) */ /****************************************/ static void ZREM_RestrictionModes0e1( void ) { ZREM_RestrictionModeState[ZREM_RESTRICTIONMODE] = ( uint8_t )ZREM_RESTRICTIONMODES1; - stm_rem_start_activity_restriction_mode_1_on(); -} - -/****************************************/ -/* Action function */ -/* STM : RestrictionMode */ -/* State : restriction_mode_off( No 0 ) */ -/* Event : evt_restriction_mode_2_on( No 2 ) */ -/****************************************/ -static void ZREM_RestrictionModes0e2( void ) -{ - ZREM_RestrictionModeState[ZREM_RESTRICTIONMODE] = ( uint8_t )ZREM_RESTRICTIONMODES2; - stm_rem_start_activity_restriction_mode_2_on(); + stm_rem_start_activity_restriction_mode_off(); } /****************************************/ /* Action function */ /* STM : RestrictionMode */ -/* State : restriction_mode_1_on( No 1 ) */ -/* Event : evt_restriction_mode_off( No 0 ) */ +/* State : restriction_mode_off( No 1 ) */ +/* Event : evt_restriction_mode_on( No 0 ) */ /****************************************/ static void ZREM_RestrictionModes1e0( void ) { ZREM_RestrictionModeState[ZREM_RESTRICTIONMODE] = ( uint8_t )ZREM_RESTRICTIONMODES0; - stm_rem_start_activity_restriction_mode_off(); + stm_rem_start_activity_restriction_mode_on(); } /****************************************/ /* Event appraisal function */ /* STM : RestrictionMode */ -/* State : restriction_mode_off( No 0 ) */ +/* State : restriction_mode_on( No 0 )*/ /****************************************/ static void ZREM_RestrictionModes0Event( void ) { - /*evt_restriction_mode_1_on*/ - if( g_stm_event == StmEvtNoRestrictionMode1On ) - { - ZREM_RestrictionModes0e1(); - } - /*evt_restriction_mode_2_on*/ - else if( g_stm_event == StmEvtNoRestrictionMode2On ) - { - ZREM_RestrictionModes0e2(); - } - else - { - /*Else and default design have not done.*/ - /*Please confirm the STM and design else and default.*/ - } -} - -/****************************************/ -/* Event appraisal function */ -/* STM : RestrictionMode */ -/* State : restriction_mode_1_on( No 1 ) */ -/****************************************/ -static void ZREM_RestrictionModes1Event( void ) -{ /*evt_restriction_mode_off*/ if( g_stm_event == StmEvtNoRestrictionModeOff ) { - ZREM_RestrictionModes1e0(); - } - /*evt_restriction_mode_2_on*/ - else if( g_stm_event == StmEvtNoRestrictionMode2On ) - { - ZREM_RestrictionModes0e2(); + ZREM_RestrictionModes0e1(); } else { @@ -102,20 +59,15 @@ static void ZREM_RestrictionModes1Event( void ) /****************************************/ /* Event appraisal function */ /* STM : RestrictionMode */ -/* State : restriction_mode_2_on( No 2 ) */ +/* State : restriction_mode_off( No 1 ) */ /****************************************/ -static void ZREM_RestrictionModes2Event( void ) +static void ZREM_RestrictionModes1Event( void ) { - /*evt_restriction_mode_off*/ - if( g_stm_event == StmEvtNoRestrictionModeOff ) + /*evt_restriction_mode_on*/ + if( g_stm_event == StmEvtNoRestrictionModeOn ) { ZREM_RestrictionModes1e0(); } - /*evt_restriction_mode_1_on*/ - else if( g_stm_event == StmEvtNoRestrictionMode1On ) - { - ZREM_RestrictionModes0e1(); - } else { /*Else and default design have not done.*/ @@ -138,9 +90,6 @@ void stm_rem_event_call( void ) case ZREM_RESTRICTIONMODES1: ZREM_RestrictionModes1Event(); break; - case ZREM_RESTRICTIONMODES2: - ZREM_RestrictionModes2Event(); - break; default: /*Not accessible to this else (default).*/ break; @@ -153,7 +102,7 @@ void stm_rem_event_call( void ) /****************************************/ void stm_rem_initialize( void ) { - ZREM_RestrictionModeState[ZREM_RESTRICTIONMODE] = ( uint8_t )ZREM_RESTRICTIONMODES0; + ZREM_RestrictionModeState[ZREM_RESTRICTIONMODE] = ( uint8_t )ZREM_RESTRICTIONMODES1; stm_rem_start_activity_restriction_mode_off(); } diff --git a/policy_manager/stm/zipc/StateTransitionor/RestrictionMode/ZREM_RestrictionMode.h b/policy_manager/stm/zipc/StateTransitionor/RestrictionMode/ZREM_RestrictionMode.h index f2c2026..4ce0cac 100644 --- a/policy_manager/stm/zipc/StateTransitionor/RestrictionMode/ZREM_RestrictionMode.h +++ b/policy_manager/stm/zipc/StateTransitionor/RestrictionMode/ZREM_RestrictionMode.h @@ -10,33 +10,28 @@ #define ZREM_RESTRICTIONMODE ( 0U ) #define ZREM_RESTRICTIONMODES0 ( 0U ) #define ZREM_RESTRICTIONMODES1 ( 1U ) -#define ZREM_RESTRICTIONMODES2 ( 2U ) #define ZREM_RESTRICTIONMODESTATENOMAX ( 1U ) /*End state define*/ -#define ZREM_RESTRICTIONMODEEND ( 3U ) +#define ZREM_RESTRICTIONMODEEND ( 2U ) /*Terminate state define*/ #define ZREM_RESTRICTIONMODETERMINATE ( ZREM_RESTRICTIONMODEEND + 1U ) /*State no define*/ #define ZREM_RESTRICTIONMODES0STATENO ( 0U ) #define ZREM_RESTRICTIONMODES1STATENO ( 1U ) -#define ZREM_RESTRICTIONMODES2STATENO ( 2U ) /*State serial no define*/ #define ZREM_RESTRICTIONMODES0STATESERIALNO ( 0U ) #define ZREM_RESTRICTIONMODES1STATESERIALNO ( 1U ) -#define ZREM_RESTRICTIONMODES2STATESERIALNO ( 2U ) /*Event no define*/ #define ZREM_RESTRICTIONMODEE0EVENTNO ( 0U ) #define ZREM_RESTRICTIONMODEE1EVENTNO ( 1U ) -#define ZREM_RESTRICTIONMODEE2EVENTNO ( 2U ) /*Event serial no define*/ #define ZREM_RESTRICTIONMODEE0EVENTSERIALNO ( 0U ) #define ZREM_RESTRICTIONMODEE1EVENTSERIALNO ( 1U ) -#define ZREM_RESTRICTIONMODEE2EVENTSERIALNO ( 2U ) /*Extern function*/ extern void stm_rem_event_call( void ); diff --git a/policy_manager/stm/zipc/StateTransitionor/RestrictionMode/ZREM_RestrictionMode_func.c b/policy_manager/stm/zipc/StateTransitionor/RestrictionMode/ZREM_RestrictionMode_func.c index 94807f8..e920916 100644 --- a/policy_manager/stm/zipc/StateTransitionor/RestrictionMode/ZREM_RestrictionMode_func.c +++ b/policy_manager/stm/zipc/StateTransitionor/RestrictionMode/ZREM_RestrictionMode_func.c @@ -10,44 +10,36 @@ *************************************************************/ /* - * @name stm_rem_start_activity_restriction_mode_1_on + * @name stm_rem_start_activity_restriction_mode_on */ -void stm_rem_start_activity_restriction_mode_1_on() { - g_stm_crr_state.mode[StmModeNoRestrictionMode].state = StmRestrictionModeSttNo1On; - g_stm_crr_state.mode[StmModeNoRestrictionMode].changed = STM_TRUE; -} - -/* - * @name stm_rem_start_activity_restriction_mode_2_on - */ -void stm_rem_start_activity_restriction_mode_2_on() { - g_stm_crr_state.mode[StmModeNoRestrictionMode].state = StmRestrictionModeSttNo2On; - g_stm_crr_state.mode[StmModeNoRestrictionMode].changed = STM_TRUE; +void stm_rem_start_activity_restriction_mode_on() { + g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state = StmRestrictionModeSttNoOn; + g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].changed = STM_TRUE; } /* * @name stm_rem_start_activity_restriction_mode_off */ void stm_rem_start_activity_restriction_mode_off() { - g_stm_crr_state.mode[StmModeNoRestrictionMode].state = StmRestrictionModeSttNoOff; - g_stm_crr_state.mode[StmModeNoRestrictionMode].changed = STM_TRUE; + g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state = StmRestrictionModeSttNoOff; + g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].changed = STM_TRUE; } /* * @name stm_rem_initialize_variable */ void stm_rem_initialize_variable() { - g_stm_prv_state.mode[StmModeNoRestrictionMode].state = StmRestrictionModeSttNoOff; - g_stm_prv_state.mode[StmModeNoRestrictionMode].changed = STM_FALSE; + g_stm_prv_state.car_element[StmCarElementNoRestrictionMode].state = StmRestrictionModeSttNoOff; + g_stm_prv_state.car_element[StmCarElementNoRestrictionMode].changed = STM_FALSE; - g_stm_crr_state.mode[StmModeNoRestrictionMode].state = StmRestrictionModeSttNoOff; - g_stm_crr_state.mode[StmModeNoRestrictionMode].changed = STM_FALSE; + g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state = StmRestrictionModeSttNoOff; + g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].changed = STM_FALSE; } /* * @name stm_rem_start_stm */ void stm_rem_start_stm() { - g_stm_prv_state.mode[StmModeNoRestrictionMode].state = g_stm_crr_state.mode[StmModeNoRestrictionMode].state; - g_stm_crr_state.mode[StmModeNoRestrictionMode].changed = STM_FALSE; + g_stm_prv_state.car_element[StmCarElementNoRestrictionMode].state = g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].state; + g_stm_crr_state.car_element[StmCarElementNoRestrictionMode].changed = STM_FALSE; } diff --git a/policy_manager/stm/zipc/StateTransitionor/RestrictionMode/ZREM_RestrictionMode_func.h b/policy_manager/stm/zipc/StateTransitionor/RestrictionMode/ZREM_RestrictionMode_func.h index f85ab14..bbb6edf 100644 --- a/policy_manager/stm/zipc/StateTransitionor/RestrictionMode/ZREM_RestrictionMode_func.h +++ b/policy_manager/stm/zipc/StateTransitionor/RestrictionMode/ZREM_RestrictionMode_func.h @@ -6,8 +6,7 @@ #ifndef ZHEADER_ZREM_RESTRICTIONMODE_FUNC_H #define ZHEADER_ZREM_RESTRICTIONMODE_FUNC_H -extern void stm_rem_start_activity_restriction_mode_1_on(); -extern void stm_rem_start_activity_restriction_mode_2_on(); +extern void stm_rem_start_activity_restriction_mode_on(); extern void stm_rem_start_activity_restriction_mode_off(); extern void stm_rem_initialize_variable(); extern void stm_rem_start_stm(); diff --git a/policy_manager/stm/zipc/StateTransitionor/ZST_StateTransitionor_func.c b/policy_manager/stm/zipc/StateTransitionor/ZST_StateTransitionor_func.c index 3903202..daea2ca 100644 --- a/policy_manager/stm/zipc/StateTransitionor/ZST_StateTransitionor_func.c +++ b/policy_manager/stm/zipc/StateTransitionor/ZST_StateTransitionor_func.c @@ -4,12 +4,17 @@ /* ZIPC Designer Version 1.2.0 */ /************************************************************/ #include "ZST_include.h" +#include "../stm_master_apps.h" +#include "../stm_master_remote.h" /************************************************************* Function definition *************************************************************/ #include <string.h> +#include <stdbool.h> + +static bool isMaster = false; //================================= // API @@ -17,34 +22,69 @@ /** * Initialize STM */ -void stmInitializeInner() { +void stmInitializeInner(const char *ecu_name) { + + // TODO: Set master mode + if (0 == strcmp("master", ecu_name)) + { + isMaster = true; + } + // Initialize previous state memset(&g_stm_prv_state, 0, sizeof(g_stm_prv_state)); // Initialize current state g_stm_crr_state = g_stm_prv_state; - /* Initialize restriction mode state */ - stm_rem_initialize(); - stm_rem_initialize_variable(); - - // Initialize homecsreen layer - stm_hsl_initialize(); - stm_hsl_initialize_variable(); - - // Initialize apps layer - stm_apl_initialize(); - stm_apl_initialize_variable(); - - // Initialize near_homecsreen layer - stm_nhl_initialize(); - stm_nhl_initialize_variable(); - - /* Initialize restriction layer */ - stm_rel_initialize(); - stm_rel_initialize_variable(); - - g_stm_map_is_activated = STM_FALSE; + /* Initialize LightstatusBrake state */ + stm_lbs_initialize(); + stm_lbs_initialize_variable(); + + /* Initialize AccelPedal state */ + stm_aps_initialize(); + stm_aps_initialize_variable(); + + /* Initialize car state */ + stm_rns_initialize(); + stm_rns_initialize_variable(); + + /* Initialize restriction mode state */ + stm_rem_initialize(); + stm_rem_initialize_variable(); + + // Initialize homecsreen layer + stm_hsl_initialize(); + stm_hsl_initialize_variable(); + + if (isMaster) + { + // Initialize apps layer on master ecu + stm_master_apl_initialize(); + stm_master_apl_initialize_valiable(); + } + else + { + // Initialize apps layer + stm_apl_initialize(); + stm_apl_initialize_variable(); + } + + // Initialize near_homecsreen layer + stm_nhl_initialize(); + stm_nhl_initialize_variable(); + + /* Initialize restriction layer */ + stm_rel_initialize(); + stm_rel_initialize_variable(); + + if (isMaster) + { + // Initialize remote layer on master ecu + stm_mst_rmt_initialize(); + stm_mst_rmt_initialize_valiable(); + } + + g_stm_map_is_activated = STM_FALSE; } /** @@ -55,14 +95,31 @@ int stmTransitionStateInner(int event_id, StmState* state) { g_stm_category = STM_GET_CATEGORY_FROM_ID(event_id); g_stm_area = STM_GET_AREA_FROM_ID(event_id); + // LightstatusBrake state + stm_lbs_event_call(); + + // AccelPedal state + stm_aps_event_call(); + + // Car state + stm_rns_event_call(); + // restriction mode stm_rem_event_call(); // homescreen layer stm_hsl_event_call(); - // apps layer - stm_apl_event_call(); + if (isMaster) + { + // apps layer on master ecu + stm_master_apl_event_call(); + } + else + { + // apps layer + stm_apl_event_call(); + } // near_homecsreen layer stm_nhl_event_call(); @@ -73,6 +130,12 @@ int stmTransitionStateInner(int event_id, StmState* state) { // on_screen layer stm_osl_event_call(); + if (isMaster) + { + // remote layer on master ecu + stm_mst_rmt_event_call(); + } + // Copy current state for return memcpy(state, &g_stm_crr_state, sizeof(g_stm_crr_state)); @@ -85,8 +148,16 @@ int stmTransitionStateInner(int event_id, StmState* state) { void stmUndoStateInner() { g_stm_event = StmEvtNoUndo; - // apps layer - stm_apl_event_call(); + if (isMaster) + { + // apps layer on master ecu + stm_master_apl_event_call(); + } + else + { + // apps layer + stm_apl_event_call(); + } // near_homecsreen layer stm_nhl_event_call(); @@ -97,6 +168,11 @@ void stmUndoStateInner() { // on_screen layer stm_osl_event_call(); + if (isMaster) + { + // remote layer on master ecu + stm_mst_rmt_event_call(); + } + g_stm_crr_state = g_stm_prv_state; } - diff --git a/policy_manager/stm/zipc/StateTransitionor/ZST_StateTransitionor_var.c b/policy_manager/stm/zipc/StateTransitionor/ZST_StateTransitionor_var.c index b3a2273..a5e67ff 100644 --- a/policy_manager/stm/zipc/StateTransitionor/ZST_StateTransitionor_var.c +++ b/policy_manager/stm/zipc/StateTransitionor/ZST_StateTransitionor_var.c @@ -36,21 +36,21 @@ int g_stm_area; int g_stm_map_is_activated; /** - * g_prv_apps_state_rest_mode_1 + * g_prv_apps_state_car_stop */ -int g_prv_apps_state_rest_mode_1; +int g_prv_apps_state_car_stop; /** - * g_prv_near_homescreen_state_rest_mode_1 + * g_prv_near_homescreen_state_car_stop */ -int g_prv_near_homescreen_state_rest_mode_1; +int g_prv_near_homescreen_state_car_stop; /** - * g_prv_restriction_state_rest_mode_1 + * g_prv_restriction_state_car_stop */ -int g_prv_restriction_state_rest_mode_1; +int g_prv_restriction_state_car_stop; /** - * g_prv_on_screen_state_rest_mode_1 + * g_prv_on_screen_state_car_stop */ -int g_prv_on_screen_state_rest_mode_1; +int g_prv_on_screen_state_car_stop; diff --git a/policy_manager/stm/zipc/StateTransitionor/ZST_StateTransitionor_var.h b/policy_manager/stm/zipc/StateTransitionor/ZST_StateTransitionor_var.h index 57b52ee..4cabced 100644 --- a/policy_manager/stm/zipc/StateTransitionor/ZST_StateTransitionor_var.h +++ b/policy_manager/stm/zipc/StateTransitionor/ZST_StateTransitionor_var.h @@ -12,9 +12,9 @@ extern int g_stm_event; extern int g_stm_category; extern int g_stm_area; extern int g_stm_map_is_activated; -extern int g_prv_apps_state_rest_mode_1; -extern int g_prv_near_homescreen_state_rest_mode_1; -extern int g_prv_restriction_state_rest_mode_1; -extern int g_prv_on_screen_state_rest_mode_1; +extern int g_prv_apps_state_car_stop; +extern int g_prv_near_homescreen_state_car_stop; +extern int g_prv_restriction_state_car_stop; +extern int g_prv_on_screen_state_car_stop; #endif diff --git a/policy_manager/stm/zipc/StateTransitionor/ZST_include.h b/policy_manager/stm/zipc/StateTransitionor/ZST_include.h index e3d1572..2158660 100644 --- a/policy_manager/stm/zipc/StateTransitionor/ZST_include.h +++ b/policy_manager/stm/zipc/StateTransitionor/ZST_include.h @@ -11,6 +11,8 @@ #include "../Common/MisraCType.h" #include "../Common/Event.h" #include "ZST_StateTransitionor_def.h" +#include "master/layer/apps/Zmaster_apps_master_apps_def.h" +#include "master/layer/remote/Zmaster_remote_master_remote_def.h" #include "ZST_StateTransitionor_func.h" #include "ZST_StateTransitionor_var.h" #include "AppsLayer/ZAPL_Apps_func.h" @@ -19,11 +21,19 @@ #include "RestrictionLayer/ZREL_Restriction_func.h" #include "RestrictionMode/ZREM_RestrictionMode_func.h" #include "NearHomeScreen/ZNHL_NearHomeScreen_func.h" +#include "AccelPedal/ZACCEL_AccelPedalState_func.h" +#include "CarState/ZCAR_CarState_func.h" +#include "LightStatusBrake/ZLIGHT_LightstatusBrakeStatus_func.h" +#include "master/layer/apps/Zmaster_apps_apps_main.h" +#include "master/layer/remote/Zmaster_remote_remote.h" #include "AppsLayer/ZAPL_AppsLayer.h" #include "OnScreenlayer/ZOSL_OslMain.h" #include "HomeScreenLayer/ZHSL_HomeScreen.h" #include "RestrictionLayer/ZREL_RelMain.h" #include "RestrictionMode/ZREM_RestrictionMode.h" #include "NearHomeScreen/ZNHL_NearHomescreen.h" +#include "AccelPedal/ZACCEL_AccelPedal.h" +#include "CarState/ZCAR_CarState.h" +#include "LightStatusBrake/ZLIGHT_LightstatusBrake.h" #endif diff --git a/policy_manager/stm/zipc/StateTransitionor/master/layer/apps/Zmaster_apps_apps_main.c b/policy_manager/stm/zipc/StateTransitionor/master/layer/apps/Zmaster_apps_apps_main.c new file mode 100644 index 0000000..af46ea9 --- /dev/null +++ b/policy_manager/stm/zipc/StateTransitionor/master/layer/apps/Zmaster_apps_apps_main.c @@ -0,0 +1,1456 @@ +/************************************************************/ +/* Zmaster_apps_apps_main.c */ +/* apps_main State transition model source file */ +/* ZIPC Designer Version 1.2.0 */ +/************************************************************/ +#include "../../../ZST_include.h" + +/* State management variable */ +static uint8_t Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAINSTATENOMAX]; + +static void Zmaster_apps_apps_mains0StateEntry( void ); +static void Zmaster_apps_apps_mains1StateEntry( void ); +static void Zmaster_apps_apps_mains0e1( void ); +static void Zmaster_apps_apps_mains1e0( void ); +static void Zmaster_apps_apps_car_stops0e0( void ); +static void Zmaster_apps_apps_car_stops0e2( void ); +static void Zmaster_apps_apps_car_stops0e3( void ); +static void Zmaster_apps_apps_car_stops0e4( void ); +static void Zmaster_apps_apps_car_stops0e11( void ); +static void Zmaster_apps_apps_car_stops0e15( void ); +static void Zmaster_apps_apps_car_runs0e0( void ); +static void Zmaster_apps_apps_car_runs0e3( void ); +static void Zmaster_apps_apps_mains0Event( void ); +static void Zmaster_apps_apps_car_stops0Event( void ); +static void Zmaster_apps_apps_car_stops1Event( void ); +static void Zmaster_apps_apps_car_stops2Event( void ); +static void Zmaster_apps_apps_car_stops3Event( void ); +static void Zmaster_apps_apps_car_stops4Event( void ); +static void Zmaster_apps_apps_car_stops5Event( void ); +static void Zmaster_apps_apps_mains1Event( void ); +static void Zmaster_apps_apps_car_runs0Event( void ); +static void Zmaster_apps_apps_car_runs1Event( void ); + +/****************************************/ +/* State start activity function */ +/* STM : apps_main */ +/* State : lightstatus_brake_on( No 0 ) */ +/****************************************/ +static void Zmaster_apps_apps_mains0StateEntry( void ) +{ + switch( Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAINS0F] ) + { + case ZMASTER_APPS_APPS_CAR_STOPS0: + stm_mst_apl_start_activity_none(); + break; + case ZMASTER_APPS_APPS_CAR_STOPS1: + stm_mst_apl_start_activity_meter_receiver(); + break; + case ZMASTER_APPS_APPS_CAR_STOPS2: + stm_mst_apl_start_activity_meter_splitable(); + break; + case ZMASTER_APPS_APPS_CAR_STOPS3: + stm_mst_apl_start_activity_splitable_receiver(); + break; + case ZMASTER_APPS_APPS_CAR_STOPS4: + stm_mst_apl_start_activity_splitable_split(); + break; + case ZMASTER_APPS_APPS_CAR_STOPS5: + stm_mst_apl_start_activity_general(); + break; + default: + /*Not accessible to this else (default).*/ + break; + } +} + +/****************************************/ +/* State start activity function */ +/* STM : apps_main */ +/* State : lightstatus_brake_off( No 1 ) */ +/****************************************/ +static void Zmaster_apps_apps_mains1StateEntry( void ) +{ + switch( Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAINS1F] ) + { + case ZMASTER_APPS_APPS_CAR_RUNS0: + stm_mst_apl_start_activity_meter_receiver(); + break; + case ZMASTER_APPS_APPS_CAR_RUNS1: + stm_mst_apl_start_activity_meter(); + break; + default: + /*Not accessible to this else (default).*/ + break; + } +} + +/****************************************/ +/* Action function */ +/* STM : apps_main */ +/* State : lightstatus_brake_on( No 0 ) */ +/* Event : stt_lightstatus_brake_off( No 1 ) */ +/****************************************/ +static void Zmaster_apps_apps_mains0e1( void ) +{ + Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAIN] = ( uint8_t )ZMASTER_APPS_APPS_MAINS1; + Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAINS1F] = ( uint8_t )ZMASTER_APPS_APPS_CAR_RUNS0; + Zmaster_apps_apps_mains1StateEntry(); +} + +/****************************************/ +/* Action function */ +/* STM : apps_main */ +/* State : lightstatus_brake_off( No 1 ) */ +/* Event : stt_lightstatus_brake_on( No 0 ) */ +/****************************************/ +static void Zmaster_apps_apps_mains1e0( void ) +{ + Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAIN] = ( uint8_t )ZMASTER_APPS_APPS_MAINS0; + Zmaster_apps_apps_mains0StateEntry(); +} + +/****************************************/ +/* Action function */ +/* STM : apps_car_stop */ +/* State : none( No 0 ) */ +/* Event : ara_split_main( No 0 ) */ +/****************************************/ +static void Zmaster_apps_apps_car_stops0e0( void ) +{ + Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAINS0F] = ( uint8_t )ZMASTER_APPS_APPS_CAR_STOPS1; + stm_mst_apl_start_activity_meter_receiver(); +} + +/****************************************/ +/* Action function */ +/* STM : apps_car_stop */ +/* State : none( No 0 ) */ +/* Event : ara_split_main( No 2 ) */ +/****************************************/ +static void Zmaster_apps_apps_car_stops0e2( void ) +{ + Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAINS0F] = ( uint8_t )ZMASTER_APPS_APPS_CAR_STOPS3; + stm_mst_apl_start_activity_splitable_receiver(); +} + +/****************************************/ +/* Action function */ +/* STM : apps_car_stop */ +/* State : none( No 0 ) */ +/* Event : ara_split_sub( No 3 ) */ +/****************************************/ +static void Zmaster_apps_apps_car_stops0e3( void ) +{ + Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAINS0F] = ( uint8_t )ZMASTER_APPS_APPS_CAR_STOPS2; + stm_mst_apl_start_activity_meter_splitable(); +} + +/****************************************/ +/* Action function */ +/* STM : apps_car_stop */ +/* State : none( No 0 ) */ +/* Event : ara_normal( No 4 ) */ +/****************************************/ +static void Zmaster_apps_apps_car_stops0e4( void ) +{ + Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAINS0F] = ( uint8_t )ZMASTER_APPS_APPS_CAR_STOPS5; + stm_mst_apl_start_activity_general(); +} + +/****************************************/ +/* Action function */ +/* STM : apps_car_stop */ +/* State : none( No 0 ) */ +/* Event : stt_prv_layer_apps_none( No 11 ) */ +/****************************************/ +static void Zmaster_apps_apps_car_stops0e11( void ) +{ + Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAINS0F] = ( uint8_t )ZMASTER_APPS_APPS_CAR_STOPS0; + stm_mst_apl_start_activity_none(); +} + +/****************************************/ +/* Action function */ +/* STM : apps_car_stop */ +/* State : none( No 0 ) */ +/* Event : stt_prv_layer_apps_splitable_split( No 15 ) */ +/****************************************/ +static void Zmaster_apps_apps_car_stops0e15( void ) +{ + Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAINS0F] = ( uint8_t )ZMASTER_APPS_APPS_CAR_STOPS4; + stm_mst_apl_start_activity_splitable_split(); +} + +/****************************************/ +/* Action function */ +/* STM : apps_car_run */ +/* State : meter_receiver( No 0 ) */ +/* Event : ara_normal( No 0 ) */ +/****************************************/ +static void Zmaster_apps_apps_car_runs0e0( void ) +{ + Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAINS1F] = ( uint8_t )ZMASTER_APPS_APPS_CAR_RUNS1; + stm_mst_apl_start_activity_meter(); +} + +/****************************************/ +/* Action function */ +/* STM : apps_car_run */ +/* State : meter_receiver( No 0 ) */ +/* Event : stt_prv_layer_apps_meter_receiver( No 3 ) */ +/****************************************/ +static void Zmaster_apps_apps_car_runs0e3( void ) +{ + Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAINS1F] = ( uint8_t )ZMASTER_APPS_APPS_CAR_RUNS0; + stm_mst_apl_start_activity_meter_receiver(); +} + +/****************************************/ +/* Event appraisal function */ +/* STM : apps_main */ +/* State : lightstatus_brake_on( No 0 ) */ +/****************************************/ +static void Zmaster_apps_apps_mains0Event( void ) +{ + /*stt_lightstatus_brake_off*/ + if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOff ) + { + stm_mst_apl_event_lightstatus_brake_off(); + Zmaster_apps_apps_mains0e1(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } +} + +/****************************************/ +/* Event appraisal function */ +/* STM : apps_car_stop */ +/* State : none( No 0 ) */ +/****************************************/ +static void Zmaster_apps_apps_car_stops0Event( void ) +{ + /*stt_lightstatus_brake_on*/ + if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOn ) + { + /*evt_activate*/ + if( g_stm_event == StmEvtNoActivate ) + { + /*ctg_meter*/ + if( g_stm_category == StmCtgNoMeter ) + { + /*ara_split_main*/ + if( g_stm_area == StmAreaNoSplitMain ) + { + Zmaster_apps_apps_car_stops0e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_receiver*/ + else if( g_stm_category == StmCtgNoReceiver ) + { + /*ara_split_sub*/ + if( g_stm_area == StmAreaNoSplitSub ) + { + Zmaster_apps_apps_car_stops0e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_splitable_main*/ + else if( g_stm_category == StmCtgNoSplitableMain ) + { + /*ara_split_main*/ + if( g_stm_area == StmAreaNoSplitMain ) + { + Zmaster_apps_apps_car_stops0e2(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_splitable_sub*/ + else if( g_stm_category == StmCtgNoSplitableSub ) + { + /*ara_split_sub*/ + if( g_stm_area == StmAreaNoSplitSub ) + { + Zmaster_apps_apps_car_stops0e3(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_general*/ + else if( g_stm_category == StmCtgNoGeneral ) + { + /*ara_normal*/ + if( g_stm_area == StmAreaNoNormal ) + { + Zmaster_apps_apps_car_stops0e4(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*evt_undo*/ + else if( g_stm_event == StmEvtNoUndo ) + { + /*stt_prv_layer_apps_none*/ + if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoNone ) + { + Zmaster_apps_apps_car_stops0e11(); + } + /*stt_prv_layer_apps_meter_receiver*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoMtrRcv ) + { + Zmaster_apps_apps_car_stops0e0(); + } + /*stt_prv_layer_apps_meter_splitable*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoMtrSpl ) + { + Zmaster_apps_apps_car_stops0e3(); + } + /*stt_prv_layer_apps_splitable_receiver*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoSplRcv ) + { + Zmaster_apps_apps_car_stops0e2(); + } + /*stt_prv_layer_apps_splitable_split*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoSplSpl ) + { + Zmaster_apps_apps_car_stops0e15(); + } + /*stt_prv_layer_apps_gen_nml*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoGenNml ) + { + Zmaster_apps_apps_car_stops0e4(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } +} + +/****************************************/ +/* Event appraisal function */ +/* STM : apps_car_stop */ +/* State : meter_receiver( No 1 ) */ +/****************************************/ +static void Zmaster_apps_apps_car_stops1Event( void ) +{ + /*stt_lightstatus_brake_on*/ + if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOn ) + { + /*evt_activate*/ + if( g_stm_event == StmEvtNoActivate ) + { + /*ctg_splitable_main*/ + if( g_stm_category == StmCtgNoSplitableMain ) + { + /*ara_split_main*/ + if( g_stm_area == StmAreaNoSplitMain ) + { + Zmaster_apps_apps_car_stops0e2(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_splitable_sub*/ + else if( g_stm_category == StmCtgNoSplitableSub ) + { + /*ara_split_sub*/ + if( g_stm_area == StmAreaNoSplitSub ) + { + Zmaster_apps_apps_car_stops0e3(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_general*/ + else if( g_stm_category == StmCtgNoGeneral ) + { + /*ara_normal*/ + if( g_stm_area == StmAreaNoNormal ) + { + Zmaster_apps_apps_car_stops0e4(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_homescreen*/ + else if( g_stm_category == StmCtgNoHomescreen ) + { + /*ara_fullscreen*/ + if( g_stm_area == StmAreaNoFullscreen ) + { + Zmaster_apps_apps_car_stops0e11(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*evt_deactivate*/ + else if( g_stm_event == StmEvtNoDeactivate ) + { + /*ctg_meter*/ + if( g_stm_category == StmCtgNoMeter ) + { + Zmaster_apps_apps_car_stops0e11(); + } + /*ctg_receiver*/ + else if( g_stm_category == StmCtgNoReceiver ) + { + Zmaster_apps_apps_car_stops0e11(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*evt_undo*/ + else if( g_stm_event == StmEvtNoUndo ) + { + /*stt_prv_layer_apps_none*/ + if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoNone ) + { + Zmaster_apps_apps_car_stops0e11(); + } + /*stt_prv_layer_apps_meter_receiver*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoMtrRcv ) + { + Zmaster_apps_apps_car_stops0e0(); + } + /*stt_prv_layer_apps_meter_splitable*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoMtrSpl ) + { + Zmaster_apps_apps_car_stops0e3(); + } + /*stt_prv_layer_apps_splitable_receiver*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoSplRcv ) + { + Zmaster_apps_apps_car_stops0e2(); + } + /*stt_prv_layer_apps_splitable_split*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoSplSpl ) + { + Zmaster_apps_apps_car_stops0e15(); + } + /*stt_prv_layer_apps_gen_nml*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoGenNml ) + { + Zmaster_apps_apps_car_stops0e4(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } +} + +/****************************************/ +/* Event appraisal function */ +/* STM : apps_car_stop */ +/* State : meter_splitable( No 2 ) */ +/****************************************/ +static void Zmaster_apps_apps_car_stops2Event( void ) +{ + /*stt_lightstatus_brake_on*/ + if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOn ) + { + /*evt_activate*/ + if( g_stm_event == StmEvtNoActivate ) + { + /*ctg_receiver*/ + if( g_stm_category == StmCtgNoReceiver ) + { + /*ara_split_sub*/ + if( g_stm_area == StmAreaNoSplitSub ) + { + Zmaster_apps_apps_car_stops0e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_splitable_main*/ + else if( g_stm_category == StmCtgNoSplitableMain ) + { + /*ara_split_main*/ + if( g_stm_area == StmAreaNoSplitMain ) + { + Zmaster_apps_apps_car_stops0e15(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_splitable_sub*/ + else if( g_stm_category == StmCtgNoSplitableSub ) + { + /*ara_split_sub*/ + if( g_stm_area == StmAreaNoSplitSub ) + { + Zmaster_apps_apps_car_stops0e3(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_general*/ + else if( g_stm_category == StmCtgNoGeneral ) + { + /*ara_normal*/ + if( g_stm_area == StmAreaNoNormal ) + { + Zmaster_apps_apps_car_stops0e4(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_homescreen*/ + else if( g_stm_category == StmCtgNoHomescreen ) + { + /*ara_fullscreen*/ + if( g_stm_area == StmAreaNoFullscreen ) + { + Zmaster_apps_apps_car_stops0e11(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*evt_deactivate*/ + else if( g_stm_event == StmEvtNoDeactivate ) + { + /*ctg_meter*/ + if( g_stm_category == StmCtgNoMeter ) + { + Zmaster_apps_apps_car_stops0e11(); + } + /*ctg_splitable_sub*/ + else if( g_stm_category == StmCtgNoSplitableSub ) + { + /*ara_split_sub*/ + if( g_stm_area == StmAreaNoSplitSub ) + { + Zmaster_apps_apps_car_stops0e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*evt_undo*/ + else if( g_stm_event == StmEvtNoUndo ) + { + /*stt_prv_layer_apps_none*/ + if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoNone ) + { + Zmaster_apps_apps_car_stops0e11(); + } + /*stt_prv_layer_apps_meter_receiver*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoMtrRcv ) + { + Zmaster_apps_apps_car_stops0e0(); + } + /*stt_prv_layer_apps_meter_splitable*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoMtrSpl ) + { + Zmaster_apps_apps_car_stops0e3(); + } + /*stt_prv_layer_apps_splitable_receiver*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoSplRcv ) + { + Zmaster_apps_apps_car_stops0e2(); + } + /*stt_prv_layer_apps_splitable_split*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoSplSpl ) + { + Zmaster_apps_apps_car_stops0e15(); + } + /*stt_prv_layer_apps_gen_nml*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoGenNml ) + { + Zmaster_apps_apps_car_stops0e4(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } +} + +/****************************************/ +/* Event appraisal function */ +/* STM : apps_car_stop */ +/* State : splitable_receiver( No 3 ) */ +/****************************************/ +static void Zmaster_apps_apps_car_stops3Event( void ) +{ + /*stt_lightstatus_brake_on*/ + if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOn ) + { + /*evt_activate*/ + if( g_stm_event == StmEvtNoActivate ) + { + /*ctg_meter*/ + if( g_stm_category == StmCtgNoMeter ) + { + /*ara_split_main*/ + if( g_stm_area == StmAreaNoSplitMain ) + { + Zmaster_apps_apps_car_stops0e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_splitable_main*/ + else if( g_stm_category == StmCtgNoSplitableMain ) + { + /*ara_split_main*/ + if( g_stm_area == StmAreaNoSplitMain ) + { + Zmaster_apps_apps_car_stops0e2(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_splitable_sub*/ + else if( g_stm_category == StmCtgNoSplitableSub ) + { + /*ara_split_sub*/ + if( g_stm_area == StmAreaNoSplitSub ) + { + Zmaster_apps_apps_car_stops0e15(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_general*/ + else if( g_stm_category == StmCtgNoGeneral ) + { + /*ara_normal*/ + if( g_stm_area == StmAreaNoNormal ) + { + Zmaster_apps_apps_car_stops0e4(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_homescreen*/ + else if( g_stm_category == StmCtgNoHomescreen ) + { + /*ara_fullscreen*/ + if( g_stm_area == StmAreaNoFullscreen ) + { + Zmaster_apps_apps_car_stops0e11(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*evt_deactivate*/ + else if( g_stm_event == StmEvtNoDeactivate ) + { + /*ctg_receiver*/ + if( g_stm_category == StmCtgNoReceiver ) + { + Zmaster_apps_apps_car_stops0e11(); + } + /*ctg_splitable_main*/ + else if( g_stm_category == StmCtgNoSplitableMain ) + { + /*ara_split_main*/ + if( g_stm_area == StmAreaNoSplitMain ) + { + Zmaster_apps_apps_car_stops0e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*evt_undo*/ + else if( g_stm_event == StmEvtNoUndo ) + { + /*stt_prv_layer_apps_none*/ + if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoNone ) + { + Zmaster_apps_apps_car_stops0e11(); + } + /*stt_prv_layer_apps_meter_receiver*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoMtrRcv ) + { + Zmaster_apps_apps_car_stops0e0(); + } + /*stt_prv_layer_apps_meter_splitable*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoMtrSpl ) + { + Zmaster_apps_apps_car_stops0e3(); + } + /*stt_prv_layer_apps_splitable_receiver*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoSplRcv ) + { + Zmaster_apps_apps_car_stops0e2(); + } + /*stt_prv_layer_apps_splitable_split*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoSplSpl ) + { + Zmaster_apps_apps_car_stops0e15(); + } + /*stt_prv_layer_apps_gen_nml*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoGenNml ) + { + Zmaster_apps_apps_car_stops0e4(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } +} + +/****************************************/ +/* Event appraisal function */ +/* STM : apps_car_stop */ +/* State : splitable_split( No 4 ) */ +/****************************************/ +static void Zmaster_apps_apps_car_stops4Event( void ) +{ + /*stt_lightstatus_brake_on*/ + if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOn ) + { + /*evt_activate*/ + if( g_stm_event == StmEvtNoActivate ) + { + /*ctg_meter*/ + if( g_stm_category == StmCtgNoMeter ) + { + /*ara_split_main*/ + if( g_stm_area == StmAreaNoSplitMain ) + { + Zmaster_apps_apps_car_stops0e3(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_receiver*/ + else if( g_stm_category == StmCtgNoReceiver ) + { + /*ara_split_sub*/ + if( g_stm_area == StmAreaNoSplitSub ) + { + Zmaster_apps_apps_car_stops0e2(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_splitable_main*/ + else if( g_stm_category == StmCtgNoSplitableMain ) + { + /*ara_split_main*/ + if( g_stm_area == StmAreaNoSplitMain ) + { + Zmaster_apps_apps_car_stops0e15(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_splitable_sub*/ + else if( g_stm_category == StmCtgNoSplitableSub ) + { + /*ara_split_sub*/ + if( g_stm_area == StmAreaNoSplitSub ) + { + Zmaster_apps_apps_car_stops0e15(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_general*/ + else if( g_stm_category == StmCtgNoGeneral ) + { + /*ara_normal*/ + if( g_stm_area == StmAreaNoNormal ) + { + Zmaster_apps_apps_car_stops0e4(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_homescreen*/ + else if( g_stm_category == StmCtgNoHomescreen ) + { + /*ara_fullscreen*/ + if( g_stm_area == StmAreaNoFullscreen ) + { + Zmaster_apps_apps_car_stops0e11(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*evt_deactivate*/ + else if( g_stm_event == StmEvtNoDeactivate ) + { + /*ctg_splitable_main*/ + if( g_stm_category == StmCtgNoSplitableMain ) + { + /*ara_split_main*/ + if( g_stm_area == StmAreaNoSplitMain ) + { + Zmaster_apps_apps_car_stops0e3(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_splitable_sub*/ + else if( g_stm_category == StmCtgNoSplitableSub ) + { + /*ara_split_sub*/ + if( g_stm_area == StmAreaNoSplitSub ) + { + Zmaster_apps_apps_car_stops0e2(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*evt_undo*/ + else if( g_stm_event == StmEvtNoUndo ) + { + /*stt_prv_layer_apps_none*/ + if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoNone ) + { + Zmaster_apps_apps_car_stops0e11(); + } + /*stt_prv_layer_apps_meter_receiver*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoMtrRcv ) + { + Zmaster_apps_apps_car_stops0e0(); + } + /*stt_prv_layer_apps_meter_splitable*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoMtrSpl ) + { + Zmaster_apps_apps_car_stops0e3(); + } + /*stt_prv_layer_apps_splitable_receiver*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoSplRcv ) + { + Zmaster_apps_apps_car_stops0e2(); + } + /*stt_prv_layer_apps_splitable_split*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoSplSpl ) + { + Zmaster_apps_apps_car_stops0e15(); + } + /*stt_prv_layer_apps_gen_nml*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoGenNml ) + { + Zmaster_apps_apps_car_stops0e4(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } +} + +/****************************************/ +/* Event appraisal function */ +/* STM : apps_car_stop */ +/* State : general( No 5 ) */ +/****************************************/ +static void Zmaster_apps_apps_car_stops5Event( void ) +{ + /*stt_lightstatus_brake_on*/ + if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOn ) + { + /*evt_activate*/ + if( g_stm_event == StmEvtNoActivate ) + { + /*ctg_meter*/ + if( g_stm_category == StmCtgNoMeter ) + { + /*ara_split_main*/ + if( g_stm_area == StmAreaNoSplitMain ) + { + Zmaster_apps_apps_car_stops0e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_receiver*/ + else if( g_stm_category == StmCtgNoReceiver ) + { + /*ara_split_sub*/ + if( g_stm_area == StmAreaNoSplitSub ) + { + Zmaster_apps_apps_car_stops0e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_splitable_main*/ + else if( g_stm_category == StmCtgNoSplitableMain ) + { + /*ara_split_main*/ + if( g_stm_area == StmAreaNoSplitMain ) + { + Zmaster_apps_apps_car_stops0e2(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_splitable_sub*/ + else if( g_stm_category == StmCtgNoSplitableSub ) + { + /*ara_split_sub*/ + if( g_stm_area == StmAreaNoSplitSub ) + { + Zmaster_apps_apps_car_stops0e3(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_general*/ + else if( g_stm_category == StmCtgNoGeneral ) + { + /*ara_normal*/ + if( g_stm_area == StmAreaNoNormal ) + { + Zmaster_apps_apps_car_stops0e4(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_homescreen*/ + else if( g_stm_category == StmCtgNoHomescreen ) + { + /*ara_fullscreen*/ + if( g_stm_area == StmAreaNoFullscreen ) + { + Zmaster_apps_apps_car_stops0e11(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*evt_deactivate*/ + else if( g_stm_event == StmEvtNoDeactivate ) + { + /*ctg_general*/ + if( g_stm_category == StmCtgNoGeneral ) + { + Zmaster_apps_apps_car_stops0e11(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*evt_undo*/ + else if( g_stm_event == StmEvtNoUndo ) + { + /*stt_prv_layer_apps_none*/ + if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoNone ) + { + Zmaster_apps_apps_car_stops0e11(); + } + /*stt_prv_layer_apps_meter_receiver*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoMtrRcv ) + { + Zmaster_apps_apps_car_stops0e0(); + } + /*stt_prv_layer_apps_meter_splitable*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoMtrSpl ) + { + Zmaster_apps_apps_car_stops0e3(); + } + /*stt_prv_layer_apps_splitable_receiver*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoSplRcv ) + { + Zmaster_apps_apps_car_stops0e2(); + } + /*stt_prv_layer_apps_splitable_split*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoSplSpl ) + { + Zmaster_apps_apps_car_stops0e15(); + } + /*stt_prv_layer_apps_gen_nml*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoGenNml ) + { + Zmaster_apps_apps_car_stops0e4(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } +} + +/****************************************/ +/* Event appraisal function */ +/* STM : apps_main */ +/* State : lightstatus_brake_off( No 1 ) */ +/****************************************/ +static void Zmaster_apps_apps_mains1Event( void ) +{ + /*stt_lightstatus_brake_on*/ + if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOn ) + { + stm_mst_apl_event_lightstatus_brake_on(); + Zmaster_apps_apps_mains1e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } +} + +/****************************************/ +/* Event appraisal function */ +/* STM : apps_car_run */ +/* State : meter_receiver( No 0 ) */ +/****************************************/ +static void Zmaster_apps_apps_car_runs0Event( void ) +{ + /*stt_lightstatus_brake_off*/ + if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOff ) + { + /*evt_activate*/ + if( g_stm_event == StmEvtNoActivate ) + { + /*ctg_meter*/ + if( g_stm_category == StmCtgNoMeter ) + { + /*ara_normal*/ + if( g_stm_area == StmAreaNoNormal ) + { + Zmaster_apps_apps_car_runs0e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*evt_undo*/ + else if( g_stm_event == StmEvtNoUndo ) + { + /*stt_prv_layer_apps_meter_receiver*/ + if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoMtrRcv ) + { + Zmaster_apps_apps_car_runs0e3(); + } + /*stt_prv_layer_apps_meter*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoMtrNml ) + { + Zmaster_apps_apps_car_runs0e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } +} + +/****************************************/ +/* Event appraisal function */ +/* STM : apps_car_run */ +/* State : meter( No 1 ) */ +/****************************************/ +static void Zmaster_apps_apps_car_runs1Event( void ) +{ + /*stt_lightstatus_brake_off*/ + if( g_stm_crr_state.car_element[StmCarElementNoLightstatusBrake].state == StmLightstatusBrakeSttNoOff ) + { + /*evt_activate*/ + if( g_stm_event == StmEvtNoActivate ) + { + /*ctg_meter*/ + if( g_stm_category == StmCtgNoMeter ) + { + /*ara_split_main*/ + if( g_stm_area == StmAreaNoSplitMain ) + { + Zmaster_apps_apps_car_runs0e3(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*ctg_receiver*/ + else if( g_stm_category == StmCtgNoReceiver ) + { + /*ara_split_sub*/ + if( g_stm_area == StmAreaNoSplitSub ) + { + Zmaster_apps_apps_car_runs0e3(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*evt_undo*/ + else if( g_stm_event == StmEvtNoUndo ) + { + /*stt_prv_layer_apps_meter_receiver*/ + if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoMtrRcv ) + { + Zmaster_apps_apps_car_runs0e3(); + } + /*stt_prv_layer_apps_meter*/ + else if( g_stm_prv_state.layer[StmLayerNoApps].state == StmLayoutNoMtrNml ) + { + Zmaster_apps_apps_car_runs0e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } +} + +/****************************************/ +/* Event call function */ +/* STM : apps_main */ +/****************************************/ +void stm_master_apl_event_call( void ) +{ + stm_mst_apl_start_stm(); + switch( Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAIN] ) + { + case ZMASTER_APPS_APPS_MAINS0: + switch( Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAINS0F] ) + { + case ZMASTER_APPS_APPS_CAR_STOPS0: + Zmaster_apps_apps_car_stops0Event(); + break; + case ZMASTER_APPS_APPS_CAR_STOPS1: + Zmaster_apps_apps_car_stops1Event(); + break; + case ZMASTER_APPS_APPS_CAR_STOPS2: + Zmaster_apps_apps_car_stops2Event(); + break; + case ZMASTER_APPS_APPS_CAR_STOPS3: + Zmaster_apps_apps_car_stops3Event(); + break; + case ZMASTER_APPS_APPS_CAR_STOPS4: + Zmaster_apps_apps_car_stops4Event(); + break; + case ZMASTER_APPS_APPS_CAR_STOPS5: + Zmaster_apps_apps_car_stops5Event(); + break; + default: + /*Not accessible to this else (default).*/ + break; + } + Zmaster_apps_apps_mains0Event(); + break; + case ZMASTER_APPS_APPS_MAINS1: + switch( Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAINS1F] ) + { + case ZMASTER_APPS_APPS_CAR_RUNS0: + Zmaster_apps_apps_car_runs0Event(); + break; + case ZMASTER_APPS_APPS_CAR_RUNS1: + Zmaster_apps_apps_car_runs1Event(); + break; + default: + /*Not accessible to this else (default).*/ + break; + } + Zmaster_apps_apps_mains1Event(); + break; + default: + /*Not accessible to this else (default).*/ + break; + } +} + +/****************************************/ +/* Initial function */ +/* STM : apps_main */ +/****************************************/ +void stm_master_apl_initialize( void ) +{ + Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAIN] = ( uint8_t )ZMASTER_APPS_APPS_MAINS0; + Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAINS0F] = ( uint8_t )ZMASTER_APPS_APPS_CAR_STOPS0; + Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAINS1F] = ( uint8_t )ZMASTER_APPS_APPS_CAR_RUNS0; + Zmaster_apps_apps_mains0StateEntry(); +} + +/****************************************/ +/* Terminate function */ +/* STM : apps_main */ +/****************************************/ +void Zmaster_apps_apps_mainTerminate( void ) +{ + Zmaster_apps_apps_mainState[ZMASTER_APPS_APPS_MAIN] = ( uint8_t )ZMASTER_APPS_APPS_MAINTERMINATE; +} + diff --git a/policy_manager/stm/zipc/StateTransitionor/master/layer/apps/Zmaster_apps_apps_main.h b/policy_manager/stm/zipc/StateTransitionor/master/layer/apps/Zmaster_apps_apps_main.h new file mode 100644 index 0000000..afa2e67 --- /dev/null +++ b/policy_manager/stm/zipc/StateTransitionor/master/layer/apps/Zmaster_apps_apps_main.h @@ -0,0 +1,111 @@ +/************************************************************/ +/* Zmaster_apps_apps_main.h */ +/* apps_main State transition model header file */ +/* ZIPC Designer Version 1.2.0 */ +/************************************************************/ +#ifndef ZHEADER_ZMASTER_APPS_APPS_MAIN_H +#define ZHEADER_ZMASTER_APPS_APPS_MAIN_H + +/*State management variable access define*/ +#define ZMASTER_APPS_APPS_MAIN ( 0U ) +#define ZMASTER_APPS_APPS_MAINS0F ( 1U ) +#define ZMASTER_APPS_APPS_MAINS1F ( 2U ) +#define ZMASTER_APPS_APPS_MAINS0 ( 0U ) +#define ZMASTER_APPS_APPS_CAR_STOPS0 ( 0U ) +#define ZMASTER_APPS_APPS_CAR_STOPS1 ( 1U ) +#define ZMASTER_APPS_APPS_CAR_STOPS2 ( 2U ) +#define ZMASTER_APPS_APPS_CAR_STOPS3 ( 3U ) +#define ZMASTER_APPS_APPS_CAR_STOPS4 ( 4U ) +#define ZMASTER_APPS_APPS_CAR_STOPS5 ( 5U ) +#define ZMASTER_APPS_APPS_MAINS1 ( 1U ) +#define ZMASTER_APPS_APPS_CAR_RUNS0 ( 0U ) +#define ZMASTER_APPS_APPS_CAR_RUNS1 ( 1U ) +#define ZMASTER_APPS_APPS_MAINSTATENOMAX ( 3U ) + +/*End state define*/ +#define ZMASTER_APPS_APPS_MAINEND ( 6U ) +/*Terminate state define*/ +#define ZMASTER_APPS_APPS_MAINTERMINATE ( ZMASTER_APPS_APPS_MAINEND + 1U ) + +/*State no define*/ +#define ZMASTER_APPS_APPS_MAINS0STATENO ( 0U ) +#define ZMASTER_APPS_APPS_CAR_STOPS0STATENO ( 0U ) +#define ZMASTER_APPS_APPS_CAR_STOPS1STATENO ( 1U ) +#define ZMASTER_APPS_APPS_CAR_STOPS2STATENO ( 2U ) +#define ZMASTER_APPS_APPS_CAR_STOPS3STATENO ( 3U ) +#define ZMASTER_APPS_APPS_CAR_STOPS4STATENO ( 4U ) +#define ZMASTER_APPS_APPS_CAR_STOPS5STATENO ( 5U ) +#define ZMASTER_APPS_APPS_MAINS1STATENO ( 1U ) +#define ZMASTER_APPS_APPS_CAR_RUNS0STATENO ( 0U ) +#define ZMASTER_APPS_APPS_CAR_RUNS1STATENO ( 1U ) + +/*State serial no define*/ +#define ZMASTER_APPS_APPS_MAINS0STATESERIALNO ( 0U ) +#define ZMASTER_APPS_APPS_CAR_STOPS0STATESERIALNO ( 1U ) +#define ZMASTER_APPS_APPS_CAR_STOPS1STATESERIALNO ( 2U ) +#define ZMASTER_APPS_APPS_CAR_STOPS2STATESERIALNO ( 3U ) +#define ZMASTER_APPS_APPS_CAR_STOPS3STATESERIALNO ( 4U ) +#define ZMASTER_APPS_APPS_CAR_STOPS4STATESERIALNO ( 5U ) +#define ZMASTER_APPS_APPS_CAR_STOPS5STATESERIALNO ( 6U ) +#define ZMASTER_APPS_APPS_MAINS1STATESERIALNO ( 7U ) +#define ZMASTER_APPS_APPS_CAR_RUNS0STATESERIALNO ( 8U ) +#define ZMASTER_APPS_APPS_CAR_RUNS1STATESERIALNO ( 9U ) + +/*Event no define*/ +#define ZMASTER_APPS_APPS_MAINE0EVENTNO ( 0U ) +#define ZMASTER_APPS_APPS_MAINE1EVENTNO ( 1U ) +#define ZMASTER_APPS_APPS_CAR_STOPE0EVENTNO ( 0U ) +#define ZMASTER_APPS_APPS_CAR_STOPE1EVENTNO ( 1U ) +#define ZMASTER_APPS_APPS_CAR_STOPE2EVENTNO ( 2U ) +#define ZMASTER_APPS_APPS_CAR_STOPE3EVENTNO ( 3U ) +#define ZMASTER_APPS_APPS_CAR_STOPE4EVENTNO ( 4U ) +#define ZMASTER_APPS_APPS_CAR_STOPE5EVENTNO ( 5U ) +#define ZMASTER_APPS_APPS_CAR_STOPE6EVENTNO ( 6U ) +#define ZMASTER_APPS_APPS_CAR_STOPE7EVENTNO ( 7U ) +#define ZMASTER_APPS_APPS_CAR_STOPE8EVENTNO ( 8U ) +#define ZMASTER_APPS_APPS_CAR_STOPE9EVENTNO ( 9U ) +#define ZMASTER_APPS_APPS_CAR_STOPE10EVENTNO ( 10U ) +#define ZMASTER_APPS_APPS_CAR_STOPE11EVENTNO ( 11U ) +#define ZMASTER_APPS_APPS_CAR_STOPE12EVENTNO ( 12U ) +#define ZMASTER_APPS_APPS_CAR_STOPE13EVENTNO ( 13U ) +#define ZMASTER_APPS_APPS_CAR_STOPE14EVENTNO ( 14U ) +#define ZMASTER_APPS_APPS_CAR_STOPE15EVENTNO ( 15U ) +#define ZMASTER_APPS_APPS_CAR_STOPE16EVENTNO ( 16U ) +#define ZMASTER_APPS_APPS_CAR_RUNE0EVENTNO ( 0U ) +#define ZMASTER_APPS_APPS_CAR_RUNE1EVENTNO ( 1U ) +#define ZMASTER_APPS_APPS_CAR_RUNE2EVENTNO ( 2U ) +#define ZMASTER_APPS_APPS_CAR_RUNE3EVENTNO ( 3U ) +#define ZMASTER_APPS_APPS_CAR_RUNE4EVENTNO ( 4U ) + +/*Event serial no define*/ +#define ZMASTER_APPS_APPS_MAINE0EVENTSERIALNO ( 0U ) +#define ZMASTER_APPS_APPS_MAINE1EVENTSERIALNO ( 1U ) +#define ZMASTER_APPS_APPS_CAR_STOPE0EVENTNO ( 0U ) +#define ZMASTER_APPS_APPS_CAR_STOPE1EVENTNO ( 1U ) +#define ZMASTER_APPS_APPS_CAR_STOPE2EVENTNO ( 2U ) +#define ZMASTER_APPS_APPS_CAR_STOPE3EVENTNO ( 3U ) +#define ZMASTER_APPS_APPS_CAR_STOPE4EVENTNO ( 4U ) +#define ZMASTER_APPS_APPS_CAR_STOPE5EVENTNO ( 5U ) +#define ZMASTER_APPS_APPS_CAR_STOPE6EVENTNO ( 6U ) +#define ZMASTER_APPS_APPS_CAR_STOPE7EVENTNO ( 7U ) +#define ZMASTER_APPS_APPS_CAR_STOPE8EVENTNO ( 8U ) +#define ZMASTER_APPS_APPS_CAR_STOPE9EVENTNO ( 9U ) +#define ZMASTER_APPS_APPS_CAR_STOPE10EVENTNO ( 10U ) +#define ZMASTER_APPS_APPS_CAR_STOPE11EVENTNO ( 11U ) +#define ZMASTER_APPS_APPS_CAR_STOPE12EVENTNO ( 12U ) +#define ZMASTER_APPS_APPS_CAR_STOPE13EVENTNO ( 13U ) +#define ZMASTER_APPS_APPS_CAR_STOPE14EVENTNO ( 14U ) +#define ZMASTER_APPS_APPS_CAR_STOPE15EVENTNO ( 15U ) +#define ZMASTER_APPS_APPS_CAR_STOPE16EVENTNO ( 16U ) +#define ZMASTER_APPS_APPS_CAR_RUNE0EVENTNO ( 0U ) +#define ZMASTER_APPS_APPS_CAR_RUNE1EVENTNO ( 1U ) +#define ZMASTER_APPS_APPS_CAR_RUNE2EVENTNO ( 2U ) +#define ZMASTER_APPS_APPS_CAR_RUNE3EVENTNO ( 3U ) +#define ZMASTER_APPS_APPS_CAR_RUNE4EVENTNO ( 4U ) + +/*Extern function*/ +extern void stm_master_apl_event_call( void ); +extern void stm_master_apl_initialize( void ); +extern void Zmaster_apps_apps_mainTerminate( void ); + +#endif diff --git a/policy_manager/stm/zipc/StateTransitionor/master/layer/apps/Zmaster_apps_master_apps_def.h b/policy_manager/stm/zipc/StateTransitionor/master/layer/apps/Zmaster_apps_master_apps_def.h new file mode 100644 index 0000000..5c22ae6 --- /dev/null +++ b/policy_manager/stm/zipc/StateTransitionor/master/layer/apps/Zmaster_apps_master_apps_def.h @@ -0,0 +1,15 @@ +/************************************************************/ +/* Zmaster_apps_master_apps_def.h */ +/* Define header file */ +/* ZIPC Designer Version 1.2.0 */ +/************************************************************/ +#ifndef ZHEADER_ZMASTER_APPS_MASTER_APPS_DEF_H +#define ZHEADER_ZMASTER_APPS_MASTER_APPS_DEF_H + +/************************************************************* + Define definition +*************************************************************/ + +#include "../../../../stm_master_apps.h" + +#endif diff --git a/policy_manager/stm/zipc/StateTransitionor/master/layer/remote/Zmaster_remote_master_remote_def.h b/policy_manager/stm/zipc/StateTransitionor/master/layer/remote/Zmaster_remote_master_remote_def.h new file mode 100644 index 0000000..7cd92cd --- /dev/null +++ b/policy_manager/stm/zipc/StateTransitionor/master/layer/remote/Zmaster_remote_master_remote_def.h @@ -0,0 +1,15 @@ +/************************************************************/ +/* Zmaster_remote_master_remote_def.h */ +/* Define header file */ +/* ZIPC Designer Version 1.2.0 */ +/************************************************************/ +#ifndef ZHEADER_ZMASTER_REMOTE_MASTER_REMOTE_DEF_H +#define ZHEADER_ZMASTER_REMOTE_MASTER_REMOTE_DEF_H + +/************************************************************* + Define definition +*************************************************************/ + +#include "../../../../stm_master_remote.h" + +#endif diff --git a/policy_manager/stm/zipc/StateTransitionor/master/layer/remote/Zmaster_remote_remote.c b/policy_manager/stm/zipc/StateTransitionor/master/layer/remote/Zmaster_remote_remote.c new file mode 100644 index 0000000..53ceafa --- /dev/null +++ b/policy_manager/stm/zipc/StateTransitionor/master/layer/remote/Zmaster_remote_remote.c @@ -0,0 +1,206 @@ +/************************************************************/ +/* Zmaster_remote_remote.c */ +/* remote State transition model source file */ +/* ZIPC Designer Version 1.2.0 */ +/************************************************************/ +#include "../../../ZST_include.h" + +/* State management variable */ +static uint8_t Zmaster_remote_remoteState[ZMASTER_REMOTE_REMOTESTATENOMAX]; + +static void Zmaster_remote_remotes0e0( void ); +static void Zmaster_remote_remotes0e2( void ); +static void Zmaster_remote_remotes1e1( void ); +static void Zmaster_remote_remotes1e3( void ); +static void Zmaster_remote_remotes0Event( void ); +static void Zmaster_remote_remotes1Event( void ); + +/****************************************/ +/* Action function */ +/* STM : remote */ +/* State : none( No 0 ) */ +/* Event : ara_master_split_sub( No 0 ) */ +/****************************************/ +static void Zmaster_remote_remotes0e0( void ) +{ + Zmaster_remote_remoteState[ZMASTER_REMOTE_REMOTE] = ( uint8_t )ZMASTER_REMOTE_REMOTES1; + stm_mst_rmt_start_activity_tbt(); +} + +/****************************************/ +/* Action function */ +/* STM : remote */ +/* State : none( No 0 ) */ +/* Event : stt_prv_layer_remote_none( No 2 ) */ +/****************************************/ +static void Zmaster_remote_remotes0e2( void ) +{ + stm_mst_rmt_start_activity_none(); +} + +/****************************************/ +/* Action function */ +/* STM : remote */ +/* State : tbt( No 1 ) */ +/* Event : ctg_tbt( No 1 ) */ +/****************************************/ +static void Zmaster_remote_remotes1e1( void ) +{ + Zmaster_remote_remoteState[ZMASTER_REMOTE_REMOTE] = ( uint8_t )ZMASTER_REMOTE_REMOTES0; + stm_mst_rmt_start_activity_none(); +} + +/****************************************/ +/* Action function */ +/* STM : remote */ +/* State : tbt( No 1 ) */ +/* Event : stt_prv_layer_remote_tbt( No 3 ) */ +/****************************************/ +static void Zmaster_remote_remotes1e3( void ) +{ + stm_mst_rmt_start_activity_tbt(); +} + +/****************************************/ +/* Event appraisal function */ +/* STM : remote */ +/* State : none( No 0 ) */ +/****************************************/ +static void Zmaster_remote_remotes0Event( void ) +{ + /*evt_activate*/ + if( g_stm_event == StmEvtNoActivate ) + { + /*ctg_tbt*/ + if( g_stm_category == StmCtgNoTbt ) + { + /*ara_master_split_sub*/ + if( g_stm_area == StmAreaNoMasterSplitSub ) + { + Zmaster_remote_remotes0e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*evt_undo*/ + else if( g_stm_event == StmEvtNoUndo ) + { + /*stt_prv_layer_remote_none*/ + if( g_stm_prv_state.layer[StmLayerNoRemote].state == StmLayoutNoNone ) + { + Zmaster_remote_remotes0e2(); + } + /*stt_prv_layer_remote_tbt*/ + else if( g_stm_prv_state.layer[StmLayerNoRemote].state == StmLayoutNoRmtTbt ) + { + Zmaster_remote_remotes0e0(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } +} + +/****************************************/ +/* Event appraisal function */ +/* STM : remote */ +/* State : tbt( No 1 ) */ +/****************************************/ +static void Zmaster_remote_remotes1Event( void ) +{ + /*evt_deactivate*/ + if( g_stm_event == StmEvtNoDeactivate ) + { + /*ctg_tbt*/ + if( g_stm_category == StmCtgNoTbt ) + { + Zmaster_remote_remotes1e1(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + /*evt_undo*/ + else if( g_stm_event == StmEvtNoUndo ) + { + /*stt_prv_layer_remote_none*/ + if( g_stm_prv_state.layer[StmLayerNoRemote].state == StmLayoutNoNone ) + { + Zmaster_remote_remotes1e1(); + } + /*stt_prv_layer_remote_tbt*/ + else if( g_stm_prv_state.layer[StmLayerNoRemote].state == StmLayoutNoRmtTbt ) + { + Zmaster_remote_remotes1e3(); + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } + } + else + { + /*Else and default design have not done.*/ + /*Please confirm the STM and design else and default.*/ + } +} + +/****************************************/ +/* Event call function */ +/* STM : remote */ +/****************************************/ +void stm_mst_rmt_event_call( void ) +{ + stm_mst_rmt_start_stm(); + switch( Zmaster_remote_remoteState[ZMASTER_REMOTE_REMOTE] ) + { + case ZMASTER_REMOTE_REMOTES0: + Zmaster_remote_remotes0Event(); + break; + case ZMASTER_REMOTE_REMOTES1: + Zmaster_remote_remotes1Event(); + break; + default: + /*Not accessible to this else (default).*/ + break; + } +} + +/****************************************/ +/* Initial function */ +/* STM : remote */ +/****************************************/ +void stm_mst_rmt_initialize( void ) +{ + Zmaster_remote_remoteState[ZMASTER_REMOTE_REMOTE] = ( uint8_t )ZMASTER_REMOTE_REMOTES0; + stm_mst_rmt_start_activity_none(); +} + +/****************************************/ +/* Terminate function */ +/* STM : remote */ +/****************************************/ +void Zmaster_remote_remoteTerminate( void ) +{ + Zmaster_remote_remoteState[ZMASTER_REMOTE_REMOTE] = ( uint8_t )ZMASTER_REMOTE_REMOTETERMINATE; +} + diff --git a/policy_manager/stm/zipc/StateTransitionor/master/layer/remote/Zmaster_remote_remote.h b/policy_manager/stm/zipc/StateTransitionor/master/layer/remote/Zmaster_remote_remote.h new file mode 100644 index 0000000..5899b07 --- /dev/null +++ b/policy_manager/stm/zipc/StateTransitionor/master/layer/remote/Zmaster_remote_remote.h @@ -0,0 +1,45 @@ +/************************************************************/ +/* Zmaster_remote_remote.h */ +/* remote State transition model header file */ +/* ZIPC Designer Version 1.2.0 */ +/************************************************************/ +#ifndef ZHEADER_ZMASTER_REMOTE_REMOTE_H +#define ZHEADER_ZMASTER_REMOTE_REMOTE_H + +/*State management variable access define*/ +#define ZMASTER_REMOTE_REMOTE ( 0U ) +#define ZMASTER_REMOTE_REMOTES0 ( 0U ) +#define ZMASTER_REMOTE_REMOTES1 ( 1U ) +#define ZMASTER_REMOTE_REMOTESTATENOMAX ( 1U ) + +/*End state define*/ +#define ZMASTER_REMOTE_REMOTEEND ( 2U ) +/*Terminate state define*/ +#define ZMASTER_REMOTE_REMOTETERMINATE ( ZMASTER_REMOTE_REMOTEEND + 1U ) + +/*State no define*/ +#define ZMASTER_REMOTE_REMOTES0STATENO ( 0U ) +#define ZMASTER_REMOTE_REMOTES1STATENO ( 1U ) + +/*State serial no define*/ +#define ZMASTER_REMOTE_REMOTES0STATESERIALNO ( 0U ) +#define ZMASTER_REMOTE_REMOTES1STATESERIALNO ( 1U ) + +/*Event no define*/ +#define ZMASTER_REMOTE_REMOTEE0EVENTNO ( 0U ) +#define ZMASTER_REMOTE_REMOTEE1EVENTNO ( 1U ) +#define ZMASTER_REMOTE_REMOTEE2EVENTNO ( 2U ) +#define ZMASTER_REMOTE_REMOTEE3EVENTNO ( 3U ) + +/*Event serial no define*/ +#define ZMASTER_REMOTE_REMOTEE0EVENTSERIALNO ( 0U ) +#define ZMASTER_REMOTE_REMOTEE1EVENTSERIALNO ( 1U ) +#define ZMASTER_REMOTE_REMOTEE2EVENTSERIALNO ( 2U ) +#define ZMASTER_REMOTE_REMOTEE3EVENTSERIALNO ( 3U ) + +/*Extern function*/ +extern void stm_mst_rmt_event_call( void ); +extern void stm_mst_rmt_initialize( void ); +extern void Zmaster_remote_remoteTerminate( void ); + +#endif diff --git a/policy_manager/stm/zipc/stm_master_apps.c b/policy_manager/stm/zipc/stm_master_apps.c new file mode 100644 index 0000000..a8cc0e2 --- /dev/null +++ b/policy_manager/stm/zipc/stm_master_apps.c @@ -0,0 +1,63 @@ +#include "./StateTransitionor/ZST_include.h" + +void stm_mst_apl_start_activity_none() { + g_stm_crr_state.layer[StmLayerNoApps].state = StmLayoutNoNone; + g_stm_crr_state.layer[StmLayerNoApps].changed = STM_TRUE; +} + +void stm_mst_apl_start_activity_meter_receiver() { + g_stm_crr_state.layer[StmLayerNoApps].state = StmLayoutNoMtrRcv; + g_stm_crr_state.layer[StmLayerNoApps].changed = STM_TRUE; +} + +void stm_mst_apl_start_activity_meter_splitable() { + g_stm_crr_state.layer[StmLayerNoApps].state = StmLayoutNoMtrSpl; + g_stm_crr_state.layer[StmLayerNoApps].changed = STM_TRUE; +} + +void stm_mst_apl_start_activity_splitable_receiver() { + g_stm_crr_state.layer[StmLayerNoApps].state = StmLayoutNoSplRcv; + g_stm_crr_state.layer[StmLayerNoApps].changed = STM_TRUE; +} + +void stm_mst_apl_start_activity_splitable_split() { + g_stm_crr_state.layer[StmLayerNoApps].state = StmLayoutNoSplSpl; + g_stm_crr_state.layer[StmLayerNoApps].changed = STM_TRUE; +} + +void stm_mst_apl_start_activity_general() { + g_stm_crr_state.layer[StmLayerNoApps].state = StmLayoutNoGenNml; + g_stm_crr_state.layer[StmLayerNoApps].changed = STM_TRUE; +} + +void stm_mst_apl_start_activity_meter() { + g_stm_crr_state.layer[StmLayerNoApps].state = StmLayoutNoMtrNml; + g_stm_crr_state.layer[StmLayerNoApps].changed = STM_TRUE; +} + +void stm_mst_apl_event_lightstatus_brake_on() { + g_stm_crr_state.layer[StmLayerNoApps].state = g_prv_apps_state_car_stop; + g_stm_crr_state.layer[StmLayerNoApps].changed = STM_TRUE; +} + +void stm_mst_apl_event_lightstatus_brake_off() { + g_prv_apps_state_car_stop = g_stm_prv_state.layer[StmLayerNoApps].state; +} + +void stm_master_apl_initialize_valiable() { + g_stm_prv_state.layer[StmLayerNoApps].state = StmLayoutNoNone; + g_stm_prv_state.layer[StmLayerNoApps].changed = STM_FALSE; + + g_stm_crr_state.layer[StmLayerNoApps].state = StmLayoutNoNone; + g_stm_crr_state.layer[StmLayerNoApps].changed = STM_FALSE; +} + +void stm_mst_apl_start_stm() { + if (g_stm_event == StmEvtNoUndo) { + // nop + } + else { + g_stm_prv_state.layer[StmLayerNoApps].state = g_stm_crr_state.layer[StmLayerNoApps].state; + } + g_stm_crr_state.layer[StmLayerNoApps].changed = STM_FALSE; +} diff --git a/policy_manager/stm/zipc/stm_master_apps.h b/policy_manager/stm/zipc/stm_master_apps.h new file mode 100644 index 0000000..d10e56b --- /dev/null +++ b/policy_manager/stm/zipc/stm_master_apps.h @@ -0,0 +1,11 @@ +extern void stm_mst_apl_start_activity_none(); +extern void stm_mst_apl_start_activity_meter_receiver(); +extern void stm_mst_apl_start_activity_meter_splitable(); +extern void stm_mst_apl_start_activity_splitable_receiver(); +extern void stm_mst_apl_start_activity_splitable_split(); +extern void stm_mst_apl_start_activity_general(); +extern void stm_mst_apl_start_activity_meter(); +extern void stm_mst_apl_event_lightstatus_brake_on(); +extern void stm_mst_apl_event_lightstatus_brake_off(); +extern void stm_master_apl_initialize_valiable(); +extern void stm_mst_apl_start_stm(); diff --git a/policy_manager/stm/zipc/stm_master_remote.c b/policy_manager/stm/zipc/stm_master_remote.c new file mode 100644 index 0000000..d63cba1 --- /dev/null +++ b/policy_manager/stm/zipc/stm_master_remote.c @@ -0,0 +1,29 @@ +#include "./StateTransitionor/ZST_include.h" + +void stm_mst_rmt_start_activity_none() { + g_stm_crr_state.layer[StmLayerNoRemote].state = StmLayoutNoNone; + g_stm_crr_state.layer[StmLayerNoRemote].changed = STM_TRUE; +} + +void stm_mst_rmt_start_activity_tbt() { + g_stm_crr_state.layer[StmLayerNoRemote].state = StmLayoutNoRmtTbt; + g_stm_crr_state.layer[StmLayerNoRemote].changed = STM_TRUE; +} + +void stm_mst_rmt_initialize_valiable() { + g_stm_prv_state.layer[StmLayerNoRemote].state = StmLayoutNoNone; + g_stm_prv_state.layer[StmLayerNoRemote].changed = STM_FALSE; + + g_stm_crr_state.layer[StmLayerNoRemote].state = StmLayoutNoNone; + g_stm_crr_state.layer[StmLayerNoRemote].changed = STM_FALSE; +} + +void stm_mst_rmt_start_stm() { + if (g_stm_event == StmEvtNoUndo) { + // nop + } + else { + g_stm_prv_state.layer[StmLayerNoRemote].state = g_stm_crr_state.layer[StmLayerNoRemote].state; + } + g_stm_crr_state.layer[StmLayerNoRemote].changed = STM_FALSE; +} diff --git a/policy_manager/stm/zipc/stm_master_remote.h b/policy_manager/stm/zipc/stm_master_remote.h new file mode 100644 index 0000000..45d77c7 --- /dev/null +++ b/policy_manager/stm/zipc/stm_master_remote.h @@ -0,0 +1,4 @@ +extern void stm_mst_rmt_start_activity_none(); +extern void stm_mst_rmt_start_activity_tbt(); +extern void stm_mst_rmt_initialize_valiable(); +extern void stm_mst_rmt_start_stm(); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3c8da4c..9fa4b73 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,10 +14,9 @@ # limitations under the License. # -wlproto(IVI_CON ivi-wm) - include(FindPkgConfig) pkg_check_modules(AFB REQUIRED afb-daemon) +pkg_check_modules(ILM REQUIRED ilmControl ilmCommon) pkg_check_modules(SD REQUIRED libsystemd>=222) # We do not want a prefix for our module @@ -27,23 +26,24 @@ set(TARGETS_WM windowmanager-service) add_library(${TARGETS_WM} MODULE main.cpp - wayland_ivi_wm.cpp util.cpp - layout.cpp - ${IVI_CON_PROTO} json_helper.cpp + applist.cpp + request.cpp + pm_wrapper.cpp window_manager.cpp - layers.cpp wm_client.cpp wm_error.cpp - applist.cpp - request.cpp - pm_wrapper.cpp) + wm_layer.cpp + wm_layer_control.cpp + wm_connection.cpp + low_can_client.cpp) target_include_directories(${TARGETS_WM} PRIVATE ${AFB_INCLUDE_DIRS} ${SD_INCLUDE_DIRS} + ${ILM_INCLUDE_DIRS} ../include ../src ../${PLUGIN_PM}) @@ -52,6 +52,7 @@ target_link_libraries(${TARGETS_WM} PRIVATE ${AFB_LIBRARIES} ${WLC_LIBRARIES} + ${ILM_LIBRARIES} ${SD_LIBRARIES} ${PLUGIN_PM}) @@ -112,9 +113,10 @@ add_custom_command(TARGET ${TARGETS_WM} POST_BUILD COMMAND mkdir -p ${PROJECT_BINARY_DIR}/package/root/lib COMMAND cp -rf ${PROJECT_BINARY_DIR}/src/${TARGETS_WM}.so ${PROJECT_BINARY_DIR}/package/root/lib COMMAND mkdir -p ${PROJECT_BINARY_DIR}/package/root/etc - COMMAND cp -f ${PROJECT_SOURCE_DIR}/layers.json ${PROJECT_BINARY_DIR}/package/root/etc - COMMAND cp -f ${PROJECT_SOURCE_DIR}/src/db/old_roles.db ${PROJECT_BINARY_DIR}/package/root/etc - COMMAND cp -f ${PROJECT_SOURCE_DIR}/src/db/areas.db ${PROJECT_BINARY_DIR}/package/root/etc + COMMAND cp -f ${PROJECT_SOURCE_DIR}/layers_setting.json ${PROJECT_BINARY_DIR}/package/root/etc + COMMAND cp -f ${PROJECT_SOURCE_DIR}/src/config/old_roles.json ${PROJECT_BINARY_DIR}/package/root/etc + COMMAND cp -f ${PROJECT_SOURCE_DIR}/src/config/areas.json ${PROJECT_BINARY_DIR}/package/root/etc + COMMAND cp -f ${PROJECT_SOURCE_DIR}/src/config/connection.json ${PROJECT_BINARY_DIR}/package/root/etc ) add_custom_target(package DEPENDS ${PROJECT_BINARY_DIR}/package/root diff --git a/src/applist.cpp b/src/applist.cpp index a5ae9f0..44865f6 100644 --- a/src/applist.cpp +++ b/src/applist.cpp @@ -16,7 +16,7 @@ #include <iostream> #include <algorithm> #include "applist.hpp" -#include "../include/hmi-debug.h" +#include "util.hpp" using std::shared_ptr; using std::string; @@ -65,7 +65,7 @@ AppList::~AppList() {} * @attention This function should be called once for the app * Caller should take care not to be called more than once. */ -void AppList::addClient(const std::string &appid, unsigned layer, unsigned surface, const std::string &role) +void AppList::addClient(const string &appid, unsigned layer, unsigned surface, const string &role) { std::lock_guard<std::mutex> lock(this->mtx); shared_ptr<WMClient> client = std::make_shared<WMClient>(appid, layer, surface, role); @@ -73,6 +73,14 @@ void AppList::addClient(const std::string &appid, unsigned layer, unsigned surfa this->clientDump(); } +void AppList::addClient(const string &appid, unsigned layer, const string &role) +{ + std::lock_guard<std::mutex> lock(this->mtx); + shared_ptr<WMClient> client = std::make_shared<WMClient>(appid, layer, role); + this->app2client[appid] = client; + this->clientDump(); +} + /** * Remove WMClient from the list * @@ -82,7 +90,7 @@ void AppList::removeClient(const string &appid) { std::lock_guard<std::mutex> lock(this->mtx); this->app2client.erase(appid); - HMI_INFO("wm", "Remove client %s", appid.c_str()); + HMI_INFO("Remove client %s", appid.c_str()); } /** @@ -111,7 +119,7 @@ void AppList::removeSurface(unsigned surface){ { ret = x.second->removeSurfaceIfExist(surface); if(ret){ - HMI_DEBUG("wm", "remove surface %d from Client %s finish", + HMI_DEBUG("remove surface %d from Client %s finish", surface, x.second->appID().c_str()); break; } @@ -132,7 +140,14 @@ void AppList::removeSurface(unsigned surface){ */ shared_ptr<WMClient> AppList::lookUpClient(const string &appid) { - return this->app2client.at(appid); + if(this->app2client.count(appid) != 0) + { + return this->app2client.at(appid); + } + else + { + return nullptr; + } } /** @@ -159,7 +174,7 @@ int AppList::countClient() const * @return AppID * @attention If AppID is not found, param found will be false. */ -string AppList::getAppID(unsigned surface, const string& role, bool* found) const +/* string AppList::getAppID(unsigned surface, const string& role, bool* found) const { *found = false; for (const auto &x : this->app2client) @@ -170,6 +185,77 @@ string AppList::getAppID(unsigned surface, const string& role, bool* found) cons } } return string(""); +} */ + +string AppList::getAppID(unsigned surface, bool* found) const +{ + *found = false; + for (const auto &x : this->app2client) + { + if(x.second->surfaceID() == surface){ + *found = true; + return x.second->appID(); + } + } + return string(""); +} + +WMError AppList::popFloatingSurface(unsigned pid, unsigned *surface) +{ + WMError ret = WMError::NO_ENTRY; + + auto fwd_itr = std::remove_if(this->floating_surfaces.begin(), this->floating_surfaces.end(), + [pid, surface, &ret](FloatingSurface x) { + if(pid == x.pid){ + *surface = x.surface_id; + ret = WMError::SUCCESS; + return true; + } + else{ + return false; + } + }); + if (fwd_itr != this->floating_surfaces.cend()) + { + HMI_INFO("pop floating surface: %d", *surface); + } + this->floating_surfaces.erase(fwd_itr, this->floating_surfaces.end()); + return ret; +} + +// =================== Floating(Temporary) surface/client API =================== + +// TODO: After testing setRole, remove these API + +WMError AppList::popFloatingSurface(const string &appid, unsigned *surface) +{ + HMI_ERROR("This function is not implemented"); + return WMError::SUCCESS; +} + +void AppList::addFloatingClient(const string &appid, unsigned layer, const string &role) +{ +} + +void AppList::addFloatingSurface(const string &appid, unsigned surface, unsigned pid) +{ + struct FloatingSurface fsurface{appid, surface, pid}; + this->floating_surfaces.push_back(fsurface); + this->dumpFloatingSurfaces(); +} + +void AppList::removeFloatingSurface(unsigned surface) +{ + this->dumpFloatingSurfaces(); + auto fwd_itr = std::remove_if( + this->floating_surfaces.begin(), this->floating_surfaces.end(), + [surface](FloatingSurface x) { + return x.surface_id == surface; + }); + if(fwd_itr != this->floating_surfaces.cend()){ + HMI_INFO("remove floating surface: %d", surface); + } + this->floating_surfaces.erase(fwd_itr, this->floating_surfaces.end()); } // =================== Request Date container API =================== @@ -351,7 +437,7 @@ WMError AppList::setAction(unsigned req_num, const struct WMAction &action) * otherwise (visible is false) app should be invisible. Then enddraw_finished param is set to true. * This function doesn't support actions for focus yet. */ -WMError AppList::setAction(unsigned req_num, const string &appid, const string &role, const string &area, TaskVisible visible) +WMError AppList::setAction(unsigned req_num, shared_ptr<WMClient> client, const string &role, const string &area, TaskVisible visible) { std::lock_guard<std::mutex> lock(this->mtx); WMError result = WMError::FAIL; @@ -363,7 +449,7 @@ WMError AppList::setAction(unsigned req_num, const string &appid, const string & } // If visible task is not invisible, redraw is required -> true bool edraw_f = (visible != TaskVisible::INVISIBLE) ? false : true; - WMAction action{appid, role, area, visible, edraw_f}; + WMAction action{req_num, client, role, area, visible, edraw_f, TaskCarState::NO_TASK}; x.sync_draw_req.push_back(action); result = WMError::SUCCESS; @@ -399,11 +485,23 @@ bool AppList::setEndDrawFinished(unsigned req_num, const string &appid, const st { for (auto &y : x.sync_draw_req) { - if (y.appid == appid && y.role == role) + if (nullptr != y.client) + { + if (y.client->appID() == appid && y.role == role) + { + HMI_SEQ_INFO(req_num, "Role %s finish redraw", y.role.c_str()); + y.end_draw_finished = true; + result = true; + } + } + else { - HMI_SEQ_INFO(req_num, "Role %s finish redraw", y.role.c_str()); - y.end_draw_finished = true; - result = true; + if (y.role == role) + { + HMI_SEQ_INFO(req_num, "Role %s finish redraw", y.role.c_str()); + y.end_draw_finished = true; + result = true; + } } } } @@ -514,7 +612,7 @@ void AppList::reqDump() { DUMP( "Action : (APPID :%s, ROLE :%s, AREA :%s, VISIBLE : %s, END_DRAW_FINISHED: %d)", - y.appid.c_str(), + (y.client) ? y.client->appID().c_str() : "-", y.role.c_str(), y.area.c_str(), (y.visible == TaskVisible::INVISIBLE) ? "invisible" : "visible", @@ -523,4 +621,15 @@ void AppList::reqDump() } DUMP("======= req dump end ====="); } + +void AppList::dumpFloatingSurfaces() +{ + DUMP("======= floating surface dump ====="); + for (const auto &x : this->floating_surfaces) + { + DUMP("surface : %d, pid : %d", x.surface_id, x.pid); + } + DUMP("======= floating surface dump end =====\n"); +} + } // namespace wm diff --git a/src/applist.hpp b/src/applist.hpp index a794b53..36e0524 100644 --- a/src/applist.hpp +++ b/src/applist.hpp @@ -31,6 +31,13 @@ namespace wm /* using std::experimental::nullopt; using std::experimental::optional; */ +struct FloatingSurface +{ + std::string appid; + unsigned surface_id; + unsigned pid; +}; + class AppList { public: @@ -43,20 +50,29 @@ class AppList If the WMClient should be more flexible, I think this param should be WMClient class */ void addClient(const std::string &appid, unsigned layer, - unsigned surface,const std::string &role); + unsigned surface, const std::string &role); + void addClient(const std::string &appid, unsigned layer, const std::string &role); void removeClient(const std::string &appid); bool contains(const std::string &appid) const; int countClient() const; std::shared_ptr<WMClient> lookUpClient(const std::string &appid); void removeSurface(unsigned surface); - std::string getAppID(unsigned surface, const std::string &role, bool *found) const; + std::string getAppID(unsigned surface, bool* found) const; // TODO: remove + + + // Floating surface + void addFloatingClient(const std::string &appid, unsigned layer, const std::string &role); + void addFloatingSurface(const std::string &appid, unsigned surface, unsigned pid); + WMError popFloatingSurface(unsigned pid, unsigned *surface); + WMError popFloatingSurface(const std::string &appid, unsigned *surface); + void removeFloatingSurface(unsigned surface); // Request Interface unsigned currentRequestNumber() const; unsigned getRequestNumber(const std::string &appid) const; unsigned addRequest(WMRequest req); WMError setAction(unsigned req_num, const struct WMAction &action); - WMError setAction(unsigned req_num, const std::string &appid, + WMError setAction(unsigned req_num, std::shared_ptr<WMClient> client, const std::string &role, const std::string &area, TaskVisible visible); bool setEndDrawFinished(unsigned req_num, const std::string &appid, const std::string &role); bool endDrawFullfilled(unsigned req_num); @@ -69,12 +85,14 @@ class AppList void clientDump(); void reqDump(); + void dumpFloatingSurfaces(); private: std::vector<WMRequest> req_list; std::unordered_map<std::string, std::shared_ptr<WMClient>> app2client; unsigned current_req; std::mutex mtx; + std::vector<struct FloatingSurface> floating_surfaces; }; } // namespace wm diff --git a/src/config/areas.json b/src/config/areas.json new file mode 100644 index 0000000..d4f3531 --- /dev/null +++ b/src/config/areas.json @@ -0,0 +1,204 @@ +{ + "ecus": [ + { + "name": "master", + "screens": [ + { + "id": 0, + "areas": [ + { + "name": "fullscreen", + "rect": { + "x": 0, + "y": 0, + "w": 1920, + "h": 720 + } + }, + { + "name": "normal.full", + "rect": { + "x": 0, + "y": 0, + "w": 1920, + "h": 720 + } + }, + { + "name": "split.main", + "rect": { + "x": 0, + "y": 0, + "w": 1280, + "h": 720 + } + }, + { + "name": "split.sub", + "rect": { + "x": 1280, + "y": 0, + "w": 640, + "h": 720 + } + }, + { + "name": "software_keyboard", + "rect": { + "x": 0, + "y": 962, + "w": 1080, + "h": 744 + } + }, + { + "name": "restriction.normal", + "rect": { + "x": 0, + "y": 0, + "w": 1920, + "h": 1080 + } + }, + { + "name": "restriction.split.main", + "rect": { + "x": 0, + "y": 0, + "w": 1920, + "h": 540 + } + }, + { + "name": "restriction.split.sub", + "rect": { + "x": 0, + "y": 540, + "w": 1920, + "h": 540 + } + }, + { + "name": "on_screen", + "rect": { + "x": 1280, + "y": 0, + "w": 640, + "h": 720 + } + }, + { + "name": "master.split.sub", + "rect": { + "x": 1280, + "y": 0, + "w": 640, + "h": 720 + } + } + ] + } + ] + }, + { + "name": "slave", + "screens": [ + { + "id": 0, + "areas": [ + { + "name": "fullscreen", + "rect": { + "x": 0, + "y": 0, + "w": 1080, + "h": 1920 + } + }, + { + "name": "normal.full", + "rect": { + "x": 0, + "y": 218, + "w": 1080, + "h": 1488 + } + }, + { + "name": "split.main", + "rect": { + "x": 0, + "y": 218, + "w": 1080, + "h": 744 + } + }, + { + "name": "split.sub", + "rect": { + "x": 0, + "y": 962, + "w": 1080, + "h": 744 + } + }, + { + "name": "software_keyboard", + "rect": { + "x": 0, + "y": 962, + "w": 1080, + "h": 744 + } + }, + { + "name": "restriction.normal", + "rect": { + "x": 0, + "y": 218, + "w": 1080, + "h": 1488 + } + }, + { + "name": "restriction.split.main", + "rect": { + "x": 0, + "y": 218, + "w": 1080, + "h": 744 + } + }, + { + "name": "restriction.split.sub", + "rect": { + "x": 0, + "y": 962, + "w": 1080, + "h": 744 + } + }, + { + "name": "on_screen", + "rect": { + "x": 0, + "y": 218, + "w": 1080, + "h": 1488 + } + }, + { + "name": "master.split.sub", + "rect": { + "x": 0, + "y": 180, + "w": 640, + "h": 720 + } + } + ] + } + ] + } + ] +} diff --git a/src/config/connection.json b/src/config/connection.json new file mode 100644 index 0000000..3ee06c3 --- /dev/null +++ b/src/config/connection.json @@ -0,0 +1,5 @@ +{ + "mode": "master", + "master_ip": "10.4.1.78", + "master_port": 54400 +} diff --git a/src/db/old_roles.db b/src/config/old_roles.json index 02a4c2d..02a4c2d 100644 --- a/src/db/old_roles.db +++ b/src/config/old_roles.json diff --git a/src/controller_hooks.hpp b/src/controller_hooks.hpp index dd0a3aa..ae88187 100644 --- a/src/controller_hooks.hpp +++ b/src/controller_hooks.hpp @@ -34,6 +34,7 @@ struct controller_hooks void surface_removed(uint32_t surface_id); void surface_visibility(uint32_t surface_id, uint32_t v); void surface_destination_rectangle(uint32_t surface_id, uint32_t x, uint32_t y, uint32_t w, uint32_t h); + void surface_properties(uint32_t surface_id, uint32_t pid); }; } // namespace wm diff --git a/src/db/areas.db b/src/db/areas.db deleted file mode 100644 index 03ddfe4..0000000 --- a/src/db/areas.db +++ /dev/null @@ -1,85 +0,0 @@ -{ - "areas": [ - { - "name": "fullscreen", - "rect": { - "x": 0, - "y": 0, - "w": 1080, - "h": 1920 - } - }, - { - "name": "normal.full", - "rect": { - "x": 0, - "y": 218, - "w": 1080, - "h": 1488 - } - }, - { - "name": "split.main", - "rect": { - "x": 0, - "y": 218, - "w": 1080, - "h": 744 - } - }, - { - "name": "split.sub", - "rect": { - "x": 0, - "y": 962, - "w": 1080, - "h": 744 - } - }, - { - "name": "software_keyboard", - "rect": { - "x": 0, - "y": 962, - "w": 1080, - "h": 744 - } - }, - { - "name": "restriction.normal", - "rect": { - "x": 0, - "y": 218, - "w": 1080, - "h": 1488 - } - }, - { - "name": "restriction.split.main", - "rect": { - "x": 0, - "y": 218, - "w": 1080, - "h": 744 - } - }, - { - "name": "restriction.split.sub", - "rect": { - "x": 0, - "y": 962, - "w": 1080, - "h": 744 - } - }, - { - "name": "on_screen", - "rect": { - "x": 0, - "y": 218, - "w": 1080, - "h": 1488 - } - } - ] -} diff --git a/src/json_helper.cpp b/src/json_helper.cpp index b97f21d..d9cf5eb 100644 --- a/src/json_helper.cpp +++ b/src/json_helper.cpp @@ -15,69 +15,7 @@ */ #include "json_helper.hpp" -#include "hmi-debug.h" - -#include <json.h> - -json_object *to_json(compositor::surface_properties const &s) -{ - // auto j = json::object({ - auto j = json_object_new_object(); - - // {"id", s.id}, - json_object_object_add(j, "id", json_object_new_int(s.id)); - - // {"size", {{"width", s.size.w}, {"height", s.size.h}}}, - auto jsize = json_object_new_object(); - json_object_object_add(jsize, "width", json_object_new_int(s.size.w)); - json_object_object_add(jsize, "height", json_object_new_int(s.size.h)); - json_object_object_add(j, "size", jsize); - - // {"dst", - // {{"width", s.dst_rect.w}, - // {"height", s.dst_rect.h}, - // {"x", s.dst_rect.x}, - // {"y", s.dst_rect.y}}}, - auto jdst = json_object_new_object(); - json_object_object_add(jdst, "width", json_object_new_int(s.dst_rect.w)); - json_object_object_add(jdst, "height", json_object_new_int(s.dst_rect.h)); - json_object_object_add(jdst, "x", json_object_new_int(s.dst_rect.x)); - json_object_object_add(jdst, "y", json_object_new_int(s.dst_rect.y)); - json_object_object_add(j, "dst", jdst); - - // {"src", - // {{"width", s.src_rect.w}, - // {"height", s.src_rect.h}, - // {"x", s.src_rect.x}, - // {"y", s.src_rect.y}}}, - auto jsrc = json_object_new_object(); - json_object_object_add(jsrc, "width", json_object_new_int(s.src_rect.w)); - json_object_object_add(jsrc, "height", json_object_new_int(s.src_rect.h)); - json_object_object_add(jsrc, "x", json_object_new_int(s.src_rect.x)); - json_object_object_add(jsrc, "y", json_object_new_int(s.src_rect.y)); - json_object_object_add(j, "src", jsrc); - - // {"visibility", s.visibility}, - json_object_object_add( - j, "visibility", - json_object_new_boolean(static_cast<json_bool>(s.visibility == 1))); - - // {"opacity", s.opacity}, - json_object_object_add(j, "opacity", json_object_new_double(s.opacity)); - - // {"orientation", s.orientation}, - json_object_object_add(j, "orientation", json_object_new_int(s.orientation)); - - // }); - return j; -} - -json_object *to_json(compositor::screen const *s) -{ - auto o = json_object_new_object(); - json_object_object_add(o, "id", json_object_new_int(s->id)); - return o; -} +#include "util.hpp" template <typename T> json_object *to_json_(T const &s) @@ -95,11 +33,6 @@ json_object *to_json_(T const &s) return a; } -json_object *to_json(compositor::controller::props_map const &s) -{ - return to_json_(s); -} - json_object *to_json(std::vector<uint32_t> const &v) { auto a = json_object_new_array(); @@ -117,7 +50,7 @@ const char* getStringFromJson(json_object* obj, const char* key) json_object* tmp; if (!json_object_object_get_ex(obj, key, &tmp)) { - HMI_DEBUG("wm:jh", "Not found key \"%s\"", key); + HMI_DEBUG("Not found key \"%s\"", key); return nullptr; } @@ -129,19 +62,31 @@ int getIntFromJson(json_object *obj, const char *key) json_object *tmp; if (!json_object_object_get_ex(obj, key, &tmp)) { - HMI_DEBUG("wm:jh", "Not found key \"%s\"", key); + HMI_DEBUG("Not found key \"%s\"", key); return 0; } return json_object_get_int(tmp); } +double getDoubleFromJson(json_object *obj, const char *key) +{ + json_object *tmp; + if (!json_object_object_get_ex(obj, key, &tmp)) + { + HMI_DEBUG("Not found key \"%s\"", key); + return 0; + } + + return json_object_get_double(tmp); +} + json_bool getBoolFromJson(json_object *obj, const char *key) { json_object *tmp; if (!json_object_object_get_ex(obj, key, &tmp)) { - HMI_DEBUG("wm:jh", "Not found key \"%s\"", key); + HMI_DEBUG("Not found key \"%s\"", key); return FALSE; } @@ -153,13 +98,13 @@ int inputJsonFilie(const char* file, json_object** obj) const int input_size = 128; int ret = -1; - HMI_DEBUG("wm:jh", "Input file: %s", file); + HMI_DEBUG("Input file: %s", file); // Open json file FILE *fp = fopen(file, "rb"); if (nullptr == fp) { - HMI_ERROR("wm:jh", "Could not open file"); + HMI_ERROR("Could not open file"); return ret; } @@ -174,7 +119,7 @@ int inputJsonFilie(const char* file, json_object** obj) *obj = json_tokener_parse_ex(tokener, buffer, len); if (nullptr != *obj) { - HMI_DEBUG("wm:jh", "File input is success"); + HMI_DEBUG("File input is success"); ret = 0; break; } @@ -183,9 +128,9 @@ int inputJsonFilie(const char* file, json_object** obj) if ((json_tokener_continue != json_error) || (input_size > len)) { - HMI_ERROR("wm:jh", "Failed to parse file (byte:%d err:%s)", + HMI_ERROR("Failed to parse file (byte:%d err:%s)", (input_size * block_cnt), json_tokener_error_desc(json_error)); - HMI_ERROR("wm:jh", "\n%s", buffer); + HMI_ERROR("\n%s", buffer); *obj = nullptr; break; } diff --git a/src/json_helper.hpp b/src/json_helper.hpp index 5333130..d4ae85a 100644 --- a/src/json_helper.hpp +++ b/src/json_helper.hpp @@ -14,24 +14,21 @@ * limitations under the License. */ -#ifndef TMCAGLWM_JSON_HELPER_HPP -#define TMCAGLWM_JSON_HELPER_HPP +#ifndef JSON_HELPER_HPP +#define JSON_HELPER_HPP #include <json-c/json.h> -#include "../include/json.hpp" -#include "wayland_ivi_wm.hpp" +#include <vector> 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); +double getDoubleFromJson(json_object *obj, const char *key); json_bool getBoolFromJson(json_object *obj, const char *key); int inputJsonFilie(const char* file, json_object** obj); } // namespace jh -#endif // TMCAGLWM_JSON_HELPER_HPP +#endif // JSON_HELPER_HPP diff --git a/src/layers.cpp b/src/layers.cpp index bbe7c09..05d404d 100644 --- a/src/layers.cpp +++ b/src/layers.cpp @@ -18,7 +18,7 @@ #include "layers.hpp" #include "json_helper.hpp" -#include "hmi-debug.h" +#include "util.hpp" namespace wm { @@ -58,7 +58,7 @@ layer::layer(nlohmann::json const &j) return l; }); } - HMI_DEBUG("wm", "layer_id:%d is_normal_layout_only:%d\n", + HMI_DEBUG("layer_id:%d is_normal_layout_only:%d\n", this->layer_id, this->is_normal_layout_only); } @@ -136,11 +136,11 @@ optional<int> layer_map::get_layer_id(std::string const &role) auto re = std::regex(r.first); if (std::regex_match(role, re)) { - HMI_DEBUG("wm", "role %s matches layer %d", role.c_str(), r.second); + HMI_DEBUG("role %s matches layer %d", role.c_str(), r.second); return optional<int>(r.second); } } - HMI_DEBUG("wm", "role %s does NOT match any layer", role.c_str()); + HMI_DEBUG("role %s does NOT match any layer", role.c_str()); return nullopt; } 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 3430ef3..0000000 --- a/src/layout.hpp +++ /dev/null @@ -1,41 +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 - -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/low_can_client.cpp b/src/low_can_client.cpp new file mode 100644 index 0000000..090aa14 --- /dev/null +++ b/src/low_can_client.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2018 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "low_can_client.hpp" +#include "json_helper.hpp" +#include "util.hpp" + +extern "C" +{ +#include <afb/afb-binding.h> +} + +namespace wm +{ + +LowCanClient::LowCanClient() + : vehicle_speed(0), + trans_gear_pos(0), + headlamp_status(FALSE), + parking_brake_status(TRUE), + accel_pedal_pos(0), + accel_pedal_stt(FALSE), + lightstatus_brake_status(TRUE), + is_changed_accel_pedal_stt(false) +{ +} + +void LowCanClient::initialize() +{ + int ret; + + // Require API "low-can" + ret = afb_daemon_require_api_v2("low-can", 1); + if (0 > ret) + { + HMI_INFO("Requirement API \"low-can\" failed"); + return; + } + + // Subscribe low-level-can + // low-can subscribe { "event": "vehicle.speed" } + // low-can subscribe { "event": "transmission_gear_position" } + // low-can subscribe { "event": "headlamp_status" } + // low-can subscribe { "event": "parking_brake_status" } + // low-can subscribe { "event": "accelerator.pedal.position" } + // low-can subscribe { "event": "lightstatus.brake" } + for (int i = SignalNoMin; i <= SignalNoMax; i++) + { + // Set Event + json_object *json_obj = json_object_new_object(); + json_object_object_add(json_obj, "event", + json_object_new_string(this->kSignalName[i])); + + // Set filter + if (0 != strcmp("", this->kFilterValue[i])) + { + json_object_object_add(json_obj, "filter", + json_tokener_parse(this->kFilterValue[i])); + } + HMI_DEBUG("subscribe message:%s", json_object_get_string(json_obj)); + + // Subscribe + afb_service_call("low-can", "subscribe", json_obj, + [](void *closure, int status, json_object *result) { + HMI_DEBUG("subscribe result:%s", json_object_get_string(result)); + }, + nullptr); + } + + return; +} + +const char *LowCanClient::analyzeCanSignal(struct json_object *object) +{ + HMI_DEBUG("object:%s", json_object_get_string(object)); + + const char *name = jh::getStringFromJson(object, "name"); + HMI_DEBUG("CAN signal name:%s", name); + + if (strstr(name, this->kSignalName[SignalNoVehicliSpeed])) + { + // Update vehicle speed + this->vehicle_speed = jh::getIntFromJson(object, "value"); + HMI_DEBUG("Update vehicle speed:%d", this->vehicle_speed); + } + else if (strstr(name, this->kSignalName[SignalNoTransGearPos])) + { + // Update transmission gear position + this->trans_gear_pos = jh::getIntFromJson(object, "value"); + HMI_DEBUG("Update transmission gear position:%d", this->trans_gear_pos); + } + else if (strstr(name, this->kSignalName[SignalNoHeadlame])) + { + // Update headlamp status + this->headlamp_status = jh::getBoolFromJson(object, "value"); + HMI_DEBUG("Update headlamp status:%d", this->headlamp_status); + } + else if (strstr(name, this->kSignalName[SignalNoParkingBrake])) + { + // Update parking gear status + this->parking_brake_status = jh::getBoolFromJson(object, "value"); + HMI_DEBUG("Update parking brake status:%d", this->parking_brake_status); + } + else if (strstr(name, this->kSignalName[SignalNoAccelPedalPos])) + { + // Clear flag for whether accel pedal state is changed + this->is_changed_accel_pedal_stt = false; + + // Update accelerator pedal status + this->accel_pedal_pos = jh::getDoubleFromJson(object, "value"); + HMI_DEBUG("Update accelerator pedal position:%lf", this->accel_pedal_pos); + + bool accel_pedal_stt; + if (0 != this->accel_pedal_pos) + { + accel_pedal_stt = true; + } + else + { + accel_pedal_stt = false; + } + + if (accel_pedal_stt != this->accel_pedal_stt) + { + this->is_changed_accel_pedal_stt = true; + this->accel_pedal_stt = accel_pedal_stt; + } + } + else if (strstr(name, this->kSignalName[SignalNoLightstatusBrake])) + { + // Update lightstatus brake status + this->lightstatus_brake_status = jh::getBoolFromJson(object, "value"); + HMI_DEBUG("Update lightstatus brake status:%d", this->lightstatus_brake_status); + } + + return name; +} + +bool LowCanClient::isChangedAccelPedalState() +{ + return this->is_changed_accel_pedal_stt; +} + +int LowCanClient::getCurrentTransGearState() +{ + return this->trans_gear_pos; +} + +bool LowCanClient::getCurrentHeadlampState() +{ + return (bool)this->headlamp_status; +} + +bool LowCanClient::getCurrentParkingBrakeState() +{ + return (bool)this->parking_brake_status; +} + +double LowCanClient::getCurrentAccelPedalPosition() +{ + return this->accel_pedal_pos; +} + +bool LowCanClient::getCurrentAccelPedalState() +{ + return this->accel_pedal_stt; +} + +bool LowCanClient::getCurrentLightstatusBrakeState() +{ + return (bool)this->lightstatus_brake_status; +} + +} // namespace wm diff --git a/src/low_can_client.hpp b/src/low_can_client.hpp new file mode 100644 index 0000000..9b7f509 --- /dev/null +++ b/src/low_can_client.hpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2017 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TMCAGLWM_LOW_CAN_CLIENT_HPP +#define TMCAGLWM_LOW_CAN_CLIENT_HPP + +#include <string> +#include <vector> +#include <json-c/json.h> + +namespace wm +{ + +class LowCanClient +{ + + public: + explicit LowCanClient(); + ~LowCanClient() = default; + + enum SignalNo + { + SignalNoVehicliSpeed = 0, + SignalNoTransGearPos, + SignalNoHeadlame, + SignalNoParkingBrake, + SignalNoAccelPedalPos, + SignalNoLightstatusBrake, + + SignalNum, + + SignalNoMin = SignalNoVehicliSpeed, + SignalNoMax = SignalNum - 1, + }; + + const std::vector<const char *> kSignalName{ + "vehicle.speed", + "transmission_gear_position", + "headlamp_status", + "parking_brake_status", + "accelerator.pedal.position", + "lightstatus.brake", + }; + + void initialize(); + const char *analyzeCanSignal(struct json_object *object); + + int getCurrentTransGearState(); + bool getCurrentHeadlampState(); + bool getCurrentParkingBrakeState(); + double getCurrentAccelPedalPosition(); + bool getCurrentAccelPedalState(); + bool getCurrentLightstatusBrakeState(); + + bool isChangedAccelPedalState(); + + private: + // Disable copy and move + LowCanClient(LowCanClient const &) = delete; + LowCanClient &operator=(LowCanClient const &) = delete; + LowCanClient(LowCanClient &&) = delete; + LowCanClient &operator=(LowCanClient &&) = delete; + + enum TransGearPosVal + { + TransGearPosValD1 = 1, + TransGearPosValD2, + TransGearPosValD3, + TransGearPosValD4, + TransGearPosValD5, + TransGearPosValD6, + TransGearPosValD7, + TransGearPosValD8, + TransGearPosValR, + TransGearPosValN, + }; + + const std::vector<const char *> kFilterValue{ + "", // vehicle.speed + "", // transmission_gear_position + "", // headlamp_status + "", // parking_brake_status + "", // accelerator.pedal.position + "", // lightstatus.brake + }; + + int vehicle_speed; + int trans_gear_pos; + json_bool headlamp_status; + json_bool parking_brake_status; + double accel_pedal_pos; + bool accel_pedal_stt; + json_bool lightstatus_brake_status; + + bool is_changed_accel_pedal_stt; +}; + +} // namespace wm + +#endif // TMCAGLWM_LOW_CAN_CLIENT_HPP diff --git a/src/main.cpp b/src/main.cpp index 0447f86..3766152 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,10 +18,10 @@ #include <algorithm> #include <mutex> #include <json.h> -#include "../include/json.hpp" +#include <stdlib.h> +#include <vector> #include "window_manager.hpp" #include "json_helper.hpp" -#include "wayland_ivi_wm.hpp" extern "C" { @@ -42,10 +42,10 @@ typedef struct WMClientCtxt struct afb_instance { - std::unique_ptr<wl::display> display; wm::WindowManager wmgr; - afb_instance() : display{new wl::display}, wmgr{this->display.get()} {} + afb_instance() : wmgr() {} + ~afb_instance() = default; int init(); }; @@ -58,101 +58,18 @@ int afb_instance::init() return this->wmgr.init(); } -int display_event_callback(sd_event_source *evs, int /*fd*/, uint32_t events, - void * /*data*/) -{ - ST(); - - if ((events & EPOLLHUP) != 0) - { - HMI_ERROR("wm", "The compositor hung up, dying now."); - delete g_afb_instance; - g_afb_instance = nullptr; - goto error; - } - - if ((events & EPOLLIN) != 0u) - { - { - STN(display_read_events); - 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 - STN(winman_ping_api_call); - afb_service_call("windowmanager", "ping", json_object_new_object(), - [](void *c, int st, json_object *j) { - STN(winman_ping_api_call_return); - }, - 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("wm", "WinMan ver. %s", WINMAN_VERSION_STRING); + HMI_NOTICE("WinMan ver. %s", WINMAN_VERSION_STRING); - if (g_afb_instance != nullptr) - { - HMI_ERROR("wm", "Wayland context already initialized?"); - return 0; - } - - if (getenv("XDG_RUNTIME_DIR") == nullptr) - { - HMI_ERROR("wm", "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("wm", "Could not connect to compositor"); - goto error; - } - HMI_ERROR("wm", "Wait to start weston ..."); - sleep(1); - delete g_afb_instance; - g_afb_instance = new afb_instance; - } - } + g_afb_instance = new afb_instance; if (g_afb_instance->init() == -1) { - HMI_ERROR("wm", "Could not connect to compositor"); + 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("wm", "Could not initialize afb_instance event handler: %d", -ret); - goto error; - } - } - atexit([] { delete g_afb_instance; }); return 0; @@ -171,7 +88,7 @@ int binding_init() noexcept } catch (std::exception &e) { - HMI_ERROR("wm", "Uncaught exception in binding_init(): %s", e.what()); + HMI_ERROR("Uncaught exception in binding_init(): %s", e.what()); } return -1; } @@ -183,19 +100,13 @@ static void cbRemoveClientCtxt(void *data) { return; } - HMI_DEBUG("wm", "remove app %s", ctxt->name.c_str()); + 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 *errmsg) { - if (errmsg != nullptr) - { - HMI_ERROR("wm", errmsg); - return; - } - }); + [](const char *) {}); g_afb_instance->wmgr.removeClient(ctxt->name); delete ctxt; @@ -209,7 +120,7 @@ static void createSecurityContext(afb_req req, const char* appid, const char* ro // 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("wm", "create session for %s", ctxt->name.c_str()); + HMI_DEBUG("create session for %s", ctxt->name.c_str()); afb_req_session_set_LOA(req, 1); afb_req_context_set(req, ctxt, cbRemoveClientCtxt); } @@ -218,9 +129,7 @@ static void createSecurityContext(afb_req req, const char* appid, const char* ro void windowmanager_requestsurface(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); -#ifdef ST - ST(); -#endif + if (g_afb_instance == nullptr) { afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); @@ -236,18 +145,27 @@ void windowmanager_requestsurface(afb_req req) noexcept return; } - const char *appid = afb_req_get_application_id(req); - auto ret = g_afb_instance->wmgr.api_request_surface( - appid, a_drawing_name); - if (ret.is_err()) + char *appid = afb_req_get_application_id(req); + if(appid) { - afb_req_fail(req, "failed", ret.unwrap_err()); - return; - } + auto ret = g_afb_instance->wmgr.api_request_surface( + appid, a_drawing_name); - createSecurityContext(req, appid, a_drawing_name); - - afb_req_success(req, json_object_new_int(ret.unwrap()), "success"); + 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) { @@ -259,9 +177,7 @@ void windowmanager_requestsurface(afb_req req) noexcept void windowmanager_requestsurfacexdg(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); -#ifdef ST - ST(); -#endif + if (g_afb_instance == nullptr) { afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); @@ -287,19 +203,65 @@ void windowmanager_requestsurfacexdg(afb_req req) noexcept return; } char const *a_ivi_id = json_object_get_string(j_ivi_id); - char const *appid = afb_req_get_application_id(req); - auto ret = g_afb_instance->wmgr.api_request_surface( - appid, a_drawing_name, a_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; + } +} - if (ret != nullptr) +void windowmanager_setrole(afb_req req) noexcept +{ + std::lock_guard<std::mutex> guard(binding_m); + if (g_afb_instance == nullptr) + { + afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); + return; + } + try + { + json_object *jreq = afb_req_json(req); + + json_object *j_role = nullptr; + if (!json_object_object_get_ex(jreq, "role", &j_role)) { - afb_req_fail(req, "failed", ret); + afb_req_fail(req, "failed", "Need char const* argument role"); return; } + char const *a_role = json_object_get_string(j_role); + char *appid = afb_req_get_application_id(req); - createSecurityContext(req, appid, a_drawing_name); - - afb_req_success(req, NULL, "success"); + if(appid) + { + auto ret = g_afb_instance->wmgr.api_set_role(appid, a_role); + if (!ret) + { + afb_req_fail(req, "failed", "Couldn't register"); + } + else + { + createSecurityContext(req, appid, a_role); + afb_req_success(req, NULL, "success"); + } + free(appid); + } } catch (std::exception &e) { @@ -311,9 +273,7 @@ void windowmanager_requestsurfacexdg(afb_req req) noexcept void windowmanager_activatewindow(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); -#ifdef ST - ST(); -#endif + if (g_afb_instance == nullptr) { afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); @@ -336,22 +296,44 @@ void windowmanager_activatewindow(afb_req req) noexcept return; } - g_afb_instance->wmgr.api_activate_surface( - afb_req_get_application_id(req), - a_drawing_name, a_drawing_area, - [&req](const char *errmsg) { + char* appid = afb_req_get_application_id(req); + if(appid) + { + auto reply = [&req](const char *errmsg) { if (errmsg != nullptr) { - HMI_ERROR("wm", errmsg); + HMI_ERROR(errmsg); afb_req_fail(req, "failed", errmsg); return; } afb_req_success(req, NULL, "success"); - }); + }; + + if (g_afb_instance->wmgr.wmcon.isMasterMode() || + !g_afb_instance->wmgr.wmcon.isMasterArea(a_drawing_area)) + { + g_afb_instance->wmgr.api_activate_surface( + appid, a_drawing_name, a_drawing_area, reply); + } + else + { + // TODO: temporarily + if (!g_afb_instance->wmgr.wmcon.isConnecting()) + { + g_afb_instance->wmgr.wmcon.connectToMaster(); + } + + // If Window Manager is slave and this request is for master, + // request activateWindow to master + g_afb_instance->wmgr.api_activate_surface_to_master( + appid, a_drawing_name, a_drawing_area, reply); + } + free(appid); + } } catch (std::exception &e) { - HMI_WARNING("wm", "failed: Uncaught exception while calling activatesurface: %s", e.what()); + HMI_WARNING("failed: Uncaught exception while calling activatesurface: %s", e.what()); g_afb_instance->wmgr.exceptionProcessForTransition(); return; } @@ -360,9 +342,7 @@ void windowmanager_activatewindow(afb_req req) noexcept void windowmanager_deactivatewindow(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); -#ifdef ST - ST(); -#endif + if (g_afb_instance == nullptr) { afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); @@ -378,21 +358,39 @@ void windowmanager_deactivatewindow(afb_req req) noexcept return; } - g_afb_instance->wmgr.api_deactivate_surface( - afb_req_get_application_id(req), a_drawing_name, - [&req](const char *errmsg) { + char* appid = afb_req_get_application_id(req); + if(appid) + { + auto reply = [&req](const char *errmsg) { if (errmsg != nullptr) { - HMI_ERROR("wm", errmsg); + HMI_ERROR(errmsg); afb_req_fail(req, "failed", errmsg); return; } afb_req_success(req, NULL, "success"); - }); + }; + + // TODO: Check whether role is tbtnavi to request remote invisible + if (g_afb_instance->wmgr.wmcon.isMasterMode() || + ("tbtnavi" != std::string(a_drawing_name))) + { + g_afb_instance->wmgr.api_deactivate_surface( + appid, a_drawing_name, reply); + } + else + { + // If Window Manager is slave and this request is for master, + // request deactivateWindow to master + g_afb_instance->wmgr.api_deactivate_surface_to_master( + appid, a_drawing_name, reply); + } + free(appid); + } } catch (std::exception &e) { - HMI_WARNING("wm", "failed: Uncaught exception while calling deactivatesurface: %s", e.what()); + HMI_WARNING("failed: Uncaught exception while calling deactivatesurface: %s", e.what()); g_afb_instance->wmgr.exceptionProcessForTransition(); return; } @@ -401,9 +399,7 @@ void windowmanager_deactivatewindow(afb_req req) noexcept void windowmanager_enddraw(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); -#ifdef ST - ST(); -#endif + if (g_afb_instance == nullptr) { afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); @@ -420,12 +416,26 @@ void windowmanager_enddraw(afb_req req) noexcept } afb_req_success(req, NULL, "success"); - g_afb_instance->wmgr.api_enddraw( - afb_req_get_application_id(req), a_drawing_name); + char* appid = afb_req_get_application_id(req); + if(appid) + { + if (g_afb_instance->wmgr.wmcon.isMasterMode() || + !g_afb_instance->wmgr.wmcon.isSyncDrawingForRemote(appid)) + { + g_afb_instance->wmgr.api_enddraw(appid, a_drawing_name); + } + else + { + // If Window Manager is slave and requesting app is syncDrawing, + // request endDraw to master + g_afb_instance->wmgr.api_enddraw_for_remote(appid, a_drawing_name); + } + free(appid); + } } catch (std::exception &e) { - HMI_WARNING("wm", "failed: Uncaught exception while calling enddraw: %s", e.what()); + HMI_WARNING("failed: Uncaught exception while calling enddraw: %s", e.what()); g_afb_instance->wmgr.exceptionProcessForTransition(); return; } @@ -434,9 +444,7 @@ void windowmanager_enddraw(afb_req req) noexcept void windowmanager_getdisplayinfo_thunk(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); -#ifdef ST - ST(); -#endif + if (g_afb_instance == nullptr) { afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); @@ -464,9 +472,7 @@ void windowmanager_getdisplayinfo_thunk(afb_req req) noexcept void windowmanager_getareainfo_thunk(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); -#ifdef ST - ST(); -#endif + if (g_afb_instance == nullptr) { afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); @@ -501,12 +507,128 @@ void windowmanager_getareainfo_thunk(afb_req req) noexcept } } +void windowmanager_getcarinfo_thunk(afb_req req) noexcept +{ + std::lock_guard<std::mutex> guard(binding_m); + if (g_afb_instance == nullptr) + { + afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); + return; + } + + try + { + json_object *jreq = afb_req_json(req); + + json_object *j_label = nullptr; + if (! json_object_object_get_ex(jreq, "label", &j_label)) + { + afb_req_fail(req, "failed", "Need char const* argument label"); + return; + } + char const* a_label = json_object_get_string(j_label); + + auto ret = g_afb_instance->wmgr.api_get_car_info(a_label); + if (ret.is_err()) + { + afb_req_fail(req, "failed", ret.unwrap_err()); + return; + } + + afb_req_success(req, ret.unwrap(), "success"); + } + catch (std::exception &e) + { + afb_req_fail_f(req, "failed", "Uncaught exception while calling getcarinfo: %s", e.what()); + return; + } +} + +void windowmanager_set_render_order(afb_req req) noexcept +{ + std::lock_guard<std::mutex> guard(binding_m); + if (g_afb_instance == nullptr) + { + afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); + return; + } + + char* appid = afb_req_get_application_id(req); + if(appid) + { + json_object *jreq = afb_req_json(req); + json_object *j_ro; // Do not free this. binder frees jreq, then free j_ro + if (json_object_object_get_ex(jreq, "render_order", &j_ro)) + { + int size = json_object_array_length(j_ro); + std::vector<std::string> ro(size); + for(int i = 0; i < size; i++) + { + ro[i] = json_object_get_string(json_object_array_get_idx(j_ro, i)); + } + + auto ret = g_afb_instance->wmgr.api_client_set_render_order(appid, ro); + if (!ret) + { + afb_req_fail(req, "failed", nullptr); + } + else + { + afb_req_success(req, nullptr, nullptr); + } + } + free(appid); + } + else + { + afb_req_fail(req, "failed", nullptr); + } +} + +void windowmanager_attach_app(afb_req req) noexcept +{ + std::lock_guard<std::mutex> guard(binding_m); + if (g_afb_instance == nullptr) + { + afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); + return; + } + + char* appid = afb_req_get_application_id(req); + if(appid) + { + json_object *jreq = afb_req_json(req); + json_object *j_dest, *j_id; // Do not free this. binder frees jreq, then free j_ro + if (json_object_object_get_ex(jreq, "destination", &j_dest) && + json_object_object_get_ex(jreq, "service_surface", &j_id)) + { + const char* dest_app = json_object_get_string(j_dest); + const char* service = json_object_get_string(j_id); + + std::string uuid = g_afb_instance->wmgr.api_client_attach_service_surface(appid, dest_app, service); + if (uuid.empty()) + { + afb_req_fail(req, "failed", nullptr); + } + else + { + json_object *resp = json_object_new_object(); + json_object_object_add(resp, "uuid", json_object_new_string(uuid.c_str())); + afb_req_success(req, resp, nullptr); + } + } + free(appid); + } + else + { + afb_req_fail(req, "failed", nullptr); + } +} + void windowmanager_wm_subscribe(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); -#ifdef ST - ST(); -#endif + if (g_afb_instance == nullptr) { afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); @@ -543,10 +665,8 @@ void windowmanager_wm_subscribe(afb_req req) noexcept void windowmanager_list_drawing_names(afb_req req) noexcept { std::lock_guard<std::mutex> guard(binding_m); -#ifdef ST - ST(); -#endif - if (g_afb_instance == nullptr) + + /* if (g_afb_instance == nullptr) { afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); return; @@ -569,42 +689,29 @@ void windowmanager_list_drawing_names(afb_req req) noexcept { 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); -#ifdef ST - ST(); -#endif + if (g_afb_instance == nullptr) { afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); return; } - - try + else { - - 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); -#ifdef ST - ST(); -#endif - if (g_afb_instance == nullptr) + + /* if (g_afb_instance == nullptr) { afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); return; @@ -624,16 +731,14 @@ void windowmanager_debug_status(afb_req req) noexcept { 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); -#ifdef ST - ST(); -#endif - if (g_afb_instance == nullptr) + + /* if (g_afb_instance == nullptr) { afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); return; @@ -649,16 +754,14 @@ void windowmanager_debug_layers(afb_req req) noexcept { 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); -#ifdef ST - ST(); -#endif - if (g_afb_instance == nullptr) + + /* if (g_afb_instance == nullptr) { afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); return; @@ -680,15 +783,13 @@ void windowmanager_debug_surfaces(afb_req req) noexcept { 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); -#ifdef ST - ST(); -#endif + if (g_afb_instance == nullptr) { afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); @@ -713,14 +814,23 @@ void windowmanager_debug_terminate(afb_req req) noexcept } } +void on_event(const char *event, struct json_object *object) +{ + g_afb_instance->wmgr.analyzeReceivedEvent(event, object); +} + const struct afb_verb_v2 windowmanager_verbs[] = { - {"requestsurface", windowmanager_requestsurface, nullptr, nullptr, AFB_SESSION_NONE}, - {"requestsurfacexdg", windowmanager_requestsurfacexdg, nullptr, nullptr, AFB_SESSION_NONE}, - {"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}, + {"requestSurface", windowmanager_requestsurface, nullptr, nullptr, AFB_SESSION_NONE}, + {"requestSurfaceXdg", windowmanager_requestsurfacexdg, nullptr, nullptr, AFB_SESSION_NONE}, + {"setRole", windowmanager_setrole, nullptr, nullptr, AFB_SESSION_NONE}, + {"activateWindow", windowmanager_activatewindow, nullptr, nullptr, AFB_SESSION_NONE}, + {"deactivateWindow", windowmanager_deactivatewindow, nullptr, nullptr, AFB_SESSION_NONE}, + {"endDraw", windowmanager_enddraw, nullptr, nullptr, AFB_SESSION_NONE}, + {"getDisplayInfo", windowmanager_getdisplayinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE}, + {"getAreaInfo", windowmanager_getareainfo_thunk, nullptr, nullptr, AFB_SESSION_NONE}, + {"getCarInfo", windowmanager_getcarinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE }, + {"setRenderOrder", windowmanager_set_render_order, nullptr, nullptr, AFB_SESSION_NONE}, + {"attachApp", windowmanager_attach_app, 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}, @@ -731,4 +841,4 @@ const struct afb_verb_v2 windowmanager_verbs[] = { {}}; 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/pm_wrapper.cpp b/src/pm_wrapper.cpp index 1454bf9..7cf90f0 100644 --- a/src/pm_wrapper.cpp +++ b/src/pm_wrapper.cpp @@ -16,7 +16,7 @@ #include "pm_wrapper.hpp" #include "json_helper.hpp" -#include "hmi-debug.h" +#include "util.hpp" namespace wm { @@ -33,7 +33,7 @@ static void onStateTransitioned(json_object *json_out) static void onError(json_object *json_out) { - HMI_DEBUG("wm", "error message from PolicyManager:%s", + HMI_DEBUG("error message from PolicyManager:%s", json_object_get_string(json_out)); g_context->processError(); @@ -43,11 +43,11 @@ static void onError(json_object *json_out) PMWrapper::PMWrapper() {} -int PMWrapper::initialize() +int PMWrapper::initialize(std::string ecu_name) { int ret = 0; - ret = this->pm.initialize(); + ret = this->pm.initialize(ecu_name); if (0 > ret) { HMI_ERROR("wm:pmw", "Faild to initialize PolicyManager"); @@ -81,7 +81,39 @@ int PMWrapper::setInputEventData(Task task, std::string role, std::string area) { event = "deactivate"; } - else + else if (Task::TASK_PARKING_BRAKE_OFF == task) + { + event = "parking_brake_off"; + } + else if (Task::TASK_PARKING_BRAKE_ON == task) + { + event = "parking_brake_on"; + } + else if (Task::TASK_ACCEL_PEDAL_OFF == task) + { + event = "accel_pedal_off"; + } + else if (Task::TASK_ACCEL_PEDAL_ON == task) + { + event = "accel_pedal_on"; + } + else if (Task::TASK_HEDLAMP_OFF == task) + { + event = "headlamp_off"; + } + else if (Task::TASK_HEDLAMP_ON == task) + { + event = "headlamp_on"; + } + else if (Task::TASK_LIGHTSTATUS_BRAKE_OFF == task) + { + event = "lightstatus_brake_off"; + } + else if (Task::TASK_LIGHTSTATUS_BRAKE_ON == task) + { + event = "lightstatus_brake_on"; + } + else { event = ""; } @@ -125,25 +157,165 @@ void PMWrapper::updateStates(json_object *json_out) { std::vector<WMAction> actions; - HMI_DEBUG("wm", "json_out dump:%s", json_object_get_string(json_out)); + HMI_DEBUG("json_out dump:%s", json_object_get_string(json_out)); + this->createCarStateChangeAction(json_out, actions); this->createLayoutChangeAction(json_out, actions); this->on_state_transitioned(actions); } +void PMWrapper::createCarStateChangeAction(json_object *json_out, std::vector<WMAction> &actions) +{ + json_object *json_car_ele; + if (!json_object_object_get_ex(json_out, "car_elements", &json_car_ele)) + { + HMI_DEBUG("Not found key \"car_elements\""); + return; + } + + int len = json_object_array_length(json_car_ele); + HMI_DEBUG("json_car_ele len:%d", len); + + for (int i = 0; i < len; i++) + { + json_object *json_tmp = json_object_array_get_idx(json_car_ele, i); + + std::string car_ele_name = jh::getStringFromJson(json_tmp, "name"); + std::string state = jh::getStringFromJson(json_tmp, "state"); + json_bool changed = jh::getBoolFromJson(json_tmp, "changed"); + HMI_DEBUG("car_element:%s changed:%d", car_ele_name.c_str(), changed); + + if (changed) + { + TaskCarState task = TaskCarState::NO_TASK; + if ("parking_brake" == car_ele_name) + { + if ("off" == state) + { + task = TaskCarState::PARKING_BRAKE_OFF; + } + else if ("on" == state) + { + task = TaskCarState::PARKING_BRAKE_ON; + } + else + { + HMI_DEBUG("Unknown parking brake state: %s", state.c_str()); + } + } + else if ("accel_pedal" == car_ele_name) + { + if ("off" == state) + { + task = TaskCarState::ACCEL_PEDAL_OFF; + } + else if ("on" == state) + { + task = TaskCarState::ACCEL_PEDAL_ON; + } + else + { + HMI_DEBUG("Unknown accel pedal state: %s", state.c_str()); + } + } + else if ("lamp" == car_ele_name) + { + if ("off" == state) + { + task = TaskCarState::HEDLAMP_OFF; + } + else if ("on" == state) + { + task = TaskCarState::HEDLAMP_ON; + } + else + { + HMI_DEBUG("Unknown lamp state: %s", state.c_str()); + } + } + else if ("lightstatus_brake" == car_ele_name) + { + if ("off" == state) + { + task = TaskCarState::LIGHTSTATUS_BRAKE_OFF; + } + else if ("on" == state) + { + task = TaskCarState::LIGHTSTATUS_BRAKE_ON; + } + else + { + HMI_DEBUG("Unknown lightstatus brake state: %s", state.c_str()); + } + } + else if ("running" == car_ele_name) + { + if ("stop" == state) + { + task = TaskCarState::CAR_STOP; + } + else if ("run" == state) + { + task = TaskCarState::CAR_RUN; + } + else + { + HMI_DEBUG("Unknown car state: %s", state.c_str()); + } + } + else if ("restriction_mode" == car_ele_name) + { + if ("off" == state) + { + task = TaskCarState::RESTRICTION_MODE_OFF; + } + else if ("on" == state) + { + task = TaskCarState::RESTRICTION_MODE_ON; + } + else + { + HMI_DEBUG("Unknown car state: %s", state.c_str()); + } + } + else + { + HMI_DEBUG("Unknown car element: %s", car_ele_name.c_str()); + } + + // Set action + if (TaskCarState::NO_TASK != task) + { + bool end_draw_finished = true; + WMAction act + { + 0, + nullptr, + "", + "", + TaskVisible::NO_CHANGE, + end_draw_finished, + task + }; + actions.push_back(act); + } + } + } +} + void PMWrapper::createLayoutChangeAction(json_object *json_out, std::vector<WMAction> &actions) { // Get displayed roles from previous layout json_object *json_layers; if (!json_object_object_get_ex(json_out, "layers", &json_layers)) { - HMI_DEBUG("wm", "Not found key \"layers\""); + HMI_DEBUG("Not found key \"layers\""); return; } int len = json_object_array_length(json_layers); - HMI_DEBUG("wm", "json_layers len:%d", len); + HMI_DEBUG("json_layers len:%d", len); for (int i = 0; i < len; i++) { @@ -151,19 +323,19 @@ void PMWrapper::createLayoutChangeAction(json_object *json_out, std::vector<WMAc std::string layer_name = jh::getStringFromJson(json_tmp, "name"); json_bool changed = jh::getBoolFromJson(json_tmp, "changed"); - HMI_DEBUG("wm", "layer:%s changed:%d", layer_name.c_str(), changed); + HMI_DEBUG("layer:%s changed:%d", layer_name.c_str(), changed); if (changed) { json_object *json_areas; if (!json_object_object_get_ex(json_tmp, "areas", &json_areas)) { - HMI_DEBUG("wm", "Not found key \"areas\""); + HMI_DEBUG("Not found key \"areas\""); return; } int len = json_object_array_length(json_areas); - HMI_DEBUG("wm", "json_layers len:%d", len); + HMI_DEBUG("json_layers len:%d", len); // Store previous role state in this layer this->prvlayer2rolestate[layer_name] = this->crrlayer2rolestate[layer_name]; @@ -180,45 +352,49 @@ void PMWrapper::createLayoutChangeAction(json_object *json_out, std::vector<WMAc crr_roles[role_name] = area_name; auto i_prv = prv_roles.find(role_name); - HMI_DEBUG("wm", "current role:%s area:%s", + HMI_DEBUG("current role:%s area:%s", role_name.c_str(), area_name.c_str()); // If current role does not exist in previous if (prv_roles.end() == i_prv) { - HMI_DEBUG("wm", "current role does not exist in previous"); + HMI_DEBUG("current role does not exist in previous"); // Set activate action bool end_draw_finished = false; WMAction act { - "", + 0, + nullptr, role_name, area_name, TaskVisible::VISIBLE, - end_draw_finished + end_draw_finished, + TaskCarState::NO_TASK }; actions.push_back(act); } else { - HMI_DEBUG("wm", "previous role:%s area:%s", + HMI_DEBUG("previous role:%s area:%s", i_prv->first.c_str(), i_prv->second.c_str()); // If current role exists in previous and area is different with previous if (area_name != i_prv->second) { - HMI_DEBUG("wm", "current role exists in previous and area is different with previous"); + HMI_DEBUG("current role exists in previous and area is different with previous"); // Set activate action bool end_draw_finished = false; WMAction act { - "", + 0, + nullptr, role_name, area_name, TaskVisible::VISIBLE, - end_draw_finished + end_draw_finished, + TaskCarState::NO_TASK }; actions.push_back(act); } @@ -232,17 +408,19 @@ void PMWrapper::createLayoutChangeAction(json_object *json_out, std::vector<WMAc // because these are not displayed in current layout for (auto i_prv : prv_roles) { - HMI_DEBUG("wm", "Deactivate role:%s", i_prv.first.c_str()); + HMI_DEBUG("Deactivate role:%s", i_prv.first.c_str()); // Set deactivate action bool end_draw_finished = true; WMAction act { - "", + 0, + nullptr, i_prv.first, "", TaskVisible::INVISIBLE, - end_draw_finished + end_draw_finished, + TaskCarState::NO_TASK }; actions.push_back(act); } diff --git a/src/pm_wrapper.hpp b/src/pm_wrapper.hpp index 31ec002..84d68df 100644 --- a/src/pm_wrapper.hpp +++ b/src/pm_wrapper.hpp @@ -41,7 +41,7 @@ class PMWrapper using StateTransitionHandler = std::function<void(std::vector<WMAction>)>; using ErrorHandler = std::function<void(void)>; - int initialize(); + int initialize(std::string ecu_name); void registerCallback(StateTransitionHandler on_state_transitioned, ErrorHandler on_error); int setInputEventData(Task task, std::string role, std::string area); @@ -67,6 +67,7 @@ class PMWrapper std::map<std::string, RoleState> prvlayer2rolestate; std::map<std::string, RoleState> crrlayer2rolestate; + void createCarStateChangeAction(json_object *json_out, std::vector<WMAction> &actions); void createLayoutChangeAction(json_object *json_out, std::vector<WMAction> &actions); }; diff --git a/src/request.cpp b/src/request.cpp index 069f8ff..0d8e5d4 100644 --- a/src/request.cpp +++ b/src/request.cpp @@ -30,6 +30,13 @@ WMRequest::WMRequest(string appid, string role, string area, Task task) { } +WMRequest::WMRequest(Task task) + : req_num(0), + trigger{"", "", "", task}, + sync_draw_req(0) +{ +} + WMRequest::~WMRequest() { } @@ -41,4 +48,4 @@ WMRequest::WMRequest(const WMRequest &obj) this->sync_draw_req = obj.sync_draw_req; } -} // namespace wm
\ No newline at end of file +} // namespace wm diff --git a/src/request.hpp b/src/request.hpp index 6b2bda1..bb203e3 100644 --- a/src/request.hpp +++ b/src/request.hpp @@ -19,14 +19,27 @@ #include <string> #include <vector> +#include <memory> namespace wm { +class WMClient; + enum Task { TASK_ALLOCATE, TASK_RELEASE, + TASK_PARKING_BRAKE_OFF, + TASK_PARKING_BRAKE_ON, + TASK_ACCEL_PEDAL_OFF, + TASK_ACCEL_PEDAL_ON, + TASK_HEDLAMP_OFF, + TASK_HEDLAMP_ON, + TASK_LIGHTSTATUS_BRAKE_OFF, + TASK_LIGHTSTATUS_BRAKE_ON, + TASK_RESTRICTION_MODE_OFF, + TASK_RESTRICTION_MODE_ON, TASK_INVALID }; @@ -34,9 +47,30 @@ enum TaskVisible { VISIBLE, INVISIBLE, + REQ_REMOTE_VISIBLE, + REQ_REMOTE_INVISIBLE, + REMOTE_VISIBLE, + REMOTE_INVISIBLE, NO_CHANGE }; +enum TaskCarState +{ + PARKING_BRAKE_OFF, + PARKING_BRAKE_ON, + ACCEL_PEDAL_OFF, + ACCEL_PEDAL_ON, + HEDLAMP_OFF, + HEDLAMP_ON, + LIGHTSTATUS_BRAKE_OFF, + LIGHTSTATUS_BRAKE_ON, + CAR_STOP, + CAR_RUN, + RESTRICTION_MODE_OFF, + RESTRICTION_MODE_ON, + NO_TASK, +}; + struct WMTrigger { std::string appid; @@ -47,11 +81,13 @@ struct WMTrigger struct WMAction { - std::string appid; + unsigned req_num; + std::shared_ptr<WMClient> client; std::string role; std::string area; TaskVisible visible; bool end_draw_finished; + TaskCarState car_state; }; struct WMRequest @@ -59,6 +95,7 @@ struct WMRequest WMRequest(); explicit WMRequest(std::string appid, std::string role, std::string area, Task task); + explicit WMRequest(Task task); virtual ~WMRequest(); WMRequest(const WMRequest &obj); @@ -69,4 +106,4 @@ struct WMRequest } // namespace wm -#endif //WMREQUEST_HPP
\ No newline at end of file +#endif //WMREQUEST_HPP diff --git a/src/util.cpp b/src/util.cpp index 672b089..b22a704 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -16,30 +16,15 @@ #include "util.hpp" -#include <cerrno> -#include <cstdarg> -#include <cstdio> -#include <cstdlib> -#include <ctime> +#include <sstream> +#include <time.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> #include <unistd.h> -#ifdef SCOPE_TRACING -thread_local int ScopeTrace::indent = 0; -ScopeTrace::ScopeTrace(char const *func) : f(func) -{ - fprintf(stderr, "%lu %*s%s -->\n", pthread_self(), 2 * indent++, "", this->f); -} -ScopeTrace::~ScopeTrace() { fprintf(stderr, "%lu %*s%s <--\n", pthread_self(), 2 * --indent, "", this->f); } -#endif - -unique_fd::~unique_fd() -{ - if (this->fd != -1) - { - close(this->fd); - } -} +static char ERROR_FLAG[6][20] = {"NONE", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG"}; void rectangle::fit(unsigned long to_width, unsigned long to_height) { @@ -93,3 +78,95 @@ void rectangle::set_aspect(double ratio) } } +void _HMI_LOG(enum LOG_LEVEL level, const char* file, const char* func, const int line, const char* prefix, const char* log, ...) +{ + const int log_level = (getenv("USE_HMI_DEBUG") == NULL)?LOG_LEVEL_ERROR:atoi(getenv("USE_HMI_DEBUG")); + if(log_level < level) + { + return; + } + + char *message; + struct timespec tp; + unsigned int time; + + clock_gettime(CLOCK_REALTIME, &tp); + time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); + + va_list args; + va_start(args, log); + if (log == NULL || vasprintf(&message, log, args) < 0) + message = NULL; + fprintf(stderr, "[%10.3f] [%s %s] [%s, %s(), Line:%d] >>> %s \n", time / 1000.0, prefix, ERROR_FLAG[level], file, func, line, message); + va_end(args); + free(message); +} + +void _HMI_SEQ_LOG(enum LOG_LEVEL level, const char* file, const char* func, const int line, unsigned seq_num, const char* log, ...){ + const int log_level = (getenv("USE_HMI_DEBUG") == NULL) ? LOG_LEVEL_ERROR:atoi(getenv("USE_HMI_DEBUG")); + if(log_level < level) + { + return; + } + + char *message; + struct timespec tp; + unsigned int time; + + clock_gettime(CLOCK_REALTIME, &tp); + time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); + + va_list args; + va_start(args, log); + if (log == NULL || vasprintf(&message, log, args) < 0) + message = NULL; + fprintf(stderr, "[%10.3f] [wm %s] [%s, %s(), Line:%d] >>> req %d: %s \n", time / 1000.0, ERROR_FLAG[level], file, func, line, seq_num, message); + va_end(args); + free(message); +} + +void _DUMP(enum LOG_LEVEL level, const char *log, ...) +{ + const int log_level = (getenv("USE_HMI_DEBUG") == NULL) ? LOG_LEVEL_ERROR : atoi(getenv("USE_HMI_DEBUG")); + if (log_level < level) + { + return; + } + char *message; + va_list args; + va_start(args, log); + if (log == NULL || vasprintf(&message, log, args) < 0) + message = NULL; + fprintf(stderr, "%s \n", message); + va_end(args); + free(message); +} + +std::vector<std::string> 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()) + { + // Delete space and push back to vector + vct.push_back(deleteSpace(buf)); + } + } + return vct; +} + +std::string deleteSpace(std::string str) +{ + std::string ret = str; + size_t pos; + while ((pos = ret.find_first_of(" ")) != std::string::npos) + { + ret.erase(pos, 1); + } + return ret; +} + diff --git a/src/util.hpp b/src/util.hpp index 2f17845..d049fff 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -19,94 +19,53 @@ #include <functional> #include <thread> +#include <string> #include <vector> - #include <sys/poll.h> - -#ifndef DO_NOT_USE_AFB -extern "C" -{ -#include <afb/afb-binding.h> +#include <string.h> + +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) + +#define HMI_ERROR(args,...) _HMI_LOG(LOG_LEVEL_ERROR, __FILENAME__, __FUNCTION__, __LINE__,"wm",args, ##__VA_ARGS__) +#define HMI_WARNING(args,...) _HMI_LOG(LOG_LEVEL_WARNING, __FILENAME__, __FUNCTION__,__LINE__, "wm", args,##__VA_ARGS__) +#define HMI_NOTICE(args,...) _HMI_LOG(LOG_LEVEL_NOTICE, __FILENAME__, __FUNCTION__,__LINE__, "wm", args,##__VA_ARGS__) +#define HMI_INFO(args,...) _HMI_LOG(LOG_LEVEL_INFO, __FILENAME__, __FUNCTION__,__LINE__, "wm", args,##__VA_ARGS__) +#define HMI_DEBUG(args,...) _HMI_LOG(LOG_LEVEL_DEBUG, __FILENAME__, __FUNCTION__,__LINE__, "wm", args,##__VA_ARGS__) + +#define HMI_SEQ_ERROR(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_ERROR, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__) +#define HMI_SEQ_WARNING(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_WARNING, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__) +#define HMI_SEQ_NOTICE(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_NOTICE, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__) +#define HMI_SEQ_INFO(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_INFO, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__) +#define HMI_SEQ_DEBUG(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_DEBUG, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__) + +#define DUMP(args, ...) _DUMP(LOG_LEVEL_DEBUG, args, ##__VA_ARGS__) + +enum LOG_LEVEL{ + LOG_LEVEL_NONE = 0, + LOG_LEVEL_ERROR, + LOG_LEVEL_WARNING, + LOG_LEVEL_NOTICE, + LOG_LEVEL_INFO, + LOG_LEVEL_DEBUG, + LOG_LEVEL_MAX = LOG_LEVEL_DEBUG }; -#endif - -#define CONCAT_(X, Y) X##Y -#define CONCAT(X, Y) CONCAT_(X, Y) - -#ifdef __GNUC__ -#define ATTR_FORMAT(stringindex, firsttocheck) \ - __attribute__((format(printf, stringindex, firsttocheck))) -#define ATTR_NORETURN __attribute__((noreturn)) -#else -#define ATTR_FORMAT(stringindex, firsttocheck) -#define ATTR_NORETURN -#endif - -#ifdef AFB_BINDING_VERSION -#define lognotice(...) AFB_NOTICE(__VA_ARGS__) -#define logerror(...) AFB_ERROR(__VA_ARGS__) -#define fatal(...) \ - do \ - { \ - AFB_ERROR(__VA_ARGS__); \ - abort(); \ - } while (0) -#else -#define lognotice(...) -#define logerror(...) -#define fatal(...) \ - do \ - { \ - abort(); \ - } while (0) -#endif - -#ifdef DEBUG_OUTPUT -#ifdef AFB_BINDING_VERSION -#define logdebug(...) AFB_DEBUG(__VA_ARGS__) -#else -#define logdebug(...) -#endif -#else -#define logdebug(...) -#endif - -#ifndef SCOPE_TRACING -#define ST() -#define STN(N) -#else -#define ST() \ - ScopeTrace __attribute__((unused)) CONCAT(trace_scope_, __LINE__)(__func__) -#define STN(N) \ - ScopeTrace __attribute__((unused)) CONCAT(named_trace_scope_, __LINE__)(#N) - -struct ScopeTrace + +void _HMI_LOG(enum LOG_LEVEL level, const char* file, const char* func, const int line, const char* prefix, const char* log, ...); +void _HMI_SEQ_LOG(enum LOG_LEVEL level, const char* file, const char* func, const int line, unsigned seq_num, const char* log, ...); +void _DUMP(enum LOG_LEVEL level, const char *log, ...); + +std::vector<std::string> parseString(std::string str, char delimiter); +std::string deleteSpace(std::string str); + +struct rect { - thread_local static int indent; - char const *f{}; - explicit ScopeTrace(char const *func); - ~ScopeTrace(); + int32_t w, h; + int32_t x, y; }; -#endif -/** - * @struct unique_fd - */ -struct unique_fd +struct size { - int fd{-1}; - unique_fd() = default; - explicit unique_fd(int f) : fd{f} {} - operator int() const { return fd; } - ~unique_fd(); - unique_fd(unique_fd const &) = delete; - unique_fd &operator=(unique_fd const &) = delete; - unique_fd(unique_fd &&o) : fd(o.fd) { o.fd = -1; } - unique_fd &operator=(unique_fd &&o) - { - std::swap(this->fd, o.fd); - return *this; - } + uint32_t w, h; }; class rectangle diff --git a/src/wayland_ivi_wm.cpp b/src/wayland_ivi_wm.cpp index 8b04c64..28bd024 100644 --- a/src/wayland_ivi_wm.cpp +++ b/src/wayland_ivi_wm.cpp @@ -15,7 +15,6 @@ */ #include "wayland_ivi_wm.hpp" -#include "hmi-debug.h" /** * namespace wl @@ -41,10 +40,9 @@ int display::dispatch_pending() { return wl_display_dispatch_pending(this->d.get int display::read_events() { - ST(); + ; while (wl_display_prepare_read(this->d.get()) == -1) { - STN(pending_events_dispatch); if (wl_display_dispatch_pending(this->d.get()) == -1) { return -1; @@ -112,7 +110,7 @@ void registry::global_created(uint32_t name, char const *iface, uint32_t v) { b->second(this->proxy.get(), name, v); } - HMI_DEBUG("wm", "wl::registry @ %p global n %u i %s v %u", this->proxy.get(), name, + HMI_DEBUG("wl::registry @ %p global n %u i %s v %u", this->proxy.get(), name, iface, v); } @@ -173,7 +171,7 @@ void output::geometry(int32_t x, int32_t y, int32_t pw, int32_t ph, void output::mode(uint32_t flags, int32_t w, int32_t h, int32_t r) { - HMI_DEBUG("wm", "wl::output %s @ %p f %x w %i h %i r %i", __func__, + HMI_DEBUG("wl::output %s @ %p f %x w %i h %i r %i", __func__, this->proxy.get(), flags, w, h, r); if ((flags & WL_OUTPUT_MODE_CURRENT) != 0u) { @@ -185,7 +183,7 @@ void output::mode(uint32_t flags, int32_t w, int32_t h, int32_t r) void output::done() { - HMI_DEBUG("wm", "wl::output %s @ %p done", __func__, this->proxy.get()); + HMI_DEBUG("wl::output %s @ %p done", __func__, this->proxy.get()); // Pivot and flipped if (this->transform == WL_OUTPUT_TRANSFORM_90 || this->transform == WL_OUTPUT_TRANSFORM_270 || @@ -199,7 +197,7 @@ void output::done() void output::scale(int32_t factor) { - HMI_DEBUG("wm", "wl::output %s @ %p f %i", __func__, this->proxy.get(), factor); + HMI_DEBUG("wl::output %s @ %p f %i", __func__, this->proxy.get(), factor); } } // namespace wl @@ -363,14 +361,14 @@ void layer_added(void *data, struct ivi_wm_screen *ivi_wm_screen, uint32_t layer_id) { - HMI_DEBUG("wm", "added layer_id:%d", layer_id); + HMI_DEBUG("added layer_id:%d", layer_id); } void connector_name(void *data, struct ivi_wm_screen *ivi_wm_screen, const char *process_name) { - HMI_DEBUG("wm", "process_name:%s", process_name); + HMI_DEBUG("process_name:%s", process_name); } void screen_error(void *data, @@ -378,7 +376,7 @@ void screen_error(void *data, uint32_t error, const char *message) { - HMI_DEBUG("wm", "screen error:%d message:%s", error, message); + HMI_DEBUG("screen error:%d message:%s", error, message); } constexpr struct ivi_wm_screen_listener screen_listener = { @@ -400,7 +398,7 @@ surface::surface(uint32_t i, struct controller *c) void surface::set_visibility(uint32_t visibility) { - HMI_DEBUG("wm", "compositor::surface id:%d v:%d", this->id, visibility); + HMI_DEBUG("compositor::surface id:%d v:%d", this->id, visibility); ivi_wm_set_surface_visibility(this->parent->proxy.get(), this->id, visibility); } @@ -459,7 +457,7 @@ screen::screen(uint32_t i, struct controller *c, struct wl_output *o) : wayland_proxy(ivi_wm_create_screen(c->proxy.get(), o)), controller_child(c, i) { - HMI_DEBUG("wm", "compositor::screen @ %p id %u o %p", this->proxy.get(), i, o); + HMI_DEBUG("compositor::screen @ %p id %u o %p", this->proxy.get(), i, o); // Add listener for screen ivi_wm_screen_add_listener(this->proxy.get(), &screen_listener, this); @@ -469,7 +467,7 @@ void screen::clear() { ivi_wm_screen_clear(this->proxy.get()); } void screen::screen_created(struct screen *screen, uint32_t id) { - HMI_DEBUG("wm", "compositor::screen @ %p screen %u (%x) @ %p", this->proxy.get(), + HMI_DEBUG("compositor::screen @ %p screen %u (%x) @ %p", this->proxy.get(), id, id, screen); this->id = id; this->parent->screens[id] = screen; @@ -484,7 +482,7 @@ void screen::set_render_order(std::vector<uint32_t> const &ro) for (i = 0; i < ro.size(); i++) { - HMI_DEBUG("wm", "compositor::screen @ %p add layer %u", this->proxy.get(), ro[i]); + HMI_DEBUG("compositor::screen @ %p add layer %u", this->proxy.get(), ro[i]); // Add the layer to screen render order at nearest z-position ivi_wm_screen_add_layer(this->proxy.get(), ro[i]); } @@ -538,10 +536,10 @@ void controller::get_surface_properties(uint32_t surface_id, int param) void controller::layer_created(uint32_t id) { - HMI_DEBUG("wm", "compositor::controller @ %p layer %u (%x)", this->proxy.get(), id, id); + HMI_DEBUG("compositor::controller @ %p layer %u (%x)", this->proxy.get(), id, id); if (this->layers.find(id) != this->layers.end()) { - HMI_DEBUG("wm", "WindowManager has created layer %u (%x) already", id, id); + HMI_DEBUG("WindowManager has created layer %u (%x) already", id, id); } else { @@ -552,13 +550,13 @@ void controller::layer_created(uint32_t id) void controller::layer_error_detected(uint32_t object_id, uint32_t error_code, const char *error_text) { - HMI_DEBUG("wm", "compositor::controller @ %p error o %d c %d text %s", + HMI_DEBUG("compositor::controller @ %p error o %d c %d text %s", this->proxy.get(), object_id, error_code, error_text); } void controller::surface_visibility_changed(uint32_t id, int32_t visibility) { - HMI_DEBUG("wm", "compositor::surface %s @ %d v %i", __func__, id, + HMI_DEBUG("compositor::surface %s @ %d v %i", __func__, id, visibility); this->sprops[id].visibility = visibility; this->chooks->surface_visibility(id, visibility); @@ -566,7 +564,7 @@ void controller::surface_visibility_changed(uint32_t id, int32_t visibility) void controller::surface_opacity_changed(uint32_t id, float opacity) { - HMI_DEBUG("wm", "compositor::surface %s @ %d o %f", + HMI_DEBUG("compositor::surface %s @ %d o %f", __func__, id, opacity); this->sprops[id].opacity = opacity; } @@ -575,7 +573,7 @@ void controller::surface_source_rectangle_changed(uint32_t id, int32_t x, int32_t y, int32_t width, int32_t height) { - HMI_DEBUG("wm", "compositor::surface %s @ %d x %i y %i w %i h %i", __func__, + HMI_DEBUG("compositor::surface %s @ %d x %i y %i w %i h %i", __func__, id, x, y, width, height); this->sprops[id].src_rect = rect{width, height, x, y}; } @@ -584,7 +582,7 @@ void controller::surface_destination_rectangle_changed(uint32_t id, int32_t x, int32_t y, int32_t width, int32_t height) { - HMI_DEBUG("wm", "compositor::surface %s @ %d x %i y %i w %i h %i", __func__, + HMI_DEBUG("compositor::surface %s @ %d x %i y %i w %i h %i", __func__, id, x, y, width, height); this->sprops[id].dst_rect = rect{width, height, x, y}; this->chooks->surface_destination_rectangle(id, x, y, width, height); @@ -593,7 +591,7 @@ void controller::surface_destination_rectangle_changed(uint32_t id, int32_t x, void controller::surface_size_changed(uint32_t id, int32_t width, int32_t height) { - HMI_DEBUG("wm", "compositor::surface %s @ %d w %i h %i", __func__, id, + HMI_DEBUG("compositor::surface %s @ %d w %i h %i", __func__, id, width, height); this->sprops[id].size = size{uint32_t(width), uint32_t(height)}; this->surfaces[id]->set_source_rectangle(0, 0, width, height); @@ -601,20 +599,21 @@ void controller::surface_size_changed(uint32_t id, int32_t width, void controller::surface_added_to_layer(uint32_t layer_id, uint32_t surface_id) { - HMI_DEBUG("wm", "compositor::surface %s @ %d l %u", + HMI_DEBUG("compositor::surface %s @ %d l %u", __func__, layer_id, surface_id); } void controller::surface_stats_received(uint32_t surface_id, uint32_t frame_count, uint32_t pid) { - HMI_DEBUG("wm", "compositor::surface %s @ %d f %u pid %u", + HMI_DEBUG("compositor::surface %s @ %d f %u pid %u", __func__, surface_id, frame_count, pid); + this->sprops[surface_id].pid = pid; } void controller::surface_created(uint32_t id) { - HMI_DEBUG("wm", "compositor::controller @ %p surface %u (%x)", this->proxy.get(), id, + HMI_DEBUG("compositor::controller @ %p surface %u (%x)", this->proxy.get(), id, id); if (this->surfaces.find(id) == this->surfaces.end()) { @@ -632,7 +631,7 @@ void controller::surface_created(uint32_t id) void controller::surface_destroyed(uint32_t surface_id) { - HMI_DEBUG("wm", "compositor::surface %s @ %d", __func__, surface_id); + HMI_DEBUG("compositor::surface %s @ %d", __func__, surface_id); this->chooks->surface_removed(surface_id); this->sprops.erase(surface_id); this->surfaces.erase(surface_id); @@ -641,19 +640,19 @@ void controller::surface_destroyed(uint32_t surface_id) void controller::surface_error_detected(uint32_t object_id, uint32_t error_code, const char *error_text) { - HMI_DEBUG("wm", "compositor::controller @ %p error o %d c %d text %s", + HMI_DEBUG("compositor::controller @ %p error o %d c %d text %s", this->proxy.get(), object_id, error_code, error_text); } void controller::layer_visibility_changed(uint32_t layer_id, int32_t visibility) { - HMI_DEBUG("wm", "compositor::layer %s @ %d v %i", __func__, layer_id, visibility); + HMI_DEBUG("compositor::layer %s @ %d v %i", __func__, layer_id, visibility); this->lprops[layer_id].visibility = visibility; } void controller::layer_opacity_changed(uint32_t layer_id, float opacity) { - HMI_DEBUG("wm", "compositor::layer %s @ %d o %f", __func__, layer_id, opacity); + HMI_DEBUG("compositor::layer %s @ %d o %f", __func__, layer_id, opacity); this->lprops[layer_id].opacity = opacity; } @@ -661,7 +660,7 @@ void controller::layer_source_rectangle_changed(uint32_t layer_id, int32_t x, int32_t y, int32_t width, int32_t height) { - HMI_DEBUG("wm", "compositor::layer %s @ %d x %i y %i w %i h %i", + HMI_DEBUG("compositor::layer %s @ %d x %i y %i w %i h %i", __func__, layer_id, x, y, width, height); this->lprops[layer_id].src_rect = rect{width, height, x, y}; } @@ -670,14 +669,14 @@ void controller::layer_destination_rectangle_changed(uint32_t layer_id, int32_t x, int32_t y, int32_t width, int32_t height) { - HMI_DEBUG("wm", "compositor::layer %s @ %d x %i y %i w %i h %i", + HMI_DEBUG("compositor::layer %s @ %d x %i y %i w %i h %i", __func__, layer_id, x, y, width, height); this->lprops[layer_id].dst_rect = rect{width, height, x, y}; } void controller::layer_destroyed(uint32_t layer_id) { - HMI_DEBUG("wm", "compositor::layer %s @ %d", __func__, layer_id); + HMI_DEBUG("compositor::layer %s @ %d", __func__, layer_id); this->lprops.erase(layer_id); this->layers.erase(layer_id); } @@ -685,40 +684,40 @@ void controller::layer_destroyed(uint32_t layer_id) void controller::add_proxy_to_sid_mapping(struct ivi_wm *p, uint32_t id) { - HMI_DEBUG("wm", "Add surface proxy mapping for %p (%u)", p, id); + HMI_DEBUG("Add surface proxy mapping for %p (%u)", p, id); this->surface_proxy_to_id[uintptr_t(p)] = id; this->sprops[id].id = id; } void controller::remove_proxy_to_sid_mapping(struct ivi_wm *p) { - HMI_DEBUG("wm", "Remove surface proxy mapping for %p", p); + HMI_DEBUG("Remove surface proxy mapping for %p", p); this->surface_proxy_to_id.erase(uintptr_t(p)); } void controller::add_proxy_to_lid_mapping(struct ivi_wm *p, uint32_t id) { - HMI_DEBUG("wm", "Add layer proxy mapping for %p (%u)", p, id); + HMI_DEBUG("Add layer proxy mapping for %p (%u)", p, id); this->layer_proxy_to_id[uintptr_t(p)] = id; this->lprops[id].id = id; } void controller::remove_proxy_to_lid_mapping(struct ivi_wm *p) { - HMI_DEBUG("wm", "Remove layer proxy mapping for %p", p); + HMI_DEBUG("Remove layer proxy mapping for %p", p); this->layer_proxy_to_id.erase(uintptr_t(p)); } void controller::add_proxy_to_id_mapping(struct wl_output *p, uint32_t id) { - HMI_DEBUG("wm", "Add screen proxy mapping for %p (%u)", p, id); + HMI_DEBUG("Add screen proxy mapping for %p (%u)", p, id); this->screen_proxy_to_id[uintptr_t(p)] = id; } void controller::remove_proxy_to_id_mapping(struct wl_output *p) { - HMI_DEBUG("wm", "Remove screen proxy mapping for %p", p); + HMI_DEBUG("Remove screen proxy mapping for %p", p); this->screen_proxy_to_id.erase(uintptr_t(p)); } diff --git a/src/wayland_ivi_wm.hpp b/src/wayland_ivi_wm.hpp index b515a06..d8915a1 100644 --- a/src/wayland_ivi_wm.hpp +++ b/src/wayland_ivi_wm.hpp @@ -166,6 +166,7 @@ struct surface_properties int32_t orientation; int32_t visibility; float opacity; + uint32_t pid; }; /** diff --git a/src/window_manager.cpp b/src/window_manager.cpp index 42930dc..31caebf 100644 --- a/src/window_manager.cpp +++ b/src/window_manager.cpp @@ -16,6 +16,7 @@ #include <fstream> #include <regex> +#include <sstream> #include "window_manager.hpp" #include "json_helper.hpp" @@ -26,6 +27,9 @@ extern "C" #include <systemd/sd-event.h> } +using std::string; +using std::vector; + namespace wm { @@ -53,54 +57,33 @@ const char kKeyHeightMm[] = "height_mm"; const char kKeyScale[] = "scale"; const char kKeyIds[] = "ids"; +static const char kPathOldRolesConfigFile[] = "/etc/old_roles.json"; + static sd_event_source *g_timer_ev_src = nullptr; static AppList g_app_list; static WindowManager *g_context; -namespace -{ - -using nlohmann::json; - -result<json> file_to_json(char const *filename) -{ - json j; - std::ifstream i(filename); - if (i.fail()) - { - HMI_DEBUG("wm", "Could not open config file, so use default layer information"); - j = default_layers_json; - } - else - { - i >> j; - } - - return Ok(j); -} +struct AfbClosure { +public: + AfbClosure(unsigned pid, unsigned ppid, unsigned surface) + : pid(pid), ppid(ppid), surface(surface) {} + ~AfbClosure() = default; + unsigned pid; + unsigned ppid; + unsigned surface; +}; -struct result<layer_map> load_layer_map(char const *filename) +namespace { - HMI_DEBUG("wm", "loading IDs from %s", filename); - - auto j = file_to_json(filename); - if (j.is_err()) - { - return Err<layer_map>(j.unwrap_err()); - } - json jids = j.unwrap(); - - return to_layer_map(jids); -} static int processTimerHandler(sd_event_source *s, uint64_t usec, void *userdata) { - HMI_NOTICE("wm", "Time out occurs because the client replys endDraw slow, so revert the request"); + HMI_NOTICE("Time out occurs because the client replys endDraw slow, so revert the request"); reinterpret_cast<wm::WindowManager *>(userdata)->timerHandler(); return 0; } -static void onStateTransitioned(std::vector<WMAction> actions) +static void onStateTransitioned(vector<WMAction> actions) { g_context->startTransitionWrapper(actions); } @@ -109,134 +92,90 @@ static void onError() { g_context->processError(WMError::LAYOUT_CHANGE_FAIL); } + +static void onReceiveRemoteRequest(json_object *data) +{ + g_context->processForRemoteRequest(data); +} } // namespace /** * WindowManager Impl */ -WindowManager::WindowManager(wl::display *d) - : chooks{this}, - display{d}, - controller{}, - outputs(), - layers(), - id_alloc{}, - pending_events(false) -{ - char const *path_layers_json = getenv("AFM_APP_INSTALL_DIR"); - std::string path; - if (!path_layers_json) - { - HMI_ERROR("wm", "AFM_APP_INSTALL_DIR is not defined"); - path = std::string(path_layers_json); - } - else +WindowManager::WindowManager() + : wmcon{}, + id_alloc{} +{ + const char *path = getenv("AFM_APP_INSTALL_DIR"); + if (!path) { - path = std::string(path_layers_json) + std::string("/etc/layers.json"); + HMI_ERROR("AFM_APP_INSTALL_DIR is not defined"); } + string root = path; - try - { - { - auto l = load_layer_map(path.c_str()); - if (l.is_ok()) - { - this->layers = l.unwrap(); - } - else - { - HMI_ERROR("wm", "%s", l.err().value()); - } - } - } - catch (std::exception &e) - { - HMI_ERROR("wm", "Loading of configuration failed: %s", e.what()); - } + // TODO: ECU name should be decide by config file + // Get mode and decide ECU name + string ecu_name = this->wmcon.getEcuName(); + + this->lc = std::make_shared<LayerControl>(root, ecu_name); + + HMI_DEBUG("Layer Controller initialized"); } int WindowManager::init() { - if (!this->display->ok()) - { - return -1; - } - - if (this->layers.mapping.empty()) - { - HMI_ERROR("wm", "No surface -> layer mapping loaded"); - return -1; - } + LayerControlCallbacks lmcb; + lmcb.surfaceCreated = [&](unsigned pid, unsigned surface){ + this->surface_created(pid, surface); + }; + lmcb.surfaceDestroyed = [&](unsigned surface){ + this->surface_removed(surface); + }; + this->lc->init(lmcb); // TODO: application requests by old role, // so create role map (old, new) - // Load old_role.db - this->loadOldRoleDb(); + // Load old_roles config file + this->loadOldRolesConfigFile(); + + // Initialize LowCanClient + this->lcc.initialize(); // Store my context for calling callback from PolicyManager g_context = this; // Initialize PMWrapper - this->pmw.initialize(); + this->pmw.initialize(this->wmcon.getEcuName()); // Register callback to PolicyManager this->pmw.registerCallback(onStateTransitioned, onError); + // Initialize WMConnection + this->wmcon.initialize(); + + // Register callback to WMConnection + this->wmcon.registerCallback(onReceiveRemoteRequest); + // Make afb event for (int i = Event_Val_Min; i <= Event_Val_Max; i++) { map_afb_event[kListEventName[i]] = afb_daemon_make_event(kListEventName[i]); } - this->display->add_global_handler( - "wl_output", [this](wl_registry *r, uint32_t name, uint32_t v) { - this->outputs.emplace_back(std::make_unique<wl::output>(r, name, v)); - }); - - this->display->add_global_handler( - "ivi_wm", [this](wl_registry *r, uint32_t name, uint32_t v) { - this->controller = - std::make_unique<struct compositor::controller>(r, name, v); - - // Init controller hooks - this->controller->chooks = &this->chooks; - - // This protocol needs the output, so lets just add our mapping here... - this->controller->add_proxy_to_id_mapping( - this->outputs.front()->proxy.get(), - wl_proxy_get_id(reinterpret_cast<struct wl_proxy *>( - this->outputs.front()->proxy.get()))); - - // Create screen - this->controller->create_screen(this->outputs.front()->proxy.get()); + const struct rect css_bg = this->lc->getAreaSize("fullscreen"); + Screen screen = this->lc->getScreenInfo(); + rectangle dp_bg(screen.width(), screen.height()); - // Set display to controller - this->controller->display = this->display; - }); - - // First level objects - this->display->roundtrip(); - // Second level objects - this->display->roundtrip(); - // Third level objects - this->display->roundtrip(); + dp_bg.set_aspect(static_cast<double>(css_bg.w) / css_bg.h); + dp_bg.fit(screen.width(), screen.height()); + dp_bg.center(screen.width(), screen.height()); + HMI_DEBUG("SCALING: CSS BG(%dx%d) -> DDP %dx%d,(%dx%d)", + css_bg.w, css_bg.h, dp_bg.left(), dp_bg.top(), dp_bg.width(), dp_bg.height()); - return init_layers(); -} + double scale = static_cast<double>(dp_bg.height()) / css_bg.h; + this->lc->setupArea(dp_bg, scale); -int WindowManager::dispatch_pending_events() -{ - if (this->pop_pending_events()) - { - this->display->dispatch_pending(); - return 0; - } - return -1; -} - -void WindowManager::set_pending_events() -{ - this->pending_events.store(true, std::memory_order_release); + return 0; //init_layers(); } result<int> WindowManager::api_request_surface(char const *appid, char const *drawing_name) @@ -244,42 +183,52 @@ result<int> WindowManager::api_request_surface(char const *appid, char const *dr // TODO: application requests by old role, // so convert role old to new const char *role = this->convertRoleOldToNew(drawing_name); + string l_name; + string s_appid = appid; + string s_role = role; - auto lid = this->layers.get_layer_id(std::string(role)); - if (!lid) + if(!g_app_list.contains(s_appid)) { - /** - * register drawing_name as fallback and make it displayed. - */ - lid = this->layers.get_layer_id(std::string("fallback")); - HMI_DEBUG("wm", "%s is not registered in layers.json, then fallback as normal app", role); - if (!lid) + // auto lid = this->layers.get_layer_id(string(role)); + unsigned l_id = this->lc->getNewLayerID(s_role, &l_name); + if (l_id == 0) + { + /** + * register drawing_name as fallback and make it displayed. + */ + l_id = this->lc->getNewLayerID("fallback", &l_name); + HMI_DEBUG("%s is not registered in layers.json, then fallback as normal app", role); + if (l_id == 0) + { + return Err<int>("Designated role does not match any role, fallback is disabled"); + } + } + + // TODO: remote layer size is fixed value + if ("Remote" == l_name) { - return Err<int>("Drawing name does not match any role, fallback is disabled"); + this->lc->createNewRemoteLayer(l_id); } + else + { + this->lc->createNewLayer(l_id); + } + + // add client into the db + g_app_list.addClient(s_appid, l_id, s_role); } - auto rname = this->lookup_id(role); + // generate surface ID for ivi-shell application + + auto rname = this->id_alloc.lookup(string(role)); if (!rname) { // name does not exist yet, allocate surface id... auto id = int(this->id_alloc.generate_id(role)); - this->layers.add_surface(id, *lid); - - // set the main_surface[_name] here and now - if (!this->layers.main_surface_name.empty() && - this->layers.main_surface_name == drawing_name) - { - this->layers.main_surface = id; - HMI_DEBUG("wm", "Set main_surface id to %u", id); - } - - // add client into the db - std::string appid_str(appid); - g_app_list.addClient(appid_str, *lid, id, std::string(role)); + this->tmp_surface2app[id] = {s_appid, 0}; // Set role map of (new, old) - this->rolenew2old[role] = std::string(drawing_name); + this->rolenew2old[role] = string(drawing_name); return Ok<int>(id); } @@ -291,30 +240,61 @@ result<int> WindowManager::api_request_surface(char const *appid, char const *dr char const *WindowManager::api_request_surface(char const *appid, char const *drawing_name, char const *ivi_id) { - ST(); + unsigned sid = std::stol(ivi_id); + + HMI_DEBUG("This API(requestSurfaceXDG) is for XDG Application using runXDG"); + /* + * IVI-shell doesn't send surface_size event via ivi-wm protocol + * if the application is using XDG surface. + * So WM has to set surface size with original size here + */ + WMError ret = this->lc->setXDGSurfaceOriginSize(sid); + if(ret != SUCCESS) + { + HMI_ERROR("%s", errorDescription(ret)); + HMI_WARNING("The main user of this API is runXDG"); + return "fail"; + } // TODO: application requests by old role, // so convert role old to new const char *role = this->convertRoleOldToNew(drawing_name); + string s_role = role; + string s_appid = appid; + string l_name; - auto lid = this->layers.get_layer_id(std::string(role)); - unsigned sid = std::stol(ivi_id); - - if (!lid) + if(!g_app_list.contains(s_appid)) { - /** - * register drawing_name as fallback and make it displayed. - */ - lid = this->layers.get_layer_id(std::string("fallback")); - HMI_DEBUG("wm", "%s is not registered in layers.json, then fallback as normal app", role); - if (!lid) + // auto lid = this->layers.get_layer_id(string(role)); + unsigned l_id = this->lc->getNewLayerID(s_role, &l_name); + if (l_id == 0) { - return "Drawing name does not match any role, fallback is disabled"; + /** + * register drawing_name as fallback and make it displayed. + */ + l_id = this->lc->getNewLayerID("fallback", &l_name); + HMI_DEBUG("%s is not registered in layers.json, then fallback as normal app", role); + if (l_id == 0) + { + return "Designated role does not match any role, fallback is disabled"; + } + } + + // TODO: remote layer size is fixed value + if ("Remote" == l_name) + { + this->lc->createNewRemoteLayer(l_id); + } + else + { + this->lc->createNewLayer(l_id); } - } - auto rname = this->lookup_id(role); + // add client into the db + g_app_list.addClient(s_appid, l_id, s_role); + } + auto rname = this->id_alloc.lookup(s_role); if (rname) { return "Surface already present"; @@ -322,45 +302,149 @@ char const *WindowManager::api_request_surface(char const *appid, char const *dr // register pair drawing_name and ivi_id this->id_alloc.register_name_id(role, sid); - this->layers.add_surface(sid, *lid); - - // this surface is already created - HMI_DEBUG("wm", "surface_id is %u, layer_id is %u", sid, *lid); - this->controller->layers[*lid]->add_surface(sid); - this->layout_commit(); - - // add client into the db - std::string appid_str(appid); - g_app_list.addClient(appid_str, *lid, sid, std::string(role)); + auto client = g_app_list.lookUpClient(s_appid); + client->addSurface(sid); // Set role map of (new, old) - this->rolenew2old[role] = std::string(drawing_name); + this->rolenew2old[role] = string(drawing_name); return nullptr; } +bool WindowManager::api_set_role(char const *appid, char const *drawing_name) +{ + bool ret = false; + + // TODO: application requests by old role, + // so convert role old to new + const char *role = this->convertRoleOldToNew(drawing_name); + string s_role = role; + string s_appid = appid; + string l_name; + + // Create WMClient + if(!g_app_list.contains(s_appid)) + { + // auto lid = this->layers.get_layer_id(string(role)); + unsigned l_id = this->lc->getNewLayerID(s_role, &l_name); + if (l_id == 0) + { + /** + * register drawing_name as fallback and make it displayed. + */ + l_id = this->lc->getNewLayerID("fallback", &l_name); + HMI_DEBUG("%s is not registered in layers.json, then fallback as normal app", role); + if (l_id == 0) + { + HMI_ERROR("Designated role does not match any role, fallback is disabled"); + return ret; + } + } + + // TODO: remote layer size is fixed value + if ("Remote" == l_name) + { + this->lc->createNewRemoteLayer(l_id); + } + else + { + this->lc->createNewLayer(l_id); + } + + // add client into the db + g_app_list.addClient(s_appid, l_id, s_role); + // Set role map of (new, old) + this->rolenew2old[role] = string(drawing_name); + } + + // for(auto itr = this->tmp_surface2app.begin(); + // itr != this->tmp_surface2app.end() ; ++itr) + // { + for(auto& x : this->tmp_surface2app) + { + if(x.second.appid == s_appid) + { + unsigned surface = x.first; + auto client = g_app_list.lookUpClient(s_appid); + client->addSurface(surface); + this->tmp_surface2app.erase(surface); + this->id_alloc.register_name_id(s_role, surface); + break; + } + } + +/* if(0 != pid){ + // search floating surfaceID from pid if pid is designated. + wm_err = g_app_list.popFloatingSurface(pid, &surface); + } + else{ + // get floating surface with appid. If WM queries appid from pid, + // WM can bind surface and role with appid(not implemented yet) + //wm_err = g_app_list.popFloatingSurface(id); + } + if(wm_err != WMError::SUCCESS){ + HMI_ERROR("No floating surface for app: %s", id.c_str()); + g_app_list.addFloatingClient(id, lid, role); + HMI_NOTICE("%s : Waiting for surface creation", id.c_str()); + return ret; + } + + ret = true; + if (g_app_list.contains(id)) + { + HMI_INFO("Add role: %s with surface: %d. Client %s has multi surfaces.", + role.c_str(), surface, id.c_str()); + auto client = g_app_list.lookUpClient(id); + client->appendRole(role); + } + else{ + HMI_INFO("Create new client: %s, surface: %d into layer: %d with role: %s", + id.c_str(), surface, lid, role.c_str()); + g_app_list.addClient(id, lid, role); + } */ + + // register pair drawing_name and ivi_id + + return true; +} + void WindowManager::api_activate_surface(char const *appid, char const *drawing_name, char const *drawing_area, const reply_func &reply) { - ST(); - // TODO: application requests by old role, // so convert role old to new const char *c_role = this->convertRoleOldToNew(drawing_name); - std::string id = appid; - std::string role = c_role; - std::string area = drawing_area; + string id = appid; + string role = c_role; + string area = drawing_area; + + if(!g_app_list.contains(id)) + { + reply("app doesn't request 'requestSurface' or 'setRole' yet"); + return; + } + auto client = g_app_list.lookUpClient(id); + + // unsigned srfc = client->surfaceID(role); + // unsigned layer = client->layerID(); + + // g_app_list.removeFloatingSurface(client->surfaceID()); + // g_app_list.removeFloatingSurface(client); + Task task = Task::TASK_ALLOCATE; unsigned req_num = 0; WMError ret = WMError::UNKNOWN; ret = this->setRequest(id, role, area, task, &req_num); + //vector<WMLayerState> current_states = this->lc->getCurrentStates(); + // ret = this->setRequest(id, role, area, task, current_states, &req_num); + if(ret != WMError::SUCCESS) { - HMI_ERROR("wm", errorDescription(ret)); + HMI_ERROR(errorDescription(ret)); reply("Failed to set request"); return; } @@ -376,7 +460,7 @@ void WindowManager::api_activate_surface(char const *appid, char const *drawing_ /* * Do allocate tasks */ - ret = this->doTransition(req_num); + ret = this->checkPolicy(req_num); if (ret != WMError::SUCCESS) { @@ -387,11 +471,188 @@ void WindowManager::api_activate_surface(char const *appid, char const *drawing_ } } +void WindowManager::api_activate_surface_for_slave( + char const *appid, char const *drawing_name, + char const *drawing_area, const reply_func &reply) +{ + // TODO: application requests by old role, + // so convert role old to new + const char *c_role = this->convertRoleOldToNew(drawing_name); + + string id = appid; + string role = c_role; + string area = drawing_area; + + if(!g_app_list.contains(id)) + { + // Request surface of app in slave to register app information + this->api_request_surface(appid, drawing_name); + + // Set role of app in slave to register app information + this->api_set_role(appid, drawing_name); + } + auto client = g_app_list.lookUpClient(id); + + // unsigned srfc = client->surfaceID(role); + // unsigned layer = client->layerID(); + + // g_app_list.removeFloatingSurface(client->surfaceID()); + // g_app_list.removeFloatingSurface(client); + + Task task = Task::TASK_ALLOCATE; + unsigned req_num = 0; + WMError ret = WMError::UNKNOWN; + + ret = this->setRequestForSlave(id, role, area, task, &req_num); + + //vector<WMLayerState> current_states = this->lc->getCurrentStates(); + // ret = this->setRequest(id, role, area, task, current_states, &req_num); + + if(ret != WMError::SUCCESS) + { + HMI_ERROR(errorDescription(ret)); + reply("Failed to set request"); + return; + } + + reply(nullptr); + if (req_num != g_app_list.currentRequestNumber()) + { + // Add request, then invoked after the previous task is finished + HMI_SEQ_DEBUG(req_num, "request is accepted"); + return; + } + + /* + * Do allocate tasks + */ + ret = this->checkPolicyForSlave(req_num); + + if (ret != WMError::SUCCESS) + { + //this->emit_error() + HMI_SEQ_ERROR(req_num, errorDescription(ret)); + g_app_list.removeRequest(req_num); + this->processNextRequest(); + } +} + +void WindowManager::api_activate_surface_to_master( + char const *appid, char const *drawing_name, + char const *drawing_area, const reply_func &reply) +{ + // TODO: application requests by old role, + // so convert role old to new + const char *c_role = this->convertRoleOldToNew(drawing_name); + + string id = appid; + string role = c_role; + string area = drawing_area; + + if(!g_app_list.contains(id)) + { + reply("app doesn't request 'requestSurface' or 'setRole' yet"); + return; + } + auto client = g_app_list.lookUpClient(id); + + // unsigned srfc = client->surfaceID(role); + // unsigned layer = client->layerID(); + + // g_app_list.removeFloatingSurface(client->surfaceID()); + // g_app_list.removeFloatingSurface(client); + + Task task = Task::TASK_ALLOCATE; + unsigned req_num = 0; + WMError ret = WMError::UNKNOWN; + + ret = this->setRequest(id, role, area, task, &req_num); + + //vector<WMLayerState> current_states = this->lc->getCurrentStates(); + // ret = this->setRequest(id, role, area, task, current_states, &req_num); + + if(ret != WMError::SUCCESS) + { + HMI_ERROR(errorDescription(ret)); + reply("Failed to set request"); + return; + } + + reply(nullptr); + if (req_num != g_app_list.currentRequestNumber()) + { + // Add request, then invoked after the previous task is finished + HMI_SEQ_DEBUG(req_num, "request is accepted"); + return; + } + + /* + * Do allocate tasks + */ + int i_ret = this->wmcon.sendRequest("activateWindow", appid, + drawing_name, drawing_area); + if (0 > i_ret) + { + //this->emit_error() + HMI_SEQ_ERROR(req_num, errorDescription(ret)); + g_app_list.removeRequest(req_num); + this->processNextRequest(); + } + + this->setTimer(); +} + void WindowManager::api_deactivate_surface(char const *appid, char const *drawing_name, const reply_func &reply) { - ST(); + // TODO: application requests by old role, + // so convert role old to new + const char *c_role = this->convertRoleOldToNew(drawing_name); + + /* + * Check Phase + */ + string id = appid; + string role = c_role; + string area = ""; //drawing_area; + Task task = Task::TASK_RELEASE; + unsigned req_num = 0; + WMError ret = WMError::UNKNOWN; + + ret = this->setRequest(id, role, area, task, &req_num); + if (ret != WMError::SUCCESS) + { + HMI_ERROR(errorDescription(ret)); + reply("Failed to set request"); + return; + } + + reply(nullptr); + if (req_num != g_app_list.currentRequestNumber()) + { + // Add request, then invoked after the previous task is finished + HMI_SEQ_DEBUG(req_num, "request is accepted"); + return; + } + + /* + * Do allocate tasks + */ + ret = this->checkPolicy(req_num); + + if (ret != WMError::SUCCESS) + { + //this->emit_error() + HMI_SEQ_ERROR(req_num, errorDescription(ret)); + g_app_list.removeRequest(req_num); + this->processNextRequest(); + } +} + +void WindowManager::api_deactivate_surface_for_slave(char const *appid, char const *drawing_name, + const reply_func &reply) +{ // TODO: application requests by old role, // so convert role old to new const char *c_role = this->convertRoleOldToNew(drawing_name); @@ -399,9 +660,9 @@ void WindowManager::api_deactivate_surface(char const *appid, char const *drawin /* * Check Phase */ - std::string id = appid; - std::string role = c_role; - std::string area = ""; //drawing_area; + string id = appid; + string role = c_role; + string area = "";//drawing_area; Task task = Task::TASK_RELEASE; unsigned req_num = 0; WMError ret = WMError::UNKNOWN; @@ -410,7 +671,7 @@ void WindowManager::api_deactivate_surface(char const *appid, char const *drawin if (ret != WMError::SUCCESS) { - HMI_ERROR("wm", errorDescription(ret)); + HMI_ERROR(errorDescription(ret)); reply("Failed to set request"); return; } @@ -426,15 +687,65 @@ void WindowManager::api_deactivate_surface(char const *appid, char const *drawin /* * Do allocate tasks */ - ret = this->doTransition(req_num); + ret = this->checkPolicyForSlave(req_num); + + if (ret != WMError::SUCCESS) + { + //this->emit_error() + HMI_SEQ_ERROR(req_num, errorDescription(ret)); + g_app_list.removeRequest(req_num); + this->processNextRequest(); + } +} + +void WindowManager::api_deactivate_surface_to_master(char const *appid, char const *drawing_name, + const reply_func &reply) +{ + // TODO: application requests by old role, + // so convert role old to new + const char *c_role = this->convertRoleOldToNew(drawing_name); + + /* + * Check Phase + */ + string id = appid; + string role = c_role; + string area = "";//drawing_area; + Task task = Task::TASK_RELEASE; + unsigned req_num = 0; + WMError ret = WMError::UNKNOWN; + + ret = this->setRequest(id, role, area, task, &req_num); if (ret != WMError::SUCCESS) { + HMI_ERROR(errorDescription(ret)); + reply("Failed to set request"); + return; + } + + reply(nullptr); + if (req_num != g_app_list.currentRequestNumber()) + { + // Add request, then invoked after the previous task is finished + HMI_SEQ_DEBUG(req_num, "request is accepted"); + return; + } + + /* + * Do allocate tasks + */ + int i_ret = this->wmcon.sendRequest("deactivateWindow", appid, + drawing_name, ""); + if (0 > i_ret) + { //this->emit_error() HMI_SEQ_ERROR(req_num, errorDescription(ret)); g_app_list.removeRequest(req_num); this->processNextRequest(); } + + this->setTimer(); } void WindowManager::api_enddraw(char const *appid, char const *drawing_name) @@ -443,14 +754,14 @@ void WindowManager::api_enddraw(char const *appid, char const *drawing_name) // so convert role old to new const char *c_role = this->convertRoleOldToNew(drawing_name); - std::string id = appid; - std::string role = c_role; + string id = appid; + string role = c_role; unsigned current_req = g_app_list.currentRequestNumber(); bool result = g_app_list.setEndDrawFinished(current_req, id, role); if (!result) { - HMI_ERROR("wm", "%s is not in transition state", id.c_str()); + HMI_ERROR("%s is not in transition state", id.c_str()); return; } @@ -466,6 +777,7 @@ void WindowManager::api_enddraw(char const *appid, char const *drawing_name) // Undo state of PolicyManager this->pmw.undoState(); + this->lc->undoUpdate(); } this->emitScreenUpdated(current_req); HMI_SEQ_INFO(current_req, "Finish request status: %s", errorDescription(ret)); @@ -481,55 +793,85 @@ void WindowManager::api_enddraw(char const *appid, char const *drawing_name) } } -result<json_object *> WindowManager::api_get_display_info() +void WindowManager::api_enddraw_for_remote(char const *appid, char const *drawing_name) { - if (!this->display->ok()) + int ret = this->wmcon.sendRequest("endDraw", appid, drawing_name, ""); + if (0 > ret) { - return Err<json_object *>("Wayland compositor is not available"); + //this->emit_error() + + this->pmw.undoState(); + this->lc->undoUpdate(); + + unsigned current_req = g_app_list.currentRequestNumber(); + g_app_list.removeRequest(current_req); + this->processNextRequest(); + + return; } - // Set display info - compositor::size o_size = this->controller->output_size; - compositor::size p_size = this->controller->physical_size; + this->api_enddraw(appid, drawing_name); +} + +bool WindowManager::api_client_set_render_order(char const* appid, const vector<string>& render_order) +{ + bool ret = false; + string id = appid; + auto client = g_app_list.lookUpClient(id); + if(client) + { + client->setRenderOrder(render_order); + } + return ret; +} + +string WindowManager::api_client_attach_service_surface + (const char* appid, const char* dest, const char* service_surface) +{ + string uuid, s_dest = dest; + auto client = g_app_list.lookUpClient(s_dest); + if(!client) + { + HMI_ERROR("Failed to look up destination [%s]", dest); + return uuid; + } + uuid = client->attachTmpServiceSurface(appid, service_surface); + this->tmp_services.emplace_back(TmpService{appid, dest, service_surface, uuid}); + return uuid; +} + +result<json_object *> WindowManager::api_get_display_info() +{ + Screen screen = this->lc->getScreenInfo(); json_object *object = json_object_new_object(); - json_object_object_add(object, kKeyWidthPixel, json_object_new_int(o_size.w)); - json_object_object_add(object, kKeyHeightPixel, json_object_new_int(o_size.h)); - json_object_object_add(object, kKeyWidthMm, json_object_new_int(p_size.w)); - json_object_object_add(object, kKeyHeightMm, json_object_new_int(p_size.h)); - json_object_object_add(object, kKeyScale, json_object_new_double(this->controller->scale)); + json_object_object_add(object, kKeyWidthPixel, json_object_new_int(screen.width())); + json_object_object_add(object, kKeyHeightPixel, json_object_new_int(screen.height())); + // TODO: set size + json_object_object_add(object, kKeyWidthMm, json_object_new_int(0)); + json_object_object_add(object, kKeyHeightMm, json_object_new_int(0)); + json_object_object_add(object, kKeyScale, json_object_new_double(this->lc->scale())); return Ok<json_object *>(object); } result<json_object *> WindowManager::api_get_area_info(char const *drawing_name) { - HMI_DEBUG("wm", "called"); + HMI_DEBUG("called"); // TODO: application requests by old role, // so convert role old to new const char *role = this->convertRoleOldToNew(drawing_name); // Check drawing name, surface/layer id - auto const &surface_id = this->lookup_id(role); + auto const &surface_id = this->id_alloc.lookup(string(role)); if (!surface_id) { return Err<json_object *>("Surface does not exist"); } - if (!this->controller->surface_exists(*surface_id)) - { - return Err<json_object *>("Surface does not exist in controller!"); - } - - auto layer_id = this->layers.get_layer_id(*surface_id); - if (!layer_id) - { - return Err<json_object *>("Surface is not on any layer!"); - } - // Set area rectangle - compositor::rect area_info = this->area_info[*surface_id]; + rect area_info = this->area_info[*surface_id]; json_object *object = json_object_new_object(); json_object_object_add(object, kKeyX, json_object_new_int(area_info.x)); json_object_object_add(object, kKeyY, json_object_new_int(area_info.y)); @@ -539,11 +881,60 @@ result<json_object *> WindowManager::api_get_area_info(char const *drawing_name) return Ok<json_object *>(object); } -void WindowManager::api_ping() { this->dispatch_pending_events(); } +result<json_object *> WindowManager::api_get_car_info(char const *label) +{ + json_object *j_in = nullptr; + json_object *j_out = nullptr; + + if (0 == strcmp("parking_brake_status", label)) + { + // Get parking brake status + json_bool val = (this->crr_car_info.parking_brake_stt) ? TRUE : FALSE; + j_in = json_object_new_boolean(val); + } + else if (0 == strcmp("accelerator.pedal.position", label)) + { + // Get accelerator pedal position + double val = this->crr_car_info.accel_pedal_pos; + j_in = json_object_new_double(val); + } + else if (0 == strcmp("car_state", label)) + { + // Get running state + const char* val = (this->crr_car_info.running_stt) ? "run" : "stop"; + j_in = json_object_new_string(val); + } + else if (0 == strcmp("lightstatus.brake", label)) { + // Get lightstatus brake status + json_bool val = (this->crr_car_info.lightstatus_brake_stt) ? TRUE : FALSE; + j_in = json_object_new_boolean(val); + } + else + { + return Err<json_object *>("Car info does not exist"); + } + + // Create output object + j_out = json_object_new_object(); + json_object_object_add(j_out, "value", j_in); + + return Ok<json_object *>(j_out); +} + +void WindowManager::send_event(char const *evname) +{ + HMI_DEBUG("%s: %s", __func__, evname); + + int ret = afb_event_push(this->map_afb_event[evname], nullptr); + if (ret != 0) + { + HMI_DEBUG("afb_event_push: %m"); + } +} void WindowManager::send_event(char const *evname, char const *label) { - HMI_DEBUG("wm", "%s: %s(%s)", __func__, evname, label); + HMI_DEBUG("%s: %s(%s)", __func__, evname, label); json_object *j = json_object_new_object(); json_object_object_add(j, kKeyDrawingName, json_object_new_string(label)); @@ -551,14 +942,14 @@ void WindowManager::send_event(char const *evname, char const *label) int ret = afb_event_push(this->map_afb_event[evname], j); if (ret != 0) { - HMI_DEBUG("wm", "afb_event_push failed: %m"); + HMI_DEBUG("afb_event_push failed: %m"); } } void WindowManager::send_event(char const *evname, char const *label, char const *area, int x, int y, int w, int h) { - HMI_DEBUG("wm", "%s: %s(%s, %s) x:%d y:%d w:%d h:%d", + HMI_DEBUG("%s: %s(%s, %s) x:%d y:%d w:%d h:%d", __func__, evname, label, area, x, y, w, h); json_object *j_rect = json_object_new_object(); @@ -575,42 +966,159 @@ void WindowManager::send_event(char const *evname, char const *label, char const int ret = afb_event_push(this->map_afb_event[evname], j); if (ret != 0) { - HMI_DEBUG("wm", "afb_event_push failed: %m"); + HMI_DEBUG("afb_event_push failed: %m"); + } +} + +string WindowManager::searchApp(unsigned pid, unsigned ppid, unsigned surface, json_object* resp) +{ + // retrieve appid from pid from application manager + string appid; + // check appid then add it to the client + HMI_INFO("Runners:%s", json_object_get_string(resp)); + int size = json_object_array_length(resp); + HMI_INFO("pid %d, ppid %d, surface %d",pid, ppid, surface); + for(int i = 0; i < size; i++) + { + json_object *j = json_object_array_get_idx(resp, i); + int runid = jh::getIntFromJson(j, "runid"); + const char* id = jh::getStringFromJson(j, "id"); + HMI_DEBUG("Appid %s, runid %d", id, runid); + if(id && (runid == ppid)) + { + string s_id = id; + s_id.erase(s_id.find('@')); + appid = s_id; + HMI_INFO("App found %s", appid.c_str()); + break; + } + } + if(appid.empty()) + { + HMI_WARNING("Failed to retrieve id"); + } + return appid; +} + +void WindowManager::storeSurface(const string& appid, unsigned ppid, unsigned surface) +{ + auto elem = std::find_if(this->tmp_services.begin(), this->tmp_services.end(), + [&appid](TmpService& ts){ + return (ts.dest == appid ); + }); + + this->lc->setXDGSurfaceOriginSize(surface); + if(elem != this->tmp_services.end()) + { + // attachApp + auto client = g_app_list.lookUpClient(elem->dest); + if(client == nullptr) + { + return; + } + HMI_INFO("Attach surface %d (service %s) to app %s", surface, elem->service.c_str(), elem->dest.c_str()); + client->attachServiceSurface(elem->service, surface); + } + else + { + // setRole + auto client = g_app_list.lookUpClient(appid); + if(client != nullptr) + { + client->addSurface(surface); + this->id_alloc.register_name_id(client->role(), surface); + } + else + { + // Store tmp surface and appid for application + // who requests setRole after creating shell surface + this->tmp_surface2app.emplace(surface, TmpClient{appid, ppid}); + } } } /** * proxied events */ -void WindowManager::surface_created(uint32_t surface_id) +void WindowManager::surface_created(unsigned pid, unsigned surface_id) { - this->controller->get_surface_properties(surface_id, IVI_WM_PARAM_SIZE); - - auto layer_id = this->layers.get_layer_id(surface_id); - if (!layer_id) + // requestSurface + if(this->tmp_surface2app.count(surface_id) != 0) { - HMI_DEBUG("wm", "Newly created surfce %d is not associated with any layer!", - surface_id); - return; + string appid = this->tmp_surface2app[surface_id].appid; + auto client = g_app_list.lookUpClient(appid); + if(client != nullptr) + { + WMError ret = client->addSurface(surface_id); + HMI_INFO("Add surface %d to \"%s\"", surface_id, appid.c_str()); + if(ret != WMError::SUCCESS) + { + HMI_ERROR("Failed to add surface to client %s", client->appID().c_str()); + } + } + this->tmp_surface2app.erase(surface_id); + } + else + { + HMI_NOTICE("Unknown surface %d", surface_id); + // retrieve ppid + std::ostringstream os; + os << pid ; + string path = "/proc/" + os.str() + "/stat"; + std::ifstream ifs(path.c_str()); + string str; + unsigned ppid = 0; + if(!ifs.fail() && std::getline(ifs, str)) + { + std::sscanf(str.data(), "%*d %*s %*c %d", &ppid); + HMI_INFO("Retrieve ppid %d", ppid); + } + else + { + HMI_ERROR("Failed to open /proc/%d/stat", pid); + HMI_ERROR("File system may be different"); + return; + } + struct AfbClosure* c = new struct AfbClosure(pid, ppid, surface_id); + // search pid from surfaceID + afb_service_call("afm-main", "runners", json_object_new_object(), + [](void* closure, int stat, json_object* resp){ + HMI_DEBUG("check %s", json_object_get_string(resp)); + struct AfbClosure* c = static_cast<struct AfbClosure*>(closure); + HMI_DEBUG("check"); + if(stat != 0) + { + HMI_ERROR("Failed to call runners"); + } + else + { + json_object* j; + json_object_object_get_ex(resp, "response", &j); + string appid = g_context->searchApp(c->pid, c->ppid, c->surface, j); + if(!appid.empty()) + { + g_context->storeSurface(appid, c->ppid, c->surface); + } + } + json_object_put(resp); + delete c; + }, c); } - - HMI_DEBUG("wm", "surface_id is %u, layer_id is %u", surface_id, *layer_id); - - this->controller->layers[*layer_id]->add_surface(surface_id); - this->layout_commit(); } -void WindowManager::surface_removed(uint32_t surface_id) +void WindowManager::surface_removed(unsigned surface_id) { - HMI_DEBUG("wm", "Delete surface_id %u", surface_id); + HMI_DEBUG("Delete surface_id %u", surface_id); this->id_alloc.remove_id(surface_id); - this->layers.remove_surface(surface_id); + // this->layers.remove_surface(surface_id); g_app_list.removeSurface(surface_id); } -void WindowManager::removeClient(const std::string &appid) +void WindowManager::removeClient(const string &appid) { - HMI_DEBUG("wm", "Remove clinet %s from list", appid.c_str()); + HMI_DEBUG("Remove clinet %s from list", appid.c_str()); + auto client = g_app_list.lookUpClient(appid); + this->lc->terminateApp(client); g_app_list.removeClient(appid); } @@ -623,6 +1131,25 @@ void WindowManager::exceptionProcessForTransition() this->processNextRequest(); } +void WindowManager::analyzeReceivedEvent(const char *event, struct json_object *object) +{ + HMI_DEBUG("event:%s", event); + + // If receive low can signal + if (strstr(event, "low-can")) + { + // Analyze low can signal + const char *signal_name = this->lcc.analyzeCanSignal(object); + + // Create task for car state and input it to PolicyManager + Task task = this->convertCanSignalToCarStateTask(signal_name); + if (Task::TASK_INVALID != task) + { + this->inputCarStateTask(task); + } + } +} + void WindowManager::timerHandler() { unsigned req_num = g_app_list.currentRequestNumber(); @@ -632,10 +1159,12 @@ void WindowManager::timerHandler() this->processNextRequest(); } -void WindowManager::startTransitionWrapper(std::vector<WMAction> &actions) +void WindowManager::startTransitionWrapper(vector<WMAction> &actions) { - WMError ret; + WMError ret = WMError::UNKNOWN; + // req_num is guaranteed by Window Manager unsigned req_num = g_app_list.currentRequestNumber(); + Task task = Task::TASK_INVALID; if (actions.empty()) { @@ -651,32 +1180,83 @@ void WindowManager::startTransitionWrapper(std::vector<WMAction> &actions) } } + // Check weather there is the no request task + // [The no request task] + // - TaskCarState::RESTRICTION_MODE_OFF + // - TaskCarState::RESTRICTION_MODE_ON + for (const auto &act : actions) + { + if (TaskCarState::RESTRICTION_MODE_OFF == act.car_state) + { + task = Task::TASK_RESTRICTION_MODE_OFF; + break; + } + else if (TaskCarState::RESTRICTION_MODE_ON == act.car_state) + { + task = Task::TASK_RESTRICTION_MODE_ON; + break; + } + } + + // If there is the request-less task, set request here + if (Task::TASK_INVALID != task) { + unsigned req_num; + ret = this->setRequest(task, &req_num); + + if(ret != WMError::SUCCESS) + { + goto error; + } + } + for (auto &act : actions) { if ("" != act.role) { bool found; - auto const &surface_id = this->lookup_id(act.role.c_str()); + auto const &surface_id = this->id_alloc.lookup(act.role.c_str()); if(surface_id == nullopt) { - goto proc_remove_request; + HMI_SEQ_DEBUG(req_num, "There is not surface id for role:%s", act.role.c_str()); + continue; } - std::string appid = g_app_list.getAppID(*surface_id, act.role, &found); + + std::string appid = g_app_list.getAppID(*surface_id, &found); if (!found) { if (TaskVisible::INVISIBLE == act.visible) { - // App is killed, so do not set this action + HMI_SEQ_DEBUG(req_num, "role:%s is killed, so do not set this action", act.role.c_str()); continue; } else { - HMI_SEQ_ERROR(req_num, "appid which is visible is not found"); + HMI_SEQ_ERROR(req_num, "appid of role:%s which is visible is not found", act.role.c_str()); ret = WMError::FAIL; goto error; } } - act.appid = appid; + auto client = g_app_list.lookUpClient(appid); + act.req_num = req_num; + act.client = client; + + // If Window Manager is master and this action is for slave, + // change TaskVisible + if (this->wmcon.isMasterMode()) + { + if (this->wmcon.isMasterArea(act.area.c_str())) + { + HMI_DEBUG("Set TaskVisible::REQ_REMOTE_VISIBLE"); + act.visible = TaskVisible::REQ_REMOTE_VISIBLE; + } + // TODO: Check whether role is tbtnavi to request remote invisible + else if (("tbtnavi" == act.role) && + (TaskVisible::INVISIBLE == act.visible)) + { + HMI_DEBUG("Set TaskVisible::REQ_REMOTE_INVISIBLE"); + act.visible = TaskVisible::REQ_REMOTE_INVISIBLE; + } + } } ret = g_app_list.setAction(req_num, act); @@ -724,147 +1304,156 @@ void WindowManager::processError(WMError error) this->processNextRequest(); } -/* - ******* Private Functions ******* - */ - -bool WindowManager::pop_pending_events() +void WindowManager::processForRemoteRequest(json_object *data) { - bool x{true}; - return this->pending_events.compare_exchange_strong( - x, false, std::memory_order_consume); -} + const char *req = jh::getStringFromJson(data, "req"); + const char *appid = jh::getStringFromJson(data, "appid"); + const char *drawing_name = jh::getStringFromJson(data, "drawing_name"); + const char *drawing_area = jh::getStringFromJson(data, "drawing_area"); -optional<int> WindowManager::lookup_id(char const *name) -{ - return this->id_alloc.lookup(std::string(name)); -} -optional<std::string> WindowManager::lookup_name(int id) -{ - return this->id_alloc.lookup(id); -} - -/** - * init_layers() - */ -int WindowManager::init_layers() -{ - if (!this->controller) + if (!req || !drawing_name) { - HMI_ERROR("wm", "ivi_controller global not available"); - return -1; + HMI_ERROR("Parse Error!!"); + return; } - if (this->outputs.empty()) + if (this->wmcon.isMasterMode()) { - HMI_ERROR("wm", "no output was set up!"); - return -1; - } - - auto &c = this->controller; - - auto &o = this->outputs.front(); - auto &s = c->screens.begin()->second; - auto &layers = c->layers; - - // Write output dimensions to ivi controller... - c->output_size = compositor::size{uint32_t(o->width), uint32_t(o->height)}; - c->physical_size = compositor::size{uint32_t(o->physical_width), - uint32_t(o->physical_height)}; - - - HMI_DEBUG("wm", "SCALING: screen (%dx%d), physical (%dx%d)", - o->width, o->height, o->physical_width, o->physical_height); - - this->layers.loadAreaDb(); - - const compositor::rect css_bg = this->layers.getAreaSize("fullscreen"); - rectangle dp_bg(o->width, o->height); - - dp_bg.set_aspect(static_cast<double>(css_bg.w) / css_bg.h); - dp_bg.fit(o->width, o->height); - dp_bg.center(o->width, o->height); - HMI_DEBUG("wm", "SCALING: CSS BG(%dx%d) -> DDP %dx%d,(%dx%d)", - css_bg.w, css_bg.h, dp_bg.left(), dp_bg.top(), dp_bg.width(), dp_bg.height()); + if (!appid) + { + HMI_ERROR("Parse Error!!"); + return; + } - // Clear scene - layers.clear(); + auto reply = [](const char *errmsg) { + if (errmsg != nullptr) + { + HMI_ERROR(errmsg); + return; + } + }; - // Clear screen - s->clear(); + if ("activateWindow" == std::string(req)) + { + if (!drawing_area) + { + HMI_ERROR("Parse Error!!"); + return; + } - // Quick and dirty setup of layers - for (auto const &i : this->layers.mapping) - { - c->layer_create(i.second.layer_id, dp_bg.width(), dp_bg.height()); - auto &l = layers[i.second.layer_id]; - l->set_destination_rectangle(dp_bg.left(), dp_bg.top(), dp_bg.width(), dp_bg.height()); - l->set_visibility(1); - HMI_DEBUG("wm", "Setting up layer %s (%d) for surface role match \"%s\"", - i.second.name.c_str(), i.second.layer_id, i.second.role.c_str()); + this->api_activate_surface_for_slave( + appid, drawing_name, drawing_area, reply); + } + else if ("deactivateWindow" == std::string(req)) + { + this->api_deactivate_surface_for_slave( + appid, drawing_name, reply); + } + else if ("endDraw" == std::string(req)) + { + this->api_enddraw(appid, drawing_name); + } } - - // Add layers to screen - s->set_render_order(this->layers.layers); - - this->layout_commit(); - - c->scale = static_cast<double>(dp_bg.height()) / css_bg.h; - this->layers.setupArea(c->scale); - - return 0; -} - -void WindowManager::surface_set_layout(int surface_id, const std::string& area) -{ - if (!this->controller->surface_exists(surface_id)) + else { - HMI_ERROR("wm", "Surface %d does not exist", surface_id); - return; - } + if ("syncDraw" == std::string(req)) + { + this->stopTimer(); - auto o_layer_id = this->layers.get_layer_id(surface_id); + if (!appid || !drawing_area) + { + HMI_ERROR("Parse Error!!"); + return; + } - if (!o_layer_id) - { - HMI_ERROR("wm", "Surface %d is not associated with any layer!", surface_id); - return; - } + unsigned req_num = g_app_list.currentRequestNumber(); + auto client = g_app_list.lookUpClient(appid); - uint32_t layer_id = *o_layer_id; + // TODO: application requests by old role, + // so convert role old to new + const char *c_role = this->convertRoleOldToNew(drawing_name); - auto const &layer = this->layers.get_layer(layer_id); - auto rect = this->layers.getAreaSize(area); - HMI_SEQ_DEBUG(g_app_list.currentRequestNumber(), "%s : x:%d y:%d w:%d h:%d", area.c_str(), - rect.x, rect.y, rect.w, rect.h); - auto &s = this->controller->surfaces[surface_id]; + // Create action + bool end_draw_finished = false; + WMAction act + { + req_num, + client, + string(c_role), + string(drawing_area), + TaskVisible::REMOTE_VISIBLE, + end_draw_finished, + TaskCarState::NO_TASK + }; + + // Set action + WMError ret = g_app_list.setAction(req_num, act); + if (ret != WMError::SUCCESS) + { + HMI_SEQ_ERROR(req_num, "Setting action is failed"); + return; + } - int x = rect.x; - int y = rect.y; - int w = rect.w; - int h = rect.h; + this->emit_syncdraw(string(drawing_name), string(drawing_area)); + this->wmcon.startSyncDrawForRemote(appid); + this->setTimer(); + } + else if ("activated" == std::string(req)) + { + this->emit_visible(drawing_name); + this->emit_activated(drawing_name); + } + else if ("deactivated" == std::string(req)) + { + this->stopTimer(); - HMI_DEBUG("wm", "surface_set_layout for surface %u on layer %u", surface_id, - layer_id); + if (!appid || !drawing_area) + { + HMI_ERROR("Parse Error!!"); + return; + } - // set destination to the display rectangle - s->set_destination_rectangle(x, y, w, h); + unsigned req_num = g_app_list.currentRequestNumber(); + auto client = g_app_list.lookUpClient(appid); - // 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; + // TODO: application requests by old role, + // so convert role old to new + const char *c_role = this->convertRoleOldToNew(drawing_name); - HMI_DEBUG("wm", "Surface %u now on layer %u with rect { %d, %d, %d, %d }", - surface_id, layer_id, x, y, w, h); + // Create action + bool end_draw_finished = true; + WMAction act + { + req_num, + client, + string(c_role), + "", + TaskVisible::REMOTE_INVISIBLE, + end_draw_finished, + TaskCarState::NO_TASK + }; + + this->lc->visibilityChange(act); + this->lc->renderLayers(); + this->lc->renderLayersRemote(); + + this->emit_invisible(drawing_name); + this->emit_deactivated(drawing_name); + this->emitScreenUpdated(req_num); + + g_app_list.removeRequest(req_num); + this->processNextRequest(); + } + else if ("flushDraw" == std::string(req)) + { + this->emit_flushdraw(drawing_name); + } + } } -void WindowManager::layout_commit() -{ - this->controller->commit_changes(); - this->display->flush(); -} +/* + ******* Private Functions ******* + */ void WindowManager::emit_activated(char const *label) { @@ -881,11 +1470,11 @@ void WindowManager::emit_syncdraw(char const *label, char const *area, int x, in this->send_event(kListEventName[Event_SyncDraw], label, area, x, y, w, h); } -void WindowManager::emit_syncdraw(const std::string &role, const std::string &area) +void WindowManager::emit_syncdraw(const string &role, const string &area) { - compositor::rect rect = this->layers.getAreaSize(area); + rect rect = this->lc->getAreaSize(area); this->send_event(kListEventName[Event_SyncDraw], - role.c_str(), area.c_str(), rect.x, rect.y, rect.w, rect.h); + role.c_str(), area.c_str(), rect.x, rect.y, rect.w, rect.h); } void WindowManager::emit_flushdraw(char const *label) @@ -905,106 +1494,55 @@ void WindowManager::emit_invisible(char const *label) void WindowManager::emit_visible(char const *label) { return emit_visible(label, true); } -void WindowManager::activate(int id) +void WindowManager::emitHeadlampOff() { - auto ip = this->controller->sprops.find(id); - if (ip != this->controller->sprops.end()) - { - this->controller->surfaces[id]->set_visibility(1); - char const *label = - this->lookup_name(id).value_or("unknown-name").c_str(); - - // FOR CES DEMO >>> - if ((0 == strcmp(label, "radio")) || - (0 == strcmp(label, "music")) || - (0 == strcmp(label, "video")) || - (0 == strcmp(label, "map"))) - { - for (auto i = surface_bg.begin(); i != surface_bg.end(); ++i) - { - if (id == *i) - { - // Remove id - this->surface_bg.erase(i); - - // Remove from BG layer (999) - HMI_DEBUG("wm", "Remove %s(%d) from BG layer", label, id); - this->controller->layers[999]->remove_surface(id); - - // Add to FG layer (1001) - HMI_DEBUG("wm", "Add %s(%d) to FG layer", label, id); - this->controller->layers[1001]->add_surface(id); - - for (int j : this->surface_bg) - { - HMI_DEBUG("wm", "Stored id:%d", j); - } - break; - } - } - } - // <<< FOR CES DEMO - - this->layout_commit(); - - // TODO: application requests by old role, - // so convert role new to old for emitting event - const char* old_role = this->rolenew2old[label].c_str(); - - this->emit_visible(old_role); - this->emit_activated(old_role); - } + // Send HeadlampOff event for all application + this->send_event(kListEventName[Event_HeadlampOff]); } -void WindowManager::deactivate(int id) +void WindowManager::emitHeadlampOn() { - auto ip = this->controller->sprops.find(id); - if (ip != this->controller->sprops.end()) - { - char const *label = - this->lookup_name(id).value_or("unknown-name").c_str(); - - // FOR CES DEMO >>> - if ((0 == strcmp(label, "radio")) || - (0 == strcmp(label, "music")) || - (0 == strcmp(label, "video")) || - (0 == strcmp(label, "map"))) - { - - // Store id - this->surface_bg.push_back(id); + // Send HeadlampOn event for all application + this->send_event(kListEventName[Event_HeadlampOn]); +} - // Remove from FG layer (1001) - HMI_DEBUG("wm", "Remove %s(%d) from FG layer", label, id); - this->controller->layers[1001]->remove_surface(id); +void WindowManager::emitParkingBrakeOff() +{ + // Send ParkingBrakeOff event for all application + this->send_event(kListEventName[Event_ParkingBrakeOff]); +} - // Add to BG layer (999) - HMI_DEBUG("wm", "Add %s(%d) to BG layer", label, id); - this->controller->layers[999]->add_surface(id); +void WindowManager::emitParkingBrakeOn() +{ + // Send ParkingBrakeOn event for all application + this->send_event(kListEventName[Event_ParkingBrakeOn]); +} - for (int j : surface_bg) - { - HMI_DEBUG("wm", "Stored id:%d", j); - } - } - else - { - this->controller->surfaces[id]->set_visibility(0); - } - // <<< FOR CES DEMO +void WindowManager::emitLightstatusBrakeOff() +{ + // Send LightstatusBrakeOff event for all application + this->send_event(kListEventName[Event_LightstatusBrakeOff]); +} - this->layout_commit(); +void WindowManager::emitLightstatusBrakeOn() +{ + // Send LightstatusBrakeOn event for all application + this->send_event(kListEventName[Event_LightstatusBrakeOn]); +} - // TODO: application requests by old role, - // so convert role new to old for emitting event - const char* old_role = this->rolenew2old[label].c_str(); +void WindowManager::emitCarStop() +{ + // Send CarStop event for all application + this->send_event(kListEventName[Event_CarStop]); +} - this->emit_deactivated(old_role); - this->emit_invisible(old_role); - } +void WindowManager::emitCarRun() +{ + // Send CarRun event for all application + this->send_event(kListEventName[Event_CarRun]); } -WMError WindowManager::setRequest(const std::string& appid, const std::string &role, const std::string &area, +WMError WindowManager::setRequest(const string& appid, const string &role, const string &area, Task task, unsigned* req_num) { if (!g_app_list.contains(appid)) @@ -1036,11 +1574,46 @@ WMError WindowManager::setRequest(const std::string& appid, const std::string &r return WMError::SUCCESS; } -WMError WindowManager::doTransition(unsigned req_num) +WMError WindowManager::setRequest(Task task, unsigned* req_num) { - HMI_SEQ_DEBUG(req_num, "check policy"); - WMError ret = this->checkPolicy(req_num); - return ret; + /* + * Queueing Phase + */ + unsigned current = g_app_list.currentRequestNumber(); + + WMRequest req = WMRequest(task); + unsigned new_req = g_app_list.addRequest(req); + *req_num = new_req; + g_app_list.reqDump(); + + HMI_SEQ_DEBUG(current, "start sequence for task:%d", task); + + return WMError::SUCCESS; +} + +WMError WindowManager::setRequestForSlave(const string& appid, const string &role, const string &area, + Task task, unsigned* req_num) +{ + /* + * Queueing Phase + */ + unsigned current = g_app_list.currentRequestNumber(); + unsigned requested_num = g_app_list.getRequestNumber(appid); + if (requested_num != 0) + { + HMI_SEQ_INFO(requested_num, + "%s %s %s request is already queued", appid.c_str(), role.c_str(), area.c_str()); + return REQ_REJECTED; + } + + WMRequest req = WMRequest(appid, role, area, task); + unsigned new_req = g_app_list.addRequest(req); + *req_num = new_req; + g_app_list.reqDump(); + + HMI_SEQ_DEBUG(current, "%s start sequence with %s, %s", appid.c_str(), role.c_str(), area.c_str()); + + return WMError::SUCCESS; } WMError WindowManager::checkPolicy(unsigned req_num) @@ -1057,7 +1630,7 @@ WMError WindowManager::checkPolicy(unsigned req_num) ret = WMError::NO_ENTRY; return ret; } - std::string req_area = trigger.area; + string req_area = trigger.area; if (trigger.task == Task::TASK_ALLOCATE) { @@ -1091,6 +1664,43 @@ WMError WindowManager::checkPolicy(unsigned req_num) return ret; } +WMError WindowManager::checkPolicyForSlave(unsigned req_num) +{ + /* + * Check Policy + */ + // get current trigger + bool found = false; + WMError ret = WMError::LAYOUT_CHANGE_FAIL; + auto trigger = g_app_list.getRequest(req_num, &found); + if (!found) + { + ret = WMError::NO_ENTRY; + return ret; + } + string req_area = trigger.area; + + // Input event data to PolicyManager + if (0 > this->pmw.setInputEventData(trigger.task, trigger.role, trigger.area)) + { + HMI_SEQ_ERROR(req_num, "Failed to set input event data to PolicyManager"); + return ret; + } + + // Execute state transition of PolicyManager + if (0 > this->pmw.executeStateTransition()) + { + HMI_SEQ_ERROR(req_num, "Failed to execute state transition of PolicyManager"); + return ret; + } + + ret = WMError::SUCCESS; + + g_app_list.reqDump(); + + return ret; +} + WMError WindowManager::startTransition(unsigned req_num) { bool sync_draw_happen = false; @@ -1105,20 +1715,31 @@ WMError WindowManager::startTransition(unsigned req_num) return ret; } + g_app_list.reqDump(); for (const auto &action : actions) { + // TODO: application requests by old role, + // so convert role new to old for emitting event + string old_role = this->rolenew2old[action.role]; + if (action.visible == TaskVisible::VISIBLE) { sync_draw_happen = true; - // TODO: application requests by old role, - // so convert role new to old for emitting event - std::string old_role = this->rolenew2old[action.role]; - this->emit_syncdraw(old_role, action.area); /* TODO: emit event for app not subscriber - if(g_app_list.contains(y.appid)) - g_app_list.lookUpClient(y.appid)->emit_syncdraw(y.role, y.area); */ + if(g_app_list.contains(y.appid)) + g_app_list.lookUpClient(y.appid)->emit_syncdraw(y.role, y.area); */ + } + else if(action.visible == TaskVisible::REQ_REMOTE_VISIBLE) + { + // If this action is for slave, send to slave + this->wmcon.sendRequest("syncDraw", action.client->appID().c_str(), + old_role.c_str(), action.area.c_str()); + } + else if (action.car_state != TaskCarState::NO_TASK) + { + this->transitionCarState(action.car_state); } } @@ -1132,17 +1753,89 @@ WMError WindowManager::startTransition(unsigned req_num) // Make it deactivate here for (const auto &x : actions) { - if (g_app_list.contains(x.appid)) + this->lc->visibilityChange(x); + string old_role = this->rolenew2old[x.role]; + + if (x.visible == TaskVisible::INVISIBLE) { - auto client = g_app_list.lookUpClient(x.appid); - this->deactivate(client->surfaceID(x.role)); + emit_deactivated(old_role.c_str()); + } + else if (x.visible == TaskVisible::REQ_REMOTE_INVISIBLE) + { + // If this action is for slave, send to slave + int i_ret = this->wmcon.sendRequest("deactivated", x.client->appID().c_str(), + old_role.c_str(), ""); + if (0 > i_ret) + { + ret = WMError::FAIL; + } } + + /* if (g_app_list.contains(x.appid)) + { + auto client = g_app_list.lookUpClient(x.appid); + //this->deactivate(client->surfaceID(x.role)); + } */ } + this->lc->renderLayers(); + this->lc->renderLayersRemote(); ret = WMError::NO_LAYOUT_CHANGE; } return ret; } +void WindowManager::transitionCarState(TaskCarState task) +{ + if (TaskCarState::PARKING_BRAKE_OFF == task) + { + this->crr_car_info.parking_brake_stt = false; + this->emitParkingBrakeOff(); + } + else if (TaskCarState::PARKING_BRAKE_ON == task) + { + this->crr_car_info.parking_brake_stt = true; + this->emitParkingBrakeOn(); + } + else if (TaskCarState::ACCEL_PEDAL_OFF == task) + { + this->crr_car_info.accel_pedal_stt = false; + } + else if (TaskCarState::ACCEL_PEDAL_ON == task) + { + this->crr_car_info.accel_pedal_stt = true; + } + else if (TaskCarState::HEDLAMP_OFF == task) + { + this->crr_car_info.headlamp_stt = false; + this->emitHeadlampOff(); + } + else if (TaskCarState::HEDLAMP_ON == task) + { + this->crr_car_info.headlamp_stt = true; + this->emitHeadlampOn(); + } + else if (TaskCarState::LIGHTSTATUS_BRAKE_OFF == task) + { + this->crr_car_info.lightstatus_brake_stt = false; + this->emitLightstatusBrakeOff(); + } + else if (TaskCarState::LIGHTSTATUS_BRAKE_ON == task) + { + this->crr_car_info.lightstatus_brake_stt = true; + this->emitLightstatusBrakeOn(); + } + else if (TaskCarState::CAR_STOP == task) + { + this->crr_car_info.running_stt = false; + this->emitCarStop(); + } + else if (TaskCarState::CAR_RUN == task) + { + this->crr_car_info.running_stt = true; + this->emitCarRun(); + } +} + WMError WindowManager::doEndDraw(unsigned req_num) { // get actions @@ -1163,17 +1856,51 @@ WMError WindowManager::doEndDraw(unsigned req_num) if(act.visible != TaskVisible::NO_CHANGE) { // layout change - if(!g_app_list.contains(act.appid)){ - ret = WMError::NOT_REGISTERED; - } - ret = this->layoutChange(act); + ret = this->lc->layoutChange(act); if(ret != WMError::SUCCESS) { HMI_SEQ_WARNING(req_num, "Failed to manipulate surfaces while state change : %s", errorDescription(ret)); return ret; } - ret = this->visibilityChange(act); + ret = this->lc->visibilityChange(act); + + // Emit active/deactive event + string old_role = this->rolenew2old[act.role]; + if(act.visible == TaskVisible::VISIBLE) + { + emit_visible(old_role.c_str()); + emit_activated(old_role.c_str()); + } + else if(act.visible == TaskVisible::REQ_REMOTE_VISIBLE) + { + // If this action is for slave, send to slave + int i_ret = this->wmcon.sendRequest("activated", "", old_role.c_str(), ""); + if (0 > i_ret) + { + ret = WMError::FAIL; + } + } + else if(act.visible == TaskVisible::REQ_REMOTE_INVISIBLE) + { + // If this action is for slave, send to slave + int i_ret = this->wmcon.sendRequest("deactivated", "", old_role.c_str(), ""); + if (0 > i_ret) + { + ret = WMError::FAIL; + } + } + else if((act.visible == TaskVisible::REMOTE_VISIBLE) || + (act.visible == TaskVisible::REMOTE_INVISIBLE)) + { + // nop because emit active/deactive by event from remote + } + else + { + emit_invisible(old_role.c_str()); + emit_deactivated(old_role.c_str()); + } + if (ret != WMError::SUCCESS) { HMI_SEQ_WARNING(req_num, @@ -1181,81 +1908,33 @@ WMError WindowManager::doEndDraw(unsigned req_num) return ret; } HMI_SEQ_DEBUG(req_num, "visible %s", act.role.c_str()); - //this->lm_enddraw(act.role.c_str()); } } - this->layout_commit(); + this->lc->renderLayers(); + this->lc->renderLayersRemote(); HMI_SEQ_INFO(req_num, "emit flushDraw"); for(const auto &act_flush : actions) { + // TODO: application requests by old role, + // so convert role new to old for emitting event + string old_role = this->rolenew2old[act_flush.role]; + if(act_flush.visible == TaskVisible::VISIBLE) { - // TODO: application requests by old role, - // so convert role new to old for emitting event - std::string old_role = this->rolenew2old[act_flush.role]; - this->emit_flushdraw(old_role.c_str()); } + else if(act_flush.visible == TaskVisible::REQ_REMOTE_VISIBLE) + { + // If this action is for slave, send to slave + this->wmcon.sendRequest("flushDraw", "", old_role.c_str(), ""); + } } return ret; } -WMError WindowManager::layoutChange(const WMAction &action) -{ - if (action.visible == TaskVisible::INVISIBLE) - { - // Visibility is not change -> no redraw is required - return WMError::SUCCESS; - } - auto client = g_app_list.lookUpClient(action.appid); - unsigned surface = client->surfaceID(action.role); - if (surface == 0) - { - HMI_SEQ_ERROR(g_app_list.currentRequestNumber(), - "client doesn't have surface with role(%s)", action.role.c_str()); - return WMError::NOT_REGISTERED; - } - // Layout Manager - WMError ret = this->setSurfaceSize(surface, action.area); - return ret; -} - -WMError WindowManager::visibilityChange(const WMAction &action) -{ - HMI_SEQ_DEBUG(g_app_list.currentRequestNumber(), "Change visibility"); - if(!g_app_list.contains(action.appid)){ - return WMError::NOT_REGISTERED; - } - auto client = g_app_list.lookUpClient(action.appid); - unsigned surface = client->surfaceID(action.role); - if(surface == 0) - { - HMI_SEQ_ERROR(g_app_list.currentRequestNumber(), - "client doesn't have surface with role(%s)", action.role.c_str()); - return WMError::NOT_REGISTERED; - } - - if (action.visible != TaskVisible::INVISIBLE) - { - this->activate(surface); // Layout Manager task - } - else - { - this->deactivate(surface); // Layout Manager task - } - return WMError::SUCCESS; -} - -WMError WindowManager::setSurfaceSize(unsigned surface, const std::string &area) -{ - this->surface_set_layout(surface, area); - - return WMError::SUCCESS; -} - void WindowManager::emitScreenUpdated(unsigned req_num) { // Get visible apps @@ -1263,15 +1942,17 @@ void WindowManager::emitScreenUpdated(unsigned req_num) bool found = false; auto actions = g_app_list.getActions(req_num, &found); + HMI_DEBUG("@@@@@"); // create json object json_object *j = json_object_new_object(); json_object *jarray = json_object_new_array(); for(const auto& action: actions) { - if(action.visible != TaskVisible::INVISIBLE) + if((action.visible == TaskVisible::VISIBLE) || + (action.visible == TaskVisible::REMOTE_VISIBLE)) { - json_object_array_add(jarray, json_object_new_string(action.appid.c_str())); + json_object_array_add(jarray, json_object_new_string(action.client->appID().c_str())); } } json_object_object_add(j, kKeyIds, jarray); @@ -1281,7 +1962,7 @@ void WindowManager::emitScreenUpdated(unsigned req_num) this->map_afb_event[kListEventName[Event_ScreenUpdated]], j); if (ret != 0) { - HMI_DEBUG("wm", "afb_event_push failed: %m"); + HMI_DEBUG("afb_event_push failed: %m"); } } @@ -1289,7 +1970,7 @@ void WindowManager::setTimer() { struct timespec ts; if (clock_gettime(CLOCK_BOOTTIME, &ts) != 0) { - HMI_ERROR("wm", "Could't set time (clock_gettime() returns with error"); + HMI_ERROR("Could't set time (clock_gettime() returns with error"); return; } @@ -1301,7 +1982,7 @@ void WindowManager::setTimer() CLOCK_BOOTTIME, (uint64_t)(ts.tv_sec + kTimeOut) * 1000000ULL, 1, processTimerHandler, this); if (ret < 0) { - HMI_ERROR("wm", "Could't set timer"); + HMI_ERROR("Could't set timer"); } } else @@ -1331,7 +2012,7 @@ void WindowManager::processNextRequest() if (g_app_list.haveRequest()) { HMI_SEQ_DEBUG(req_num, "Process next request"); - WMError rc = doTransition(req_num); + WMError rc = checkPolicy(req_num); if (rc != WMError::SUCCESS) { HMI_SEQ_ERROR(req_num, errorDescription(rc)); @@ -1364,48 +2045,48 @@ const char* WindowManager::convertRoleOldToNew(char const *old_role) new_role = old_role; } - HMI_DEBUG("wm", "old:%s -> new:%s", old_role, new_role); + HMI_DEBUG("old:%s -> new:%s", old_role, new_role); return new_role; } -int WindowManager::loadOldRoleDb() +int WindowManager::loadOldRolesConfigFile() { // 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); + HMI_DEBUG("afm_app_install_dir:%s", afm_app_install_dir); - std::string file_name; + string file_name; if (!afm_app_install_dir) { - HMI_ERROR("wm", "AFM_APP_INSTALL_DIR is not defined"); + HMI_ERROR("AFM_APP_INSTALL_DIR is not defined"); } else { - file_name = std::string(afm_app_install_dir) + std::string("/etc/old_roles.db"); + file_name = string(afm_app_install_dir) + string(kPathOldRolesConfigFile); } - // Load old_role.db + // Load old_rolea config file json_object* json_obj; int ret = jh::inputJsonFilie(file_name.c_str(), &json_obj); if (0 > ret) { - HMI_ERROR("wm", "Could not open old_role.db, so use default old_role information"); - json_obj = json_tokener_parse(kDefaultOldRoleDb); + HMI_ERROR("Could not open %s, so use default old_roles information", kPathOldRolesConfigFile); + json_obj = json_tokener_parse(kDefaultOldRolesConfig); } - HMI_DEBUG("wm", "json_obj dump:%s", json_object_get_string(json_obj)); + HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj)); // Perse apps json_object* json_cfg; if (!json_object_object_get_ex(json_obj, "old_roles", &json_cfg)) { - HMI_ERROR("wm", "Parse Error!!"); + HMI_ERROR("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)); + HMI_DEBUG("json_cfg len:%d", len); + HMI_DEBUG("json_cfg dump:%s", json_object_get_string(json_cfg)); for (int i=0; i<len; i++) { @@ -1414,25 +2095,25 @@ int WindowManager::loadOldRoleDb() const char* old_role = jh::getStringFromJson(json_tmp, "name"); if (nullptr == old_role) { - HMI_ERROR("wm", "Parse Error!!"); + HMI_ERROR("Parse Error!!"); return -1; } const char* new_role = jh::getStringFromJson(json_tmp, "new"); if (nullptr == new_role) { - HMI_ERROR("wm", "Parse Error!!"); + HMI_ERROR("Parse Error!!"); return -1; } - this->roleold2new[old_role] = std::string(new_role); + this->roleold2new[old_role] = string(new_role); } // Check for(auto itr = this->roleold2new.begin(); itr != this->roleold2new.end(); ++itr) { - HMI_DEBUG("wm", ">>> role old:%s new:%s", + HMI_DEBUG(">>> role old:%s new:%s", itr->first.c_str(), itr->second.c_str()); } @@ -1442,31 +2123,132 @@ int WindowManager::loadOldRoleDb() return 0; } +Task WindowManager::convertCanSignalToCarStateTask(const char *signal_name) +{ + wm::LowCanClient *lcc = &(this->lcc); + Task task = Task::TASK_INVALID; + + // If car info is updated, set car state change event + if (strstr(signal_name, lcc->kSignalName[lcc->SignalNoParkingBrake])) + { + HMI_DEBUG("Parking Brake state is changed"); + + if (lcc->getCurrentParkingBrakeState()) + { + task = wm::Task::TASK_PARKING_BRAKE_ON; + } + else + { + task = wm::Task::TASK_PARKING_BRAKE_OFF; + } + } + else if (strstr(signal_name, lcc->kSignalName[lcc->SignalNoAccelPedalPos])) + { + // Update accel pedal position + this->crr_car_info.accel_pedal_pos = lcc->getCurrentAccelPedalPosition(); + + if (lcc->isChangedAccelPedalState()) + { + HMI_DEBUG("Accelerator Pedal state is changed"); + + if (lcc->getCurrentAccelPedalState()) + { + task = wm::Task::TASK_ACCEL_PEDAL_ON; + } + else + { + task = wm::Task::TASK_ACCEL_PEDAL_OFF; + } + } + } + else if (strstr(signal_name, lcc->kSignalName[lcc->SignalNoHeadlame])) + { + HMI_DEBUG("Headlamp state is changed"); + + if (lcc->getCurrentHeadlampState()) + { + task = wm::Task::TASK_HEDLAMP_ON; + } + else + { + task = wm::Task::TASK_HEDLAMP_OFF; + } + } + else if (strstr(signal_name, lcc->kSignalName[lcc->SignalNoLightstatusBrake])) + { + HMI_DEBUG("Lightstatus Brake state is changed"); + + if (lcc->getCurrentLightstatusBrakeState()) + { + task = wm::Task::TASK_LIGHTSTATUS_BRAKE_ON; + } + else + { + task = wm::Task::TASK_LIGHTSTATUS_BRAKE_OFF; + } + } + return task; +} + +void WindowManager::inputCarStateTask(Task task) +{ + unsigned req_num = 0; + WMError ret = WMError::UNKNOWN; + + ret = this->setRequest(task, &req_num); + + if(ret != WMError::SUCCESS) + { + HMI_ERROR(errorDescription(ret)); + return; + } + + if (req_num != g_app_list.currentRequestNumber()) + { + // Add request, then invoked after the previous task is finished + HMI_SEQ_DEBUG(req_num, "request is accepted"); + return; + } + + /* + * Do allocate tasks + */ + ret = this->checkPolicy(req_num); + + if (ret != WMError::SUCCESS) + { + //this->emit_error() + HMI_SEQ_ERROR(req_num, errorDescription(ret)); + g_app_list.removeRequest(req_num); + this->processNextRequest(); + } +} + const char *WindowManager::check_surface_exist(const char *drawing_name) { - auto const &surface_id = this->lookup_id(drawing_name); + auto const &surface_id = this->id_alloc.lookup(string(drawing_name)); if (!surface_id) { return "Surface does not exist"; } - if (!this->controller->surface_exists(*surface_id)) + /* if (!this->controller->surface_exists(*surface_id)) { return "Surface does not exist in controller!"; - } + } */ - auto layer_id = this->layers.get_layer_id(*surface_id); + /* auto layer_id = this->layers.get_layer_id(*surface_id); if (!layer_id) { return "Surface is not on any layer!"; - } + } */ - HMI_DEBUG("wm", "surface %d is detected", *surface_id); + HMI_DEBUG("surface %d is detected", *surface_id); return nullptr; } -const char* WindowManager::kDefaultOldRoleDb = "{ \ +const char* WindowManager::kDefaultOldRolesConfig = "{ \ \"old_roles\": [ \ { \ \"name\": \"HomeScreen\", \ @@ -1535,26 +2317,4 @@ const char* WindowManager::kDefaultOldRoleDb = "{ \ ] \ }"; -/** - * controller_hooks - */ -void controller_hooks::surface_created(uint32_t surface_id) -{ - this->wmgr->surface_created(surface_id); -} - -void controller_hooks::surface_removed(uint32_t surface_id) -{ - this->wmgr->surface_removed(surface_id); -} - -void controller_hooks::surface_visibility(uint32_t /*surface_id*/, - uint32_t /*v*/) {} - -void controller_hooks::surface_destination_rectangle(uint32_t /*surface_id*/, - uint32_t /*x*/, - uint32_t /*y*/, - uint32_t /*w*/, - uint32_t /*h*/) {} - } // namespace wm diff --git a/src/window_manager.hpp b/src/window_manager.hpp index 6cbd355..c4ad0f5 100644 --- a/src/window_manager.hpp +++ b/src/window_manager.hpp @@ -14,33 +14,27 @@ * limitations under the License. */ -#ifndef TMCAGLWM_APP_HPP -#define TMCAGLWM_APP_HPP +#ifndef WINDOW_MANAGER_HPP +#define WINDOW_MANAGER_HPP #include <atomic> #include <memory> #include <unordered_map> #include <experimental/optional> -#include "controller_hooks.hpp" -#include "layers.hpp" -#include "layout.hpp" -#include "wayland_ivi_wm.hpp" +#include "result.hpp" #include "pm_wrapper.hpp" -#include "hmi-debug.h" +#include "util.hpp" #include "request.hpp" #include "wm_error.hpp" - -struct json_object; - -namespace wl +#include "wm_layer_control.hpp" +#include "wm_connection.hpp" +#include "low_can_client.hpp" +extern "C" { -struct display; +#include <afb/afb-binding.h> } -namespace compositor -{ -struct controller; -} +struct json_object; namespace wm { @@ -88,7 +82,7 @@ struct id_allocator unsigned sid = this->next++; this->id2name[sid] = name; this->name2id[name] = sid; - HMI_DEBUG("wm", "allocated new id %u with name %s", sid, name.c_str()); + HMI_DEBUG("allocated new id %u with name %s", sid, name.c_str()); return sid; } @@ -97,7 +91,7 @@ struct id_allocator { this->id2name[sid] = name; this->name2id[name] = sid; - HMI_DEBUG("wm", "register id %u with name %s", sid, name.c_str()); + HMI_DEBUG("register id %u with name %s", sid, name.c_str()); return; } @@ -137,10 +131,46 @@ struct id_allocator } }; +struct TmpClient +{ + std::string appid; + unsigned pid; +}; + +struct TmpService +{ + std::string appid; // Used to search who create service surface + std::string dest; // Used to attach service to destination application + std::string service;// The name of service surface + std::string uuid; // uuid + TmpService(const std::string& app, const std::string& dst, + const std::string& svc, const std::string& uuid) + : appid(app), dest(dst), service(svc), uuid(uuid) {} +}; + +struct CarInfo +{ + CarInfo() + : parking_brake_stt(true), + accel_pedal_stt(false), + accel_pedal_pos(0.0), + running_stt(false), + headlamp_stt(false), + lightstatus_brake_stt(true) + {}; + + bool parking_brake_stt; + bool accel_pedal_stt; + double accel_pedal_pos; + bool running_stt; + bool headlamp_stt; + bool lightstatus_brake_stt; +}; + class WindowManager { public: - typedef std::unordered_map<uint32_t, struct compositor::rect> rect_map; + typedef std::unordered_map<uint32_t, struct rect> rect_map; typedef std::function<void(const char *err_msg)> reply_func; enum EventType @@ -158,47 +188,24 @@ class WindowManager Event_ScreenUpdated, - Event_Error, - - Event_Val_Max = Event_Error, - }; - - const std::vector<const char *> kListEventName{ - "active", - "inactive", - "visible", - "invisible", - "syncDraw", - "flushDraw", - "screenUpdated", - "error"}; - - struct controller_hooks chooks; + Event_HeadlampOff, + Event_HeadlampOn, - // This is the one thing, we do not own. - struct wl::display *display; + Event_ParkingBrakeOff, + Event_ParkingBrakeOn, - std::unique_ptr<struct compositor::controller> controller; - std::vector<std::unique_ptr<struct wl::output>> outputs; + Event_LightstatusBrakeOff, + Event_LightstatusBrakeOn, - // track current layouts separately - layer_map layers; + Event_CarStop, + Event_CarRun, - // ID allocation and proxy methods for lookup - struct id_allocator id_alloc; - - // Set by AFB API when wayland events need to be dispatched - std::atomic<bool> pending_events; - - std::map<const char *, struct afb_event> map_afb_event; - - // Surface are info (x, y, w, h) - rect_map area_info; + Event_Error, - // FOR CES DEMO - std::vector<int> surface_bg; + Event_Val_Max = Event_Error, + }; - explicit WindowManager(wl::display *d); + explicit WindowManager(); ~WindowManager() = default; WindowManager(WindowManager const &) = delete; @@ -207,41 +214,71 @@ class WindowManager WindowManager &operator=(WindowManager &&) = delete; int init(); - int dispatch_pending_events(); - void set_pending_events(); result<int> api_request_surface(char const *appid, char const *role); char const *api_request_surface(char const *appid, char const *role, char const *ivi_id); + bool api_set_role(char const *appid, char const *role); void api_activate_surface(char const *appid, char const *role, char const *drawing_area, const reply_func &reply); + void api_activate_surface_for_slave(char const *appid, char const *drawing_name, + char const *drawing_area, const reply_func &reply); + void api_activate_surface_to_master(char const *appid, char const *drawing_name, + char const *drawing_area, const reply_func &reply); void api_deactivate_surface(char const *appid, char const *role, const reply_func &reply); + void api_deactivate_surface_for_slave(char const *appid, char const *drawing_name, + const reply_func &reply); + void api_deactivate_surface_to_master(char const *appid, char const *drawing_name, + const reply_func &reply); void api_enddraw(char const *appid, char const *role); + void api_enddraw_for_remote(char const *appid, char const *drawing_name); + bool api_client_set_render_order(const char *appid, const std::vector<std::string> &render_order); + std::string api_client_attach_service_surface(const char* appid, const char* dest, const char* service_surface); result<json_object *> api_get_display_info(); result<json_object *> api_get_area_info(char const *role); - void api_ping(); + result<json_object *> api_get_car_info(char const *label); + 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); // Events from the compositor we are interested in - void surface_created(uint32_t surface_id); - void surface_removed(uint32_t surface_id); + void surface_created(unsigned pid, unsigned surface_id); + void surface_removed(unsigned surface_id); void removeClient(const std::string &appid); void exceptionProcessForTransition(); const char* convertRoleOldToNew(char const *role); + void analyzeReceivedEvent(const char *event, struct json_object *object); + // Do not use this function void timerHandler(); void startTransitionWrapper(std::vector<WMAction> &actions); void processError(WMError error); + void processForRemoteRequest(json_object *data); + std::string searchApp(unsigned pid, unsigned ppid, unsigned surface, json_object* resp); + void storeSurface(const std::string& appid, unsigned ppid, unsigned surface); - private: - bool pop_pending_events(); - optional<int> lookup_id(char const *name); - optional<std::string> lookup_name(int id); - int init_layers(); - void surface_set_layout(int surface_id, const std::string& area = ""); - void layout_commit(); + const std::vector<const char *> kListEventName{ + "active", + "inactive", + "visible", + "invisible", + "syncDraw", + "flushDraw", + "screenUpdated", + "headlampOff", + "headlampOn", + "parkingBrakeOff", + "parkingBrakeOn", + "lightstatusBrakeOff", + "lightstatusBrakeOn", + "carStop", + "carRun", + "error"}; + std::map<const char *, struct afb_event> map_afb_event; + WMConnection wmcon; + + private: // WM Events to clients void emit_activated(char const *label); void emit_deactivated(char const *label); @@ -251,39 +288,59 @@ class WindowManager 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 emitParkingBrakeOff(); + void emitParkingBrakeOn(); + void emitLightstatusBrakeOff(); + void emitLightstatusBrakeOn(); + void emitCarStop(); + void emitCarRun(); - void activate(int id); - void deactivate(int id); WMError setRequest(const std::string &appid, const std::string &role, const std::string &area, Task task, unsigned *req_num); - WMError doTransition(unsigned sequence_number); + WMError setRequest(Task task, unsigned* req_num); + WMError setRequestForSlave(const std::string& appid, const std::string &role, + const std::string &area, Task task, unsigned* req_num); WMError checkPolicy(unsigned req_num); + WMError checkPolicyForSlave(unsigned req_num); WMError startTransition(unsigned req_num); + void transitionCarState(TaskCarState task); WMError doEndDraw(unsigned req_num); - WMError layoutChange(const WMAction &action); - WMError visibilityChange(const WMAction &action); - WMError setSurfaceSize(unsigned surface, const std::string& area); void emitScreenUpdated(unsigned req_num); void setTimer(); void stopTimer(); void processNextRequest(); - int loadOldRoleDb(); + int loadOldRolesConfigFile(); + + Task convertCanSignalToCarStateTask(const char *signal_name); + void inputCarStateTask(Task task); const char *check_surface_exist(const char *role); private: - std::unordered_map<std::string, struct compositor::rect> area2size; std::unordered_map<std::string, std::string> roleold2new; std::unordered_map<std::string, std::string> rolenew2old; + std::shared_ptr<LayerControl> lc; + + LowCanClient lcc; + CarInfo crr_car_info; PMWrapper pmw; - static const char* kDefaultOldRoleDb; + // ID allocation and proxy methods for lookup + struct id_allocator id_alloc; + // Surface are info (x, y, w, h) + rect_map area_info; + // FOR CES DEMO + std::unordered_map<unsigned, struct TmpClient> tmp_surface2app; + std::vector<struct TmpService> tmp_services; + static const char* kDefaultOldRolesConfig; }; } // namespace wm -#endif // TMCAGLWM_APP_HPP +#endif // WINDOW_MANAGER_HPP diff --git a/src/wm_client.cpp b/src/wm_client.cpp index 09e2e00..f2ad7be 100644 --- a/src/wm_client.cpp +++ b/src/wm_client.cpp @@ -16,7 +16,10 @@ #include <json-c/json.h> #include "wm_client.hpp" -#include "hmi-debug.h" +#include "util.hpp" +#include <ilm/ilm_control.h> +#include <uuid/uuid.h> + #define INVALID_SURFACE_ID 0 @@ -49,7 +52,7 @@ WMClient::WMClient(const string &appid, unsigned layer, unsigned surface, const #else afb_event ev = afb_daemon_make_event(x.c_str()); #endif - event2list[x] = ev; + evname2afb_event[x] = ev; } } @@ -57,7 +60,7 @@ WMClient::WMClient(const string &appid, const string &role) : id(appid), layer(0), role2surface(0), - event2list(0) + evname2afb_event(0) { role2surface[role] = INVALID_SURFACE_ID; for (auto x : kWMEvents) @@ -67,12 +70,27 @@ WMClient::WMClient(const string &appid, const string &role) #else afb_event ev = afb_daemon_make_event(x.c_str()); #endif - event2list[x] = ev; + evname2afb_event[x] = ev; } } -WMClient::~WMClient() +WMClient::WMClient(const string &appid, unsigned layer, const string &role) + : id(appid), + layer(layer), + main_role(role), + role2surface(0), + evname2afb_event(0) { + role2surface[role] = INVALID_SURFACE_ID; + for (auto x : kWMEvents) + { +#if GTEST_ENABLED + string ev = x; +#else + afb_event ev = afb_daemon_make_event(x.c_str()); +#endif + evname2afb_event[x] = ev; + } } string WMClient::appID() const @@ -80,25 +98,9 @@ string WMClient::appID() const return this->id; } -unsigned WMClient::surfaceID(const string &role) const -{ - if (0 == this->role2surface.count(role)) - { - return INVALID_SURFACE_ID; - } - return this->role2surface.at(role); -} - -std::string WMClient::role(unsigned surface) const +string WMClient::role() const { - for(const auto& x : this->role2surface) - { - if(x.second == surface) - { - return x.first; - } - } - return std::string(""); + return this->main_role; } unsigned WMClient::layerID() const @@ -106,70 +108,120 @@ unsigned WMClient::layerID() const return this->layer; } -/** - * Set layerID the client belongs to - * - * This function set layerID the client belongs to. - * But this function may not used because the layer should be fixed at constructor. - * So this function will be used to change layer by some reasons. - * - * @param unsigned[in] layerID - * @return None - * @attention WMClient can't have multiple layer - */ -void WMClient::registerLayer(unsigned layer) +unsigned WMClient::surfaceID() const { - this->layer = layer; + return this->surface; } /** - * Add the pair of role and surface to the client + * Add surface to the client * - * This function set the pair of role and surface to the client. - * This function is used for the client which has multi surfaces. - * If the model and relationship for role and surface(layer) - * is changed, this function will be changed - * Current Window Manager doesn't use this function. + * This function add main surface to the client(ivi_layer). * * @param string[in] role - * @param unsigned[in] surface - * @return true + * @return WMError */ -bool WMClient::addSurface(const string &role, unsigned surface) +WMError WMClient::addSurface(unsigned surface) { - HMI_DEBUG("wm", "Add role %s with surface %d", role.c_str(), surface); - if (0 != this->role2surface.count(role)) + this->surface = surface; + ilmErrorTypes err = ilm_layerAddSurface(this->layer, surface); + + if(err == ILM_SUCCESS) { - HMI_NOTICE("wm", "override surfaceID %d with %d", this->role2surface[role], surface); + err = ilm_commitChanges(); } - this->role2surface[role] = surface; - return true; + return (err == ILM_SUCCESS) ? WMError::SUCCESS : WMError::FAIL; } bool WMClient::removeSurfaceIfExist(unsigned surface) { bool ret = false; - for (auto &x : this->role2surface) + if(surface == this->surface) { - if (surface == x.second) + this->surface = INVALID_SURFACE_ID; + ret = true; + } + else + { + for(auto &x : this->service2surfaces) + { + if(x.second = surface) + { + ret = true; + string key = x.first; + this->service2surfaces.erase(key); + this->service2supplier.erase(key); + } + } + } + return ret; +} + +WMError WMClient::setRenderOrder(const vector<string> &order) +{ + WMError ret = WMError::SUCCESS; + this->surface_render_order.clear(); + for(const auto& x : order) + { + unsigned s; // surface + if(x == this->role()) + { + s = this->surfaceID(); + } + else if(this->service2surfaces.count(x) != 0) + { + s = this->service2surfaces[x]; + } + else { - HMI_INFO("wm", "Remove surface from client %s: role %s, surface: %d", - this->id.c_str(), x.first.c_str(), x.second); - this->role2surface.erase(x.first); - ret = true; + ret = WMError::NOT_REGISTERED; break; } + this->surface_render_order.push_back(s); + } + if(ret == WMError::SUCCESS) + { + int count = 0; + t_ilm_layer* id_array = new t_ilm_surface[this->surface_render_order.size()]; + if(id_array == nullptr) + { + HMI_WARNING("short memory"); + ret = WMError::FAIL; + } + else + { + for(const auto& i : this->surface_render_order) + { + id_array[count] = i; + ++count; + } + ilm_layerSetRenderOrder(this->layerID(), + id_array, this->surface_render_order.size()); + delete id_array; + } } return ret; } -bool WMClient::removeRole(const string &role) +string WMClient::attachTmpServiceSurface(const string& supplier, const string& service_surface) { - bool ret = false; - if (this->role2surface.count(role) != 0) + string uuid; + uuid_t u; + char out[37]; // uuid is 36 characters + uuid_generate_random(u); + uuid_unparse(u, out); + uuid = out; + this->service2supplier.emplace(service_surface, supplier); + return uuid; +} + +WMError WMClient::attachServiceSurface(const string& service_surface, unsigned surface) +{ + WMError ret = WMError::NOT_REGISTERED; + if(this->service2supplier.count(service_surface) != 0) { - this->role2surface.erase(role); - ret = true; + this->service2surfaces.emplace(service_surface, surface); + ret = WMError::SUCCESS; } return ret; } @@ -178,13 +230,13 @@ bool WMClient::removeRole(const string &role) bool WMClient::subscribe(afb_req req, const string &evname) { if(evname != kKeyError){ - HMI_DEBUG("wm", "error is only enabeled for now"); + HMI_DEBUG("error is only enabeled for now"); return false; } - int ret = afb_req_subscribe(req, this->event2list[evname]); + int ret = afb_req_subscribe(req, this->evname2afb_event[evname]); if (ret) { - HMI_DEBUG("wm", "Failed to subscribe %s", evname.c_str()); + HMI_DEBUG("Failed to subscribe %s", evname.c_str()); return false; } return true; @@ -192,19 +244,19 @@ bool WMClient::subscribe(afb_req req, const string &evname) void WMClient::emitError(WM_CLIENT_ERROR_EVENT ev) { - if (!afb_event_is_valid(this->event2list[kKeyError])){ - HMI_ERROR("wm", "event err is not valid"); + if (!afb_event_is_valid(this->evname2afb_event[kKeyError])){ + HMI_ERROR("event err is not valid"); return; } json_object *j = json_object_new_object(); json_object_object_add(j, kKeyError, json_object_new_int(ev)); json_object_object_add(j, kKeyErrorDesc, json_object_new_string(kErrorDescription[ev].c_str())); - HMI_DEBUG("wm", "error: %d, description:%s", ev, kErrorDescription[ev].c_str()); + HMI_DEBUG("error: %d, description:%s", ev, kErrorDescription[ev].c_str()); - int ret = afb_event_push(this->event2list[kKeyError], j); + int ret = afb_event_push(this->evname2afb_event[kKeyError], j); if (ret != 0) { - HMI_DEBUG("wm", "afb_event_push failed: %m"); + HMI_DEBUG("afb_event_push failed: %m"); } } #endif @@ -213,10 +265,7 @@ void WMClient::dumpInfo() { DUMP("APPID : %s", id.c_str()); DUMP(" LAYER : %d", layer); - for (const auto &x : this->role2surface) - { - DUMP(" ROLE : %s , SURFACE : %d", x.first.c_str(), x.second); - } + DUMP(" ROLE : %s , SURFACE : %d", main_role.c_str(), surface); } } // namespace wm
\ No newline at end of file diff --git a/src/wm_client.hpp b/src/wm_client.hpp index 259d504..fc171f4 100644 --- a/src/wm_client.hpp +++ b/src/wm_client.hpp @@ -20,6 +20,7 @@ #include <vector> #include <string> #include <unordered_map> +#include "wm_error.hpp" extern "C" { @@ -42,16 +43,24 @@ class WMClient WMClient(const std::string &appid, unsigned layer, unsigned surface, const std::string &role); WMClient(const std::string &appid, const std::string &role); - virtual ~WMClient(); + WMClient(const std::string &appid, unsigned layer, const std::string &role); + WMClient(const std::string &appid, unsigned layer, + const std::string& layer_name, unsigned surface, const std::string &role); + ~WMClient() = default; std::string appID() const; - unsigned surfaceID(const std::string &role) const; + std::string role() const; unsigned layerID() const; - std::string role(unsigned surface) const; - void registerLayer(unsigned layer); - bool addSurface(const std::string& role, unsigned surface); + unsigned surfaceID() const; + // void setRole(const std::string& role); + // void appendRole(const std::string& role); + WMError addSurface(unsigned surface); bool removeSurfaceIfExist(unsigned surface); - bool removeRole(const std::string& role); + // bool removeRole(const std::string& role); + std::vector<unsigned> renderOrder() const; + WMError setRenderOrder(const std::vector<std::string>& order); + std::string attachTmpServiceSurface(const std::string& from, const std::string& service_surface); + WMError attachServiceSurface(const std::string& service_surface, unsigned surface); #if GTEST_ENABLED bool subscribe(afb_req req, const std::string &event_name); @@ -63,12 +72,19 @@ class WMClient private: std::string id; unsigned layer; + std::string main_role; + std::string area; + unsigned surface; // currently, main application has only one surface. + //std::vector<std::string> role_list; + std::vector<unsigned> surface_render_order; + std::unordered_map<std::string, unsigned> service2surfaces; std::unordered_map<std::string, unsigned> role2surface; + std::unordered_map<std::string, std::string> service2supplier; #if GTEST_ENABLED // This is for unit test. afb_make_event occurs sig11 if call not in afb-binding - std::unordered_map<std::string, std::string> event2list; + std::unordered_map<std::string, std::string> evname2afb_event; #else - std::unordered_map<std::string, struct afb_event> event2list; + std::unordered_map<std::string, struct afb_event> evname2afb_event; #endif }; } // namespace wm diff --git a/src/wm_connection.cpp b/src/wm_connection.cpp new file mode 100644 index 0000000..10ecc3b --- /dev/null +++ b/src/wm_connection.cpp @@ -0,0 +1,457 @@ +/* + * Copyright (c) 2017 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wm_connection.hpp" +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include "json_helper.hpp" +#include "util.hpp" + +extern "C" +{ +#include <afb/afb-binding.h> +#include <systemd/sd-event.h> +} + + +/** + * namespace wm + */ +namespace wm +{ + + +namespace +{ + +static const char kPathConnectionConfigFile[] = "/etc/connection.json"; +static const char kDefaultIpAddr[] = "192.168.10.10"; +static const int kDefaultPort = 4000; + +static int onIoEventReceive(sd_event_source *src, int fd, uint32_t revents, void * data) +{ + WMConnection *p_wmcon = (WMConnection*)data; + + json_object *j_out; + int ret = p_wmcon->receive(&j_out); + if (0 > ret) + { + return 0; + } + + const char* rq = jh::getStringFromJson(j_out, "req"); + const char* id = jh::getStringFromJson(j_out, "appid"); + const char* dn = jh::getStringFromJson(j_out, "drawing_name"); + const char* da = jh::getStringFromJson(j_out, "drawing_area"); + + HMI_DEBUG("req:%s appid:%s, drawing_name:%s, drawing_area:%s", rq, id, dn, da); + + // Callback + p_wmcon->callOnReceivedHandler(j_out); + + return 0; +} + +static int onIoEventAccept(sd_event_source *src, int fd, uint32_t revents, void * data) +{ + struct sockaddr_in addr; + + WMConnection *p_wmcon = (WMConnection*)data; + + // Accept connection + socklen_t len = sizeof(addr); + int my_socket = p_wmcon->getMySocket(); + int connected_socket = accept(my_socket, (struct sockaddr *)&addr, &len); + if (0 > connected_socket) + { + HMI_ERROR("Failed to accept connection (%s)", strerror(errno)); + return -1; + } + + // Store connected socket + p_wmcon->setConnectedSocket(connected_socket); + + // Register callback to receive + int ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr, + connected_socket, EPOLLIN, + onIoEventReceive, p_wmcon); + if (0 > ret) + { + HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret)); + return -1; + } + + return 0; +} + +} // namespace + +WMConnection::WMConnection() +{ + // Load connection config file + this->loadConnectionConfigFile(); + + // TODO: ECU name should be decide by config file + this->ecu_name = this->mode; +} + +int WMConnection::initialize() +{ + int ret; + + // Initialize for Master/Slave + if (this->isMasterMode()) + { + ret = this->initializeMaster(); + } + else + { + ret = this->initializeSlave(); + } + + return ret; +} + +void WMConnection::registerCallback(ReceivedHandler on_received) +{ + this->onReceived = on_received; +} + +int WMConnection::sendRequest(char const *req, char const *appid, + char const *drawing_name, char const *drawing_area) +{ + int ret; + json_object *j_obj = json_object_new_object(); + json_object_object_add(j_obj, "req", json_object_new_string(req)); + json_object_object_add(j_obj, "appid", json_object_new_string(appid)); + json_object_object_add(j_obj, "drawing_name", json_object_new_string(drawing_name)); + json_object_object_add(j_obj, "drawing_area", json_object_new_string(drawing_area)); + + ret = this->send(j_obj); + + json_object_put(j_obj); + + return ret; +} + +int WMConnection::send(struct json_object* j_in) +{ + // Convert json_object to string to send + const char *buf = json_object_to_json_string(j_in); + if (nullptr == buf) + { + HMI_ERROR("Failed to convert json_object to string"); + return -1; + } + + int len = strlen(buf); + + HMI_DEBUG("Send data(len:%d): %s", len, buf); + + int n = write(this->connected_socket, buf, len); + if(0 > n) + { + HMI_ERROR("Failed to send data (%s)", strerror(errno)); + return -1; + } + + return 0; +} + +bool WMConnection::isMasterMode() +{ + if ("master" == this->mode) + { + return true; + } + else + { + return false; + } +} + +bool WMConnection::isMasterArea(const char* area) +{ + if (nullptr == area) + { + return false; + } + + std::string str_area = std::string(area); + if ("" == str_area) + { + return false; + } + + std::vector<std::string> elements; + elements = parseString(str_area, '.'); + + if ("master" == elements[0]) + { + return true; + } + else + { + return false; + } +} + +bool WMConnection::isConnecting() +{ + return (0 > this->connected_socket) ? false : true; +} + +std::string WMConnection::parseMasterArea(const char* area) +{ + std::string ret_area = ""; + std::vector<std::string> elements; + elements = parseString(std::string(area), '.'); + + if ("master" != elements[0]) + { + return std::string(area); + } + + for (auto itr = (elements.begin() + 1); itr != elements.end(); ++itr) + { + ret_area += *itr; + + if ((elements.end() - 1) != itr) + { + ret_area += "."; + } + } + return ret_area; +} + +bool WMConnection::isSyncDrawingForRemote(const char* appid) +{ + if (std::string(appid) == this->syndDrawingAppId) + { + return true; + } + else + { + return false; + } +} + +void WMConnection::startSyncDrawForRemote(const char* appid) +{ + this->syndDrawingAppId = std::string(appid); +} + +void WMConnection::finishSyncDrawForRemote(const char* appid) +{ + if (std::string(appid) == this->syndDrawingAppId) + { + this->syndDrawingAppId = ""; + } +} + +int WMConnection::getMySocket() +{ + return this->my_socket; +} + +int WMConnection::getConnectedSocket() +{ + return this->connected_socket; +} + +void WMConnection::setConnectedSocket(int connected_socket) +{ + this->connected_socket = connected_socket; +} + +std::string WMConnection::getEcuName() +{ + return this->ecu_name; +} + +void WMConnection::callOnReceivedHandler(json_object *j_out) +{ + this->onReceived(j_out); +} + +int WMConnection::initializeMaster() +{ + int ret = 0; + struct sockaddr_in addr; + + // Create socket + this->my_socket = socket(AF_INET, SOCK_STREAM, 0); + if (0 > this->my_socket) + { + HMI_ERROR("Failed to create socket (%s)", strerror(errno)); + return -1; + } + + // Bind socket + addr.sin_family = AF_INET; + addr.sin_port = htons(this->port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + ret = bind(this->my_socket, (struct sockaddr *)&addr, sizeof(addr)); + if (0 > ret) + { + HMI_ERROR("Failed to bind socket (%s)", strerror(errno)); + return -1; + } + + // Listen connection + ret = listen(this->my_socket, 1); + if (0 > ret) + { + HMI_ERROR("Failed to listen connection (%s)", strerror(errno)); + return -1; + } + + // Register callback to accept connection + ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr, + this->my_socket, EPOLLIN, + onIoEventAccept, this); + if (0 > ret) + { + HMI_ERROR("Failed to add I/O event accept(%s)", strerror(-ret)); + return -1; + } + + return ret; +} + +int WMConnection::initializeSlave() +{ + // Create socket + this->my_socket = socket(AF_INET, SOCK_STREAM, 0); + if (0 > this->my_socket) + { + HMI_ERROR("Failed to create socket (%s)", strerror(errno)); + return -1; + } + + return 0; +} + +int WMConnection::connectToMaster() +{ + int ret = 0; + struct sockaddr_in addr; + + // Connect to master + addr.sin_family = AF_INET; + addr.sin_port = htons(this->port); + addr.sin_addr.s_addr = inet_addr(this->ip.c_str()); + + ret = connect(this->my_socket, (struct sockaddr *)&addr, sizeof(addr)); + if (0 > ret) + { + HMI_ERROR("Failed to connect to master (%s)", strerror(errno)); + return ret; + } + + HMI_DEBUG("Connected to master"); + + // Store connected socket + this->connected_socket = this->my_socket; + + // Register callback to receive + ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr, + this->connected_socket, EPOLLIN, + onIoEventReceive, this); + if (0 > ret) + { + HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret)); + return -1; + } + + return ret; +} + +int WMConnection::receive(struct json_object** j_out) +{ + char buf[1024]; + int n; + + n = read(this->connected_socket, buf, sizeof(buf)); + if(0 > n) + { + HMI_ERROR("Failed to receive data (%s)", strerror(errno)); + return -1; + } + + HMI_DEBUG("Received data length: %d", n); + HMI_DEBUG("Received data: %s", buf); + + // Parse received data + struct json_tokener *tokener = json_tokener_new(); + *j_out = json_tokener_parse_ex(tokener, buf, n); + if (nullptr == *j_out) + { + HMI_DEBUG("Failed to parse received data"); + return -1; + } + + return 0; +} + +int WMConnection::loadConnectionConfigFile() +{ + // Get afm application installed dir + char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR"); + if (!afm_app_install_dir) + { + HMI_ERROR("AFM_APP_INSTALL_DIR is not defined"); + } + std::string path = std::string(afm_app_install_dir) + std::string(kPathConnectionConfigFile); + + // Load connection config file + json_object* json_obj; + int ret = jh::inputJsonFilie(path.c_str(), &json_obj); + if (0 > ret) + { + HMI_ERROR("Could not open %s, so use default mode \"slave\"", kPathConnectionConfigFile); + this->mode = "slave"; + this->ip = kDefaultIpAddr; + this->port = kDefaultPort; + return 0; + } + HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj)); + + const char* mode = jh::getStringFromJson(json_obj, "mode"); + this->mode = (nullptr != mode) ? mode : "slave"; + + const char* ip = jh::getStringFromJson(json_obj, "master_ip"); + this->ip = (nullptr != ip) ? ip : kDefaultIpAddr; + + int port = jh::getIntFromJson(json_obj, "master_port"); + this->port = (0 != port) ? port : kDefaultPort; + + // Check + HMI_DEBUG("mode:%s master_ip:%s master_port:%d", mode, ip, port); + + // Release json_object + json_object_put(json_obj); + + return 0; +} + + +} // namespace wm diff --git a/src/wm_connection.hpp b/src/wm_connection.hpp new file mode 100644 index 0000000..9d3180f --- /dev/null +++ b/src/wm_connection.hpp @@ -0,0 +1,64 @@ +/* + * Insert Copyright if needed. + */ + +#ifndef WM_CONNECTION_HPP +#define WM_CONNECTION_HPP + +#include <functional> + +struct json_object; + +namespace wm +{ + +class WMConnection +{ + public: + WMConnection(); + ~WMConnection() = default; + + using ReceivedHandler = std::function<void(json_object* j_out)>; + + int initialize(); + void registerCallback(ReceivedHandler on_received); + int sendRequest(char const *req, char const *appid, + char const *drawing_name, char const *drawing_area); + bool isMasterMode(); + bool isMasterArea(const char* area); + bool isConnecting(); + std::string parseMasterArea(const char* area); + bool isSyncDrawingForRemote(const char* role); + void startSyncDrawForRemote(const char* role); + void finishSyncDrawForRemote(const char* role); + int getMySocket(); + int getConnectedSocket(); + void setConnectedSocket(int connected_socket); + std::string getEcuName(); + void callOnReceivedHandler(json_object *j_out); + int connectToMaster(); + + int receive(json_object** j_out); + + private: + std::string mode; + std::string ip; + int port; + int my_socket = -1; + int connected_socket = -1; + ReceivedHandler onReceived; + std::string syndDrawingAppId; + + std::string ecu_name; + + int initializeMaster(); + int initializeSlave(); + int loadConnectionConfigFile(); + + int send(json_object* j_in); +}; + +} // namespace wm + +#endif // WM_CONNECTION_HPP + diff --git a/src/wm_layer.cpp b/src/wm_layer.cpp new file mode 100644 index 0000000..d3e7073 --- /dev/null +++ b/src/wm_layer.cpp @@ -0,0 +1,271 @@ +/* + * 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 <regex> +#include <ilm/ilm_control.h> +#include <stdlib.h> +#include "wm_client.hpp" +#include "wm_layer.hpp" +#include "json_helper.hpp" +#include "util.hpp" + +using std::string; +using std::vector; +using std::unordered_map; + +#define BG_LAYER_NAME "BackGroundLayer" + +namespace wm +{ + +LayerState::LayerState() + : render_order(), + area2appid() +{} + + +void LayerState::attachIdToArea(const string& area, const WMClient& client) +{ + this->area2appid[area] = client.appID(); + this->render_order.push_back(client.layerID()); +} + +const unordered_map<string, string> LayerState::popCurrentState() +{ + unordered_map<string, string> tmp = this->area2appid; + this->area2appid.clear(); + this->render_order.clear(); + return tmp; +} + +const unordered_map<string, string> LayerState::getCurrentState() +{ + return this->area2appid; +} + +const vector<unsigned> LayerState::getIviIdList() +{ + return this->render_order; +} + +void LayerState::addLayer(unsigned layer) +{ + auto result = std::find(this->render_order.begin(), this->render_order.end(), layer); + if(result == this->render_order.end()) + this->render_order.push_back(layer); +} + +void LayerState::removeLayer(unsigned layer) +{ + auto fwd_itr = std::remove_if( + this->render_order.begin(), this->render_order.end(), + [layer](unsigned elm) { + if(elm == layer) + HMI_DEBUG("remove layer %d", elm); + return elm == layer; + } + ); + this->render_order.erase(fwd_itr, this->render_order.end()); +} + +void LayerState::setArea(const string& app, const string& area) +{ + this->area2appid[area] = app; +} + +void LayerState::dump() +{ + std::string ids, apps; + for(const auto& ro : this->render_order) + { + ids += std::to_string(ro); + ids += ","; + } + for(const auto& area : this->area2appid) + { + apps += area.first; + apps += ":"; + apps += area.second; + apps += ","; + } + DUMP(" render order : %s", ids.c_str()); + DUMP(" area, app : %s", apps.c_str()); +} + +WMLayer::WMLayer(json_object* j, unsigned uuid) : tmp_state(), state(), uuid(uuid) +{ + this->name = jh::getStringFromJson(j, "name"); + this->role_list = jh::getStringFromJson(j, "role"); + const char* type = jh::getStringFromJson(j, "type"); + this->id_begin = static_cast<unsigned>(jh::getIntFromJson(j, "id_range_begin")); + this->id_end = static_cast<unsigned>(jh::getIntFromJson(j, "id_range_end")); + + if (name.size() == 0 || !type) + { + HMI_ERROR("Parse Error!!"); + exit(1); + } + if(this->id_begin > this->id_end) + { + HMI_ERROR("INVALID"); + exit(1); + } + string str_type = type; + this->type = (str_type == "tile") ? MANAGEMENT_TYPE::TILE : MANAGEMENT_TYPE::STACK; +} + +unsigned WMLayer::getNewLayerID(const string& role) +{ + unsigned ret = 0; + if(this->name == BG_LAYER_NAME) + return ret; + + // generate new layer id; + if(this->hasRole(role)) + { + if(this->id_list.size() == 0) + { + ret = this->idBegin(); + this->id_list.push_back(ret); + } + else + { + ret = this->id_list.back() + 1; + } + HMI_INFO("Generate new id: %d", ret); + } + else + { + return ret; + } + + size_t count = std::count(id_list.begin(), id_list.end(), ret); + if( (ret > this->idEnd()) || (count > 1)) + { + HMI_NOTICE("id %d is not available then generate new id", ret); + ret = 0; // reset + for(unsigned i = this->idBegin(); i < this->idEnd(); i++) + { + auto ret_found = std::find(id_list.begin(), id_list.end(), i); + if(ret_found == id_list.cend()) + { + HMI_INFO("set new id: %d", i); + ret = i; + break; + } + } + } + + if(ret != 0) + { + id_list.push_back(ret); + } + else + { + HMI_ERROR("failed to get New ID"); + } + return ret; +} + +const string& WMLayer::layerName() +{ + return this->name; +} + +WMError WMLayer::setLayerState(const LayerState& l) +{ + this->tmp_state = l; + return WMError::SUCCESS; +} + +void WMLayer::addLayerToState(unsigned layer) +{ + this->tmp_state.addLayer(layer); +} + +void WMLayer::removeLayerFromState(unsigned layer) +{ + this->tmp_state.removeLayer(layer); +} + +void WMLayer::setAreaToState(const string& app, const string& area) +{ + this->tmp_state.setArea(app, area); +} + +void WMLayer::appendArea(const string& area) +{ + this->area_list.push_back(area); +} + +void WMLayer::terminateApp(unsigned id) +{ + auto fwd_itr = std::remove_if(this->id_list.begin(), this->id_list.end(), + [id](unsigned elm) { + return elm == id; + }); + this->id_list.erase(fwd_itr, this->id_list.end()); + this->tmp_state.removeLayer(id); + this->state.removeLayer(id); + ilm_layerRemove(id); +} + +bool WMLayer::hasLayerID(unsigned id) +{ + bool ret = (id >= this->idBegin() && id <= this->idEnd()); + if(!ret) + return ret; + auto itr = std::find(this->id_list.begin(), this->id_list.end(), id); + return (itr != this->id_list.end()) ? true : false; +} + +bool WMLayer::hasRole(const string& role) +{ + auto re = std::regex(this->role_list); + if (std::regex_match(role, re)) + { + HMI_DEBUG("role %s matches layer %s", role.c_str(), this->name.c_str()); + return true; + } + return false; +} + +void WMLayer::update() +{ + this->state = this->tmp_state; +} + +void WMLayer::undo() +{ + this->tmp_state = this->state; +} + +void WMLayer::dump() +{ + DUMP("===== wm layer status ====="); + DUMP("Layer :%s", this->name.c_str()); + this->tmp_state.dump(); + this->state.dump(); + DUMP("===== wm layer status end ====="); + +} + +/* void WMLayer::undo() +{ + this->tmp_state = this->state; +} + */ +} // namespace wm diff --git a/src/wm_layer.hpp b/src/wm_layer.hpp new file mode 100644 index 0000000..a6a359e --- /dev/null +++ b/src/wm_layer.hpp @@ -0,0 +1,104 @@ +/* + * 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 WM_LAYER_HPP +#define WM_LAYER_HPP + +#include <string> +#include <vector> +#include <unordered_map> +#include <memory> +#include "wm_error.hpp" + +struct json_object; + +namespace wm +{ + +class WMClient; +class LayerState +{ + public: + LayerState(); + ~LayerState() = default; + void attachIdToArea(const std::string& area, const WMClient&); + const std::unordered_map<std::string, std::string> popCurrentState(); + const std::unordered_map<std::string, std::string> getCurrentState(); + const std::vector<unsigned> getIviIdList(); + void addLayer(unsigned layer); + void removeLayer(unsigned layer); + void setArea(const std::string& app, const std::string& area); + + // Debug + void dump(); + + private: + std::vector<unsigned> render_order; + std::unordered_map<std::string, std::string> area2appid; +}; + +class WMLayer +{ + public: + enum MANAGEMENT_TYPE + { + TILE, + STACK + }; + + explicit WMLayer(json_object* j, unsigned uuid); + ~WMLayer() = default; + + // Status & Setting API + unsigned getNewLayerID(const std::string& role); + unsigned idBegin() { return this->id_begin; } + unsigned idEnd() { return this->id_end; } + unsigned getUuid() { return this->uuid; } + const std::string& layerName(); + MANAGEMENT_TYPE layerType() { return this->type; } + void appendArea(const std::string& area); + LayerState& getLayerState() { return tmp_state; } + WMError setLayerState(const LayerState& l); + bool hasLayerID(unsigned id); + bool hasRole(const std::string& role); + + // Manipulation + void addLayerToState(unsigned layer); + void removeLayerFromState(unsigned layer); + void setAreaToState(const std::string& app, const std::string& area); + void terminateApp(unsigned layer); + void update(); + void undo(); + + // Debug + void dump(); + + private: + LayerState tmp_state; + LayerState state; + unsigned uuid; + std::string name = ""; // Layer name + MANAGEMENT_TYPE type; + std::string role_list; + std::vector<std::string> area_list; + std::vector<unsigned> id_list; + unsigned id_begin; + unsigned id_end; +}; + +} // namespace wm + +#endif // WM_LAYER_HPP diff --git a/src/wm_layer_control.cpp b/src/wm_layer_control.cpp new file mode 100644 index 0000000..10e99b9 --- /dev/null +++ b/src/wm_layer_control.cpp @@ -0,0 +1,899 @@ +/* + * 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 <assert.h> +#include <unistd.h> +#include "wm_layer_control.hpp" +#include "wm_layer.hpp" +#include "wm_client.hpp" +#include "request.hpp" +#include "json_helper.hpp" + +#define LC_AREA_PATH "/etc/areas.json" +#define LC_LAYER_SETTING_PATH "/etc/layers_setting.json" +#define LC_DEFAULT_AREA "fullscreen" +#define BACK_GROUND_LAYER "BackGroundLayer" + +using std::string; +using std::vector; +using std::shared_ptr; + +namespace wm { + +LayerControl* g_lc_ctxt; + +static void createCallback_static(ilmObjectType object, + t_ilm_uint id, + t_ilm_bool created, + void* data) +{ + static_cast<LayerControl*>(data)->dispatchCreateEvent(object, id, created); +} + +static void surfaceCallback_static(t_ilm_surface surface, + struct ilmSurfaceProperties* surface_prop, + t_ilm_notification_mask mask) +{ + g_lc_ctxt->dispatchSurfacePropChangeEvent(surface, surface_prop, mask); +} + +static void layerCallback_static(t_ilm_layer layer, + struct ilmLayerProperties* layer_prop, + t_ilm_notification_mask mask) +{ + g_lc_ctxt->dispatchLayerPropChangeEvent(layer, layer_prop, mask); +} + +LayerControl::LayerControl(const std::string& root, const std::string& ecu_name) +{ + string area_path = root + LC_AREA_PATH; + string layer_path= root + LC_LAYER_SETTING_PATH; + // load layers.setting.json + WMError ret = this->loadLayerSetting(layer_path); + assert(ret == WMError::SUCCESS); + // load areas.json + ret = this->loadAreasConfigFile(area_path, ecu_name); + assert(ret == WMError::SUCCESS); +} + +WMError LayerControl::init(const LayerControlCallbacks& cb) +{ + HMI_DEBUG("Initialize of ilm library and display"); + t_ilm_uint num = 0; + t_ilm_uint *ids; + int cnt = 0; + ilmErrorTypes rc = ilm_init(); + + while (rc != ILM_SUCCESS) + { + cnt++; + if (20 <= cnt) + { + HMI_ERROR("Could not connect to compositor"); + goto lc_init_error; + } + HMI_ERROR("Wait to start weston ..."); + sleep(1); + rc = ilm_init(); + } + if(rc != ILM_SUCCESS) goto lc_init_error; + + // Get current screen setting + rc = ilm_getScreenIDs(&num, &ids); + + if(rc != ILM_SUCCESS) goto lc_init_error; + + for(unsigned i = 0; i < num; i++) + { + HMI_INFO("get screen: %d", ids[i]); + } + // Currently, 0 is only available + this->screenID = ids[0]; + + if (1 < num) + { + // TODO: set remote screen id + HMI_INFO("There is remote screen (id:%d)", ids[1]); + this->remoteScreenID = ids[1]; + } + else + { + HMI_INFO("There is no remote screen"); + this->remoteScreenID = -1; + } + + rc = ilm_getPropertiesOfScreen(this->screenID, &this->screen_prop); + + if(rc != ILM_SUCCESS) goto lc_init_error; + + // Register Callback to Window Manager and from ILM + this->cb = cb; + ilm_registerNotification(createCallback_static, this); + + return WMError::SUCCESS; + +lc_init_error: + HMI_ERROR("Failed to initialize. Terminate WM"); + + return WMError::FAIL; +} + +void LayerControl::createNewLayer(unsigned id) +{ + HMI_INFO("create new ID :%d", id); + struct rect rct = this->area2size[LC_DEFAULT_AREA]; + ilm_layerCreateWithDimension(&id, rct.w, rct.h); + //ilm_layerSetSourceRectangle(id, rct.x, rct.y, rct.w, rct.h); + ilm_layerSetDestinationRectangle(id, this->offset_x, this->offset_y, rct.w, rct.h); + ilm_layerSetOpacity(id, 1.0); + ilm_layerSetVisibility(id, ILM_FALSE); + ilm_commitChanges(); + auto wm_layer = getWMLayer(id); + wm_layer->addLayerToState(id); + this->renderLayers(); + this->renderLayersRemote(); +} + +void LayerControl::createNewRemoteLayer(unsigned id) +{ + HMI_INFO("create new ID :%d (For remote layer)", id); + struct rect rct = {640, 720, 0, 0}; + ilm_layerCreateWithDimension(&id, rct.w, rct.h); + //ilm_layerSetSourceRectangle(id, rct.x, rct.y, rct.w, rct.h); + ilm_layerSetDestinationRectangle(id, this->offset_x, this->offset_y, rct.w, rct.h); + ilm_layerSetOpacity(id, 1.0); + ilm_layerSetVisibility(id, ILM_FALSE); + ilm_commitChanges(); + auto wm_layer = getWMLayer(id); + wm_layer->addLayerToState(id); + this->renderLayers(); + this->renderLayersRemote(); +} + +unsigned LayerControl::getNewLayerID(const string& role, string* layer_name) +{ + unsigned ret = 0; + for(const auto& l: this->wm_layers) + { + ret = l->getNewLayerID(role); + if(ret != 0) + { + *layer_name = l->layerName(); + unsigned uid = l->getUuid(); + this->lid2wmlid[ret] = uid; + break; + } + } + return ret; +} + +shared_ptr<WMLayer> LayerControl::getWMLayer(unsigned layer) +{ + unsigned uuid = this->lid2wmlid[layer]; + return this->wm_layers[uuid]; +} + +std::shared_ptr<WMLayer> LayerControl::getWMLayer(std::string layer_name) +{ + for(auto &l : this->wm_layers) + { + if(l->layerName() == layer_name) + { + return l; + } + } + return nullptr; +} + +struct rect LayerControl::getAreaSize(const std::string& area) +{ + return area2size[area]; +} + +void LayerControl::setupArea(const rectangle& base_rct, double scaling) +{ + this->scaling = scaling; + this->offset_x = base_rct.left(); + this->offset_y = base_rct.top(); + + for (auto &i : this->area2size) + { + i.second.x = static_cast<int>(scaling * i.second.x + 0.5); + i.second.y = static_cast<int>(scaling * i.second.y + 0.5); + i.second.w = static_cast<int>(scaling * i.second.w + 0.5); + i.second.h = static_cast<int>(scaling * i.second.h + 0.5); + + HMI_DEBUG("area:%s size(after) : x:%d y:%d w:%d h:%d", + i.first.c_str(), i.second.x, i.second.y, i.second.w, i.second.h); + } +} + +Screen LayerControl::getScreenInfo() +{ + return Screen(this->screen_prop.screenWidth, this->screen_prop.screenHeight); +} + +double LayerControl::scale() +{ + return this->scaling; +} + +WMError LayerControl::updateLayer(LayerState& layer_state) +{ + return WMError::SUCCESS; +} + +WMError LayerControl::renderLayers() +{ + HMI_INFO("Commit change"); + WMError rc = WMError::SUCCESS; + + // Check the number of layers + vector<unsigned> ivi_l_ids; + for(auto& l : this->wm_layers) + { + auto state = l->getLayerState(); + HMI_DEBUG("layer %s", l->layerName().c_str()); + for(const auto& id : state.getIviIdList()) + { + HMI_DEBUG("Add %d", id); + ivi_l_ids.push_back(id); + } + } + + // Create render order + t_ilm_layer* id_array = new t_ilm_layer[ivi_l_ids.size()]; + if(id_array == nullptr) + { + HMI_WARNING("short memory"); + this->undoUpdate(); + return WMError::FAIL; + } + int count = 0; + for(const auto& i : ivi_l_ids) + { + id_array[count] = i; + ++count; + } + + // Display + ilmErrorTypes ret = ilm_displaySetRenderOrder(this->screenID, id_array, ivi_l_ids.size()); + if(ret != ILM_SUCCESS) + { + this->undoUpdate(); + rc = WMError::FAIL; + } + else + { + for(auto& l : this->wm_layers) + { + l->update(); + } + } + ilm_commitChanges(); + delete id_array; + return rc; +} + +WMError LayerControl::renderLayersRemote() +{ + HMI_INFO("Commit change"); + WMError rc = WMError::SUCCESS; + + if (0 > this->remoteScreenID) + { + return rc; + } + + // Check the number of layers + vector<unsigned> ivi_l_ids; + for(auto& l : this->wm_remote_layers) + { + auto state = l->getLayerState(); + HMI_DEBUG("layer %s", l->layerName().c_str()); + for(const auto& id : state.getIviIdList()) + { + HMI_DEBUG("Add %d", id); + ivi_l_ids.push_back(id); + } + } + + if (0 == ivi_l_ids.size()) + { + ilm_displaySetRenderOrder(this->remoteScreenID, nullptr, 0); + return rc; + } + + // Create render order + t_ilm_layer* id_array = new t_ilm_layer[ivi_l_ids.size()]; + if(id_array == nullptr) + { + HMI_WARNING("short memory"); + this->undoUpdate(); + return WMError::FAIL; + } + int count = 0; + for(const auto& i : ivi_l_ids) + { + id_array[count] = i; + ++count; + } + + // Display + ilmErrorTypes ret = ilm_displaySetRenderOrder(this->remoteScreenID, id_array, ivi_l_ids.size()); + if(ret != ILM_SUCCESS) + { + this->undoUpdate(); + rc = WMError::FAIL; + } + else + { + for(auto& l : this->wm_remote_layers) + { + l->update(); + } + } + ilm_commitChanges(); + delete id_array; + return rc; +} + +WMError LayerControl::setXDGSurfaceOriginSize(unsigned surface) +{ + WMError ret = WMError::NOT_REGISTERED; + ilmSurfaceProperties prop; + ilmErrorTypes rc = ilm_getPropertiesOfSurface(surface, &prop); + if(rc == ILM_SUCCESS) + { + HMI_INFO("xdg surface info %d, %d", prop.origSourceWidth, prop.origSourceHeight); + ilm_surfaceSetSourceRectangle(surface, 0, 0, prop.origSourceWidth, prop.origSourceHeight); + ret = WMError::SUCCESS; + } + return ret; +} + + +void LayerControl::undoUpdate() +{ + for(auto& l : this->wm_layers) + { + l->undo(); + } +} + +WMError LayerControl::loadLayerSetting(const string &path) +{ + HMI_DEBUG("loading WMLayer(Application Containers) Setting from %s", path); + + json_object *json_obj, *json_cfg; + int ret = jh::inputJsonFilie(path.c_str(), &json_obj); + if (0 > ret) + { + HMI_ERROR("Could not open %s", path.c_str()); + return WMError::FAIL; + } + HMI_INFO("json_obj dump:%s", json_object_get_string(json_obj)); + + if (!json_object_object_get_ex(json_obj, "mappings", &json_cfg)) + { + HMI_ERROR("Parse Error!!"); + return WMError::FAIL; + } + + int len = json_object_array_length(json_cfg); + HMI_DEBUG("json_cfg len:%d", len); + + for (int i = 0; i < len; i++) + { + json_object *json_tmp = json_object_array_get_idx(json_cfg, i); + HMI_DEBUG("> json_tmp dump:%s", json_object_get_string(json_tmp)); + + this->wm_layers.emplace_back(std::make_shared<WMLayer>(json_tmp, i)); + } + json_object_put(json_obj); + + return WMError::SUCCESS; +} + +WMError LayerControl::loadAreasConfigFile(const std::string& path, const std::string& ecu_name) +{ + // Load areas config file + json_object *json_obj; + int ret = jh::inputJsonFilie(path.c_str(), &json_obj); + if (0 > ret) + { + HMI_ERROR("Could not open %s", path.c_str()); + return WMError::FAIL; + } + HMI_INFO("json_obj dump:%s", json_object_get_string(json_obj)); + + // Parse ecus + json_object *json_cfg; + if (!json_object_object_get_ex(json_obj, "ecus", &json_cfg)) + { + HMI_ERROR("Parse Error!!"); + return WMError::FAIL; + } + + int num_ecu = json_object_array_length(json_cfg); + HMI_DEBUG("json_cfg(ecus) len:%d", num_ecu); + + const char* c_ecu_name; + json_object *json_ecu; + for (int i = 0; i < num_ecu; i++) + { + json_ecu= json_object_array_get_idx(json_cfg, i); + + c_ecu_name = jh::getStringFromJson(json_ecu, "name"); + if (nullptr == c_ecu_name) + { + HMI_ERROR("Parse Error!!"); + return WMError::FAIL; + } + + if (ecu_name == string(c_ecu_name)) + { + break; + } + else + { + json_ecu = nullptr; + } + } + + if (!json_ecu) + { + HMI_ERROR("Areas for ecu:%s is NOT exist!!", ecu_name.c_str()); + return WMError::FAIL; + } + + // Parse screens + if (!json_object_object_get_ex(json_ecu, "screens", &json_cfg)) + { + HMI_ERROR("Parse Error!!"); + return WMError::FAIL; + } + + int num_screen = json_object_array_length(json_cfg); + HMI_DEBUG("json_cfg(screens) len:%d", num_screen); + + int screen_id; + json_object *json_screen; + for (int i = 0; i < num_screen; i++) + { + json_screen = json_object_array_get_idx(json_cfg, i); + HMI_INFO("json_cfg dump:%s", json_object_get_string(json_cfg)); + + // TODO: Currently only one display is connected to a ECU. + + screen_id = jh::getIntFromJson(json_screen, "id"); + + // Parse areas + json_object *json_tmp; + if (!json_object_object_get_ex(json_screen, "areas", &json_tmp)) + { + HMI_ERROR("Parse Error!!"); + return WMError::FAIL; + } + + int num_area = json_object_array_length(json_tmp); + HMI_DEBUG("json_tmp(areas) len:%d", num_area); + + const char *area; + for (int j = 0; j < num_area; j++) + { + json_object *json_area = json_object_array_get_idx(json_tmp, j); + + area = jh::getStringFromJson(json_area, "name"); + if (nullptr == area) + { + HMI_ERROR("Parse Error!!"); + return WMError::FAIL; + } + HMI_DEBUG("> area:%s", area); + + json_object *json_rect; + if (!json_object_object_get_ex(json_area, "rect", &json_rect)) + { + HMI_ERROR("Parse Error!!"); + return WMError::FAIL; + } + + struct rect area_size; + area_size.x = jh::getIntFromJson(json_rect, "x"); + area_size.y = jh::getIntFromJson(json_rect, "y"); + area_size.w = jh::getIntFromJson(json_rect, "w"); + area_size.h = jh::getIntFromJson(json_rect, "h"); + + this->area2size[area] = area_size; + } + + // Check + for (const auto& itr : this->area2size) + { + HMI_DEBUG("area:%s x:%d y:%d w:%d h:%d", + itr.first.c_str(), itr.second.x, itr.second.y, + itr.second.w, itr.second.h); + } + } + + // Release json_object + json_object_put(json_obj); + + return WMError::SUCCESS; +} + +WMError LayerControl::layoutChange(const WMAction& action) +{ + if ((action.visible == TaskVisible::INVISIBLE) || + (action.visible == TaskVisible::REQ_REMOTE_VISIBLE) || + (action.visible == TaskVisible::REQ_REMOTE_INVISIBLE)) + { + // Visibility is not change -> no redraw is required + return WMError::SUCCESS; + } + if(action.client == nullptr) + { + HMI_SEQ_ERROR(action.req_num, "client may vanish"); + return WMError::NOT_REGISTERED; + } + unsigned layer = action.client->layerID(); + unsigned surface = action.client->surfaceID(); + + auto rect = this->getAreaSize(action.area); + HMI_DEBUG("Set layout %d, %d, %d, %d",rect.x, rect.y, rect.w, rect.h); + ilm_commitChanges(); + ilm_surfaceSetDestinationRectangle(surface, rect.x, rect.y, rect.w, rect.h); + ilm_commitChanges(); + for(auto &wm_layer: this->wm_layers) + { + // Store the state who is assigned to the area + if(wm_layer->hasLayerID(layer)) + { + wm_layer->setAreaToState(action.client->appID(), action.area); + /* TODO: manipulate state directly + LayerState ls = wm_layer->getLayerState(); + ls.setArea(action.client->appID(), action.area); + wm_layer->dump(); */ + } + } + + return WMError::SUCCESS; +} + +WMError LayerControl::visibilityChange(const WMAction& action) +{ + WMError ret = WMError::FAIL; + if(action.client == nullptr) + { + HMI_SEQ_ERROR(action.req_num, "client may vanish"); + return WMError::NOT_REGISTERED; + } + + if (action.visible == TaskVisible::VISIBLE) + { + ret = this->makeVisible(action.client); + } + else if (action.visible == TaskVisible::INVISIBLE) + { + ret = this->makeInvisible(action.client); + } + else if (action.visible == TaskVisible::REMOTE_VISIBLE) + { + ret = this->makeRemoteVisible(action.client); + } + else if (action.visible == TaskVisible::REMOTE_INVISIBLE) + { + ret = this->makeRemoteInvisible(action.client); + } + else // TaskVisible::REQ_REMOTE_VISIBLE || TaskVisible::REQ_REMOTE_INVISIBLE + { + // Visibility is not change + ret = WMError::SUCCESS; + } + + return ret; +} + +void LayerControl::terminateApp(const shared_ptr<WMClient> client) +{ + for(auto& l : this->wm_layers) + { + l->terminateApp(client->layerID()); + } +} + +void LayerControl::dispatchCreateEvent(ilmObjectType object, unsigned id, bool created) +{ + if (ILM_SURFACE == object) + { + if (created) + { + ilmSurfaceProperties sp; + ilmErrorTypes rc; + rc = ilm_getPropertiesOfSurface(id, &sp); + if(rc != ILM_SUCCESS) + { + HMI_ERROR("Failed to get surface %d property due to %d", id, ilm_getError()); + return; + } + this->cb.surfaceCreated(sp.creatorPid, id); + ilm_surfaceSetSourceRectangle(id, 0, 0, sp.origSourceWidth, sp.origSourceHeight); + ilm_surfaceAddNotification(id, surfaceCallback_static); + ilm_surfaceSetVisibility(id, ILM_TRUE); + ilm_surfaceSetType(id, ILM_SURFACETYPE_DESKTOP); + } + else + { + this->cb.surfaceDestroyed(id); + } + } + if (ILM_LAYER == object) + { + if(created) + { + ilm_layerAddNotification(id, layerCallback_static); + } + else + { + // Ignore here. Nothing to do currently. + // Process of application dead is handled by Window Manager + // from binder notification + } + } +} + +void LayerControl::dispatchSurfacePropChangeEvent(unsigned id, + struct ilmSurfaceProperties* sprop, + t_ilm_notification_mask mask) +{ + /* + ILM_NOTIFICATION_CONTENT_AVAILABLE & ILM_NOTIFICATION_CONTENT_REMOVED + are not handled here, handled in create/destroy event + */ + if (ILM_NOTIFICATION_VISIBILITY & mask) + { + HMI_DEBUG("surface %d turns visibility %d", id, sprop->visibility); + } + if (ILM_NOTIFICATION_OPACITY & mask) + { + HMI_DEBUG("surface %d turns opacity %f", id, sprop->opacity); + } + if (ILM_NOTIFICATION_SOURCE_RECT & mask) + { + HMI_DEBUG("surface %d source rect changes", id); + } + if (ILM_NOTIFICATION_DEST_RECT & mask) + { + HMI_DEBUG("surface %d dest rect changes", id); + } + if (ILM_NOTIFICATION_CONFIGURED & mask) + { + HMI_DEBUG("surface %d size %d, %d, %d, %d", id, + sprop->sourceX, sprop->sourceY, sprop->origSourceWidth, sprop->origSourceHeight); + ilm_surfaceSetSourceRectangle(id, 0, 0, sprop->origSourceWidth, sprop->origSourceHeight); + } +} + +void LayerControl::dispatchLayerPropChangeEvent(unsigned id, + struct ilmLayerProperties* lprop, + t_ilm_notification_mask mask) +{ + if (ILM_NOTIFICATION_VISIBILITY & mask) + { + HMI_DEBUG("layer %d turns visibility %d", id, lprop->visibility); + } + if (ILM_NOTIFICATION_OPACITY & mask) + { + HMI_DEBUG("layer %d turns opacity %f", id, lprop->opacity); + } + if (ILM_NOTIFICATION_SOURCE_RECT & mask) + { + HMI_DEBUG("layer %d source rect changes", id); + } + if (ILM_NOTIFICATION_DEST_RECT & mask) + { + HMI_DEBUG("layer %d dest rect changes", id); + } +} + +WMError LayerControl::makeVisible(const shared_ptr<WMClient> client) +{ + WMError ret = WMError::SUCCESS; + // Don't check here the client is not nullptr + unsigned layer = client->layerID(); + + this->moveForeGround(client); + + ilm_layerSetVisibility(layer, ILM_TRUE); + + /* for(auto& wm_layer : this->wm_layers) + { + if(wm_layer->hasLayerID(layer)) + { + LayerState ls = wm_layer->getLayerState(); + ls.addLayer(layer);; + } + } */ + + // Move foreground from back ground layer + /* for(auto& wm_layer : this->wm_layers) + { + if(wm_layer->layerName() == "BackGroundLayer") + { + if(wm_layer->hasRole(client->role())) + { + LayerState ls = wm_layer->getLayerState(); + ls.removeLayer(layer); + } + break; + } + } */ + + return ret; +} + +WMError LayerControl::makeInvisible(const shared_ptr<WMClient> client) +{ + WMError ret = WMError::SUCCESS; + unsigned layer = client->layerID(); // Don't check here the client is not nullptr + + bool mv_ok = this->moveBackGround(client); + + if(!mv_ok) + { + HMI_INFO("make invisible client %s", client->appID().c_str()); + ilm_layerSetVisibility(layer, ILM_FALSE); + } + + //ilm_layerSetDestinationRectangle(layer, 0, 0, 0, 0); + + /* for(auto& wm_layer : this->wm_layers) + { + if(wm_layer->hasLayerID(layer)) + { + LayerState ls = wm_layer->getLayerState(); + ls.removeLayer(layer);; + } + } */ + + + + return ret; +} + +WMError LayerControl::makeRemoteVisible(const shared_ptr<WMClient> client) +{ + WMError ret = WMError::SUCCESS; + unsigned layer = client->layerID(); // Don't check here the client is not nullptr + + if (0 > this->remoteScreenID) + { + return ret; + } + + // TODO: Currently there is only one remote screen. + for (auto itr = this->wm_layers.begin(); itr != this->wm_layers.end(); ++itr) + { + if((*itr)->hasLayerID(layer)) + { + HMI_DEBUG("Add layer:%d to remote screen:%d", layer, this->remoteScreenID); + this->wm_remote_layers.push_back(*itr); + this->wm_layers.erase(itr); + } + + if (this->wm_layers.end() == itr) + { + HMI_DEBUG("iteretor indicates end of vector of wm_layers"); + break; + } + } + + ilm_layerSetVisibility(layer, ILM_TRUE); + + return ret; +} + +WMError LayerControl::makeRemoteInvisible(const shared_ptr<WMClient> client) +{ + WMError ret = WMError::SUCCESS; + unsigned layer = client->layerID(); // Don't check here the client is not nullptr + + if (0 > this->remoteScreenID) + { + return ret; + } + + // TODO: Currently there is only one remote screen. + for (auto itr = this->wm_remote_layers.begin(); + itr != this->wm_remote_layers.end(); ++itr) + { + if((*itr)->hasLayerID(layer)) + { + HMI_DEBUG("Remove layer:%d from remote screen:%d", layer, this->remoteScreenID); + this->wm_layers.push_back(*itr); + this->wm_remote_layers.erase(itr); + } + + if (this->wm_remote_layers.end() == itr) + { + HMI_DEBUG("iteretor indicates end of vector of wm_remote_layers"); + break; + } + } + + ilm_layerSetVisibility(layer, ILM_FALSE); + + return ret; +} + +bool LayerControl::moveBackGround(const shared_ptr<WMClient> client) +{ + bool ret = false; + + // Move background from foreground layer + auto bg = this->getWMLayer(BACK_GROUND_LAYER); + if(bg != nullptr) + { + HMI_DEBUG("client %s role %s", client->appID().c_str(), client->role().c_str()); + unsigned layer = client->layerID(); + if(bg->hasRole(client->role())) + { + HMI_INFO("%s go to background", client->appID().c_str()); + bg->addLayerToState(layer); + auto wm_layer = this->getWMLayer(layer); + wm_layer->removeLayerFromState(layer); + /* TODO: manipulate state directly + LayerState bg_ls = bg->getLayerState(); + bg_ls.addLayer(layer); + LayerState ls = wm_layer->getLayerState(); + ls.removeLayer(layer); */ + bg->dump(); + wm_layer->dump(); + ret = true; + } + } + return ret; +} + +bool LayerControl::moveForeGround(const shared_ptr<WMClient> client) +{ + bool ret = false; + + // Move foreground from foreground layer + auto bg = this->getWMLayer(BACK_GROUND_LAYER); + if(bg != nullptr) + { + if(bg->hasRole(client->role())) + { + unsigned layer = client->layerID(); + HMI_INFO("%s go to foreground", client->appID().c_str()); + bg->removeLayerFromState(layer); + auto wm_layer = this->getWMLayer(layer); + wm_layer->addLayerToState(layer); + /* TODO: manipulate state directly + LayerState bg_ls = bg->getLayerState(); + bg_ls.removeLayer(layer); + LayerState ls = wm_layer->getLayerState(); + ls.addLayer(layer); */ + bg->dump(); + wm_layer->dump(); + ret = true; + } + } + return ret; +} + +} // namespace wm diff --git a/src/wm_layer_control.hpp b/src/wm_layer_control.hpp new file mode 100644 index 0000000..fa7c7cb --- /dev/null +++ b/src/wm_layer_control.hpp @@ -0,0 +1,118 @@ +/* + * 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 <string> +#include <memory> +#include <vector> +#include <unordered_map> +#include <functional> +#include <ilm/ilm_control.h> +#include "wm_error.hpp" +#include "util.hpp" + +namespace wm { + +class Screen { + public: + Screen(unsigned w, unsigned h) : _width(w), _height(h){} + unsigned width() { return _width; } + unsigned height() { return _height; } + private: + unsigned _width; + unsigned _height; + unsigned _pysical_width = 0; + unsigned _pysical_height = 0; +}; + +class LayerControlCallbacks { + public: + LayerControlCallbacks() {}; + ~LayerControlCallbacks() = default; + LayerControlCallbacks(const LayerControlCallbacks &obj) = default; + + // callback functions + std::function<void(unsigned, unsigned)> surfaceCreated; + std::function<void(unsigned)> surfaceDestroyed; + /* std::function<void(unsigned)> surfaceDestroyed; + std::function<void(unsigned)> layerCreated; + std::function<void(unsigned)> layerDestroyed; */ +}; + +class WMLayer; +class LayerState; +class WMAction; +class WMClient; + +class LayerControl +{ + public: + explicit LayerControl(const std::string& root, const std::string& ecu_name); + ~LayerControl() = default; + WMError init(const LayerControlCallbacks& cb); + void createNewLayer(unsigned id); + void createNewRemoteLayer(unsigned id); + unsigned getNewLayerID(const std::string& role, std::string* layer_name); + std::shared_ptr<WMLayer> getWMLayer(unsigned layer); + std::shared_ptr<WMLayer> getWMLayer(std::string layer_name); + struct rect getAreaSize(const std::string& area); + void setupArea(const rectangle& base_rct, double scaling); + Screen getScreenInfo(); + double scale(); + // void setRenderOrder(const std::vector<unsigned> layer_render_order); + // std::vector<unsigned> getAllRenderOrder(); + // std::vector<std::shared_ptr<WMLayer>>& getAllLayers(); + // std::vector<unsigned> getRenderOrder(const std::string& layer_name); + WMError updateLayer(LayerState& layer_state); + WMError renderLayers(); + WMError renderLayersRemote(); + WMError setXDGSurfaceOriginSize(unsigned surface); + // WMError renderWMLayers(); + void undoUpdate(); + WMError layoutChange(const WMAction& action); + WMError visibilityChange(const WMAction &action); + void terminateApp(const std::shared_ptr<WMClient> client); + + // Don't use this function. + void dispatchCreateEvent(ilmObjectType object, unsigned id, bool created); + void dispatchSurfacePropChangeEvent(unsigned id, struct ilmSurfaceProperties*, t_ilm_notification_mask); + void dispatchLayerPropChangeEvent(unsigned id, struct ilmLayerProperties*, t_ilm_notification_mask); + + private: + WMError makeVisible(const std::shared_ptr<WMClient> client); + WMError makeInvisible(const std::shared_ptr<WMClient> client); + bool moveForeGround(const std::shared_ptr<WMClient> client); + bool moveBackGround(const std::shared_ptr<WMClient> client); + WMError loadLayerSetting(const std::string& path); + WMError loadAreasConfigFile(const std::string& path, const std::string& ecu_name); + + // For Remote + WMError makeRemoteVisible(const std::shared_ptr<WMClient> client); + WMError makeRemoteInvisible(const std::shared_ptr<WMClient> client); + + std::vector<std::shared_ptr<WMLayer>> wm_layers; + std::vector<std::shared_ptr<WMLayer>> wm_remote_layers; + std::unordered_map<unsigned, unsigned> lid2wmlid; + std::unordered_map<std::string, struct rect> area2size; + unsigned screenID; + signed remoteScreenID; + struct ilmScreenProperties screen_prop; + double scaling; + int offset_x; + int offset_y; + LayerControlCallbacks cb; +}; + +} // namespace wm |