diff --git a/Lib/QtHTTPServer/Qt5HttpServer.dll b/Lib/QtHTTPServer/Qt5HttpServer.dll new file mode 100644 index 0000000..895923e Binary files /dev/null and b/Lib/QtHTTPServer/Qt5HttpServer.dll differ diff --git a/Lib/QtHTTPServer/Qt5HttpServer.dll.debug b/Lib/QtHTTPServer/Qt5HttpServer.dll.debug new file mode 100644 index 0000000..ebae7fd Binary files /dev/null and b/Lib/QtHTTPServer/Qt5HttpServer.dll.debug differ diff --git a/Lib/QtHTTPServer/Qt5HttpServer.prl b/Lib/QtHTTPServer/Qt5HttpServer.prl new file mode 100644 index 0000000..c56a9fc --- /dev/null +++ b/Lib/QtHTTPServer/Qt5HttpServer.prl @@ -0,0 +1,5 @@ +QMAKE_PRL_BUILD_DIR = D:/Main/Dev/qthttpserver/src/httpserver +QMAKE_PRO_INPUT = httpserver.pro +QMAKE_PRL_TARGET = libQt5HttpServer.a +QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin windows prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl debug_and_release precompile_header shared shared release no_plugin_manifest win32 mingw gcc copy_dir_files sse2 aesni sse3 ssse3 sse4_1 sse4_2 compile_examples force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions release ReleaseBuild Release build_pass qml_debug release ReleaseBuild Release build_pass relative_qt_rpath git_build target_qt c++11 strict_c++ c++14 c++1z c99 c11 separate_debug_info qt_install_headers need_fwd_pri qt_install_module create_cmake skip_target_version_ext compiler_supports_fpmath create_pc release ReleaseBuild Release build_pass have_target dll exclusive_builds debug_info no_autoqmake thread moc resources +QMAKE_PRL_VERSION = 5.12.0 diff --git a/Lib/QtHTTPServer/Qt5SslServer.dll b/Lib/QtHTTPServer/Qt5SslServer.dll new file mode 100644 index 0000000..f756175 Binary files /dev/null and b/Lib/QtHTTPServer/Qt5SslServer.dll differ diff --git a/Lib/QtHTTPServer/Qt5SslServer.dll.debug b/Lib/QtHTTPServer/Qt5SslServer.dll.debug new file mode 100644 index 0000000..85e8171 Binary files /dev/null and b/Lib/QtHTTPServer/Qt5SslServer.dll.debug differ diff --git a/Lib/QtHTTPServer/Qt5SslServer.prl b/Lib/QtHTTPServer/Qt5SslServer.prl new file mode 100644 index 0000000..015bd0c --- /dev/null +++ b/Lib/QtHTTPServer/Qt5SslServer.prl @@ -0,0 +1,5 @@ +QMAKE_PRL_BUILD_DIR = D:/Main/Dev/qthttpserver/src/sslserver +QMAKE_PRO_INPUT = sslserver.pro +QMAKE_PRL_TARGET = libQt5SslServer.a +QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin windows prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl debug_and_release shared shared release no_plugin_manifest win32 mingw gcc copy_dir_files sse2 aesni sse3 ssse3 sse4_1 sse4_2 compile_examples force_debug_info largefile rdrnd shani x86SimdAlways prefix_build force_independent utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions release ReleaseBuild Release build_pass qml_debug release ReleaseBuild Release build_pass relative_qt_rpath git_build target_qt c++11 strict_c++ c++14 c++1z c99 c11 separate_debug_info qt_install_headers need_fwd_pri qt_install_module create_cmake skip_target_version_ext compiler_supports_fpmath create_pc release ReleaseBuild Release build_pass have_target dll exclusive_builds debug_info no_autoqmake thread moc resources +QMAKE_PRL_VERSION = 5.12.0 diff --git a/Lib/QtHTTPServer/cmake/Qt5HttpServer/Qt5HttpServerConfig.cmake b/Lib/QtHTTPServer/cmake/Qt5HttpServer/Qt5HttpServerConfig.cmake new file mode 100644 index 0000000..e489514 --- /dev/null +++ b/Lib/QtHTTPServer/cmake/Qt5HttpServer/Qt5HttpServerConfig.cmake @@ -0,0 +1,223 @@ + +if (CMAKE_VERSION VERSION_LESS 3.1.0) + message(FATAL_ERROR "Qt 5 HttpServer module requires at least CMake version 3.1.0") +endif() + +get_filename_component(_qt5HttpServer_install_prefix "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE) + +# For backwards compatibility only. Use Qt5HttpServer_VERSION instead. +set(Qt5HttpServer_VERSION_STRING 5.12.0) + +set(Qt5HttpServer_LIBRARIES Qt5::HttpServer) + +macro(_qt5_HttpServer_check_file_exists file) + if(NOT EXISTS "${file}" ) + message(FATAL_ERROR "The imported target \"Qt5::HttpServer\" references the file + \"${file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() +endmacro() + + +macro(_populate_HttpServer_target_properties Configuration LIB_LOCATION IMPLIB_LOCATION + IsDebugAndRelease) + set_property(TARGET Qt5::HttpServer APPEND PROPERTY IMPORTED_CONFIGURATIONS ${Configuration}) + + set(imported_location "${_qt5HttpServer_install_prefix}/bin/${LIB_LOCATION}") + _qt5_HttpServer_check_file_exists(${imported_location}) + set(_deps + ${_Qt5HttpServer_LIB_DEPENDENCIES} + ) + set(_static_deps + ) + + set_target_properties(Qt5::HttpServer PROPERTIES + "IMPORTED_LOCATION_${Configuration}" ${imported_location} + # For backward compatibility with CMake < 2.8.12 + "IMPORTED_LINK_INTERFACE_LIBRARIES_${Configuration}" "${_deps};${_static_deps}" + ) + set_property(TARGET Qt5::HttpServer APPEND PROPERTY INTERFACE_LINK_LIBRARIES + "${_deps}" + ) + + + set(imported_implib "${_qt5HttpServer_install_prefix}/lib/${IMPLIB_LOCATION}") + _qt5_HttpServer_check_file_exists(${imported_implib}) + if(NOT "${IMPLIB_LOCATION}" STREQUAL "") + set_target_properties(Qt5::HttpServer PROPERTIES + "IMPORTED_IMPLIB_${Configuration}" ${imported_implib} + ) + endif() +endmacro() + +if (NOT TARGET Qt5::HttpServer) + + set(_Qt5HttpServer_OWN_INCLUDE_DIRS "${_qt5HttpServer_install_prefix}/include/" "${_qt5HttpServer_install_prefix}/include/QtHttpServer") + set(Qt5HttpServer_PRIVATE_INCLUDE_DIRS + "${_qt5HttpServer_install_prefix}/include/QtHttpServer/5.12.0" + "${_qt5HttpServer_install_prefix}/include/QtHttpServer/5.12.0/QtHttpServer" + ) + + foreach(_dir ${_Qt5HttpServer_OWN_INCLUDE_DIRS}) + _qt5_HttpServer_check_file_exists(${_dir}) + endforeach() + + # Only check existence of private includes if the Private component is + # specified. + list(FIND Qt5HttpServer_FIND_COMPONENTS Private _check_private) + if (NOT _check_private STREQUAL -1) + foreach(_dir ${Qt5HttpServer_PRIVATE_INCLUDE_DIRS}) + _qt5_HttpServer_check_file_exists(${_dir}) + endforeach() + endif() + + set(Qt5HttpServer_INCLUDE_DIRS ${_Qt5HttpServer_OWN_INCLUDE_DIRS}) + + set(Qt5HttpServer_DEFINITIONS -DQT_HTTPSERVER_LIB) + set(Qt5HttpServer_COMPILE_DEFINITIONS QT_HTTPSERVER_LIB) + set(_Qt5HttpServer_MODULE_DEPENDENCIES "SslServer;WebSockets;Network;Concurrent;Core") + + + set(Qt5HttpServer_OWN_PRIVATE_INCLUDE_DIRS ${Qt5HttpServer_PRIVATE_INCLUDE_DIRS}) + + set(_Qt5HttpServer_FIND_DEPENDENCIES_REQUIRED) + if (Qt5HttpServer_FIND_REQUIRED) + set(_Qt5HttpServer_FIND_DEPENDENCIES_REQUIRED REQUIRED) + endif() + set(_Qt5HttpServer_FIND_DEPENDENCIES_QUIET) + if (Qt5HttpServer_FIND_QUIETLY) + set(_Qt5HttpServer_DEPENDENCIES_FIND_QUIET QUIET) + endif() + set(_Qt5HttpServer_FIND_VERSION_EXACT) + if (Qt5HttpServer_FIND_VERSION_EXACT) + set(_Qt5HttpServer_FIND_VERSION_EXACT EXACT) + endif() + + set(Qt5HttpServer_EXECUTABLE_COMPILE_FLAGS "") + + foreach(_module_dep ${_Qt5HttpServer_MODULE_DEPENDENCIES}) + if (NOT Qt5${_module_dep}_FOUND) + find_package(Qt5${_module_dep} + 5.12.0 ${_Qt5HttpServer_FIND_VERSION_EXACT} + ${_Qt5HttpServer_DEPENDENCIES_FIND_QUIET} + ${_Qt5HttpServer_FIND_DEPENDENCIES_REQUIRED} + PATHS "${CMAKE_CURRENT_LIST_DIR}/.." NO_DEFAULT_PATH + ) + endif() + + if (NOT Qt5${_module_dep}_FOUND) + set(Qt5HttpServer_FOUND False) + return() + endif() + + list(APPEND Qt5HttpServer_INCLUDE_DIRS "${Qt5${_module_dep}_INCLUDE_DIRS}") + list(APPEND Qt5HttpServer_PRIVATE_INCLUDE_DIRS "${Qt5${_module_dep}_PRIVATE_INCLUDE_DIRS}") + list(APPEND Qt5HttpServer_DEFINITIONS ${Qt5${_module_dep}_DEFINITIONS}) + list(APPEND Qt5HttpServer_COMPILE_DEFINITIONS ${Qt5${_module_dep}_COMPILE_DEFINITIONS}) + list(APPEND Qt5HttpServer_EXECUTABLE_COMPILE_FLAGS ${Qt5${_module_dep}_EXECUTABLE_COMPILE_FLAGS}) + endforeach() + list(REMOVE_DUPLICATES Qt5HttpServer_INCLUDE_DIRS) + list(REMOVE_DUPLICATES Qt5HttpServer_PRIVATE_INCLUDE_DIRS) + list(REMOVE_DUPLICATES Qt5HttpServer_DEFINITIONS) + list(REMOVE_DUPLICATES Qt5HttpServer_COMPILE_DEFINITIONS) + list(REMOVE_DUPLICATES Qt5HttpServer_EXECUTABLE_COMPILE_FLAGS) + + # It can happen that the same FooConfig.cmake file is included when calling find_package() + # on some Qt component. An example of that is when using a Qt static build with auto inclusion + # of plugins: + # + # Qt5WidgetsConfig.cmake -> Qt5GuiConfig.cmake -> Qt5Gui_QSvgIconPlugin.cmake -> + # Qt5SvgConfig.cmake -> Qt5WidgetsConfig.cmake -> + # finish processing of second Qt5WidgetsConfig.cmake -> + # return to first Qt5WidgetsConfig.cmake -> + # add_library cannot create imported target Qt5::Widgets. + # + # Make sure to return early in the original Config inclusion, because the target has already + # been defined as part of the second inclusion. + if(TARGET Qt5::HttpServer) + return() + endif() + + set(_Qt5HttpServer_LIB_DEPENDENCIES "Qt5::SslServer;Qt5::WebSockets;Qt5::Network;Qt5::Concurrent;Qt5::Core") + + + add_library(Qt5::HttpServer SHARED IMPORTED) + + set_property(TARGET Qt5::HttpServer PROPERTY + INTERFACE_INCLUDE_DIRECTORIES ${_Qt5HttpServer_OWN_INCLUDE_DIRS}) + set_property(TARGET Qt5::HttpServer PROPERTY + INTERFACE_COMPILE_DEFINITIONS QT_HTTPSERVER_LIB) + + set_property(TARGET Qt5::HttpServer PROPERTY INTERFACE_QT_ENABLED_FEATURES ) + set_property(TARGET Qt5::HttpServer PROPERTY INTERFACE_QT_DISABLED_FEATURES ) + + set_property(TARGET Qt5::HttpServer PROPERTY INTERFACE_QT_PLUGIN_TYPES "") + + set(_Qt5HttpServer_PRIVATE_DIRS_EXIST TRUE) + foreach (_Qt5HttpServer_PRIVATE_DIR ${Qt5HttpServer_OWN_PRIVATE_INCLUDE_DIRS}) + if (NOT EXISTS ${_Qt5HttpServer_PRIVATE_DIR}) + set(_Qt5HttpServer_PRIVATE_DIRS_EXIST FALSE) + endif() + endforeach() + + if (_Qt5HttpServer_PRIVATE_DIRS_EXIST) + add_library(Qt5::HttpServerPrivate INTERFACE IMPORTED) + set_property(TARGET Qt5::HttpServerPrivate PROPERTY + INTERFACE_INCLUDE_DIRECTORIES ${Qt5HttpServer_OWN_PRIVATE_INCLUDE_DIRS} + ) + set(_Qt5HttpServer_PRIVATEDEPS) + foreach(dep ${_Qt5HttpServer_LIB_DEPENDENCIES}) + if (TARGET ${dep}Private) + list(APPEND _Qt5HttpServer_PRIVATEDEPS ${dep}Private) + endif() + endforeach() + set_property(TARGET Qt5::HttpServerPrivate PROPERTY + INTERFACE_LINK_LIBRARIES Qt5::HttpServer ${_Qt5HttpServer_PRIVATEDEPS} + ) + endif() + + + _populate_HttpServer_target_properties(DEBUG "Qt5HttpServer.dll" "libQt5HttpServer.a" FALSE) + + if (EXISTS + "${_qt5HttpServer_install_prefix}/bin/Qt5HttpServer.dll" + AND EXISTS + "${_qt5HttpServer_install_prefix}/lib/libQt5HttpServer.a" ) + _populate_HttpServer_target_properties(RELEASE "Qt5HttpServer.dll" "libQt5HttpServer.a" FALSE) + endif() + + + + file(GLOB pluginTargets "${CMAKE_CURRENT_LIST_DIR}/Qt5HttpServer_*Plugin.cmake") + + macro(_populate_HttpServer_plugin_properties Plugin Configuration PLUGIN_LOCATION + IsDebugAndRelease) + set_property(TARGET Qt5::${Plugin} APPEND PROPERTY IMPORTED_CONFIGURATIONS ${Configuration}) + + set(imported_location "${_qt5HttpServer_install_prefix}/plugins/${PLUGIN_LOCATION}") + _qt5_HttpServer_check_file_exists(${imported_location}) + set_target_properties(Qt5::${Plugin} PROPERTIES + "IMPORTED_LOCATION_${Configuration}" ${imported_location} + ) + + endmacro() + + if (pluginTargets) + foreach(pluginTarget ${pluginTargets}) + include(${pluginTarget}) + endforeach() + endif() + + + + + +_qt5_HttpServer_check_file_exists("${CMAKE_CURRENT_LIST_DIR}/Qt5HttpServerConfigVersion.cmake") + +endif() diff --git a/Lib/QtHTTPServer/cmake/Qt5HttpServer/Qt5HttpServerConfigVersion.cmake b/Lib/QtHTTPServer/cmake/Qt5HttpServer/Qt5HttpServerConfigVersion.cmake new file mode 100644 index 0000000..e5b7a75 --- /dev/null +++ b/Lib/QtHTTPServer/cmake/Qt5HttpServer/Qt5HttpServerConfigVersion.cmake @@ -0,0 +1,11 @@ + +set(PACKAGE_VERSION 5.12.0) + +if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) + endif() +endif() diff --git a/Lib/QtHTTPServer/cmake/Qt5SslServer/Qt5SslServerConfig.cmake b/Lib/QtHTTPServer/cmake/Qt5SslServer/Qt5SslServerConfig.cmake new file mode 100644 index 0000000..1a30ee0 --- /dev/null +++ b/Lib/QtHTTPServer/cmake/Qt5SslServer/Qt5SslServerConfig.cmake @@ -0,0 +1,223 @@ + +if (CMAKE_VERSION VERSION_LESS 3.1.0) + message(FATAL_ERROR "Qt 5 SslServer module requires at least CMake version 3.1.0") +endif() + +get_filename_component(_qt5SslServer_install_prefix "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE) + +# For backwards compatibility only. Use Qt5SslServer_VERSION instead. +set(Qt5SslServer_VERSION_STRING 5.12.0) + +set(Qt5SslServer_LIBRARIES Qt5::SslServer) + +macro(_qt5_SslServer_check_file_exists file) + if(NOT EXISTS "${file}" ) + message(FATAL_ERROR "The imported target \"Qt5::SslServer\" references the file + \"${file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() +endmacro() + + +macro(_populate_SslServer_target_properties Configuration LIB_LOCATION IMPLIB_LOCATION + IsDebugAndRelease) + set_property(TARGET Qt5::SslServer APPEND PROPERTY IMPORTED_CONFIGURATIONS ${Configuration}) + + set(imported_location "${_qt5SslServer_install_prefix}/bin/${LIB_LOCATION}") + _qt5_SslServer_check_file_exists(${imported_location}) + set(_deps + ${_Qt5SslServer_LIB_DEPENDENCIES} + ) + set(_static_deps + ) + + set_target_properties(Qt5::SslServer PROPERTIES + "IMPORTED_LOCATION_${Configuration}" ${imported_location} + # For backward compatibility with CMake < 2.8.12 + "IMPORTED_LINK_INTERFACE_LIBRARIES_${Configuration}" "${_deps};${_static_deps}" + ) + set_property(TARGET Qt5::SslServer APPEND PROPERTY INTERFACE_LINK_LIBRARIES + "${_deps}" + ) + + + set(imported_implib "${_qt5SslServer_install_prefix}/lib/${IMPLIB_LOCATION}") + _qt5_SslServer_check_file_exists(${imported_implib}) + if(NOT "${IMPLIB_LOCATION}" STREQUAL "") + set_target_properties(Qt5::SslServer PROPERTIES + "IMPORTED_IMPLIB_${Configuration}" ${imported_implib} + ) + endif() +endmacro() + +if (NOT TARGET Qt5::SslServer) + + set(_Qt5SslServer_OWN_INCLUDE_DIRS "${_qt5SslServer_install_prefix}/include/" "${_qt5SslServer_install_prefix}/include/QtSslServer") + set(Qt5SslServer_PRIVATE_INCLUDE_DIRS + "${_qt5SslServer_install_prefix}/include/QtSslServer/5.12.0" + "${_qt5SslServer_install_prefix}/include/QtSslServer/5.12.0/QtSslServer" + ) + + foreach(_dir ${_Qt5SslServer_OWN_INCLUDE_DIRS}) + _qt5_SslServer_check_file_exists(${_dir}) + endforeach() + + # Only check existence of private includes if the Private component is + # specified. + list(FIND Qt5SslServer_FIND_COMPONENTS Private _check_private) + if (NOT _check_private STREQUAL -1) + foreach(_dir ${Qt5SslServer_PRIVATE_INCLUDE_DIRS}) + _qt5_SslServer_check_file_exists(${_dir}) + endforeach() + endif() + + set(Qt5SslServer_INCLUDE_DIRS ${_Qt5SslServer_OWN_INCLUDE_DIRS}) + + set(Qt5SslServer_DEFINITIONS -DQT_SSLSERVER_LIB) + set(Qt5SslServer_COMPILE_DEFINITIONS QT_SSLSERVER_LIB) + set(_Qt5SslServer_MODULE_DEPENDENCIES "Network;Core") + + + set(Qt5SslServer_OWN_PRIVATE_INCLUDE_DIRS ${Qt5SslServer_PRIVATE_INCLUDE_DIRS}) + + set(_Qt5SslServer_FIND_DEPENDENCIES_REQUIRED) + if (Qt5SslServer_FIND_REQUIRED) + set(_Qt5SslServer_FIND_DEPENDENCIES_REQUIRED REQUIRED) + endif() + set(_Qt5SslServer_FIND_DEPENDENCIES_QUIET) + if (Qt5SslServer_FIND_QUIETLY) + set(_Qt5SslServer_DEPENDENCIES_FIND_QUIET QUIET) + endif() + set(_Qt5SslServer_FIND_VERSION_EXACT) + if (Qt5SslServer_FIND_VERSION_EXACT) + set(_Qt5SslServer_FIND_VERSION_EXACT EXACT) + endif() + + set(Qt5SslServer_EXECUTABLE_COMPILE_FLAGS "") + + foreach(_module_dep ${_Qt5SslServer_MODULE_DEPENDENCIES}) + if (NOT Qt5${_module_dep}_FOUND) + find_package(Qt5${_module_dep} + 5.12.0 ${_Qt5SslServer_FIND_VERSION_EXACT} + ${_Qt5SslServer_DEPENDENCIES_FIND_QUIET} + ${_Qt5SslServer_FIND_DEPENDENCIES_REQUIRED} + PATHS "${CMAKE_CURRENT_LIST_DIR}/.." NO_DEFAULT_PATH + ) + endif() + + if (NOT Qt5${_module_dep}_FOUND) + set(Qt5SslServer_FOUND False) + return() + endif() + + list(APPEND Qt5SslServer_INCLUDE_DIRS "${Qt5${_module_dep}_INCLUDE_DIRS}") + list(APPEND Qt5SslServer_PRIVATE_INCLUDE_DIRS "${Qt5${_module_dep}_PRIVATE_INCLUDE_DIRS}") + list(APPEND Qt5SslServer_DEFINITIONS ${Qt5${_module_dep}_DEFINITIONS}) + list(APPEND Qt5SslServer_COMPILE_DEFINITIONS ${Qt5${_module_dep}_COMPILE_DEFINITIONS}) + list(APPEND Qt5SslServer_EXECUTABLE_COMPILE_FLAGS ${Qt5${_module_dep}_EXECUTABLE_COMPILE_FLAGS}) + endforeach() + list(REMOVE_DUPLICATES Qt5SslServer_INCLUDE_DIRS) + list(REMOVE_DUPLICATES Qt5SslServer_PRIVATE_INCLUDE_DIRS) + list(REMOVE_DUPLICATES Qt5SslServer_DEFINITIONS) + list(REMOVE_DUPLICATES Qt5SslServer_COMPILE_DEFINITIONS) + list(REMOVE_DUPLICATES Qt5SslServer_EXECUTABLE_COMPILE_FLAGS) + + # It can happen that the same FooConfig.cmake file is included when calling find_package() + # on some Qt component. An example of that is when using a Qt static build with auto inclusion + # of plugins: + # + # Qt5WidgetsConfig.cmake -> Qt5GuiConfig.cmake -> Qt5Gui_QSvgIconPlugin.cmake -> + # Qt5SvgConfig.cmake -> Qt5WidgetsConfig.cmake -> + # finish processing of second Qt5WidgetsConfig.cmake -> + # return to first Qt5WidgetsConfig.cmake -> + # add_library cannot create imported target Qt5::Widgets. + # + # Make sure to return early in the original Config inclusion, because the target has already + # been defined as part of the second inclusion. + if(TARGET Qt5::SslServer) + return() + endif() + + set(_Qt5SslServer_LIB_DEPENDENCIES "Qt5::Network;Qt5::Core") + + + add_library(Qt5::SslServer SHARED IMPORTED) + + set_property(TARGET Qt5::SslServer PROPERTY + INTERFACE_INCLUDE_DIRECTORIES ${_Qt5SslServer_OWN_INCLUDE_DIRS}) + set_property(TARGET Qt5::SslServer PROPERTY + INTERFACE_COMPILE_DEFINITIONS QT_SSLSERVER_LIB) + + set_property(TARGET Qt5::SslServer PROPERTY INTERFACE_QT_ENABLED_FEATURES ) + set_property(TARGET Qt5::SslServer PROPERTY INTERFACE_QT_DISABLED_FEATURES ) + + set_property(TARGET Qt5::SslServer PROPERTY INTERFACE_QT_PLUGIN_TYPES "") + + set(_Qt5SslServer_PRIVATE_DIRS_EXIST TRUE) + foreach (_Qt5SslServer_PRIVATE_DIR ${Qt5SslServer_OWN_PRIVATE_INCLUDE_DIRS}) + if (NOT EXISTS ${_Qt5SslServer_PRIVATE_DIR}) + set(_Qt5SslServer_PRIVATE_DIRS_EXIST FALSE) + endif() + endforeach() + + if (_Qt5SslServer_PRIVATE_DIRS_EXIST) + add_library(Qt5::SslServerPrivate INTERFACE IMPORTED) + set_property(TARGET Qt5::SslServerPrivate PROPERTY + INTERFACE_INCLUDE_DIRECTORIES ${Qt5SslServer_OWN_PRIVATE_INCLUDE_DIRS} + ) + set(_Qt5SslServer_PRIVATEDEPS) + foreach(dep ${_Qt5SslServer_LIB_DEPENDENCIES}) + if (TARGET ${dep}Private) + list(APPEND _Qt5SslServer_PRIVATEDEPS ${dep}Private) + endif() + endforeach() + set_property(TARGET Qt5::SslServerPrivate PROPERTY + INTERFACE_LINK_LIBRARIES Qt5::SslServer ${_Qt5SslServer_PRIVATEDEPS} + ) + endif() + + + _populate_SslServer_target_properties(DEBUG "Qt5SslServer.dll" "libQt5SslServer.a" FALSE) + + if (EXISTS + "${_qt5SslServer_install_prefix}/bin/Qt5SslServer.dll" + AND EXISTS + "${_qt5SslServer_install_prefix}/lib/libQt5SslServer.a" ) + _populate_SslServer_target_properties(RELEASE "Qt5SslServer.dll" "libQt5SslServer.a" FALSE) + endif() + + + + file(GLOB pluginTargets "${CMAKE_CURRENT_LIST_DIR}/Qt5SslServer_*Plugin.cmake") + + macro(_populate_SslServer_plugin_properties Plugin Configuration PLUGIN_LOCATION + IsDebugAndRelease) + set_property(TARGET Qt5::${Plugin} APPEND PROPERTY IMPORTED_CONFIGURATIONS ${Configuration}) + + set(imported_location "${_qt5SslServer_install_prefix}/plugins/${PLUGIN_LOCATION}") + _qt5_SslServer_check_file_exists(${imported_location}) + set_target_properties(Qt5::${Plugin} PROPERTIES + "IMPORTED_LOCATION_${Configuration}" ${imported_location} + ) + + endmacro() + + if (pluginTargets) + foreach(pluginTarget ${pluginTargets}) + include(${pluginTarget}) + endforeach() + endif() + + + + + +_qt5_SslServer_check_file_exists("${CMAKE_CURRENT_LIST_DIR}/Qt5SslServerConfigVersion.cmake") + +endif() diff --git a/Lib/QtHTTPServer/cmake/Qt5SslServer/Qt5SslServerConfigVersion.cmake b/Lib/QtHTTPServer/cmake/Qt5SslServer/Qt5SslServerConfigVersion.cmake new file mode 100644 index 0000000..e5b7a75 --- /dev/null +++ b/Lib/QtHTTPServer/cmake/Qt5SslServer/Qt5SslServerConfigVersion.cmake @@ -0,0 +1,11 @@ + +set(PACKAGE_VERSION 5.12.0) + +if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) + endif() +endif() diff --git a/Lib/QtHTTPServer/include/QtHttpServer/qabstracthttpserver.h b/Lib/QtHTTPServer/include/QtHttpServer/qabstracthttpserver.h new file mode 100644 index 0000000..df0af73 --- /dev/null +++ b/Lib/QtHTTPServer/include/QtHttpServer/qabstracthttpserver.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTHTTPSERVER_H +#define QABSTRACTHTTPSERVER_H + +#include + +#include + +#include + +#if QT_CONFIG(ssl) +#include +#include +#include +#endif + +QT_BEGIN_NAMESPACE + +class QHttpServerRequest; +class QHttpServerResponder; +class QTcpServer; +class QTcpSocket; +class QWebSocket; + +class QAbstractHttpServerPrivate; +class Q_HTTPSERVER_EXPORT QAbstractHttpServer : public QObject +{ + Q_OBJECT + +public: + QAbstractHttpServer(QObject *parent = nullptr); + + quint16 listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0); + QVector serverPorts(); + + void bind(QTcpServer *server = nullptr); + QVector servers() const; + +#if QT_CONFIG(ssl) + void sslSetup(const QSslCertificate &certificate, const QSslKey &privateKey, + QSsl::SslProtocol protocol = QSsl::SecureProtocols); + void sslSetup(const QSslConfiguration &sslConfiguration); +#endif + +Q_SIGNALS: + void missingHandler(const QHttpServerRequest &request, QTcpSocket *socket); + +#if defined(QT_WEBSOCKETS_LIB) + void newWebSocketConnection(); + +public: + bool hasPendingWebSocketConnections() const; + QWebSocket *nextPendingWebSocketConnection(); +#endif // defined(QT_WEBSOCKETS_LIB) + +protected: + QAbstractHttpServer(QAbstractHttpServerPrivate &dd, QObject *parent = nullptr); + + virtual bool handleRequest(const QHttpServerRequest &request, QTcpSocket *socket) = 0; + static QHttpServerResponder makeResponder(const QHttpServerRequest &request, + QTcpSocket *socket); + +private: + Q_DECLARE_PRIVATE(QAbstractHttpServer) +}; + +QT_END_NAMESPACE + +#endif // QABSTRACTHTTPSERVER_H diff --git a/Lib/QtHTTPServer/include/QtHttpServer/qabstracthttpserver_p.h b/Lib/QtHTTPServer/include/QtHttpServer/qabstracthttpserver_p.h new file mode 100644 index 0000000..2c02b19 --- /dev/null +++ b/Lib/QtHTTPServer/include/QtHttpServer/qabstracthttpserver_p.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTHTTPSERVER_P_H +#define QABSTRACTHTTPSERVER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of QHttpServer. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#include +#include + +#include + +#if defined(QT_WEBSOCKETS_LIB) +#include +#endif // defined(QT_WEBSOCKETS_LIB) + +QT_BEGIN_NAMESPACE + +class QHttpServerRequest; + +class Q_HTTPSERVER_EXPORT QAbstractHttpServerPrivate: public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QAbstractHttpServer) + +public: + QAbstractHttpServerPrivate(); + +#if defined(QT_WEBSOCKETS_LIB) + QWebSocketServer websocketServer { + QLatin1String("QtHttpServer"), + QWebSocketServer::NonSecureMode + }; +#endif // defined(QT_WEBSOCKETS_LIB) + + void handleNewConnections(); + void handleReadyRead(QTcpSocket *socket, + QHttpServerRequest *request); + +#if QT_CONFIG(ssl) + QSslConfiguration sslConfiguration; + bool sslEnabled = false; +#endif +}; + +QT_END_NAMESPACE + +#endif // QABSTRACTHTTPSERVER_P_H diff --git a/Lib/QtHTTPServer/include/QtHttpServer/qhttpserver.h b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserver.h new file mode 100644 index 0000000..5274d0f --- /dev/null +++ b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserver.h @@ -0,0 +1,222 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Mikhail Svetkin +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTPSERVER_H +#define QHTTPSERVER_H + +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QTcpSocket; +class QHttpServerRequest; + +class QHttpServerPrivate; +class Q_HTTPSERVER_EXPORT QHttpServer final : public QAbstractHttpServer +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QHttpServer) + + template + struct VariadicTypeAt { using Type = typename std::tuple_element>::type; }; + + template + struct VariadicTypeLast { + using Type = typename VariadicTypeAt::Type; + }; + + + template + using ResponseType = + typename std::conditional< + std::is_base_of::value, + T, + QHttpServerResponse + >::type; + +public: + explicit QHttpServer(QObject *parent = nullptr); + ~QHttpServer(); + + QHttpServerRouter *router(); + + template + bool route(Args && ... args) + { + using ViewHandler = typename VariadicTypeLast::Type; + using ViewTraits = QHttpServerRouterViewTraits; + static_assert(ViewTraits::Arguments::StaticAssert, + "ViewHandler arguments are in the wrong order or not supported"); + return routeHelper( + QtPrivate::makeIndexSequence{}, + std::forward(args)...); + } + + template + void afterRequest(ViewHandler &&viewHandler) + { + using ViewTraits = QHttpServerAfterRequestViewTraits; + static_assert(ViewTraits::Arguments::StaticAssert, + "ViewHandler arguments are in the wrong order or not supported"); + afterRequestHelper(std::move(viewHandler)); + } + + using AfterRequestHandler = + std::function; +private: + template + typename std::enable_if::type + afterRequestHelper(ViewHandler &&viewHandler) { + auto handler = [viewHandler](QHttpServerResponse &&resp, + const QHttpServerRequest &request) { + return std::move(viewHandler(std::move(resp), request)); + }; + + afterRequestImpl(std::move(handler)); + } + + template + typename std::enable_if::type + afterRequestHelper(ViewHandler &&viewHandler) { + auto handler = [viewHandler](QHttpServerResponse &&resp, + const QHttpServerRequest &) { + return std::move(viewHandler(std::move(resp))); + }; + + afterRequestImpl(std::move(handler)); + } + + template + typename std::enable_if::type + afterRequestHelper(ViewHandler &&viewHandler) { + auto handler = [viewHandler](QHttpServerResponse &&resp, + const QHttpServerRequest &request) { + return std::move(viewHandler(request, std::move(resp))); + }; + + afterRequestImpl(std::move(handler)); + } + + void afterRequestImpl(AfterRequestHandler &&afterRequestHandler); + +private: + template + bool routeHelper(QtPrivate::IndexesList, Args &&... args) + { + return routeImpl::Type...>(std::forward(args)...); + } + + template + bool routeImpl(Args &&...args, ViewHandler &&viewHandler) + { + auto routerHandler = [this, viewHandler] ( + const QRegularExpressionMatch &match, + const QHttpServerRequest &request, + QTcpSocket *socket) mutable { + auto boundViewHandler = router()->bindCaptured( + std::move(viewHandler), match); + responseImpl(boundViewHandler, request, socket); + }; + + return router()->addRule( + new Rule(std::forward(args)..., std::move(routerHandler))); + } + + template + typename std::enable_if::type + responseImpl(T &boundViewHandler, + const QHttpServerRequest &request, + QTcpSocket *socket) + { + ResponseType response(boundViewHandler()); + sendResponse(std::move(response), request, socket); + } + + template + typename std::enable_if::type + responseImpl(T &boundViewHandler, const QHttpServerRequest &request, QTcpSocket *socket) + { + ResponseType response(boundViewHandler(request)); + sendResponse(std::move(response), request, socket); + } + + template + typename std::enable_if::type + responseImpl(T &boundViewHandler, const QHttpServerRequest &request, QTcpSocket *socket) + { + boundViewHandler(makeResponder(request, socket), request); + } + + template + typename std::enable_if::type + responseImpl(T &boundViewHandler, + const QHttpServerRequest &request, + QTcpSocket *socket) + { + boundViewHandler(request, makeResponder(request, socket)); + } + + template + typename std::enable_if::type + responseImpl(T &boundViewHandler, + const QHttpServerRequest &request, + QTcpSocket *socket) + { + boundViewHandler(makeResponder(request, socket)); + } + + bool handleRequest(const QHttpServerRequest &request, QTcpSocket *socket) override final; + + void sendResponse(QHttpServerResponse &&response, + const QHttpServerRequest &request, + QTcpSocket *socket); +}; + +QT_END_NAMESPACE + +#endif // QHTTPSERVER_H diff --git a/Lib/QtHTTPServer/include/QtHttpServer/qhttpserver_p.h b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserver_p.h new file mode 100644 index 0000000..eb39a9e --- /dev/null +++ b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserver_p.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTPSERVER_P_H +#define QHTTPSERVER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of QHttpServer. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#include + +#include +#include +#include +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QHttpServerPrivate: public QAbstractHttpServerPrivate +{ + Q_DECLARE_PUBLIC(QHttpServer) + +public: + QHttpServerPrivate() = default; + + QHttpServerRouter router; + std::list afterRequestHandlers; +}; + +QT_END_NAMESPACE + +#endif // QHTTPSERVER_P_H diff --git a/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverfutureresponse.h b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverfutureresponse.h new file mode 100644 index 0000000..d5c8fe1 --- /dev/null +++ b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverfutureresponse.h @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Mikhail Svetkin +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTPSERVERFUTURERESPONSE_H +#define QHTTPSERVERFUTURERESPONSE_H + +#include + +#include +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + +template <> +class QFutureInterface : public QFutureInterfaceBase +{ +public: + QFutureInterface(State initialState = NoState) + : QFutureInterfaceBase(initialState) + { + refT(); + } + QFutureInterface(const QFutureInterface &other) + : QFutureInterfaceBase(other) + { + refT(); + } + ~QFutureInterface() + { + if (!derefT()) + resultStoreBase().template clear(); + } + + static QFutureInterface canceledResult() + { return QFutureInterface(State(Started | Finished | Canceled)); } + + QFutureInterface &operator=(const QFutureInterface &other) + { + other.refT(); + if (!derefT()) + resultStoreBase().template clear(); + QFutureInterfaceBase::operator=(other); + return *this; + } + + inline QFuture future() + { + return QFuture(this); + } + + void reportAndMoveResult(QHttpServerResponse &&result, int index = -1) + { +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) + std::lock_guard locker{*mutex()}; +#else + std::lock_guard locker{mutex(0)}; +#endif + if (queryState(Canceled) || queryState(Finished)) + return; + + QtPrivate::ResultStoreBase &store = resultStoreBase(); + + const int oldResultCount = store.count(); + const int insertIndex = store.addResult( + index, static_cast(new QHttpServerResponse(std::move_if_noexcept(result)))); + if (!store.filterMode() || oldResultCount < store.count()) // Let's make sure it's not in pending results. + reportResultsReady(insertIndex, store.count()); + } + + void reportFinished() + { + QFutureInterfaceBase::reportFinished(); + } + + QHttpServerResponse takeResult(); +}; + +#endif // QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + +namespace QtConcurrent { + +template <> +class RunFunctionTask : public RunFunctionTaskBase +{ +public: + void run() override + { + if (this->isCanceled()) { + this->reportFinished(); + return; + } +#ifndef QT_NO_EXCEPTIONS + try { +#endif + this->runFunctor(); +#ifndef QT_NO_EXCEPTIONS + } catch (QException &e) { + QFutureInterface::reportException(e); + } catch (...) { + QFutureInterface::reportException(QUnhandledException()); + } +#endif + this->reportAndMoveResult(std::move_if_noexcept(result)); + this->reportFinished(); + } + + QHttpServerResponse result{QHttpServerResponse::StatusCode::NotFound}; +}; + +} + +class QHttpServerFutureResponsePrivate; +class Q_HTTPSERVER_EXPORT QHttpServerFutureResponse : public QHttpServerResponse +{ + Q_DECLARE_PRIVATE(QHttpServerFutureResponse) + +public: + using QHttpServerResponse::QHttpServerResponse; + + QHttpServerFutureResponse(const QFuture &futureResponse); + + virtual void write(QHttpServerResponder &&responder) const override; + +protected: + QHttpServerFutureResponse(QHttpServerFutureResponsePrivate *d); +}; + +QT_END_NAMESPACE + +#endif // QHTTPSERVERFUTURERESPONSE_H diff --git a/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverliterals_p.h b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverliterals_p.h new file mode 100644 index 0000000..a6ac05a --- /dev/null +++ b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverliterals_p.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Mikhail Svetkin +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTPSERVERLITERALS_P_H +#define QHTTPSERVERLITERALS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of QHttpServer. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#include + +#include + +QT_BEGIN_NAMESPACE + +class Q_HTTPSERVER_EXPORT QHttpServerLiterals +{ + +public: + static QByteArray contentTypeHeader(); + static QByteArray contentTypeXEmpty(); + static QByteArray contentTypeTextHtml(); + static QByteArray contentTypeJson(); + static QByteArray contentLengthHeader(); +}; + +QT_END_NAMESPACE + +#endif // QHTTPSERVERLITERALS_P_H diff --git a/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrequest.h b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrequest.h new file mode 100644 index 0000000..4ace46a --- /dev/null +++ b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrequest.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTPSERVERREQUEST_H +#define QHTTPSERVERREQUEST_H + +#include + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QRegularExpression; +class QString; +class QTcpSocket; + +class QHttpServerRequestPrivate; +class Q_HTTPSERVER_EXPORT QHttpServerRequest +{ + friend class QAbstractHttpServerPrivate; + friend class QHttpServerResponse; + + Q_GADGET + +public: + virtual ~QHttpServerRequest(); + + enum class Method + { + Unknown = 0x0000, + Get = 0x0001, + Put = 0x0002, + Delete = 0x0004, + Post = 0x0008, + Head = 0x0010, + Options = 0x0020, + Patch = 0x0040, + Connect = 0x0080, + + All = Get | Put | Delete | Post | Head | Options | Patch | Connect, + + // Include upper-case aliases for the sake of parsing from strings: + GET = Get, + PUT = Put, + DELETE = Delete, + POST = Post, + HEAD = Head, + OPTIONS = Options, + PATCH = Patch, + CONNECT = Connect + }; + Q_ENUM(Method) + Q_DECLARE_FLAGS(Methods, Method) + Q_FLAG(Methods) + + QByteArray value(const QByteArray &key) const; + QUrl url() const; + QUrlQuery query() const; + Method method() const; + QVariantMap headers() const; + QByteArray body() const; + QHostAddress remoteAddress() const; + +private: + Q_DISABLE_COPY(QHttpServerRequest) + +#if !defined(QT_NO_DEBUG_STREAM) + friend Q_HTTPSERVER_EXPORT QDebug operator<<(QDebug debug, const QHttpServerRequest &request); +#endif + + explicit QHttpServerRequest(const QHostAddress &remoteAddress); + + QScopedPointer d; +}; + +QT_END_NAMESPACE + +#endif // QHTTPSERVERREQUEST_H diff --git a/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrequest_p.h b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrequest_p.h new file mode 100644 index 0000000..6459cc4 --- /dev/null +++ b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrequest_p.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTPSERVERREQUEST_P_H +#define QHTTPSERVERREQUEST_P_H + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../3rdparty/http-parser/http_parser.h" + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of QHttpServer. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +QT_BEGIN_NAMESPACE + +class QHttpServerRequestPrivate : public QSharedData +{ +public: + QHttpServerRequestPrivate(const QHostAddress &remoteAddress); + + quint16 port = 0; + enum class State { + NotStarted, + OnMessageBegin, + OnUrl, + OnStatus, + OnHeaders, + OnHeadersComplete, + OnBody, + OnMessageComplete, + OnChunkHeader, + OnChunkComplete + } state = State::NotStarted; + QByteArray body; + + QUrl url; + + http_parser httpParser; + + QByteArray header(const QByteArray &key) const; + bool parse(QIODevice *socket); + + QByteArray lastHeader; + QMap> headers; + const uint headersSeed = uint(qGlobalQHashSeed()); + uint headerHash(const QByteArray &key) const; + + void clear(); + QHostAddress remoteAddress; + bool handling{false}; + +private: + static http_parser_settings httpParserSettings; + static bool parseUrl(const char *at, size_t length, bool connect, QUrl *url); + + static QHttpServerRequestPrivate *instance(http_parser *httpParser); + + static int onMessageBegin(http_parser *httpParser); + static int onUrl(http_parser *httpParser, const char *at, size_t length); + static int onStatus(http_parser *httpParser, const char *at, size_t length); + static int onHeaderField(http_parser *httpParser, const char *at, size_t length); + static int onHeaderValue(http_parser *httpParser, const char *at, size_t length); + static int onHeadersComplete(http_parser *httpParser); + static int onBody(http_parser *httpParser, const char *at, size_t length); + static int onMessageComplete(http_parser *httpParser); + static int onChunkHeader(http_parser *httpParser); + static int onChunkComplete(http_parser *httpParser); +}; + +QT_END_NAMESPACE + +#endif // QHTTPSERVERREQUEST_P_H diff --git a/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverresponder.h b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverresponder.h new file mode 100644 index 0000000..f19f263 --- /dev/null +++ b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverresponder.h @@ -0,0 +1,187 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTPSERVERRESPONDER_H +#define QHTTPSERVERRESPONDER_H + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QTcpSocket; +class QHttpServerRequest; + +class QHttpServerResponderPrivate; +class Q_HTTPSERVER_EXPORT QHttpServerResponder final +{ + Q_DECLARE_PRIVATE(QHttpServerResponder) + + friend class QAbstractHttpServer; + +public: + enum class StatusCode { + // 1xx: Informational + Continue = 100, + SwitchingProtocols, + Processing, + + // 2xx: Success + Ok = 200, + Created, + Accepted, + NonAuthoritativeInformation, + NoContent, + ResetContent, + PartialContent, + MultiStatus, + AlreadyReported, + IMUsed = 226, + + // 3xx: Redirection + MultipleChoices = 300, + MovedPermanently, + Found, + SeeOther, + NotModified, + UseProxy, + // 306: not used, was proposed as "Switch Proxy" but never standardized + TemporaryRedirect = 307, + PermanentRedirect, + + // 4xx: Client Error + BadRequest = 400, + Unauthorized, + PaymentRequired, + Forbidden, + NotFound, + MethodNotAllowed, + NotAcceptable, + ProxyAuthenticationRequired, + RequestTimeout, + Conflict, + Gone, + LengthRequired, + PreconditionFailed, + PayloadTooLarge, + UriTooLong, + UnsupportedMediaType, + RequestRangeNotSatisfiable, + ExpectationFailed, + ImATeapot, + MisdirectedRequest = 421, + UnprocessableEntity, + Locked, + FailedDependency, + UpgradeRequired = 426, + PreconditionRequired = 428, + TooManyRequests, + RequestHeaderFieldsTooLarge = 431, + UnavailableForLegalReasons = 451, + + // 5xx: Server Error + InternalServerError = 500, + NotImplemented, + BadGateway, + ServiceUnavailable, + GatewayTimeout, + HttpVersionNotSupported, + VariantAlsoNegotiates, + InsufficientStorage, + LoopDetected, + NotExtended = 510, + NetworkAuthenticationRequired, + NetworkConnectTimeoutError = 599, + }; + + using HeaderList = std::initializer_list>; + + QHttpServerResponder(QHttpServerResponder &&other); + ~QHttpServerResponder(); + + void write(QIODevice *data, + HeaderList headers, + StatusCode status = StatusCode::Ok); + + void write(QIODevice *data, + const QByteArray &mimeType, + StatusCode status = StatusCode::Ok); + + void write(const QJsonDocument &document, + HeaderList headers, + StatusCode status = StatusCode::Ok); + + void write(const QJsonDocument &document, + StatusCode status = StatusCode::Ok); + + void write(const QByteArray &data, + HeaderList headers, + StatusCode status = StatusCode::Ok); + + void write(const QByteArray &data, + const QByteArray &mimeType, + StatusCode status = StatusCode::Ok); + + void write(HeaderList headers, StatusCode status = StatusCode::Ok); + void write(StatusCode status = StatusCode::Ok); + + + void writeStatusLine(StatusCode status = StatusCode::Ok, + const QPair &version = qMakePair(1u, 1u)); + + void writeHeader(const QByteArray &key, const QByteArray &value); + void writeHeaders(HeaderList headers); + + void writeBody(const char *body, qint64 size); + void writeBody(const char *body); + void writeBody(const QByteArray &body); + + QTcpSocket *socket() const; + +private: + QHttpServerResponder(const QHttpServerRequest &request, QTcpSocket *socket); + + QScopedPointer d_ptr; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QHttpServerResponder::StatusCode) + +#endif // QHTTPSERVERRESPONDER_H diff --git a/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverresponder_p.h b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverresponder_p.h new file mode 100644 index 0000000..f8b1fb0 --- /dev/null +++ b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverresponder_p.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTPSERVERRESPONDER_P_H +#define QHTTPSERVERRESPONDER_P_H + +#include +#include +#include + +#include +#include +#include +#include + +#include + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of QHttpServer. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +QT_BEGIN_NAMESPACE + +class QHttpServerResponderPrivate +{ +public: + QHttpServerResponderPrivate(const QHttpServerRequest &request, QTcpSocket *const socket) + : request(request), socket(socket) {} + + const QHttpServerRequest &request; +#if defined(QT_DEBUG) + const QPointer socket; +#else + QTcpSocket *const socket; +#endif + bool bodyStarted{false}; +}; + +QT_END_NAMESPACE + +#endif // QHTTPSERVERRESPONDER_P_H diff --git a/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverresponse.h b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverresponse.h new file mode 100644 index 0000000..6d2bc1d --- /dev/null +++ b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverresponse.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTPSERVERRESPONSE_H +#define QHTTPSERVERRESPONSE_H + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QJsonObject; + +class QHttpServerResponsePrivate; +class Q_HTTPSERVER_EXPORT QHttpServerResponse +{ + Q_DECLARE_PRIVATE(QHttpServerResponse) + +public: + using StatusCode = QHttpServerResponder::StatusCode; + + QHttpServerResponse() = delete; + QHttpServerResponse(const QHttpServerResponse &other) = delete; + QHttpServerResponse& operator=(const QHttpServerResponse &other) = delete; + + QHttpServerResponse(QHttpServerResponse &&other) noexcept; + QHttpServerResponse& operator=(QHttpServerResponse &&other) noexcept; + + QHttpServerResponse(const StatusCode statusCode); + + QHttpServerResponse(const char *data); + + QHttpServerResponse(const QString &data); + + explicit QHttpServerResponse(const QByteArray &data); + explicit QHttpServerResponse(QByteArray &&data); + + QHttpServerResponse(const QJsonObject &data); + QHttpServerResponse(const QJsonArray &data); + + QHttpServerResponse(const QByteArray &mimeType, + const QByteArray &data, + const StatusCode status = StatusCode::Ok); + QHttpServerResponse(QByteArray &&mimeType, + const QByteArray &data, + const StatusCode status = StatusCode::Ok); + QHttpServerResponse(const QByteArray &mimeType, + QByteArray &&data, + const StatusCode status = StatusCode::Ok); + QHttpServerResponse(QByteArray &&mimeType, + QByteArray &&data, + const StatusCode status = StatusCode::Ok); + + virtual ~QHttpServerResponse(); + static QHttpServerResponse fromFile(const QString &fileName); + + QByteArray data() const; + + QByteArray mimeType() const; + + StatusCode statusCode() const; + + void addHeader(QByteArray &&name, QByteArray &&value); + void addHeader(QByteArray &&name, const QByteArray &value); + void addHeader(const QByteArray &name, QByteArray &&value); + void addHeader(const QByteArray &name, const QByteArray &value); + + void addHeaders(QHttpServerResponder::HeaderList headers); + + template + void addHeaders(const Container &headerList) + { + for (const auto &header : headerList) + addHeader(header.first, header.second); + } + + void clearHeader(const QByteArray &name); + void clearHeaders(); + + void setHeader(QByteArray &&name, QByteArray &&value); + void setHeader(QByteArray &&name, const QByteArray &value); + void setHeader(const QByteArray &name, QByteArray &&value); + void setHeader(const QByteArray &name, const QByteArray &value); + + void setHeaders(QHttpServerResponder::HeaderList headers); + + bool hasHeader(const QByteArray &name) const; + bool hasHeader(const QByteArray &name, const QByteArray &value) const; + + QVector headers(const QByteArray &name) const; + + virtual void write(QHttpServerResponder &&responder) const; + +protected: + QHttpServerResponse(QHttpServerResponsePrivate *d); + + QScopedPointer d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QHTTPSERVERRESPONSE_H diff --git a/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverresponse_p.h b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverresponse_p.h new file mode 100644 index 0000000..5011552 --- /dev/null +++ b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverresponse_p.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTPSERVERRESPONSE_P_H +#define QHTTPSERVERRESPONSE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of QHttpServerResponse. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#include + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QHttpServerResponsePrivate +{ + struct HashHelper { + std::size_t operator()(const QByteArray& key) const + { + return qHash(key.toLower()); + } + }; + +public: + explicit QHttpServerResponsePrivate() = default; + virtual ~QHttpServerResponsePrivate() = default; + + QHttpServerResponsePrivate(QByteArray &&d, const QHttpServerResponse::StatusCode sc); + QHttpServerResponsePrivate(const QHttpServerResponse::StatusCode sc); + + QByteArray data; + QHttpServerResponse::StatusCode statusCode; + std::unordered_multimap headers; + bool derived{false}; +}; + +QT_END_NAMESPACE + +#endif // QHTTPSERVERRESPONSE_P_H diff --git a/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrouter.h b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrouter.h new file mode 100644 index 0000000..8e4b79f --- /dev/null +++ b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrouter.h @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTPSERVERROUTER_H +#define QHTTPSERVERROUTER_H + +#include +#include + +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace QtPrivate { + template struct QHttpServerRouterPlaceholder {}; +} + +QT_END_NAMESPACE + +namespace std { + +template +struct is_placeholder)> : + integral_constant +{}; + +} + +QT_BEGIN_NAMESPACE + +class QTcpSocket; +class QHttpServerRequest; +class QHttpServerRouterRule; + +class QHttpServerRouterPrivate; +class Q_HTTPSERVER_EXPORT QHttpServerRouter +{ + Q_DECLARE_PRIVATE(QHttpServerRouter) + +public: + QHttpServerRouter(); + ~QHttpServerRouter(); + + template + bool addConverter(const QLatin1String ®exp) { + static_assert(QMetaTypeId2::Defined, + "Type is not registered with Qt's meta-object system: " + "please apply Q_DECLARE_METATYPE() to it"); + + if (!QMetaType::registerConverter()) + return false; + + addConverter(qMetaTypeId(), regexp); + return true; + } + + void addConverter(const int type, const QLatin1String ®exp); + void removeConverter(const int); + void clearConverters(); + const QMap &converters() const; + + static const QMap &defaultConverters(); + + template> + bool addRule(QHttpServerRouterRule *rule) + { + return addRuleHelper( + rule, + typename ViewTraits::Arguments::Indexes{}); + } + + template> + typename ViewTraits::BindableType bindCaptured(ViewHandler &&handler, + const QRegularExpressionMatch &match) const + { + return bindCapturedImpl( + std::forward(handler), + match, + typename ViewTraits::Arguments::CapturableIndexes{}, + typename ViewTraits::Arguments::PlaceholdersIndexes{}); + } + + bool handleRequest(const QHttpServerRequest &request, + QTcpSocket *socket) const; + +private: + template + bool addRuleHelper(QHttpServerRouterRule *rule, + QtPrivate::IndexesList) + { + const std::initializer_list types = { + ViewTraits::Arguments::template metaTypeId()...}; + return addRuleImpl(rule, types); + } + + bool addRuleImpl(QHttpServerRouterRule *rule, + const std::initializer_list &metaTypes); + + template + typename std::enable_if::type + bindCapturedImpl(ViewHandler &&handler, + const QRegularExpressionMatch &match, + QtPrivate::IndexesList, + QtPrivate::IndexesList) const + { + return std::bind( + std::forward(handler), + QVariant(match.captured(Cx + 1)) + .value::CleanType>()..., + QtPrivate::QHttpServerRouterPlaceholder{}...); + } + + template + typename std::enable_if::type + bindCapturedImpl(ViewHandler &&handler, + const QRegularExpressionMatch &, + QtPrivate::IndexesList, + QtPrivate::IndexesList) const + { + return std::bind( + std::forward(handler), + QtPrivate::QHttpServerRouterPlaceholder{}...); + } + + QScopedPointer d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QHTTPSERVERROUTER_H diff --git a/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrouter_p.h b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrouter_p.h new file mode 100644 index 0000000..71078a6 --- /dev/null +++ b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrouter_p.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTPSERVERROUTER_P_H +#define QHTTPSERVERROUTER_P_H + +#include +#include + +#include +#include +#include + +#include + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of QHttpServer. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +QT_BEGIN_NAMESPACE + +class QHttpServerRouterPrivate +{ +public: + QHttpServerRouterPrivate(); + + QMap converters; + std::list> rules; +}; + +QT_END_NAMESPACE + +#endif // QHTTPSERVERROUTER_P_H diff --git a/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrouterrule.h b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrouterrule.h new file mode 100644 index 0000000..20ad2a2 --- /dev/null +++ b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrouterrule.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTPSERVERROUTERRULE_H +#define QHTTPSERVERROUTERRULE_H + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QString; +class QHttpServerRequest; +class QTcpSocket; +class QRegularExpressionMatch; +class QHttpServerRouter; + +class QHttpServerRouterRulePrivate; +class Q_HTTPSERVER_EXPORT QHttpServerRouterRule +{ + Q_DECLARE_PRIVATE(QHttpServerRouterRule) + +public: + using RouterHandler = std::function; + + explicit QHttpServerRouterRule(const QString &pathPattern, RouterHandler &&routerHandler); + explicit QHttpServerRouterRule(const QString &pathPattern, + const QHttpServerRequest::Methods methods, + RouterHandler &&routerHandler); + explicit QHttpServerRouterRule(const QString &pathPattern, + const char * methods, + RouterHandler &&routerHandler); + + QHttpServerRouterRule(QHttpServerRouterRule &&other) = delete; + QHttpServerRouterRule &operator=(QHttpServerRouterRule &&other) = delete; + + virtual ~QHttpServerRouterRule(); + +protected: + bool exec(const QHttpServerRequest &request, QTcpSocket *socket) const; + + bool hasValidMethods() const; + + bool createPathRegexp(const std::initializer_list &metaTypes, + const QMap &converters); + + virtual bool matches(const QHttpServerRequest &request, + QRegularExpressionMatch *match) const; + + QHttpServerRouterRule(QHttpServerRouterRulePrivate *d); + +private: + Q_DISABLE_COPY(QHttpServerRouterRule) + QScopedPointer d_ptr; + + friend class QHttpServerRouter; +}; + +QT_END_NAMESPACE + +#endif // QHTTPSERVERROUTERRULE_H diff --git a/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrouterrule_p.h b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrouterrule_p.h new file mode 100644 index 0000000..149c1c6 --- /dev/null +++ b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrouterrule_p.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTPSERVERROUTERRULE_P_H +#define QHTTPSERVERROUTERRULE_P_H + +#include + +#include +#include + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of QHttpServer. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +QT_BEGIN_NAMESPACE + +class Q_HTTPSERVER_EXPORT QHttpServerRouterRulePrivate +{ +public: + QString pathPattern; + QHttpServerRequest::Methods methods; + QHttpServerRouterRule::RouterHandler routerHandler; + + QRegularExpression pathRegexp; +}; + +QT_END_NAMESPACE + +#endif // QHTTPSERVERROUTERRULE_P_H diff --git a/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrouterviewtraits.h b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrouterviewtraits.h new file mode 100644 index 0000000..b572675 --- /dev/null +++ b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrouterviewtraits.h @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Mikhail Svetkin +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTPSERVERROUTERVIEWTRAITS_H +#define QHTTPSERVERROUTERVIEWTRAITS_H + +#include + +QT_BEGIN_NAMESPACE + +class QHttpServerRequest; +class QHttpServerResponder; + +namespace QtPrivate { + +template +struct RouterViewTraitsHelper : ViewTraits { + using VTraits = ViewTraits; + using FunctionTraits = typename VTraits::FTraits; + + template + struct ArgumentChecker : FunctionTraits::template Arg { + using IsRequest = typename VTraits::template Special; + static_assert(IsRequest::AssertCondition, + "ViewHandler arguments error: " + "QHttpServerRequest can only be passed as a const reference"); + + using IsResponder = typename VTraits::template Special; + static_assert(IsResponder::AssertCondition, + "ViewHandler arguments error: " + "QHttpServerResponder can only be passed as a universal reference"); + + using IsSpecial = CheckAny; + + struct IsSimple { + static constexpr bool Value = !IsSpecial::Value && + I < FunctionTraits::ArgumentCount && + FunctionTraits::ArgumentIndexMax != -1; + static constexpr bool Valid = FunctionTraits::template Arg::Defined; + + static constexpr bool StaticAssert = + DisableStaticAssert || !Value || Valid; + + + static_assert(StaticAssert, + "ViewHandler arguments error: " + "Type is not registered, please use the Q_DECLARE_METATYPE macro " + "to make it known to Qt's meta-object system"); + }; + + using CheckOk = CheckAny; + + static constexpr bool Valid = CheckOk::Valid; + static constexpr bool StaticAssert = CheckOk::StaticAssert; + }; + + + struct Arguments { + template + struct ArgumentsReturn { + template + using Arg = ArgumentChecker; + + template + static constexpr int metaTypeId() noexcept + { + using Type = typename FunctionTraits::template Arg::CleanType; + + return qMetaTypeId< + typename std::conditional< + QMetaTypeId2::Defined, + Type, + void>::type>(); + } + + static constexpr std::size_t Count = FunctionTraits::ArgumentCount; + static constexpr std::size_t CapturableCount = + StaticMath::Sum::eval( + static_cast(FunctionTraits::template Arg::Defined)...); + static constexpr std::size_t PlaceholdersCount = Count - CapturableCount; + + static constexpr bool Valid = StaticMath::And::eval(Arg::Valid...); + static constexpr bool StaticAssert = + StaticMath::And::eval(Arg::StaticAssert...); + + using Indexes = typename QtPrivate::IndexesList; + + using CapturableIndexes = + typename QtPrivate::Indexes::Value; + + using PlaceholdersIndexes = + typename QtPrivate::Indexes::Value; + + using Last = Arg; + }; + + template + static constexpr ArgumentsReturn eval(QtPrivate::IndexesList) noexcept + { + return ArgumentsReturn{}; + } + }; + + template + struct BindType { + template + struct FunctionWrapper { + using Type = std::function; + }; + + template + using OffsetArg = typename FunctionTraits::template Arg::Type; + + template + static constexpr typename FunctionWrapper...>::Type + eval(QtPrivate::IndexesList) noexcept; + }; +}; + + +} // namespace QtPrivate + +template +struct QHttpServerRouterViewTraits +{ + using Helpers = typename QtPrivate::RouterViewTraitsHelper; + using ReturnType = typename Helpers::FunctionTraits::ReturnType; + using Arguments = decltype(Helpers::Arguments::eval(typename Helpers::ArgumentIndexes{})); + using BindableType = decltype( + Helpers::template BindType::eval( + typename Arguments::PlaceholdersIndexes{})); +}; + + +QT_END_NAMESPACE + +#endif // QHTTPSERVERROUTERVIEWTRAITS_H diff --git a/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverviewtraits.h b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverviewtraits.h new file mode 100644 index 0000000..0469ffb --- /dev/null +++ b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverviewtraits.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Mikhail Svetkin +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTPSERVERVIEWTRAITS_H +#define QHTTPSERVERVIEWTRAITS_H + +#include + +QT_BEGIN_NAMESPACE + +class QHttpServerRequest; +class QHttpServerResponse; + +namespace QtPrivate { + +template +struct AfterRequestViewTraitsHelper : ViewTraits { + using VTraits = ViewTraits; + using FunctionTraits = typename VTraits::FTraits; + + static_assert(DisableStaticAssert || + FunctionTraits::ArgumentCount == 2 || + FunctionTraits::ArgumentCount == 1, + "ViewHandler arguments error: " + "afterRequest can only accept QHttpServerResponse and QHttpServerRequest"); + + static_assert(DisableStaticAssert || + std::is_same::value, + "ViewHandler return type error: " + "Return type can only be QHttpServerResponse"); + + template + struct ArgumentChecker { + using IsRequest = typename VTraits::template Special; + static_assert(IsRequest::AssertCondition, + "ViewHandler arguments error: " + "QHttpServerRequest can only be passed as a const reference"); + + using IsResponse = typename VTraits::template Special; + static_assert(IsResponse::AssertCondition, + "ViewHandler arguments error: " + "QHttpServerResponse can only be passed as a universal reference"); + + using IsSpecial = CheckAny; + + static constexpr bool Valid = IsSpecial::Valid; + static constexpr bool StaticAssert = IsSpecial::StaticAssert; + }; + + struct Arguments { + template + struct ArgumentsReturn { + template + using Arg = ArgumentChecker; + static constexpr bool Valid = QtPrivate::StaticMath::And::eval(Arg::Valid...); + static constexpr bool StaticAssert = QtPrivate::StaticMath::And::eval( + Arg::StaticAssert...); + using Last = Arg; + static constexpr std::size_t Count = FunctionTraits::ArgumentCount; + }; + + template + static constexpr ArgumentsReturn eval(QtPrivate::IndexesList) noexcept + { + return ArgumentsReturn{}; + } + }; +}; + +} // namespace QtPrivate + +template +struct QHttpServerAfterRequestViewTraits +{ + using Helpers = typename QtPrivate::AfterRequestViewTraitsHelper; + using Arguments = decltype(Helpers::Arguments::eval(typename Helpers::ArgumentIndexes{})); +}; + +QT_END_NAMESPACE + +#endif // QHTTPSERVERVIEWTRAITS_H diff --git a/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverviewtraits_impl.h b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverviewtraits_impl.h new file mode 100644 index 0000000..45c46d7 --- /dev/null +++ b/Lib/QtHTTPServer/include/QtHttpServer/qhttpserverviewtraits_impl.h @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Mikhail Svetkin +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTPSERVERVIEWTRAITS_IMPL_H +#define QHTTPSERVERVIEWTRAITS_IMPL_H + +#include +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace QtPrivate { + +template +struct RemoveCVRef +{ + using Type = typename std::remove_cv::type>::type; +}; + + +template +struct FunctionTraitsHelper +{ + static constexpr const int ArgumentCount = sizeof ... (Args); + static constexpr const int ArgumentIndexMax = ArgumentCount - 1; + static constexpr const bool IsClassMember = classMember; + using ReturnType = ReturnT; + + template + struct Arg { + using Type = typename std::tuple_element>::type; + + using CleanType = typename QtPrivate::RemoveCVRef::Type; + + static constexpr bool Defined = QMetaTypeId2::Defined; + }; +}; + +template +struct FunctionTraitsHelper +{ + static constexpr const int ArgumentCount = 0; + static constexpr const int ArgumentIndexMax = -1; + static constexpr const bool IsClassMember = classMember; + using ReturnType = ReturnT; + + template + struct Arg { + using Type = std::false_type; + using CleanType = Type; + static constexpr bool Defined = QMetaTypeId2::Defined; + }; +}; + +template +struct FunctionTraits; + +template +struct FunctionTraits : public FunctionTraits{}; + +template +struct FunctionTraits + : public FunctionTraitsHelper +{ +}; + +template +struct FunctionTraits + : public FunctionTraitsHelper +{ + using classType = ClassT; +}; + +struct StaticMath { + template class Predicate, bool defaultValue> + struct Loop { + static constexpr bool eval() noexcept { + return defaultValue; + } + + template + static constexpr T eval(const T it, N ...n) noexcept { + return Predicate::eval(it, eval(n...)); + } + }; + + template + struct SumPredicate { + static constexpr T eval(const T rs, const T ls) noexcept + { + return rs + ls; + } + }; + + template + struct AndPredicate { + static constexpr T eval(const T rs, const T ls) noexcept + { + return rs && ls; + } + }; + + using Sum = Loop; + using And = Loop; + using Or = Sum; +}; + +template +struct CheckAny { + static constexpr bool Value = StaticMath::Or::eval(T::Value...); + static constexpr bool Valid = StaticMath::Or::eval(T::Valid...); + static constexpr bool StaticAssert = StaticMath::Or::eval(T::StaticAssert...); +}; + +template +struct ViewTraits { + using FTraits = FunctionTraits; + using ArgumentIndexes = typename Indexes::Value; + + template + struct SpecialHelper { + using Arg = typename FTraits::template Arg; + using CleanSpecialT = typename RemoveCVRef::Type; + + static constexpr bool TypeMatched = std::is_same::value; + static constexpr bool TypeCVRefMatched = std::is_same::value; + + static constexpr bool ValidPosition = + (I == FTraits::ArgumentIndexMax || + I == FTraits::ArgumentIndexMax - 1); + static constexpr bool ValidAll = TypeCVRefMatched && ValidPosition; + + static constexpr bool AssertCondition = + DisableStaticAssert || !TypeMatched || TypeCVRefMatched; + + static constexpr bool AssertConditionOrder = + DisableStaticAssert || !TypeMatched || ValidPosition; + + static constexpr bool StaticAssert = AssertCondition && AssertConditionOrder; + + static_assert(AssertConditionOrder, + "ViewHandler arguments error: " + "QHttpServerRequest or QHttpServerResponder" + " can only be the last argument"); + }; + + template + struct Special { + using Helper = SpecialHelper; + static constexpr bool Value = Helper::TypeMatched; + static constexpr bool Valid = Helper::ValidAll; + static constexpr bool StaticAssert = Helper::StaticAssert; + static constexpr bool AssertCondition = Helper::AssertCondition; + }; +}; + +} // namespace QtPrivate + +QT_END_NAMESPACE + +#endif // QHTTPSERVERVIEWTRAITS_IMPL_H diff --git a/Lib/QtHTTPServer/include/QtHttpServer/qthttpserverglobal.h b/Lib/QtHTTPServer/include/QtHttpServer/qthttpserverglobal.h new file mode 100644 index 0000000..8190256 --- /dev/null +++ b/Lib/QtHTTPServer/include/QtHttpServer/qthttpserverglobal.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTHTTPSERVERGLOBAL_H +#define QTHTTPSERVERGLOBAL_H + +#include + +QT_BEGIN_NAMESPACE + +#ifndef QT_STATIC +# if defined(QT_BUILD_HTTPSERVER_LIB) +# define Q_HTTPSERVER_EXPORT Q_DECL_EXPORT +# else +# define Q_HTTPSERVER_EXPORT Q_DECL_IMPORT +# endif +#else +# define Q_HTTPSERVER_EXPORT +#endif + +QT_END_NAMESPACE + +#endif // QTHTTPSERVERGLOBAL_H + diff --git a/Lib/QtHTTPServer/include/QtSslServer/qsslserver.h b/Lib/QtHTTPServer/include/QtSslServer/qsslserver.h new file mode 100644 index 0000000..841fc4f --- /dev/null +++ b/Lib/QtHTTPServer/include/QtSslServer/qsslserver.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Sylvain Garcia . +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSSLSERVER_H +#define QSSLSERVER_H + +#include + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QSslServerPrivate; +class Q_SSLSERVER_EXPORT QSslServer : public QTcpServer +{ + Q_OBJECT +public: + QSslServer(QObject *parent = nullptr); + QSslServer(const QSslConfiguration &sslConfiguration, QObject *parent = nullptr); + ~QSslServer(); + + void setSslConfiguration(const QSslConfiguration &sslConfiguration); + +Q_SIGNALS: + void sslErrors(QSslSocket *socket, const QList &errors); + +protected: + void incomingConnection(qintptr handle) override final; + +private: + QScopedPointer d; +}; + +QT_END_NAMESPACE + +#endif // QSSLSERVER_HPP diff --git a/Lib/QtHTTPServer/include/QtSslServer/qsslserver_p.h b/Lib/QtHTTPServer/include/QtSslServer/qsslserver_p.h new file mode 100644 index 0000000..26d0ad1 --- /dev/null +++ b/Lib/QtHTTPServer/include/QtSslServer/qsslserver_p.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Sylvain Garcia . +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSSLSERVER_P_H +#define QSSLSERVER_P_H + +#include + +QT_BEGIN_NAMESPACE + +class QSslServerPrivate +{ +public: + QSslConfiguration sslConfiguration; +}; + +QT_END_NAMESPACE + +#endif // QSSLSERVER_P_H diff --git a/Lib/QtHTTPServer/include/QtSslServer/qtsslserverglobal.h b/Lib/QtHTTPServer/include/QtSslServer/qtsslserverglobal.h new file mode 100644 index 0000000..8f9b55d --- /dev/null +++ b/Lib/QtHTTPServer/include/QtSslServer/qtsslserverglobal.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Sylvain Garcia . +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTSSLSERVERGLOBAL_H +#define QTSSLSERVERGLOBAL_H + +#include + +QT_BEGIN_NAMESPACE + +#ifndef QT_STATIC +# if defined(QT_BUILD_SSLSERVER_LIB) +# define Q_SSLSERVER_EXPORT Q_DECL_EXPORT +# else +# define Q_SSLSERVER_EXPORT Q_DECL_IMPORT +# endif +#else +# define Q_SSLSERVER_EXPORT +#endif + +QT_END_NAMESPACE + +#endif // QTSSLSERVERGLOBAL_H diff --git a/Lib/QtHTTPServer/libQt5HttpServer.a b/Lib/QtHTTPServer/libQt5HttpServer.a new file mode 100644 index 0000000..b9dc938 Binary files /dev/null and b/Lib/QtHTTPServer/libQt5HttpServer.a differ diff --git a/Lib/QtHTTPServer/libQt5SslServer.a b/Lib/QtHTTPServer/libQt5SslServer.a new file mode 100644 index 0000000..2085ea1 Binary files /dev/null and b/Lib/QtHTTPServer/libQt5SslServer.a differ diff --git a/Lib/QtHTTPServer/pkgconfig/Qt5HttpServer.pc b/Lib/QtHTTPServer/pkgconfig/Qt5HttpServer.pc new file mode 100644 index 0000000..d65ba55 --- /dev/null +++ b/Lib/QtHTTPServer/pkgconfig/Qt5HttpServer.pc @@ -0,0 +1,13 @@ +prefix=C:/Qt/Qt5.14.2/5.14.2/mingw73_64 +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + + +Name: Qt5 HttpServer +Description: Qt HttpServer module +Version: 5.12.0 +Libs: -L${libdir} -lQt5HttpServer +Cflags: -DQT_HTTPSERVER_LIB -I${includedir}/QtHttpServer -I${includedir} +Requires: Qt5Network Qt5Core Qt5WebSockets Qt5SslServer Qt5Concurrent + diff --git a/Lib/QtHTTPServer/pkgconfig/Qt5SslServer.pc b/Lib/QtHTTPServer/pkgconfig/Qt5SslServer.pc new file mode 100644 index 0000000..3deca5a --- /dev/null +++ b/Lib/QtHTTPServer/pkgconfig/Qt5SslServer.pc @@ -0,0 +1,13 @@ +prefix=C:/Qt/Qt5.14.2/5.14.2/mingw73_64 +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + + +Name: Qt5 SslServer +Description: Qt SslServer module +Version: 5.12.0 +Libs: -L${libdir} -lQt5SslServer +Cflags: -DQT_SSLSERVER_LIB -I${includedir}/QtSslServer -I${includedir} +Requires: Qt5Network Qt5Core + diff --git a/MasterCtrl.pro b/MasterCtrl.pro index d3308aa..c48263c 100644 --- a/MasterCtrl.pro +++ b/MasterCtrl.pro @@ -1,6 +1,6 @@ #QT += Network #QT += gui declarative network -QT += gui network serialport +QT += gui network serialport mqtt greaterThan(QT_MAJOR_VERSION, 4): QT += widgets #CONFIG += console @@ -41,7 +41,38 @@ HEADERS += \ Sources/Chalet/ChaletNetworkMessage.h \ Sources/HttpServer/HttpServer.h \ Sources/BlynkCloudClient.h \ - Sources/Chalet/ChaletDataLogger.h + Sources/Chalet/ChaletDataLogger.h \ + Sources/Chalet/ChaletUbidotsInterface.h \ + Sources/Chalet/ThingsBoardInterface.h \ + Lib/QtHTTPServer/include/QtHttpServer/qabstracthttpserver.h \ + Lib/QtHTTPServer/include/QtHttpServer/qabstracthttpserver_p.h \ + Lib/QtHTTPServer/include/QtHttpServer/qhttpserver.h \ + Lib/QtHTTPServer/include/QtHttpServer/qhttpserver_p.h \ + Lib/QtHTTPServer/include/QtHttpServer/qhttpserverfutureresponse.h \ + Lib/QtHTTPServer/include/QtHttpServer/qhttpserverliterals_p.h \ + Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrequest.h \ + Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrequest_p.h \ + Lib/QtHTTPServer/include/QtHttpServer/qhttpserverresponder.h \ + Lib/QtHTTPServer/include/QtHttpServer/qhttpserverresponder_p.h \ + Lib/QtHTTPServer/include/QtHttpServer/qhttpserverresponse.h \ + Lib/QtHTTPServer/include/QtHttpServer/qhttpserverresponse_p.h \ + Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrouter.h \ + Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrouter_p.h \ + Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrouterrule.h \ + Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrouterrule_p.h \ + Lib/QtHTTPServer/include/QtHttpServer/qhttpserverrouterviewtraits.h \ + Lib/QtHTTPServer/include/QtHttpServer/qhttpserverviewtraits.h \ + Lib/QtHTTPServer/include/QtHttpServer/qhttpserverviewtraits_impl.h \ + Lib/QtHTTPServer/include/QtHttpServer/qthttpserverglobal.h \ + Lib/QtHTTPServer/include/QtSslServer/qsslserver.h \ + Lib/QtHTTPServer/include/QtSslServer/qsslserver_p.h \ + Lib/QtHTTPServer/include/QtSslServer/qtsslserverglobal.h \ + Sources/ImageCropper/imagecropper.h \ + Sources/ImageCropper/imagecropper_e.h \ + Sources/ImageCropper/imagecropper_p.h \ + Sources/Modbus/ModbusBackend.h \ + Sources/Modbus/ModbusRepository.h \ + Sources/Chalet/ChaletModbusServer.h SOURCES += \ Sources/Chalet/ChaletData.cpp \ @@ -77,7 +108,13 @@ SOURCES += \ Sources/Chalet/ChaletNetworkMessage.cpp \ Sources/HttpServer/HttpServer.cpp \ Sources/BlynkCloudClient.cpp \ - Sources/Chalet/ChaletDataLogger.cpp + Sources/Chalet/ChaletDataLogger.cpp \ + Sources/Chalet/ChaletUbidotsInterface.cpp \ + Sources/Chalet/ThingsBoardInterface.cpp \ + Sources/ImageCropper/imagecropper.cpp \ + Sources/Modbus/ModbusBackend.cpp \ + Sources/Modbus/ModbusRepository.cpp \ + Sources/Chalet/ChaletModbusServer.cpp DEFINES -= Q_OS_UNIX @@ -96,8 +133,7 @@ INCLUDEPATH += $$PWD/ \ $$PWD/Sources/Chalet \ $$PWD/Sources/HttpServer \ $$PWD/blynk-library-master/src/ \ + $$PWD/Sources/Modbus \ + # $$PWD/Lib/QtHTTPServer/include/ \ -FORMS += - -DISTFILES += \ - ../../../../Dev/qthttpserver/mkspecs/modules/qt_lib_httpserver.pri +LIBS += -L$$PWD/Lib/QtHTTPServer/ -lQt5HttpServer diff --git a/Sources/232NetworkCommIF.cpp b/Sources/232NetworkCommIF.cpp index 9441608..10f4ce0 100644 --- a/Sources/232NetworkCommIF.cpp +++ b/Sources/232NetworkCommIF.cpp @@ -32,7 +32,7 @@ int C232NetworkCommIF::NewFrameReceived(int DeviceID, int DeviceAddress, int Mes // return 1; //} -int C232NetworkCommIF::SendNetworkMessage(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray Data) +int C232NetworkCommIF::SendNetworkMessage(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray *Data) { Q_UNUSED(DeviceID) Q_UNUSED(DeviceAddress) diff --git a/Sources/232NetworkCommIF.h b/Sources/232NetworkCommIF.h index a259389..0f2431f 100644 --- a/Sources/232NetworkCommIF.h +++ b/Sources/232NetworkCommIF.h @@ -15,7 +15,7 @@ public: int NewFrameReceived(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray Data); //NetworkCommIF implementation - virtual int SendNetworkMessage(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray Data); + virtual int SendNetworkMessage(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray *Data); private: CNetworkDevice *mDeviceHandle; diff --git a/Sources/485NetworkCommIF.cpp b/Sources/485NetworkCommIF.cpp index c9379e5..80b9a90 100644 --- a/Sources/485NetworkCommIF.cpp +++ b/Sources/485NetworkCommIF.cpp @@ -28,7 +28,7 @@ int C485NetworkCommIF::RegisterNewDevice(CNetworkDevice *NewDevice) return 1; } -int C485NetworkCommIF::SendNetworkMessage(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray Data) +int C485NetworkCommIF::SendNetworkMessage(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray *Data) { Q_UNUSED(DeviceID) Q_UNUSED(DeviceAddress) diff --git a/Sources/485NetworkCommIF.h b/Sources/485NetworkCommIF.h index 506e8c7..ef41556 100644 --- a/Sources/485NetworkCommIF.h +++ b/Sources/485NetworkCommIF.h @@ -16,7 +16,7 @@ public: virtual int NewFrameReceived(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray Data); //NetworkCommIF implementation - virtual int SendNetworkMessage(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray Data); + virtual int SendNetworkMessage(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray *Data); private: QList mDevicesList; diff --git a/Sources/AbstractNetworkInterface.h b/Sources/AbstractNetworkInterface.h index 8fb999f..26755d2 100644 --- a/Sources/AbstractNetworkInterface.h +++ b/Sources/AbstractNetworkInterface.h @@ -12,7 +12,7 @@ public: CNetworkDevice *mDevicePtr; CAbstractNetworkCommIF(){mDevicePtr = 0;} virtual ~CAbstractNetworkCommIF() {} - virtual int SendNetworkMessage(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray Data) = 0; + virtual int SendNetworkMessage(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray *Data) = 0; }; #endif // ABSTRACTNETWORKINTERFACE_H diff --git a/Sources/AvReceiver/AvReceiverInterface.cpp b/Sources/AvReceiver/AvReceiverInterface.cpp index 83e0fa4..418c355 100644 --- a/Sources/AvReceiver/AvReceiverInterface.cpp +++ b/Sources/AvReceiver/AvReceiverInterface.cpp @@ -24,7 +24,7 @@ int CAvReceiverInterface::NewDeviceFrameReceived(int DeviceID, int DeviceAddress case AV_RECEIVER_INTERFACE_GENERAL_STATUS_REQUEST: { QByteArray data = mAvReceiverDevice->GetReceiverStatus().ToByteArray(); - mNetworkInterfacePtr->SendNetworkMessage(ID_AVRECEIVER_INTERFACE,mDeviceAddress,AV_RECEIVER_INTERFACE_GENERAL_STATUS_RESPONSE,data.size(),data); + mNetworkInterfacePtr->SendNetworkMessage(ID_AVRECEIVER_INTERFACE,mDeviceAddress,AV_RECEIVER_INTERFACE_GENERAL_STATUS_RESPONSE,data.size(),&data); break; } diff --git a/Sources/Chalet/ChaletData.cpp b/Sources/Chalet/ChaletData.cpp index 821f9ec..e16fab0 100644 --- a/Sources/Chalet/ChaletData.cpp +++ b/Sources/Chalet/ChaletData.cpp @@ -11,6 +11,7 @@ CChaletMainStatus::CChaletMainStatus() mIsOnline = false; mHarakiriDone = false; mStatusToggleBit = 0; + mLostRequestPercentage = 0; } @@ -52,6 +53,10 @@ QByteArray CChaletMainStatus::ToByteArray() Strm << mBatterySOC; Strm << mIsOnline; Strm << mCurrentSensorStatus; + Strm << mLostRequestPercentage; + Strm << mThisStatusDateTime; + Strm << mLastLoraStatus; + Strm << mStatusToggleBit; return Data; } diff --git a/Sources/Chalet/ChaletData.h b/Sources/Chalet/ChaletData.h index 20860e4..9376b25 100644 --- a/Sources/Chalet/ChaletData.h +++ b/Sources/Chalet/ChaletData.h @@ -30,6 +30,11 @@ public: bool mStatusToggleBit; QDateTime mLastLoraStatus; + QDateTime mThisStatusDateTime; + + float mLostRequestPercentage; + + }; diff --git a/Sources/Chalet/ChaletDataLogger.cpp b/Sources/Chalet/ChaletDataLogger.cpp index 81b604e..ea1668e 100644 --- a/Sources/Chalet/ChaletDataLogger.cpp +++ b/Sources/Chalet/ChaletDataLogger.cpp @@ -1,36 +1,231 @@ #include "ChaletDataLogger.h" #include #include +#include +#include +#include + CChaletDataLogger::CChaletDataLogger(QObject *parent) : QObject(parent) { + mChaletLogFile = 0; + OpenTodaysFile(); + mChaletNewLogFileTimer = new QTimer; + connect(mChaletNewLogFileTimer,SIGNAL(timeout()),this,SLOT(NewLogFileTimerExpired())); + mChaletNewLogFileTimer->setInterval(1000); + mChaletNewLogFileTimer->setSingleShot(false); + mChaletNewLogFileTimer->start(); + +} + +int CChaletDataLogger::OpenTodaysFile() +{ + mTodaysDate = QDateTime::currentDateTime().date(); bool create = false; - mChaletLogFile = new QFile(CHALET_LORA_DATA_LOG_FILENAME); - if(QFile::exists(CHALET_LORA_DATA_LOG_FILENAME) == false) + QString LogFileName(CHALET_LORA_DATA_LOG_DIR); + LogFileName.append("ChaletLora-"); + LogFileName.append(mTodaysDate.toString("yyyy-MM-dd")); + LogFileName.append(".csv"); + + if(mChaletLogFile != 0) + { + if(mChaletLogFile->isOpen()) + { + mChaletLogFile->close(); + } + mChaletLogFile->setFileName(LogFileName); + } + else + { + mChaletLogFile = new QFile(LogFileName); + } + + //Check if today's file already exist, otherwise create it... + if(QFile::exists(LogFileName) == false) create = true; - if(mChaletLogFile->open(QIODevice::ReadWrite|QIODevice::Append/*|QIODevice::Text*/) == false) + if(mChaletLogFile->open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Unbuffered) == false) { delete mChaletLogFile; mChaletLogFile = 0; qDebug("Cannot open chalet LORA log file..."); - return; + return RET_ERROR; } if(create) { qDebug("Creating new chalet LORA log file..."); QString Header("Date;Heure;Courant Batterie;Tension Batterie;Inverter;Wifi\n"); - int bytes = mChaletLogFile->write(qPrintable(Header)); + mChaletLogFile->write(qPrintable(Header)); mChaletLogFile->flush(); } // mChaletLogFile->close(); qDebug("Chalet LORA log file created successfully"); + return RET_OK; } +QByteArray *CChaletDataLogger::GetChaletData(QDate StartDate) +{ + + if(StartDate > QDate::currentDate()) + { + return 0; + } + + QFile *LogFile =0; + + bool done = false; + QByteArray WorkArray, *DataArray; + DataArray = new QByteArray; + int NbReadings = 0; + DataArray->clear(); + + while(!done) + { + + if(StartDate > QDate::currentDate()) + { + done = true; + break; + } +// else if(StartDate == QDate::currentDate()) +// { +// LogFile = mChaletLogFile; +// } + else + { + QString LogFileName(CHALET_LORA_DATA_LOG_DIR); + LogFileName.append("ChaletLora-"); + LogFileName.append(StartDate.toString("yyyy-MM-dd")); + LogFileName.append(".csv"); + + if(QFileInfo::exists(LogFileName)) + { + LogFile = new QFile(LogFileName); + if(LogFile->open(QIODevice::ReadOnly|QIODevice::Unbuffered) == false) + { + delete LogFile; + LogFile = 0; + } + } + else + { + LogFile = 0; + } + } + + +// if(mChaletLogFile == 0) +// { +// return 0; +// } + +// if(mChaletLogFile->isOpen() == false) +// { +// return 0; +// } + + if(LogFile != 0) + { + + LogFile->seek(0); //seek to the beginning of the log file + WorkArray = LogFile->readLine(); //read and discard the header line. + bool Finished = false; + while(!Finished) + { + WorkArray.clear(); + WorkArray = LogFile->readLine(); + if(WorkArray.isEmpty()) + { + Finished = true; + break; + } + + + QStringList LineData = QString(WorkArray).remove("\n").split(QChar(';')); + if(LineData.size() == 6) //if we don't have 6 parameters, something went very wrong + { //"Date;Heure;Courant Batterie;Tension Batterie;Inverter;Wifi\n"); + + QString date = LineData.at(0); + // QDate Date = QDate::fromString("yyyy-MM-dd",LineData.at(0)); + QDate Date = QDate::currentDate(); + Date = QDate::fromString(date,"yyyy-MM-dd"); + QString time = LineData.at(1); + // QTime Time = QTime::fromString("hh:mm:ss",LineData.at(1)); + QTime Time = QTime::currentTime(); + Time= QTime::fromString(time,"hh:mm:ss"); + QDateTime DateTime(Date,Time); +// qDebug("Date: %s",qPrintable(Date.toString("yyyy-MM-dd"))); +// qDebug("Time: %s",qPrintable(Time.toString("hh:mm:ss"))); +// qDebug("Date Time: %s",qPrintable(DateTime.toString("yyyy-MM-dd-hh:mm:ss"))); + + // time.setDate(QDate().fromString("yyyy-MM-dd",LineData.at(0))); + // time.setTime(QTime().fromString("hh:mm:ss",LineData.at(1))); + QString temp = LineData.at(2); + bool OK; + qint16 BattCurrent = temp.toInt(&OK); + temp = LineData.at(3); + float BattVoltage = temp.toFloat(&OK); + temp = LineData.at(4); + quint8 InverterStatus = 0; + if(temp == "ON") + { + InverterStatus = 1; + } + temp = LineData.at(5); + quint8 WiFiStatus = 0; + if(temp == "ON") + { + WiFiStatus = 1; + } + CChaletMainStatus CurBlob; + CurBlob.mThisStatusDateTime = DateTime; + CurBlob.mBatteryCurrent = BattCurrent; + CurBlob.mBatteryVoltage = BattVoltage; + CurBlob.mInverterRelayStatus = InverterStatus; + CurBlob.mWiFiModuleStatus = WiFiStatus; + + DataArray->append(CurBlob.ToByteArray()); + NbReadings++; + } + else + { + qDebug("Invalid nb. of parameters in today's data extraction"); + } + + + } + } + + + if(LogFile != mChaletLogFile && LogFile != 0) + { + LogFile->close(); + delete LogFile; + } + LogFile = 0; + StartDate = StartDate.addDays(1); + + } + + QByteArray Readings; + QDataStream strm(&Readings,QIODevice::WriteOnly); + strm.device()->seek(0); + strm << NbReadings; + DataArray->prepend(Readings); + + return DataArray; //Don't forget to delete!!! +} + +QByteArray *CChaletDataLogger::GetTodaysData() +{ + return GetChaletData(QDate::currentDate()); +} + + CChaletDataLogger::~CChaletDataLogger() { if(mChaletLogFile) @@ -38,6 +233,7 @@ CChaletDataLogger::~CChaletDataLogger() mChaletLogFile->close(); delete mChaletLogFile; } + } bool CChaletDataLogger::LogChaletLORAData(CChaletMainStatus *Data) @@ -82,7 +278,21 @@ bool CChaletDataLogger::LogChaletLORAData(CChaletMainStatus *Data) mChaletLogFile->write(qPrintable(CSVData)); mChaletLogFile->flush(); + + + // mChaletLogFile->close(); return true; } + + + +void CChaletDataLogger::NewLogFileTimerExpired() +{ + if(QDateTime::currentDateTime().date() > mTodaysDate) //If it's midnight... + { + qDebug("It's midnight... creating today's file..."); + OpenTodaysFile(); + } +} diff --git a/Sources/Chalet/ChaletDataLogger.h b/Sources/Chalet/ChaletDataLogger.h index 2d6e927..3d9c954 100644 --- a/Sources/Chalet/ChaletDataLogger.h +++ b/Sources/Chalet/ChaletDataLogger.h @@ -4,9 +4,11 @@ #include #include #include "ChaletData.h" +#include + //#define CHALET_LORA_DATA_LOG_FILENAME "./ChaletLogs/ChaletLora.csv" -#define CHALET_LORA_DATA_LOG_FILENAME "D:/Main/Chalet/LoraLogs/ChaletLora.csv" +#define CHALET_LORA_DATA_LOG_DIR "D:/Main/Chalet/LoraLogs/" class CChaletMainStatus; @@ -18,13 +20,25 @@ public: ~CChaletDataLogger(); bool LogChaletLORAData(CChaletMainStatus *Data); + QByteArray *GetTodaysData(); + QByteArray *GetChaletData(QDate StartDate); QFile *mChaletLogFile; + QTimer *mChaletNewLogFileTimer; + QDate mTodaysDate; + + + +private: + int OpenTodaysFile(); + signals: + public slots: + void NewLogFileTimerExpired(); }; #endif // CHALETDATALOGGER_H diff --git a/Sources/Chalet/ChaletInterface.cpp b/Sources/Chalet/ChaletInterface.cpp index 7c0e380..6d3cc82 100644 --- a/Sources/Chalet/ChaletInterface.cpp +++ b/Sources/Chalet/ChaletInterface.cpp @@ -1,9 +1,12 @@ #include "ChaletInterface.h" +#include "ChaletDataLogger.h" CChaletInterface::CChaletInterface(int Address, CAbstractNetworkCommIF *NetworkInterface, CChaletLoraDevice *DevicePtr): CNetworkDevice(ID_CHALET_INTERFACE,Address,NetworkInterface) { mChaletLoraDevice = DevicePtr; + mChaletDataLogger = mChaletLoraDevice->GetDataLoggerHandle(); + } @@ -24,7 +27,7 @@ int CChaletInterface::NewDeviceFrameReceived(int DeviceID, int DeviceAddress, in case CHALET_INTERFACE_GENERAL_STATUS_REQUEST: { QByteArray data = mChaletLoraDevice->GetChaletMainStatus().ToByteArray(); - mNetworkInterfacePtr->SendNetworkMessage(ID_CHALET_INTERFACE,mDeviceAddress,CHALET_INTERFACE_GENERAL_STATUS_RESPONSE,data.size(),data); + mNetworkInterfacePtr->SendNetworkMessage(ID_CHALET_INTERFACE,mDeviceAddress,CHALET_INTERFACE_GENERAL_STATUS_RESPONSE,data.size(),&data); break; } @@ -74,6 +77,25 @@ int CChaletInterface::NewDeviceFrameReceived(int DeviceID, int DeviceAddress, in mChaletLoraDevice->SendRebootCmd(); break; } + case CHALET_INTERFACE_GET_TODAYS_DATA_LOG_REQUEST: + { + QByteArray *data = mChaletDataLogger->GetTodaysData(); + mNetworkInterfacePtr->SendNetworkMessage(ID_CHALET_INTERFACE,mDeviceAddress,CHALET_INTERFACE_GET_TODAYS_DATA_LOG_RESPONSE,data->size(),data); + delete data; + break; + } + case CHALET_INTERFACE_GET_DATA_LOG_REQUEST: + { + QDate StartDate; + QDataStream Strm(Data); + Strm >> StartDate; + QByteArray *data = mChaletDataLogger->GetChaletData(StartDate); + mNetworkInterfacePtr->SendNetworkMessage(ID_CHALET_INTERFACE,mDeviceAddress,CHALET_INTERFACE_GET_DATA_LOG_RESPONSE,data->size(),data); + delete data; + break; + } + case CHALET_INTERFACE_GET_DATA_LOG_RESPONSE: + case CHALET_INTERFACE_GET_TODAYS_DATA_LOG_RESPONSE: case CHALET_INTERFACE_GENERAL_STATUS_RESPONSE: case CHALET_INTERFACE_AC_POWER_STATE_STATUS_RESPONSE: case CHALET_INTERFACE_AC_POWER_SET_STATE_RESPONSE: @@ -93,3 +115,8 @@ int CChaletInterface::NewDeviceFrameReceived(int DeviceID, int DeviceAddress, in return RET_OK; } + +void CChaletInterface::SendChaletCommActivityBeacon() +{ + mNetworkInterfacePtr->SendNetworkMessage(ID_CHALET_INTERFACE,mDeviceAddress,CHALET_INTERFACE_CHALET_ACTIVITY_RESPONSE,0,0); +} diff --git a/Sources/Chalet/ChaletInterface.h b/Sources/Chalet/ChaletInterface.h index 34afe0a..fcc4ae9 100644 --- a/Sources/Chalet/ChaletInterface.h +++ b/Sources/Chalet/ChaletInterface.h @@ -2,8 +2,8 @@ #define CCHALETINTERFACE_H #include "NetworkDevice.h" -#include "ChaletLoraDevice.h" +#include "ChaletLoraDevice.h" class CChaletInterface: public QObject, public CNetworkDevice { @@ -13,8 +13,10 @@ public: CChaletInterface(int Address, CAbstractNetworkCommIF *NetworkInterface, CChaletLoraDevice *DevicePtr); virtual int NewDeviceFrameReceived(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray Data); + void SendChaletCommActivityBeacon(); private: CChaletLoraDevice *mChaletLoraDevice; + CChaletDataLogger *mChaletDataLogger; }; diff --git a/Sources/Chalet/ChaletLoraDevice.cpp b/Sources/Chalet/ChaletLoraDevice.cpp index a05667a..171854c 100644 --- a/Sources/Chalet/ChaletLoraDevice.cpp +++ b/Sources/Chalet/ChaletLoraDevice.cpp @@ -1,5 +1,6 @@ #include "ChaletLoraDevice.h" #include "GlobalDefine.h" +#include "ChaletInterface.h" @@ -10,11 +11,16 @@ CChaletLoraDevice::CChaletLoraDevice(int Address, CAbstractNetworkCommIF *Networ mDeviceAddress = Address; mDeviceID = ID_CHALET_DEVICE; - mChaletStatusTimer = new QTimer(); mChaletStatusTimer->setInterval(1000); mChaletStatusTimer->setSingleShot(true); connect(mChaletStatusTimer,SIGNAL(timeout()),this,SLOT(CommTimerExpired())); + + mJFUbidotsInterface = new CChaletJFUbidotsInterface("BBFF-tEq4lGAegEyP1H4EaYckNQ7ZHdZYzI"); + + mThingsBoardInterface.mChaletLoraDevice = this; + + ResetCommStats(); } CChaletLoraDevice::~CChaletLoraDevice() @@ -26,11 +32,16 @@ int CChaletLoraDevice::Start() { ScheduleChaletStatusRequest(); mChaletStatusTimer->start(1000); + mThingsBoardInterface.RegisterThingsboardRPC(); return RET_OK; } int CChaletLoraDevice::NewDeviceFrameReceived(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray Data) { + Q_UNUSED(DeviceID) + Q_UNUSED(DeviceAddress) + Q_UNUSED(DataSize) + switch(MessageID) { case CHALET_ACK: @@ -69,20 +80,28 @@ int CChaletLoraDevice::NewDeviceFrameReceived(int DeviceID, int DeviceAddress, i mChaletMainStatus.mBatterySOC = temp2; mChaletMainStatus.mStatusToggleBit = !mChaletMainStatus.mStatusToggleBit; + mChaletMainStatus.mLastLoraStatus = QDateTime::currentDateTime(); CmdResponseReceived(CHALET_GENERAL_STATUS_REQUEST); qDebug("voltage: %f",mChaletMainStatus.mBatteryVoltage); - qDebug("Current: %d",mChaletMainStatus.mBatteryCurrent); - qDebug("SOC: %d",mChaletMainStatus.mBatterySOC); +// qDebug("Current: %d",mChaletMainStatus.mBatteryCurrent); +// qDebug("SOC: %d",mChaletMainStatus.mBatterySOC); + qDebug("Inverter: %d",mChaletMainStatus.mInverterRelayStatus); mChaletDataLogger.LogChaletLORAData(&mChaletMainStatus); + mJFUbidotsInterface->LogUbidotsChaletData(&mChaletMainStatus); + mBlynkInterface.UpdateChaletCurrent(mChaletMainStatus.mBatteryCurrent); mBlynkInterface.UpdateChaletVoltage(mChaletMainStatus.mBatteryVoltage); // mBlynkInterface.UpdateChaletWifiStatus((int)mChaletMainStatus.mInverterRelayStatus); mBlynkInterface.UpdateChaletInverterStatus((int)mChaletMainStatus.mInverterRelayStatus); mBlynkInterface.UpdateChaletStatusLed(((int)mChaletMainStatus.mStatusToggleBit)*255); + // mThingsBoardInterface.UpdateChaletVoltage(mChaletMainStatus.mBatteryVoltage); + mThingsBoardInterface.UpdateChaletData(mChaletMainStatus.mInverterRelayStatus,mChaletMainStatus.mWiFiModuleStatus,mChaletMainStatus.mCurrentSensorStatus,mChaletMainStatus.mBatteryVoltage,mChaletMainStatus.mBatteryCurrent,mChaletMainStatus.mBatterySOC,mChaletMainStatus.mIsOnline); + + break; } case CHALET_AC_POWER_STATE_STATUS_RESPONSE: @@ -185,6 +204,8 @@ void CChaletLoraDevice::CommTimerExpired() } } mPendingNetworkMsgList[0].ResendCounter++; + mNbLostRequest++; + ComputeCommStats(); } qDebug("Sending chalet request 0x%x",mPendingNetworkMsgList.at(0).mMessageID); @@ -262,7 +283,9 @@ int CChaletLoraDevice::SendRebootCmd() int CChaletLoraDevice::SendChaletCommand(int CmdID, int DataSize, QByteArray Data) { - mNetworkInterfacePtr->SendNetworkMessage(ID_CHALET_DEVICE,mDeviceAddress,CmdID,DataSize,Data); + mNetworkInterfacePtr->SendNetworkMessage(ID_CHALET_DEVICE,mDeviceAddress,CmdID,DataSize,&Data); + mTotalNbRequest++; + ComputeCommStats(); return RET_OK; } @@ -351,3 +374,20 @@ int CChaletLoraDevice::ScheduleChaletCommand(int CmdID, QByteArray Data) return RET_OK; } +int CChaletLoraDevice::ResetCommStats() +{ + mLostRequestPercentage = 0.0; + mTotalNbRequest = 0; + mNbLostRequest = 0; + + return RET_OK; +} + +int CChaletLoraDevice::ComputeCommStats() +{ + mLostRequestPercentage = ((float)mNbLostRequest/(float)mTotalNbRequest)*100; + mChaletMainStatus.mLostRequestPercentage = mLostRequestPercentage; + + // qDebug("Percent lost request: %f%%",mLostRequestPercentage); + return RET_OK; +} diff --git a/Sources/Chalet/ChaletLoraDevice.h b/Sources/Chalet/ChaletLoraDevice.h index 520a080..db9a023 100644 --- a/Sources/Chalet/ChaletLoraDevice.h +++ b/Sources/Chalet/ChaletLoraDevice.h @@ -11,6 +11,9 @@ #include #include "BlynkCloudClient.h" #include "ChaletDataLogger.h" +#include "ChaletUbidotsInterface.h" +#include "ThingsBoardInterface.h" + #define LORA_MAGIC_WORD 0xBAADCAFE #define LORA_NORMAL_REQUEST_TIMEOUT 3000 @@ -37,22 +40,34 @@ public: CChaletMainStatus GetChaletMainStatus() {return mChaletMainStatus;} CBlynkCloudClient mBlynkInterface; + CThingsBoardInterface mThingsBoardInterface; CChaletMainStatus mChaletMainStatus; QList mPendingNetworkMsgList; CChaletDataLogger mChaletDataLogger; + CChaletJFUbidotsInterface *mJFUbidotsInterface; + + unsigned long long int mNbLostRequest, mTotalNbRequest; + float mLostRequestPercentage; + + CChaletDataLogger *GetDataLoggerHandle() {return &mChaletDataLogger;} //for Interface use... + + int SendWiFiModuleSetState(bool State); int SendInverterPowerRelayState(bool State); int SendDOHarakiri(); int SendRebootCmd(); int SendChaletCommand(int CmdID,int DataSize, QByteArray Data); + int ResetCommStats(); + int ComputeCommStats(); int CmdResponseReceived(int CmdID); int ScheduleChaletStatusRequest(); int ScheduleChaletCommand(int CmdID, int DataSize, QByteArray Data); int ScheduleChaletCommand(int CmdID,QByteArray Data); + public slots: void CommTimerExpired(); diff --git a/Sources/Chalet/ChaletModbusServer.cpp b/Sources/Chalet/ChaletModbusServer.cpp new file mode 100644 index 0000000..02ae62d --- /dev/null +++ b/Sources/Chalet/ChaletModbusServer.cpp @@ -0,0 +1,7 @@ +#include "ChaletModbusServer.h" + +CChaletModbusServer::CChaletModbusServer(CModbusRepository *Repo, int ModbusPort, int DevID) : + CModbusBackend(Repo) +{ + +} diff --git a/Sources/Chalet/ChaletModbusServer.h b/Sources/Chalet/ChaletModbusServer.h new file mode 100644 index 0000000..56ac060 --- /dev/null +++ b/Sources/Chalet/ChaletModbusServer.h @@ -0,0 +1,25 @@ +#ifndef CHALETMODBUSSERVER_H +#define CHALETMODBUSSERVER_H + +#include +#include + +class CChaletModbusServer : public CModbusBackend +{ + Q_OBJECT + +public: + CChaletModbusServer(CModbusRepository *Repo, int ModbusPort, int DevID); + virtual ~CChaletModbusServer(); + + int StartChaletModbusServer(); + int CloseChaletModbusServer(); + bool IsModbusConnected(); + + + + virtual void RegistersDatabaseUpdated(quint16 StartAddress, quint16 Length); + virtual void ModbusRequestException(quint8 ExceptionCode, quint8 FctCode); +}; + +#endif // CHALETMODUBSERVER_H diff --git a/Sources/Chalet/ChaletUbidotsInterface.cpp b/Sources/Chalet/ChaletUbidotsInterface.cpp new file mode 100644 index 0000000..a726cec --- /dev/null +++ b/Sources/Chalet/ChaletUbidotsInterface.cpp @@ -0,0 +1,89 @@ +#include "ChaletUbidotsInterface.h" + +CChaletUbidotsInterface::CChaletUbidotsInterface(QString UbidotsUsername, QObject *parent) : QObject(parent) +{ + mUbidotsUsername = UbidotsUsername; +// mUbidotsPascalChaletClient = new QMqttClient(this); +// mUbidotsPascalChaletClient->setHostname("things.ubidots.com"); +// mUbidotsPascalChaletClient->setPort(1883); +// mUbidotsPascalChaletClient->setUsername("BBFF-tEq4lGAegEyP1H4EaYckNQ7ZHdZYzI"); +// mUbidotsPascalChaletClient->setPassword("12"); +// mUbidotsPascalChaletClient->connectToHost(); + + mUbidotsChaletClient= new QMqttClient(this); + mUbidotsChaletClient->setHostname(UBIDOTS_URL); + mUbidotsChaletClient->setPort(UBIDOTS_PORT); + mUbidotsChaletClient->setUsername(mUbidotsUsername);//"BBFF-tEq4lGAegEyP1H4EaYckNQ7ZHdZYzI"); + mUbidotsChaletClient->setPassword("12"); + + connect(mUbidotsChaletClient,SIGNAL(stateChanged(ClientState)),this,SLOT(UbidotsStateChanged(ClientState))); + + mUbidotsChaletClient->connectToHost(); +} + +CChaletUbidotsInterface::~CChaletUbidotsInterface() +{ + mUbidotsChaletClient->disconnectFromHost(); + + delete mUbidotsChaletClient; +} + +int CChaletUbidotsInterface::LogUbidotsChaletData(CChaletMainStatus *Data) +{ + Q_UNUSED(Data) + + + qDebug("LogUbidotsChaletData() should only be called from derived class..."); + + + return RET_OK; +} + +void CChaletUbidotsInterface::UbidotsStateChanged(QMqttClient::ClientState state) +{ + qDebug("MQTT client %s is now in state %d",qPrintable(mInterfaceOwnerName),state); + //MQTTStateChanged(state); +} + + + + + + +//////////////////////implementation +CChaletJFUbidotsInterface::CChaletJFUbidotsInterface(QString Username) : CChaletUbidotsInterface(Username) +{ + mInterfaceOwnerName = "J-F"; + //mUbidotsChaletClient->subscribe(QMqttTopicFilter("/v1.6/devices/ChaletDuino")) + + //connect(mInverterBtnSubscritption,SIGNAL(messageReceived(QMqttMessage)),this,SLOT(InverterBtnSubscriptionMsgReceived(QMqttMessage))); + + + qDebug("JF Ubidots interface created"); +} + +int CChaletJFUbidotsInterface::LogUbidotsChaletData(CChaletMainStatus *Data) +{ + QString MQTTMsg = QString("{\"BattVoltage\": %1}").arg(Data->mBatteryVoltage); + mUbidotsChaletClient->publish(QMqttTopicName("/v1.6/devices/ChaletDuino"),MQTTMsg.toUtf8()); + MQTTMsg.clear(); + MQTTMsg = QString("{\"InverterSwitch\": %1}").arg(Data->mWiFiModuleStatus !=0); + mUbidotsChaletClient->publish(QMqttTopicName("/v1.6/devices/ChaletDuino"),MQTTMsg.toUtf8(),0,true); + + return RET_OK; +} + +void CChaletJFUbidotsInterface::InverterBtnSubscriptionMsgReceived(QMqttMessage msg) +{ + qDebug("subscription msg. Topic name: %s",qPrintable(msg.topic().name())); +} + +void CChaletJFUbidotsInterface::WiFiBtnSubscriptionMsgReceived(QMqttMessage msg) +{ + +} + +void CChaletJFUbidotsInterface::MQTTStateChanged(QMqttClient::ClientState) +{ + +} diff --git a/Sources/Chalet/ChaletUbidotsInterface.h b/Sources/Chalet/ChaletUbidotsInterface.h new file mode 100644 index 0000000..b72b43d --- /dev/null +++ b/Sources/Chalet/ChaletUbidotsInterface.h @@ -0,0 +1,48 @@ +#ifndef CHALETUBIDOTSINTERFACE_H +#define CHALETUBIDOTSINTERFACE_H + +#include +#include +#include +#include "ChaletData.h" +#include + +#define UBIDOTS_URL "things.ubidots.com" +#define UBIDOTS_PORT 1883 + +class CChaletUbidotsInterface : public QObject +{ + Q_OBJECT +public: + explicit CChaletUbidotsInterface(QString UbidotsUsername, QObject *parent = 0); + ~CChaletUbidotsInterface(); + virtual int LogUbidotsChaletData(CChaletMainStatus *Data); + virtual void MQTTStateChanged(QMqttClient::ClientState)=0; + + QMqttClient *mUbidotsChaletClient; + QString mUbidotsUsername; + QString mInterfaceOwnerName; + + + +public slots: + void UbidotsStateChanged(QMqttClient::ClientState); +}; + +class CChaletJFUbidotsInterface: public CChaletUbidotsInterface +{ + Q_OBJECT +public: + explicit CChaletJFUbidotsInterface(QString Username); + virtual int LogUbidotsChaletData(CChaletMainStatus *Data); + void MQTTStateChanged(QMqttClient::ClientState); + + QMqttSubscription *mInverterBtnSubscritption, *mWiFiBtnSubscription; + +public slots: + void InverterBtnSubscriptionMsgReceived(QMqttMessage); + void WiFiBtnSubscriptionMsgReceived(QMqttMessage); + + +}; +#endif // CHALETUBIDOTSINTERFACE_H diff --git a/Sources/Chalet/ThingsBoardInterface.cpp b/Sources/Chalet/ThingsBoardInterface.cpp new file mode 100644 index 0000000..2a7789d --- /dev/null +++ b/Sources/Chalet/ThingsBoardInterface.cpp @@ -0,0 +1,285 @@ +#include "ThingsBoardInterface.h" +#include +#include +#include +#include "ChaletLoraDevice.h" + + +CThingsBoardInterface::CThingsBoardInterface() +{ + mThingsBoardSocket = new QNetworkAccessManager; + mThingsBoardRPCSocket = new QNetworkAccessManager; + + + connect(mThingsBoardSocket,SIGNAL(finished(QNetworkReply*)),this,SLOT(ThingsBoardServerFinished(QNetworkReply*))); + connect(mThingsBoardSocket,SIGNAL(sslErrors(QNetworkReply*,QList)),this,SLOT(sslErrors(QNetworkReply*,QList))); + + connect(mThingsBoardRPCSocket,SIGNAL(finished(QNetworkReply*)),this,SLOT(ThingsBoardRPCFinished(QNetworkReply*))); + connect(mThingsBoardRPCSocket,SIGNAL(sslErrors(QNetworkReply*,QList)),this,SLOT(sslErrors(QNetworkReply*,QList))); +} + +CThingsBoardInterface::~CThingsBoardInterface() +{ + mThingsBoardRPCReply->deleteLater(); + delete mThingsBoardRPCSocket; + delete mThingsBoardSocket; + +} + +int CThingsBoardInterface::RegisterThingsboardRPC() +{ + + QNetworkRequest Req; + Req.setUrl(QUrl("http://192.168.50.100:8085/api/v1/aQIocLkJM2ECSqVT2VRx/rpc")); + + mThingsBoardRPCReply = mThingsBoardRPCSocket->get(Req); + // connect(mThingsBoardRPCReply,SIGNAL(readyRead()),this,SLOT(RPCData())); + + + return 1; +} + +void CThingsBoardInterface::UpdateChaletVoltage(float Voltage) +{ + // "{\"temperature\": 25}" http://localhost:8080/api/v1/$ACCESS_TOKEN/telemetry --header "Content-Type:application/json" + //{"doubleKey":42.0} + + QByteArray JsonByteArray = "{\"Bat_Voltage\":"; + JsonByteArray.append((QString("%1}").arg(Voltage)).toUtf8().data()); + + QNetworkRequest Req; + Req.setHeader(QNetworkRequest::ContentTypeHeader,"application/json"); + Req.setUrl(QUrl("http://192.168.50.100:8085/api/v1/aQIocLkJM2ECSqVT2VRx/telemetry")); + + mThingsBoardSocket->post(Req,JsonByteArray); + +} + +void CThingsBoardInterface::UpdateChaletData(quint8 mInverterRelayStatus, quint8 mWiFiModuleStatus, qint8 mCurrentSensorStatus, float mBatteryVoltage, qint16 mBatteryCurrent, qint16 mBatterySOC, qint8 LoraState) +{ + //{"key1":"value1", "key2":"value2"} + + QByteArray JsonByteArray = "{\"Bat_Voltage\":"; + JsonByteArray.append((QString("%1, ").arg(mBatteryVoltage)).toUtf8().data()); + + JsonByteArray.append("\"Bat_SOC\":"); + JsonByteArray.append((QString("%1, ").arg(mBatterySOC)).toUtf8().data()); + + JsonByteArray.append("\"WiFi_State\":"); + JsonByteArray.append((QString("%1, ").arg(mWiFiModuleStatus)).toUtf8().data()); + + JsonByteArray.append("\"CurrentSensor_State\":"); + JsonByteArray.append((QString("%1, ").arg(mCurrentSensorStatus)).toUtf8().data()); + + JsonByteArray.append("\"Bat_Current\":"); + JsonByteArray.append((QString("%1, ").arg(mBatteryCurrent)).toUtf8().data()); + + JsonByteArray.append("\"LoRa_State\":"); + JsonByteArray.append((QString("%1, ").arg(LoraState)).toUtf8().data()); + + JsonByteArray.append("\"Inverter_State\":"); + JsonByteArray.append((QString("%1}").arg(mInverterRelayStatus)).toUtf8().data()); + + QNetworkRequest Req; + Req.setHeader(QNetworkRequest::ContentTypeHeader,"application/json"); + Req.setUrl(QUrl("http://192.168.50.100:8085/api/v1/aQIocLkJM2ECSqVT2VRx/telemetry")); + + mThingsBoardSocket->post(Req,JsonByteArray); + +// if(mThingsBoardRPCReply->isRunning() == true) +// { +// qDebug("RPC socket running..."); +// } +// else +// { +// qDebug("RPC socket not runnging"); +// } +} + +void CThingsBoardInterface::ThingsBoardServerFinished(QNetworkReply *NetworkReply) +{ + if(NetworkReply->isFinished() == false) + return; + + if(NetworkReply->error() != QNetworkReply::NoError) + { + qDebug("Network error... %d", NetworkReply->error()); + return; + } + + + QByteArray Reply = NetworkReply->readAll(); + if(Reply.isEmpty()) + return; + + NetworkReply->deleteLater(); + + QString ReplyString(Reply); + qDebug("ThingsBoard Server Reply: %s",ReplyString.toUtf8().data()); + ReplyString.remove("[\""); + ReplyString.remove("\"]"); + QJsonValue Result(ReplyString); +// QJsonParseError error; +// QJsonDocument JsonReply = QJsonDocument::fromJson(Reply,&error); +// QJsonObject JsonObject = JsonReply.object(); +// QStringList Keys = JsonObject.keys(); + + // int toto = ReplyString.toInt(); + // qDebug("Switch = %d",toto); +} + +void CThingsBoardInterface::sslErrors(QNetworkReply *ServerReply, QList ErrorList) +{ + + qDebug("Ssl errors..."); + ServerReply->ignoreSslErrors(); +} + + +void CThingsBoardInterface::ThingsBoardRPCFinished(QNetworkReply *NetworkReply) +{ + if(mThingsBoardRPCReply->error() != QNetworkReply::NoError) + { + qDebug("Network error (ThingsBoardRPC)... %d", mThingsBoardRPCReply->error()); + RegisterThingsboardRPC(); + return; + } + + + QByteArray Reply = mThingsBoardRPCReply->readAll(); + if(Reply.isEmpty()) + { + qDebug("Received an empty RPC reply in ThiungsBoard..."); + RegisterThingsboardRPC(); + return; + } + + mThingsBoardRPCReply->deleteLater(); + + QString ReplyString(Reply); + qDebug("ThingsBoard RPC Reply: %s",ReplyString.toUtf8().data()); + QJsonDocument JSonReply = QJsonDocument::fromJson(Reply); + + QJsonObject RPCCmd = JSonReply.object(); + + QJsonValue RequestedCmd = RPCCmd.value("method"); + { + if(RequestedCmd.toString().contains("setChaletInverterState")) + { + //Fetch the required state. + bool RequestedState = RPCCmd.value("params").toBool(); + if(RequestedState == true) + { + qDebug("Server Inverter TURN ON request received."); + mChaletLoraDevice->SendInverterPowerRelayState(true); + } + if(RequestedState == false) + { + qDebug("Server Inverter TURN OFF request received."); + mChaletLoraDevice->SendInverterPowerRelayState(false); + } + + + } + else if(RequestedCmd.toString().contains("setWiFiState")) + { + //Fetch the required state. + QString RequestedState = RPCCmd.value("params").toString(); + if(RequestedState == "true") + { + qDebug("Server WiFi TURN ON request received."); + } + if(RequestedState == "false") + { + qDebug("Server WiFi TURN OFF request received."); + } + } + else + { + qDebug("Received an unknown RPC call from ThingsBoard server"); + } + } + + //Re-register for next request.. + RegisterThingsboardRPC(); +} + +void CThingsBoardInterface::RPCsslErrors(QNetworkReply *ServerReply, QList ErrorList) +{ + + qDebug("Ssl errors..."); + ServerReply->ignoreSslErrors(); +} + +void CThingsBoardInterface::RPCData() +{ +// if(mThingsBoardRPCReply->isFinished() == false) +// return; + +// if(mThingsBoardRPCReply->error() != QNetworkReply::NoError) +// { +// qDebug("Network error (RPCData)... %d", mThingsBoardRPCReply->error()); +// RegisterThingsboardRPC(); +// return; +// } + + +// QByteArray Reply = mThingsBoardRPCReply->readAll(); +// if(Reply.isEmpty()) +// { +// qDebug("Received an empty RPC reply in ThiungsBoard..."); +// RegisterThingsboardRPC(); +// return; +// } + +// mThingsBoardRPCReply->deleteLater(); + +// QString ReplyString(Reply); +// qDebug("ThingsBoard RPC Reply: %s",ReplyString.toUtf8().data()); +// QJsonDocument JSonReply = QJsonDocument::fromJson(Reply); + +// QJsonObject RPCCmd = JSonReply.object(); + +// QJsonValue RequestedCmd = RPCCmd.value("method"); +// { +// if(RequestedCmd.toString().contains("setChaletInverterState")) +// { +// //Fetch the required state. +// bool RequestedState = RPCCmd.value("params").toBool(); +// if(RequestedState == true) +// { +// qDebug("Server Inverter TURN ON request received."); +// //mChaletLoraDevice->SendInverterPowerRelayState(true); +// } +// if(RequestedState == false) +// { +// qDebug("Server Inverter TURN OFF request received."); +// // mChaletLoraDevice->SendInverterPowerRelayState(false); +// } + + +// } +// else if(RequestedCmd.toString().contains("setWiFiState")) +// { +// //Fetch the required state. +// QString RequestedState = RPCCmd.value("params").toString(); +// if(RequestedState == "true") +// { +// qDebug("Server WiFi TURN ON request received."); +// } +// if(RequestedState == "false") +// { +// qDebug("Server WiFi TURN OFF request received."); +// } +// } +// else +// { +// qDebug("Received an unknown RPC call from ThingsBoard server"); +// } +// } + +// //Re-register for next request.. +// RegisterThingsboardRPC(); + + +} diff --git a/Sources/Chalet/ThingsBoardInterface.h b/Sources/Chalet/ThingsBoardInterface.h new file mode 100644 index 0000000..67f94a7 --- /dev/null +++ b/Sources/Chalet/ThingsBoardInterface.h @@ -0,0 +1,36 @@ +#ifndef THINGSBOARDINTERFACE_H +#define THINGSBOARDINTERFACE_H + +class CChaletLoraDevice; + +#include +#include + +class CThingsBoardInterface : public QObject +{ + Q_OBJECT +public: + CThingsBoardInterface(); + ~CThingsBoardInterface(); + + CChaletLoraDevice *mChaletLoraDevice; + + int RegisterThingsboardRPC(); + void UpdateChaletVoltage(float Voltage); + void UpdateChaletData(quint8 mInverterRelayStatus, quint8 mWiFiModuleStatus, qint8 mCurrentSensorStatus, float mBatteryVoltage, qint16 mBatteryCurrent, qint16 mBatterySOC, qint8 LoraState); + +private: + QNetworkAccessManager *mThingsBoardSocket, *mThingsBoardRPCSocket; + QNetworkReply *mThingsBoardRPCReply; + +public slots: + void ThingsBoardServerFinished(QNetworkReply*); + void sslErrors(QNetworkReply*,QList); + + void ThingsBoardRPCFinished(QNetworkReply*); + void RPCsslErrors(QNetworkReply*,QList); + + void RPCData(); +}; + +#endif // THINGSBOARDINTERFACE_H diff --git a/Sources/EthernetNetworkCommIF.cpp b/Sources/EthernetNetworkCommIF.cpp index f3bcd42..1e07e34 100644 --- a/Sources/EthernetNetworkCommIF.cpp +++ b/Sources/EthernetNetworkCommIF.cpp @@ -17,7 +17,7 @@ CEthernetNetworkCommIF::~CEthernetNetworkCommIF() } -int CEthernetNetworkCommIF::SendNetworkMessage(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray Data) +int CEthernetNetworkCommIF::SendNetworkMessage(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray *Data) { // Q_UNUSED(DeviceID) // Q_UNUSED(DeviceAddress) @@ -25,7 +25,15 @@ int CEthernetNetworkCommIF::SendNetworkMessage(int DeviceID, int DeviceAddress, // Q_UNUSED(DataSize) // Q_UNUSED(Data) - QByteArray Packet = GetTxPacket(MessageID,0,Data.data(),DataSize,DeviceAddress,DeviceID); + QByteArray Packet; + if(Data != 0) + { + Packet = GetTxPacket(MessageID,0,Data->data(),DataSize,DeviceAddress,DeviceID); + } + else + { + Packet = GetTxPacket(MessageID,0,0,0,DeviceAddress,DeviceID); + } mTCPSocket->write(Packet); return RET_OK; diff --git a/Sources/EthernetNetworkCommIF.h b/Sources/EthernetNetworkCommIF.h index dbd9b1c..63e91da 100644 --- a/Sources/EthernetNetworkCommIF.h +++ b/Sources/EthernetNetworkCommIF.h @@ -21,7 +21,7 @@ public: QTcpSocket* mTCPSocket; //CNetworkCommIF implementation - virtual int SendNetworkMessage(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray Data); + virtual int SendNetworkMessage(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray *Data); //CNetworkProtocol implementation virtual int NewFrameReceived(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray Data); diff --git a/Sources/HttpServer/HttpServer.cpp b/Sources/HttpServer/HttpServer.cpp index 4f5ea6f..acf2bc8 100644 --- a/Sources/HttpServer/HttpServer.cpp +++ b/Sources/HttpServer/HttpServer.cpp @@ -1,5 +1,25 @@ #include "HttpServer.h" + CHttpServer::CHttpServer() { + mHttpServer = new QHttpServer; + mHttpServer->route("/", []() + { + qDebug("Test"); + + return "Ja Mon CB!!!!"; + }); + + + const auto port = mHttpServer->listen(QHostAddress::Any,8080); + + qDebug("Server Opened"); + + +} + +CHttpServer::~CHttpServer() +{ + delete mHttpServer; } diff --git a/Sources/HttpServer/HttpServer.h b/Sources/HttpServer/HttpServer.h index 7e7448b..309dacc 100644 --- a/Sources/HttpServer/HttpServer.h +++ b/Sources/HttpServer/HttpServer.h @@ -1,11 +1,16 @@ #ifndef HTTPSERVER_H #define HTTPSERVER_H +#include class CHttpServer { public: + + QHttpServer *mHttpServer; + CHttpServer(); + ~CHttpServer(); }; -#endif // HTTPSERVER_H \ No newline at end of file +#endif // HTTPSERVER_H diff --git a/Sources/LoraNetworkCommIF.cpp b/Sources/LoraNetworkCommIF.cpp index 9d1cfe6..f6e6f5d 100644 --- a/Sources/LoraNetworkCommIF.cpp +++ b/Sources/LoraNetworkCommIF.cpp @@ -104,9 +104,9 @@ int CLoraNetworkCommIF::NewFrameReceived(int DeviceID, int DeviceAddress, int Me return RET_OK; } -int CLoraNetworkCommIF::SendNetworkMessage(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray Data) +int CLoraNetworkCommIF::SendNetworkMessage(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray *Data) { - QByteArray Packet = GetTxPacket(MessageID,0,Data.data(),DataSize,DeviceAddress,DeviceID); + QByteArray Packet = GetTxPacket(MessageID,0,Data->data(),DataSize,DeviceAddress,DeviceID); SendLoraFrame(6,4,Packet); // SendLoraFrame(4,4,Packet); return RET_OK; diff --git a/Sources/LoraNetworkCommIF.h b/Sources/LoraNetworkCommIF.h index 4f0b25c..f4a688f 100644 --- a/Sources/LoraNetworkCommIF.h +++ b/Sources/LoraNetworkCommIF.h @@ -31,7 +31,7 @@ public: int NewFrameReceived(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray Data); //NetworkCommIF implementation - virtual int SendNetworkMessage(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray Data); + virtual int SendNetworkMessage(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray *Data); private: QByteArray GetLoraFrame(unsigned short DestAddress,unsigned char DestChannel,QByteArray Payload); diff --git a/Sources/MasterCtrl.cpp b/Sources/MasterCtrl.cpp index 64e1394..c7a319c 100644 --- a/Sources/MasterCtrl.cpp +++ b/Sources/MasterCtrl.cpp @@ -92,6 +92,7 @@ void CMasterCtrl::Start() mAVReceiverDevice->Start(); mChaletLoraNetworkCommInterface->SetLoraSerialPortSettings("COM3",QSerialPort::Baud9600); +// mChaletLoraNetworkCommInterface->SetLoraSerialPortSettings("COM5",QSerialPort::Baud9600); mChaletLoraDevice->Start(); diff --git a/Sources/Modbus/ModbusBackend.cpp b/Sources/Modbus/ModbusBackend.cpp new file mode 100644 index 0000000..ae4a92f --- /dev/null +++ b/Sources/Modbus/ModbusBackend.cpp @@ -0,0 +1,756 @@ +/******************************************************************************* +* * +* Société de Transports de Montréal. * +* 2012 - 2013 * +* * +* Projet Zones Tests * +* * +* * +* * +*******************************************************************************/ +/* + Description: + Classe qui implémente le protocole Modbus. + +*/ + +/* ************************************************************************** */ +/* Revision: +### YYYMMDD JFM + Verision d'origine. + +### YYYYMMDD Description du besoin ou du bug + Description du changement. + */ + +/* ************************************************************************** */ + + +#include "ModbusBackend.h" +#include "QBuffer" +#include +//#include "EngLog.h" +//#include "ZTLog.h" + +CModbusBackend::CModbusBackend(CModbusRepository *Repo) +{ + mModbusTCPSocketHandle = 0; + mDataLinkValid = false; + mModbusRepo = Repo; + mModbusMode = MODBUS_INVALID_MODE; + mTransactionIDCounter = 0; + mDeviceID = 9;//0xFF; + + mModbusMaxRetry = MODBUS_RETRY_MAX_COUNT; + mModbusRequestTimeout = MODBUS_RETRY_DELAY; +} + +CModbusBackend::~CModbusBackend() +{ + for(int i= 0; i < mRequestsList.size(); i++) + { + delete mRequestsList[i]; + } + mRequestsList.clear(); +} + +void CModbusBackend::ModbusDataReady() +{ + + CModbusTransaction Transaction; + QByteArray InData = mModbusTCPSocketHandle->readAll(); + + QBuffer FileBuffer(&InData); + FileBuffer.open(QIODevice::ReadOnly); + FileBuffer.seek(0); + QDataStream *TransactionDataStrm = new QDataStream(&FileBuffer); + *TransactionDataStrm >> Transaction.mHeader; + *TransactionDataStrm >> Transaction.mPDU.mFunctionCode; + Transaction.mPDU.mData = InData.right(Transaction.mHeader.mMessageLength - 2); //-2 to remove Device ID and Function Code. + // + +// qDebug("---------------------------------------"); +// qDebug("modbus data received %s",InData.toHex().data()); +// qDebug("Transaction ID 0x%X",Transaction.mHeader.mTransactionID); +// qDebug("Message Length %d",Transaction.mHeader.mMessageLength); +// qDebug("Protocol ID 0x%X",Transaction.mHeader.mProtocolID); +// qDebug("Unit ID 0x%X",Transaction.mHeader.mUnitID); +// qDebug("Function Code 0x%X",Transaction.mPDU.mFunctionCode); +// qDebug("Data %s",Transaction.mPDU.mData.toHex().data()); +// qDebug("---------------------------------------"); + + if(mModbusMode == MODBUS_MASTER_MODE) + { + AnalyzeModbusResponse(Transaction); //Le maître recoit des réponses + } + else if( mModbusMode == MODBUS_SLAVE_MODE) + { + AnalyzeModbusRequest(Transaction); //L'esclave recoit des requêtes + } + else + { + // CEngLog::instance()->AddLogString("Erreur Modbus: "); //Erreur de logique interne. Ne doit pas survenir normalement + } + + delete TransactionDataStrm; +} + +void CModbusBackend::ModbusLinkDisconnected() +{ +// qDebug("Modbus link disconnected"); + mDataLinkValid = false; + mModbusTCPSocketHandle->flush(); +} + + +//In client mode. This is the request from the master. +int CModbusBackend::AnalyzeModbusRequest(CModbusTransaction Transaction) +{ + if(Transaction.mHeader.mProtocolID != 0) + { + //Invalid protocol... what can we do? + return 0; + } + + switch(Transaction.mPDU.mFunctionCode) + { + case MODBUS_FCT_READ_HOLDING_REGISTERS: + { + bool ok = true; + unsigned short StartAdress = 0; + StartAdress = Transaction.mPDU.mData[0]&0xFF; + StartAdress <<= 8; + StartAdress += Transaction.mPDU.mData[1]&0xFF; + unsigned short NbRegisters = 0; + NbRegisters = Transaction.mPDU.mData[2]&0xFF; + NbRegisters <<= 8; + NbRegisters += Transaction.mPDU.mData[3]&0xFF; + + //Validate nb of registers + if(NbRegisters < 1 || NbRegisters > MODBUS_MAX_NB_REGISTERS) + { + SendErrorResponse(Transaction,MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE); + ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,MODBUS_FCT_READ_HOLDING_REGISTERS); //Fonction à être implémentée par le parent + return 0; + } + + //Validate data range + if(!mModbusRepo->IsHRValid(StartAdress,NbRegisters)) + { + qDebug("Reg invalid"); + //Send negative response + SendErrorResponse(Transaction,MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS); + ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,MODBUS_FCT_READ_HOLDING_REGISTERS); + return 0; + } + + QByteArray data = mModbusRepo->GetHRData(StartAdress,NbRegisters,&ok); + + // qDebug("Slave Rx Read Holding Registers. Address: %d, Nb Reg: %d",StartAdress, NbRegisters); + // qDebug("Data: %s",data.toHex().data()); + + //The response to a HR reading needs the byte count before the data. + quint8 ByteCount = data.size(); + data.prepend(ByteCount); + SendModbusResponse(Transaction, data); + + //All OK + + break; + } + case MODBUS_WRITE_SINGLE_REGISTER: + { + unsigned short StartAdress = 0; + + StartAdress = Transaction.mPDU.mData[0]&0xFF; + StartAdress <<= 8; + StartAdress += Transaction.mPDU.mData[1]&0xFF; + + //Validate data range + if(!mModbusRepo->IsHRValid(StartAdress,1)) + { + qDebug("Reg invalid"); + //Send negative response + SendErrorResponse(Transaction,MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS); + ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,MODBUS_WRITE_SINGLE_REGISTER); + return 0; + } + + //Extract data. + QByteArray data = Transaction.mPDU.mData.right(2); + + //Write register data + mModbusRepo->WriteHRData(StartAdress,1,data); +// if(StartAdress == 2000) +// { +// qDebug("debug... 2000"); +// } + +// qDebug("Slave Rx Write Single Register. Address: %d, Value: 0x%s",StartAdress, data.toHex().data()); +// qDebug("Data: %s",data.toHex().data()); + + data = Transaction.mPDU.mData.left(4); //The response corresponds to the Reg. Address & the value. Which is the first 4 bytes of the initial request. + SendModbusResponse(Transaction, data); + RegistersDatabaseUpdated(StartAdress,1); + + break; + } + case MODBUS_FCT_WRITE_MULTIPLE_REGISTERS: + { + unsigned short StartAdress = 0; + StartAdress = Transaction.mPDU.mData[0]&0xFF; + StartAdress <<= 8; + StartAdress += Transaction.mPDU.mData[1]&0xFF; + + unsigned short NbRegisters = 0; + NbRegisters = Transaction.mPDU.mData[2]&0xFF; + NbRegisters <<= 8; + NbRegisters += Transaction.mPDU.mData[3]&0xFF; + + quint8 ByteCount = Transaction.mPDU.mData[4]; + + //Validate nb of registers + if(NbRegisters < 1 || NbRegisters > 0x7D || ByteCount != (NbRegisters*2)) + { + qDebug("Invalid register number or byte count "); + SendErrorResponse(Transaction,MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE); + ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,MODBUS_FCT_WRITE_MULTIPLE_REGISTERS); + return 0; + } + + //Validate data range + if(!mModbusRepo->IsHRValid(StartAdress,NbRegisters)) + { + qDebug("Reg invalid"); + //Send negative response + SendErrorResponse(Transaction,MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS); + ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,MODBUS_FCT_WRITE_MULTIPLE_REGISTERS); + return 0; + } + + //Extract data. + QByteArray data = Transaction.mPDU.mData.right(ByteCount); + + //Write register data + mModbusRepo->WriteHRData(StartAdress,NbRegisters,data); + + // qDebug("\nSlave Rx Write Multiple Registers. Address: %d, Nb Reg: %d",StartAdress, NbRegisters); + // qDebug("Data: %s\n",data.toHex().data()); + + data = Transaction.mPDU.mData.left(4); //The response corresponds to the Start Adress and Nb of Regs. Which is the first 4 bytes of the initial request. + SendModbusResponse(Transaction, data); + + RegistersDatabaseUpdated(StartAdress,NbRegisters); + + break; + } + default: + { + //Received "Illegal function code". Send the exception code to master + //TODO: Log this. + qDebug("Slave received illegal function code from master: 0x%x",Transaction.mPDU.mFunctionCode); + SendErrorResponse(Transaction,MODBUS_EXCEPTION_ILLEGAL_FCT); + ModbusRequestException(MODBUS_EXCEPTION_ILLEGAL_FCT,Transaction.mPDU.mFunctionCode); + break; + } + } + + + return 1; +} + +int CModbusBackend::SendModbusResponse(CModbusTransaction RequestTransaction, QByteArray Data) +{ + QByteArray ModbusPacket; + + QBuffer Buffer(&ModbusPacket); + Buffer.open(QIODevice::WriteOnly|QIODevice::Unbuffered); + Buffer.seek(0); + QDataStream *PacketDataStrm = new QDataStream(&Buffer); + + //For a response, the header will be the same as the original request, except for the msg. length. + //Set the appropriate msg length. + RequestTransaction.mHeader.mMessageLength = Data.size() + 2; //+2 to add function code & Unit ID. + RequestTransaction.mPDU.mData = Data; + + *PacketDataStrm << RequestTransaction.mHeader; + *PacketDataStrm << RequestTransaction.mPDU.mFunctionCode; + Buffer.close(); + ModbusPacket.append(Data); + + + // qDebug("Response packet: %s",ModbusPacket.toHex().data()); + + mModbusTCPSocketHandle->write(ModbusPacket); + + delete PacketDataStrm; + + return RET_OK; +} + +//In Master mode. This is the response from slave to a previously sent request. +int CModbusBackend::AnalyzeModbusResponse(CModbusTransaction Transaction) +{ + if(Transaction.mHeader.mProtocolID != 0) + { + //Invalid protocol... what can we do? + return RET_ERROR; + } + + //Find matching request and remove it from the queue... + CModbusRequest *Request; + bool Found = false; + for(int i = 0; i < mRequestsList.size(); i++) + { + if(mRequestsList.at(i)->mHeader.mTransactionID == Transaction.mHeader.mTransactionID) + { + Request = mRequestsList.takeAt(i); //Remove from queue and keep a copy + Request->mRequestTimer->stop(); //Stop the resend timer + Found = true; + } + } + + if(Found == false) + { + //Invalid request number. This should happen only if a very long delay exists in the comm. + //TODO: Log this... + qDebug("Master received response to a non existent request!!!"); + return RET_ERROR; + } + + //check if we have an exception response + if((Transaction.mPDU.mFunctionCode & MODBUS_EXCEPTION_FCT_MASK) != 0) + { + //we have an exception response... something went wrong. + quint8 ExceptionCode = Transaction.mPDU.mData[0]; + + //TODO: Manage this! + qDebug("Master Rx exception code %d to request %d",ExceptionCode,Request->mPDU.mFunctionCode); + emit ModbusResponseException(ExceptionCode,Request->mPDU.mFunctionCode); + delete Request; + return RET_ERROR; + } + + switch(Transaction.mPDU.mFunctionCode) + { + case MODBUS_FCT_READ_HOLDING_REGISTERS: + { + quint8 ByteCount = 0; + ByteCount = Transaction.mPDU.mData.at(0); + + if((Request->mNbRegisters*2) != ByteCount) + { + //Inconsistency between the data range and the data count. + //TODO: Log the error. + qDebug("Master eceived a wrong data size in response for a MODBUS_FCT_READ_HOLDING_REGISTERS request"); + emit ModbusResponseException(MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,MODBUS_FCT_READ_HOLDING_REGISTERS); + delete Request; + return RET_ERROR; + } + + QByteArray RegisterValues = Transaction.mPDU.mData.right(ByteCount); + + +// qDebug("Master Rx Read Holding Registers Response."); +// qDebug("Data: %s",RegisterValues.toHex().data()); + + mModbusRepo->WriteHRData(Request->mStartAddress,Request->mNbRegisters,RegisterValues); + RegistersDatabaseUpdated(Request->mStartAddress, Request->mNbRegisters); + + break; + } + case MODBUS_WRITE_SINGLE_REGISTER: + { + quint16 RegAddress = 0; + RegAddress = Transaction.mPDU.mData[0]&0xFF; + RegAddress <<= 8; + RegAddress += Transaction.mPDU.mData[1]&0xFF; + + if(Request->mStartAddress != RegAddress) + { + //Inconsistency between the request Adress and response Adress. + //TODO: Log the error. + qDebug("Master received a wrong Register Adress in response for a MODBUS_WRITE_SINGLE_REGISTER request"); + emit ModbusResponseException(MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,MODBUS_WRITE_SINGLE_REGISTER); + delete Request; + return RET_ERROR; + } +// qDebug("Master Rx Write Single Register response. Address: %d,",RegAddress); +// qDebug("Data: %s",Transaction.mPDU.mData.toHex().data()); + + ModbusWriteSingleRegsSuccess(); + + //Everything seems good. + + break; + } + case MODBUS_FCT_WRITE_MULTIPLE_REGISTERS: + { + unsigned short StartAdress = 0; + StartAdress = Transaction.mPDU.mData[0]&0xFF; + StartAdress <<= 8; + StartAdress += Transaction.mPDU.mData[1]&0xFF; + + unsigned short NbRegisters = 0; + NbRegisters = Transaction.mPDU.mData[2]&0xFF; + NbRegisters <<= 8; + NbRegisters += Transaction.mPDU.mData[3]&0xFF; + + if(StartAdress != Request->mStartAddress || NbRegisters != Request->mNbRegisters) + { + //Inconsistency between the request Adress or NbRegisters and response. + //TODO: Log the error. + qDebug("Master Received a wrong Register Adress or NbRegisters in response for a MODBUS_FCT_WRITE_MULTIPLE_REGISTERS request"); + emit ModbusResponseException(MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,MODBUS_FCT_WRITE_MULTIPLE_REGISTERS); + delete Request; + return RET_ERROR; + } + +// qDebug("Master Rx Write Multiple Registers response. Address: %d, Nb Reg: %d",StartAdress, NbRegisters); +// qDebug("Data: %s",Transaction.mPDU.mData.toHex().data()); + ModbusWriteMultipleRegsSuccess(); + + //All is good. + + break; + } + default: + { + //Received "Illegal function code" response + //TODO: Log this. + //CEngLog::instance()->AddLogString(QString().sprintf("Modbus Maître, réception d'un code de fonction illégal: 0x%x",Transaction.mPDU.mFunctionCode)); +// qDebug("Master received illegal function code 0x%x",Transaction.mPDU.mFunctionCode); + emit ModbusResponseException(MODBUS_EXCEPTION_ILLEGAL_FCT,MODBUS_FCT_WRITE_MULTIPLE_REGISTERS); + break; + } + } + + + delete Request; + return 1; +} + +int CModbusBackend::SendModbusRequest(CModbusRequest *Request) +{ + QByteArray ModbusPacket; + + QBuffer Buffer(&ModbusPacket); + Buffer.open(QIODevice::WriteOnly|QIODevice::Unbuffered); + Buffer.seek(0); + QDataStream *PacketDataStrm = new QDataStream(&Buffer); + + *PacketDataStrm << Request->mHeader; + *PacketDataStrm << Request->mPDU.mFunctionCode; + Buffer.close(); + ModbusPacket.append(Request->mPDU.mData); + + +// qDebug("Request packet: %s",ModbusPacket.toHex().data()); + + mModbusTCPSocketHandle->write(ModbusPacket); + delete PacketDataStrm; + return RET_OK; +} + +int CModbusBackend::SendErrorResponse(CModbusTransaction RequestTransaction, quint8 ErrorCode) +{ + QByteArray ModbusPacket; + + QBuffer Buffer(&ModbusPacket); + Buffer.open(QIODevice::WriteOnly|QIODevice::Unbuffered); + Buffer.seek(0); + QDataStream *PacketDataStrm = new QDataStream(&Buffer); + + //For a response, the header will be the same as the original request, except for the msg. length. + //Set the appropriate msg length. + RequestTransaction.mHeader.mMessageLength = 3; //Unit ID, function code & Exception code. + + *PacketDataStrm << RequestTransaction.mHeader; + Buffer.close(); + ModbusPacket.append(RequestTransaction.mPDU.mFunctionCode + 0x80); + ModbusPacket.append(ErrorCode); + + + + //CEngLog::instance()->AddLogString(QString("Modbus: Envoi d'un code d'un code d'erreur. Error Code %1, Error Packet: %2").arg(ErrorCode).arg(ModbusPacket.toHex().data())); + // qDebug("Sending error code %d. Error packet: %s",ErrorCode,ModbusPacket.toHex().data()); + + mModbusTCPSocketHandle->write(ModbusPacket); + + delete PacketDataStrm; + + return RET_OK; +} + + +int CModbusBackend::SendReadHoldingRegistersRequest(quint16 StartAddress, quint16 RegisterCount) +{ + //First, validate that the reading range is within our repo + if(mModbusRepo->IsHRValid(StartAddress,RegisterCount) == false) + { + //CEngLog::instance()->AddLogString("ModbusBackend: Tentative de lecture d'un registre hors de portée."); + return RET_ERROR; + } + + //Create a request. + CModbusRequest *NewRequest = new CModbusRequest; + NewRequest->mStartAddress = StartAddress; + NewRequest->mNbRegisters = RegisterCount; + connect(NewRequest->mRequestTimer,SIGNAL(timeout()),this,SLOT(RequestTimerExpired())); + + NewRequest->mPDU.mData.clear(); + NewRequest->mPDU.mFunctionCode = MODBUS_FCT_READ_HOLDING_REGISTERS; + + quint8 HighByte, LowByte; + LowByte = StartAddress & 0x00FF; + HighByte = (StartAddress >> 8) & 0x00FF; + NewRequest->mPDU.mData.append(HighByte); + NewRequest->mPDU.mData.append(LowByte); + + LowByte = RegisterCount & 0x00FF; + HighByte = (RegisterCount >> 8) & 0x00FF; + NewRequest->mPDU.mData.append(HighByte); + NewRequest->mPDU.mData.append(LowByte); + + NewRequest->mHeader.mMessageLength = NewRequest->mPDU.mData.size() + 2; + NewRequest->mHeader.mProtocolID = 0; + NewRequest->mHeader.mTransactionID = (qint16)GetNewTransactionID(); + NewRequest->mHeader.mUnitID = mDeviceID; + + mRequestsList.append(NewRequest); + + SendModbusRequest(NewRequest); + + NewRequest->mRequestTimer->start(mModbusRequestTimeout); + + + return RET_OK; + +} + +int CModbusBackend::SendWriteHoldingRegistersRequest(quint16 StartAddress, quint16 RegisterCount) +{ + //First, validate that the reading range is within our repo + if(mModbusRepo->IsHRValid(StartAddress,RegisterCount) == false) + { + //CEngLog::instance()->AddLogString("Trying to send a Write HR in an invalid range SendWriteHoldingRegistersRequest()"); + return RET_ERROR; + } + + if(RegisterCount > MODBUS_MAX_NB_REGISTERS) + { + return RET_ERROR; + } + + //Get data. + bool OK; + QByteArray RegData = mModbusRepo->GetHRData(StartAddress,RegisterCount,&OK); + if(OK == false) + { + return RET_ERROR; + } + + //Create a request. + CModbusRequest *NewRequest = new CModbusRequest; + NewRequest->mStartAddress = StartAddress; + NewRequest->mNbRegisters = RegisterCount; + connect(NewRequest->mRequestTimer,SIGNAL(timeout()),this,SLOT(RequestTimerExpired())); + + NewRequest->mPDU.mData.clear(); + NewRequest->mPDU.mFunctionCode = MODBUS_FCT_WRITE_MULTIPLE_REGISTERS; + + //Start address + quint8 HighByte, LowByte; + LowByte = StartAddress & 0x00FF; + HighByte = (StartAddress >> 8) & 0x00FF; + NewRequest->mPDU.mData.append(HighByte); + NewRequest->mPDU.mData.append(LowByte); + + //Nb Registers + LowByte = RegisterCount & 0x00FF; + HighByte = (RegisterCount >> 8) & 0x00FF; + NewRequest->mPDU.mData.append(HighByte); + NewRequest->mPDU.mData.append(LowByte); + + //Byte Count + NewRequest->mPDU.mData.append(RegData.size()); + + NewRequest->mPDU.mData.append(RegData); + + NewRequest->mHeader.mMessageLength = NewRequest->mPDU.mData.size() + 2; + NewRequest->mHeader.mProtocolID = 0; + NewRequest->mHeader.mTransactionID = (qint16)GetNewTransactionID(); + NewRequest->mHeader.mUnitID = mDeviceID; + + mRequestsList.append(NewRequest); + + SendModbusRequest(NewRequest); + + NewRequest->mRequestTimer->start(mModbusRequestTimeout); + + + return RET_OK; +} + +int CModbusBackend::SendWriteSingleRegisterRequest(quint16 Address) +{ + //First, validate that the reading range is within our repo + if(mModbusRepo->IsHRValid(Address,1) == false) + { + //CEngLog::instance()->AddLogString("Trying to send a Write HR in an invalid range SendWriteSingleRegisterRequest()"); + return RET_ERROR; + } + + //Get data. + bool OK; + QByteArray RegData = mModbusRepo->GetHRData(Address,1,&OK); + if(OK == false) + { + return RET_ERROR; + } + + //Create a request. + CModbusRequest *NewRequest = new CModbusRequest; + NewRequest->mStartAddress = Address; + NewRequest->mNbRegisters = 1; + connect(NewRequest->mRequestTimer,SIGNAL(timeout()),this,SLOT(RequestTimerExpired())); + + NewRequest->mPDU.mData.clear(); + NewRequest->mPDU.mFunctionCode = MODBUS_WRITE_SINGLE_REGISTER; + + quint8 HighByte, LowByte; + LowByte = Address & 0x00FF; + HighByte = (Address >> 8) & 0x00FF; + NewRequest->mPDU.mData.append(HighByte); + NewRequest->mPDU.mData.append(LowByte); + + NewRequest->mPDU.mData.append(RegData); + + NewRequest->mHeader.mMessageLength = NewRequest->mPDU.mData.size() + 2; + NewRequest->mHeader.mProtocolID = 0; + NewRequest->mHeader.mTransactionID = (qint16)GetNewTransactionID(); + NewRequest->mHeader.mUnitID = mDeviceID; + + mRequestsList.append(NewRequest); + + SendModbusRequest(NewRequest); + + NewRequest->mRequestTimer->start(mModbusRequestTimeout); + + + return RET_OK; +} + +void CModbusBackend::RequestTimerExpired() +{ + //find the expired request + for(int i = 0; i < mRequestsList.size(); i++) + { + if(mRequestsList.at(i)->mRequestTimer->isActive() == false) + { + if(mRequestsList.at(i)->mRetries >= mModbusMaxRetry) + { + //The max number of retry has been reached. The device is probably offline. + + // CZTLog::instance()->AddLogString("Modbus Maître: Nombre maximal de tentatives sans réponse atteint avec le partenaire",true); + + + delete mRequestsList[i]; + mRequestsList.removeAt(i); + ModbusRequestMaxRetryReached(); + + //TODO: Manage this situation (log?) + + return; + } + else + { + SendModbusRequest(mRequestsList[i]); + mRequestsList.at(i)->mRequestTimer->start(mModbusRequestTimeout); + mRequestsList[i]->mRetries++; + } + } + } +} + +quint16 CModbusBackend::GetNewTransactionID() +{ + quint16 ID = mTransactionIDCounter++; + + if(mTransactionIDCounter == 0xFFFF - 10) + { + mTransactionIDCounter = 0; + } + + return ID; +} + + + +CModbusRequest::CModbusRequest(): + mRetries(0) +{ + mRequestTimer = new QTimer; + mRequestTimer->setSingleShot(true); +} +CModbusRequest::~CModbusRequest() +{ + delete mRequestTimer; +} + + + + + +QDataStream &operator<<(QDataStream &out, const CModbusHeader &source) +{ + out << source.mTransactionID + << source.mProtocolID + << source.mMessageLength + << source.mUnitID + ; + + return out; +} + +QDataStream &operator>>(QDataStream &in, CModbusHeader &dest) +{ + in >> dest.mTransactionID + >> dest.mProtocolID + >> dest.mMessageLength + >> dest.mUnitID + ; + + return in; +} + +//Virtual function that should not even get called... +void CModbusBackend::ModbusResponseException(quint8 ExceptionCode, quint8 FctCode) +{ + Q_UNUSED(ExceptionCode) + Q_UNUSED(FctCode) + //CEngLog::instance()->AddLogString("ModbusResponseException called from within slave object... weird stuff!"); +} + +//Virtual function that should not even get called... +void CModbusBackend::ModbusRequestException(quint8 ExceptionCode, quint8 FctCode) +{ + Q_UNUSED(ExceptionCode) + Q_UNUSED(FctCode) + //CEngLog::instance()->AddLogString("ModbusResponseException called from within master object... weird stuff!"); +} + +void CModbusBackend::ModbusWriteMultipleRegsSuccess() +{ + qDebug("Weird! Default implementation of ModbusWriteMultipleRegsSuccess() called in CModbusBackend. This function should be reimplemented in the ModbusMaster child class"); +} + +void CModbusBackend::ModbusWriteSingleRegsSuccess() +{ + qDebug("Weird! Default implementation of ModbusWriteSingleRegsSuccess() called in CModbusBackend. This function should be reimplemented in the ModbusMaster child class"); +} + +void CModbusBackend::ModbusRequestMaxRetryReached() +{ + qDebug("Weird! Default implementation of ModbusRequestMaxRetryReached() called in CModbusBackend. This function should be reimplemented in the ModbusMaster child class"); +} diff --git a/Sources/Modbus/ModbusBackend.h b/Sources/Modbus/ModbusBackend.h new file mode 100644 index 0000000..06970c5 --- /dev/null +++ b/Sources/Modbus/ModbusBackend.h @@ -0,0 +1,203 @@ +/*******************************************************************************/ +/* + Description: + Classe qui implémente le protocole Modbus. + Cette classe est héritée par la classe serveur (CModbusCCMgr) ou client (CModbusMaster). + Elle sert à interpréter ou formatter des paquets Modbus provenant ou destinés au partenaire. + Elle peut être héritée soit un parent qui implémente une instance maître ou client mais pas les deux à la fois. + sur le réseau. + +*/ + +/* ************************************************************************** */ +/* Revision: +### YYYMMDD JFM + Verision d'origine. + +### YYYYMMDD Description du besoin ou du bug + Description du changement. + */ + +/* ************************************************************************** */ + +#ifndef CMODBUSBACKEND_H +#define CMODBUSBACKEND_H +#include +#include +#include "ModbusRepository.h" +#include + + +#define MODBUS_EXCEPTION_FCT_MASK 0x80 +#define MODBUS_RETRY_DELAY 2000 //millisecs +#define MODBUS_RETRY_MAX_COUNT 2 //resend an unanswered request this many times +#define MODBUS_MAX_NB_REGISTERS 0x7D + +enum eModbusFunctions +{ + MODBUS_FCT_READ_HOLDING_REGISTERS = 3, + MODBUS_WRITE_SINGLE_REGISTER = 6, + MODBUS_FCT_WRITE_MULTIPLE_REGISTERS = 16 +}; + +enum eModbusExceptionCodes +{ + MODBUS_EXCEPTION_ILLEGAL_FCT = 1, + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS = 2, + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE = 3, + MODBUS_EXCEPTION_SERVER_DEVICE_FAILURE = 4, + MODBUS_EXCEPTION_ACKNOWLEDGE = 5, + MODBUS_EXCEPTION_SERVER_DEVICE_BUSY = 6, + MODBUS_EXCEPTION_MEMORY_PARITY_ERROR = 8, + MODBUS_EXCEPTION_GATEWAY_PATH_UNAVAILABLE = 10, + MODBUS_EXCEPTION_GATEWAY_TARGET_DEV_NOT_RESPONDING = 11 +}; + +//Énumération des différents modes possibles +enum eModbusModes +{ + MODBUS_MASTER_MODE, + MODBUS_SLAVE_MODE, + MODBUS_INVALID_MODE +}; + +class CModbusException +{ +public: + +}; + +class CModbusPDU +{ +public: + qint8 mFunctionCode; //Type de transaction (voir structure eModbusFunctions) pour les fonctions implémentées par le présent module + QByteArray mData; //Les données de la transaction +}; + +class CModbusHeader //Objet contenant les données d'un header Modbus (selon la spécification) +{ +public: + qint16 mTransactionID; + qint16 mProtocolID; + qint16 mMessageLength; + qint8 mUnitID; +}; + +class CModbusTransaction //Objet contenant les données d'une transaction Modbus +{ +public: + CModbusHeader mHeader; //Le header de la transaction + CModbusPDU mPDU; //Le PDU (fonction & données) de la transaction (voir classe CModbusPDU) +}; + +class CModbusRequest : public CModbusTransaction //Objet représentant une transaction (mode maître) +{ +public: + CModbusRequest(); + ~CModbusRequest(); + int mRetries; //nombre de fois que la transaction a été retransmise + QTimer *mRequestTimer; //Timer servant à retransmettre la requête si aucune réponse ne survient + quint16 mStartAddress, mNbRegisters; //For convinience... +}; + +class CModbusBackend : public QObject +{ + Q_OBJECT + + + +private: +//enum eModbusMasterSMStates +//{ +// MODBUS_SM_WAIT_FOR__STATE +//}; + +//enum eModbusSlaveSMStates +//{ + +//}; + +public: + CModbusBackend(CModbusRepository *Repo); //Le pointeur vers le registre des données est obligatoire. + virtual ~CModbusBackend(); + QTcpSocket *mModbusTCPSocketHandle; //Pointeur vers le Socket TCP du réseau Modbus. + CModbusRepository *mModbusRepo; //Pointeur vers le registre de données Modbus + + bool mDataLinkValid; //Flag indiquant si le lien de communication est en santé + int mModbusMode; //Indique si le lien modbus de cette instance est exploitée en "slave" (serveur) ou un "master" (client) (voir struct eModbusModes ci-haut). + qint8 mDeviceID; //Le device ID Modbus de cette instance. + void ModbusLinkDisconnected(); //Fonction appelée par le parent lors d'une perte de la connection. + void SetDeviceID(qint8 ID){mDeviceID = ID;} + + //Master (client) + int SendReadHoldingRegistersRequest(quint16 StartAddress, quint16 RegisterCount); //Fonction servant à transmettre la fonction modbus "Read HR" au partenaire + int SendWriteHoldingRegistersRequest(quint16 StartAddress, quint16 RegisterCount); //Fonction servant à transmettre la fonction modbus "Write HR" au partenaire + int SendWriteSingleRegisterRequest(quint16 Address); //Fonction servant à transmettre la fonction modbus "Write Single Register" au partenaire + + + + + virtual void RegistersDatabaseUpdated(quint16 StartAdderss, quint16 Length) = 0; //Fonction virtuelle à être implémentée par la classe dérivée + //Appelée lorsque de nouvelles données ont été reçues du réseau Modbus et écrites dans le registre + + + + //Master virtual functions + virtual void ModbusResponseException(quint8 ExceptionCode, quint8 FctCode); //Fonction virtuelle à être implémentée par la classe dérivée + virtual void ModbusWriteMultipleRegsSuccess(); //Fonction virtuelle à être implémentée par la classe dérivée (Modbus Master seulement). Appelée suite à la réception d'une réponse à une requête d'écriture multiple. + virtual void ModbusWriteSingleRegsSuccess(); //Fonction virtuelle à être implémentée par la classe dérivée (Modbus Master seulement). Appelée suite à la réception d'une réponse à une requête d'écriture simple. + virtual void ModbusRequestMaxRetryReached(); //Fonction virtuelle à être implémentée par la classe dérivée (Modbus Master seulement). Appelée lors de l'atteinte du nombre maximal d'essai de transmission d'une requête. + //Sert à informer la classe dérivée lorsqu'une exception se produit dans la communication Modbus (réponse) + + + //Slave virtual function + virtual void ModbusRequestException(quint8 ExceptionCode, quint8 FctCode); //Fonction virtuelle à être implémentée par la classe dérivée + //Sert à informer le parent lorsqu'une exception se produit dans la communication Modbus (requête) + + +private: + + + //Sur un réseau Modbus, l'eslcave (slave) est un serveur et le maître (master) est un client. + + + //Slave (server) + int AnalyzeModbusRequest(CModbusTransaction Transaction); //Exécute l'analyse des données reçues d'une requête Modbus + int SendModbusResponse(CModbusTransaction RequestTransaction, QByteArray Data); //Fonction servant à composer et transmettre une réponse à une requête. + int SendErrorResponse(CModbusTransaction RequestTransaction, quint8 ErrorCode); //Fonction servant à composer et transmettre une réponse d'erreur à une requête. + + //Master (client) + QList mRequestsList; //Liste des requêtes courantes en attente d'une réponse du serveur + int SendModbusRequest(CModbusRequest *Request); //Construit et transmet une nouvelle requête Modbus au partenaire. + quint16 GetNewTransactionID(); //Fonction (helper) servant à générer un nouvel ID de transaction nécessaire pour transmettre une nouvelle requête. + int AnalyzeModbusResponse(CModbusTransaction Transaction); //Exécute l'analyse des données reçues d'une réponse Modbus + + quint16 mTransactionIDCounter; //Compteur interne des ID de transactions Modbus + int mModbusRequestTimeout; //Valeur du délai d'attente maximal avant de recevoir une réponse à une requête. À l'expiration du timer, la requête est renvoyée. + int mModbusMaxRetry; //Valeur du nombre maximal de renvoi d'une requête avant d'invalider la requête. + +signals: + +// void RegistersDatabaseUpdated(quint16 StartAdderss, quint16 Length); + +// //Master signals +// void ModbusResponseException(quint8 ExceptionCode, quint8 FctCode); + +//// //Slave signals +// void ModbusRequestException(quint8 ExceptionCode, quint8 FctCode); + + + +public slots: + void ModbusDataReady(); //Slot indiquant au module que des données sont arrivées et sont attente dans le Socket. + + void RequestTimerExpired(); //Slot indiquant qu'un timer de requête a expiré. + + +}; + + +QDataStream &operator<<(QDataStream &out, const CModbusHeader &source); +QDataStream &operator>>(QDataStream &in, CModbusHeader &dest); + +#endif // CMODBUSBACKEND_H diff --git a/Sources/Modbus/ModbusRepository.cpp b/Sources/Modbus/ModbusRepository.cpp new file mode 100644 index 0000000..555a29b --- /dev/null +++ b/Sources/Modbus/ModbusRepository.cpp @@ -0,0 +1,220 @@ +#include "ModbusRepository.h" +#include +#include +#include +//#include "EngLog.h" + +CModbusRepository::CModbusRepository() +{ +} + +int CModbusRepository::AddHRDataMap(quint16 StartAddress, quint16 Length) +{ + mMutex.lockForWrite(); + for(int i= 0; i < mHoldingRegisters.size(); i++) + { + if((StartAddress >= mHoldingRegisters.at(i).mStartAddress && StartAddress <= mHoldingRegisters.at(i).mEndAddress) || + (StartAddress + Length - 1 >= mHoldingRegisters.at(i).mStartAddress && StartAddress + Length - 1 <= mHoldingRegisters.at(i).mEndAddress)) + { + mMutex.unlock(); + return RET_ERROR; //The data map overlaps an existing map. + } + } + + CHRDataMap NewHRMap(StartAddress,Length); + + mHoldingRegisters.append(NewHRMap); + mMutex.unlock(); + + // CEngLog::instance()->AddLogString(QString("Création d'une zone registre modbus à l'adresse: %1 de taille %2").arg(StartAddress).arg(Length)); + + return RET_OK; +} + +bool CModbusRepository::IsHRValid(quint16 StartAddress, quint16 Length, int *index) +{ + mMutex.lockForRead(); + for(int i= 0; i < mHoldingRegisters.size(); i++) + { + if((StartAddress >= mHoldingRegisters.at(i).mStartAddress && StartAddress + Length - 1 <= mHoldingRegisters.at(i).mEndAddress)) + { + if(index != 0) + { + *index = i; + } + mMutex.unlock(); + return true; + } + } + mMutex.unlock(); + + return false; +} + +QByteArray CModbusRepository::GetHRData(quint16 StartAddress, quint16 Length, bool *OK) +{ + QByteArray Data; + int RegisterIndex = 0; + + if(IsHRValid(StartAddress,Length, &RegisterIndex) == false) + { + if(OK != 0) + { + *OK = false; + } + } + else + { + mMutex.lockForRead(); + int DataIndex = StartAddress - mHoldingRegisters.at(RegisterIndex).mStartAddress; + for(int i = 0; i < Length; i++) + { + quint16 CurReg = mHoldingRegisters.at(RegisterIndex).mRegistersData.at(DataIndex++); + quint8 HighByte, LowByte; + + LowByte = CurReg & 0x00FF; + HighByte = (CurReg >> 8) & 0x00FF; + Data.append(HighByte); + Data.append(LowByte); + } + mMutex.unlock(); + + if(OK != 0) + *OK = true; + } + + return Data; +} + +int CModbusRepository::WriteHRData(quint16 StartAddress, quint16 Length, QByteArray Data) +{ + int RegisterIndex; + + if(IsHRValid(StartAddress,Length, &RegisterIndex) == false) + { + return RET_ERROR; + } + + if(Length*2 != Data.size()) + { + return RET_ERROR; + } + + mMutex.lockForWrite(); + int DataIndex = StartAddress - mHoldingRegisters.at(RegisterIndex).mStartAddress; + + for(int i = 0; i < Length; i++) + { + quint8 HighByte = Data.at(i*2); + quint8 LowByte = Data.at(i*2 + 1); + qint16 Word = HighByte; + Word <<= 8; + Word += LowByte; + Word = Word &0xFFFF; + + mHoldingRegisters[RegisterIndex].mRegistersData[DataIndex++] = Word; + } + mMutex.unlock(); + + emit RepoChanged(StartAddress,Length); + + return RET_OK; +} + +int CModbusRepository::WriteSingleReg(quint16 Address, quint16 Value) +{ + int RegisterIndex; + + if(IsHRValid(Address,1, &RegisterIndex) == false) + { + return RET_ERROR; + } + + mMutex.lockForWrite(); + int DataIndex = Address - mHoldingRegisters.at(RegisterIndex).mStartAddress; + mHoldingRegisters[RegisterIndex].mRegistersData[DataIndex] = Value; + mMutex.unlock(); + + emit RepoChanged(Address,1); + + return RET_OK; +} + +int CModbusRepository::WriteMultipleRegs(quint16 StartAddress, QList Data) +{ + int RegisterIndex; + + if(IsHRValid(StartAddress,Data.size(), &RegisterIndex) == false) + { + return RET_ERROR; + } + + mMutex.lockForWrite(); + int DataIndex = StartAddress - mHoldingRegisters.at(RegisterIndex).mStartAddress; + for(int i = 0; i < Data.size(); i++) + { + mHoldingRegisters[RegisterIndex].mRegistersData[DataIndex++] = Data.at(i); + } + mMutex.unlock(); + + emit RepoChanged(StartAddress,Data.size()); + return RET_OK; +} + +QList CModbusRepository::GetRegs(quint16 StartAddress, quint16 Length, bool *OK) +{ + int RegisterIndex; + + if(IsHRValid(StartAddress,Length, &RegisterIndex) == false) + { + if(OK != 0) + { + *OK = false; + } + return QList(); + } + + if(OK != 0) + { + *OK = true; + } + + int DataIndex = StartAddress - mHoldingRegisters.at(RegisterIndex).mStartAddress; + return mHoldingRegisters[RegisterIndex].mRegistersData.mid(DataIndex,Length); +} +quint16 CModbusRepository::GetSingleReg(quint16 Address, bool *OK) +{ + int RegisterIndex; + + if(IsHRValid(Address,1, &RegisterIndex) == false) + { + if(OK != 0) + *OK = false; + return 0; + } + + if(OK != 0) + *OK = true; + + mMutex.lockForRead(); + int DataIndex = Address - mHoldingRegisters.at(RegisterIndex).mStartAddress; + quint16 Data = mHoldingRegisters[RegisterIndex].mRegistersData[DataIndex]; + mMutex.unlock(); + + return Data; +} + + +CHRDataMap::CHRDataMap(quint16 StartAddress, quint16 Length) +{ + mStartAddress = StartAddress; + mLength = Length; + for(int i = 0; i < Length; i++) + { + mRegistersData.append(0); + } + mEndAddress = StartAddress + Length - 1; +} + + + diff --git a/Sources/Modbus/ModbusRepository.h b/Sources/Modbus/ModbusRepository.h new file mode 100644 index 0000000..ecacf5c --- /dev/null +++ b/Sources/Modbus/ModbusRepository.h @@ -0,0 +1,44 @@ +#ifndef MODBUSREPOSITORY_H +#define MODBUSREPOSITORY_H +#include "GlobalDefine.h" +#include +#include + +class CHRDataMap ///Holding Register data map. +{ +public: + CHRDataMap(quint16 StartAddress, quint16 Length); + quint16 mStartAddress,mEndAddress; + quint16 mLength; + QList mRegistersData; + +}; + +class CModbusRepository : public QObject +{ + Q_OBJECT +public: + CModbusRepository(); + + //Holding Registers + int AddHRDataMap(quint16 StartAddress, quint16 Length); + bool IsHRValid(quint16 StartAddress, quint16 Length, int *index = 0); + QByteArray GetHRData(quint16 StartAddress, quint16 Length, bool *OK = 0); + quint16 GetSingleReg(quint16 Address, bool *OK = 0); + QList GetRegs(quint16 StartAddress, quint16 Length, bool *OK = 0); + int WriteHRData(quint16 StartAddress, quint16 Length, QByteArray Data); + int WriteSingleReg(quint16 Address, quint16 Value); + int WriteMultipleRegs(quint16 StartAddress, QList Data); + const QList *GetRepo(){return &mHoldingRegisters;} + + +private: + QList mHoldingRegisters; + QReadWriteLock mMutex; + +signals: + void RepoChanged(quint16 StartAddress, quint16 Length); + +}; + +#endif // MODBUSREPOSITORY_H diff --git a/Sources/NetworkDevice.cpp b/Sources/NetworkDevice.cpp index c3f451d..2bbf774 100644 --- a/Sources/NetworkDevice.cpp +++ b/Sources/NetworkDevice.cpp @@ -13,7 +13,7 @@ CNetworkDevice::~CNetworkDevice() { if(mNetworkInterfacePtr != 0) { - delete mNetworkInterfacePtr; + // delete mNetworkInterfacePtr; } } diff --git a/Sources/ProtocolDefs.h b/Sources/ProtocolDefs.h index da039fe..d38bfa0 100644 --- a/Sources/ProtocolDefs.h +++ b/Sources/ProtocolDefs.h @@ -265,6 +265,11 @@ enum CHALET_INTERFACE_CMDS CHALET_INTERFACE_DO_HARAKIRI_RESPONSE, CHALET_INTERFACE_REBOOT_CPU_REQUEST, CHALET_INTERFACE_REBOOT_CPU_RESPONSE, + CHALET_INTERFACE_GET_TODAYS_DATA_LOG_REQUEST, + CHALET_INTERFACE_GET_TODAYS_DATA_LOG_RESPONSE, + CHALET_INTERFACE_CHALET_ACTIVITY_RESPONSE, + CHALET_INTERFACE_GET_DATA_LOG_REQUEST, + CHALET_INTERFACE_GET_DATA_LOG_RESPONSE, MAX_CHALET_INTERFACE_CMD }; diff --git a/Sources/Sprinkler/SprinklerDevice.cpp b/Sources/Sprinkler/SprinklerDevice.cpp index f97747d..bba0f1d 100644 --- a/Sources/Sprinkler/SprinklerDevice.cpp +++ b/Sources/Sprinkler/SprinklerDevice.cpp @@ -69,7 +69,7 @@ int CSprinklerDevice::NewDeviceFrameReceived(int DeviceID, int DeviceAddress, in } case SPRINKLER_DEVICE_SET_SPRINKLER_STATE_ACK: { - mNetworkInterfacePtr->SendNetworkMessage(ID_SPRINKLER_DEVICE,1,SPRINKLER_DEVICE_GET_SPRINKLER_STATE_REQUEST,0,QByteArray()); + mNetworkInterfacePtr->SendNetworkMessage(ID_SPRINKLER_DEVICE,1,SPRINKLER_DEVICE_GET_SPRINKLER_STATE_REQUEST,0,0); break; } case SPRINKLER_DEVICE_GET_SPRINKLER_STATE_RESPONSE: @@ -143,5 +143,5 @@ int CSprinklerDevice::NewDeviceFrameReceived(int DeviceID, int DeviceAddress, in void CSprinklerDevice::StatusTimerExpired() { - mNetworkInterfacePtr->SendNetworkMessage(ID_SPRINKLER_DEVICE,1,SPRINKLER_DEVICE_STATUS_REQUEST,0,QByteArray()); + mNetworkInterfacePtr->SendNetworkMessage(ID_SPRINKLER_DEVICE,1,SPRINKLER_DEVICE_STATUS_REQUEST,0,0); } diff --git a/Sources/Sprinkler/SprinklerInterface.cpp b/Sources/Sprinkler/SprinklerInterface.cpp index 11fdda0..8f47c66 100644 --- a/Sources/Sprinkler/SprinklerInterface.cpp +++ b/Sources/Sprinkler/SprinklerInterface.cpp @@ -63,7 +63,7 @@ int CSprinklerInterface::NewDeviceFrameReceived(int DeviceID, int DeviceAddress, MsgData.append(Sprinkler->mDeviceAddress); //1st device address MsgData.append((unsigned char)Sprinkler->mSprinklerState); - mNetworkInterfacePtr->SendNetworkMessage(ID_SPRINKLER_INTERFACE,mDeviceAddress,SPRINKLER_INTERFACE_GET_SPRINKLER_STATE_RESPONSE,MsgData.size(),MsgData); + mNetworkInterfacePtr->SendNetworkMessage(ID_SPRINKLER_INTERFACE,mDeviceAddress,SPRINKLER_INTERFACE_GET_SPRINKLER_STATE_RESPONSE,MsgData.size(),&MsgData); break; } diff --git a/Sources/VoipSMS/SMSDevice.cpp b/Sources/VoipSMS/SMSDevice.cpp index 4850267..0e8f01e 100644 --- a/Sources/VoipSMS/SMSDevice.cpp +++ b/Sources/VoipSMS/SMSDevice.cpp @@ -61,7 +61,7 @@ int CSMSDevice::NewDeviceFrameReceived(int DeviceID, int DeviceAddress, int Mess *FrameDataStrm << DID; FrameBuffer.seek(0); - mNetworkInterfacePtr->SendNetworkMessage(mDeviceID,mDeviceAddress,SMS_CLIENT_DEVICE_DID_INFO_RESPONSE,FrameData.size(),FrameData); + mNetworkInterfacePtr->SendNetworkMessage(mDeviceID,mDeviceAddress,SMS_CLIENT_DEVICE_DID_INFO_RESPONSE,FrameData.size(),&FrameData); delete FrameDataStrm; break; @@ -81,7 +81,7 @@ int CSMSDevice::NewDeviceFrameReceived(int DeviceID, int DeviceAddress, int Mess } FrameBuffer.seek(0); - mNetworkInterfacePtr->SendNetworkMessage(mDeviceID,mDeviceAddress,SMS_CLIENT_DEVICE_GET_ALL_MSG_RESPONSE,FrameData.size(),FrameData); + mNetworkInterfacePtr->SendNetworkMessage(mDeviceID,mDeviceAddress,SMS_CLIENT_DEVICE_GET_ALL_MSG_RESPONSE,FrameData.size(),&FrameData); FrameBuffer.close(); delete FrameDataStrm; @@ -131,7 +131,7 @@ int CSMSDevice::NewDeviceFrameReceived(int DeviceID, int DeviceAddress, int Mess } FrameBuffer.seek(0); - mNetworkInterfacePtr->SendNetworkMessage(mDeviceID,mDeviceAddress,SMS_CLIENT_DEVICE_GET_CONTACTS_RESPONSE,FrameData.size(),FrameData); + mNetworkInterfacePtr->SendNetworkMessage(mDeviceID,mDeviceAddress,SMS_CLIENT_DEVICE_GET_CONTACTS_RESPONSE,FrameData.size(),&FrameData); FrameBuffer.close(); delete FrameDataStrm; @@ -159,7 +159,7 @@ int CSMSDevice::NewDeviceFrameReceived(int DeviceID, int DeviceAddress, int Mess void CSMSDevice::RequestStatus() { - mNetworkInterfacePtr->SendNetworkMessage(mDeviceID,mDeviceAddress,SMS_CLIENT_DEVICE_STATUS_REQUEST,0,QByteArray()); + mNetworkInterfacePtr->SendNetworkMessage(mDeviceID,mDeviceAddress,SMS_CLIENT_DEVICE_STATUS_REQUEST,0,0); } void CSMSDevice::SendSMSSentAck(bool Ack) @@ -176,7 +176,7 @@ void CSMSDevice::SendSMSSentAck(bool Ack) } *FrameDataStrm << ACKData; - mNetworkInterfacePtr->SendNetworkMessage(mDeviceID,mDeviceAddress,SMS_CLIENT_DEVICE_SEND_SMS_ACK,FrameData.size(),FrameData); + mNetworkInterfacePtr->SendNetworkMessage(mDeviceID,mDeviceAddress,SMS_CLIENT_DEVICE_SEND_SMS_ACK,FrameData.size(),&FrameData); FrameBuffer.close(); @@ -198,7 +198,7 @@ void CSMSDevice::SendNewSMSReceived(QList NewMessages) } FrameBuffer.seek(0); - mNetworkInterfacePtr->SendNetworkMessage(mDeviceID,mDeviceAddress,SMS_CLIENT_DEVICE_NEW_MSG_NOTIFICATION,FrameData.size(),FrameData); + mNetworkInterfacePtr->SendNetworkMessage(mDeviceID,mDeviceAddress,SMS_CLIENT_DEVICE_NEW_MSG_NOTIFICATION,FrameData.size(),&FrameData); FrameBuffer.close(); delete FrameDataStrm;