From 4e219f14a82c3d8874b1b9b8382e3368f0251d35 Mon Sep 17 00:00:00 2001 From: Roland Winklmeier Date: Mon, 11 Mar 2013 20:41:29 +0100 Subject: [PATCH] blacklib folder reorganisation --- CMakeLists.txt | 10 +- samples/CMakeLists.txt | 6 + samples/Geodetic2Ecef/CMakeLists.txt | 6 + samples/Geodetic2Ecef/main.cpp | 53 ++++++ samples/Logging/CMakeLists.txt | 6 + samples/Logging/main.cpp | 18 ++ samples/com_client/CMakeLists.txt | 9 + samples/com_client/client.cpp | 36 ++++ samples/com_client/client.h | 19 ++ samples/com_client/main.cpp | 16 ++ samples/com_server/CMakeLists.txt | 9 + samples/com_server/main.cpp | 16 ++ samples/com_server/server.cpp | 39 ++++ samples/com_server/server.h | 32 ++++ samples/config/CMakeLists.txt | 6 + samples/config/config/config.ini | 0 samples/config/config/position.cfg | 3 + samples/config/config/test.cfg | 2 + samples/config/main.cpp | 27 +++ samples/interpolator/CMakeLists.txt | 6 + samples/interpolator/main.cpp | 76 ++++++++ src/CMakeLists.txt | 6 + src/blackbox/CMakeLists.txt | 29 +++ src/blackbox/blackbox.cpp | 48 +++++ src/blackbox/blackbox.h | 37 ++++ src/blackbox/blackbox.ui | 59 ++++++ src/blackbox/dialog_chat.cpp | 21 +++ src/blackbox/dialog_chat.h | 27 +++ src/blackbox/dialog_chat.ui | 74 ++++++++ src/blackbox/dialog_connect.cpp | 61 +++++++ src/blackbox/dialog_connect.h | 36 ++++ src/blackbox/dialog_connect.ui | 171 +++++++++++++++++ src/blackbox/main.cpp | 22 +++ src/blackcore/CMakeLists.txt | 18 ++ src/blackcore/constants.h | 55 ++++++ src/blackcore/ecef.cpp | 250 +++++++++++++++++++++++++ src/blackcore/ecef.h | 42 +++++ src/blackcore/fsd_client.cpp | 189 +++++++++++++++++++ src/blackcore/fsd_client.h | 126 +++++++++++++ src/blackcore/fsd_messages.cpp | 97 ++++++++++ src/blackcore/fsd_messages.h | 157 ++++++++++++++++ src/blackcore/fsd_protocol.h | 61 +++++++ src/blackcore/interpolator.cpp | 155 ++++++++++++++++ src/blackcore/interpolator.h | 79 ++++++++ src/blackcore/math.cpp | 33 ++++ src/blackcore/math.h | 56 ++++++ src/blackcore/matrix_3d.cpp | 255 ++++++++++++++++++++++++++ src/blackcore/matrix_3d.h | 86 +++++++++ src/blackcore/multiplayer.cpp | 96 ++++++++++ src/blackcore/multiplayer.h | 100 ++++++++++ src/blackcore/ned.cpp | 74 ++++++++ src/blackcore/ned.h | 47 +++++ src/blackcore/plane.cpp | 36 ++++ src/blackcore/plane.h | 52 ++++++ src/blackcore/sim_callbacks.h | 6 + src/blackcore/simulator.cpp | 136 ++++++++++++++ src/blackcore/simulator.h | 168 +++++++++++++++++ src/blackcore/vector_3d.cpp | 177 ++++++++++++++++++ src/blackcore/vector_3d.h | 73 ++++++++ src/blackcore/vector_geo.cpp | 86 +++++++++ src/blackcore/vector_geo.h | 58 ++++++ src/blackd/CMakeLists.txt | 25 +++ src/blackd/blackd.cpp | 169 +++++++++++++++++ src/blackd/blackd.h | 73 ++++++++ src/blackd/blackd.qrc | 5 + src/blackd/blackd.ui | 33 ++++ src/blackd/images/blackbox.svg | 101 ++++++++++ src/blackd/images/blackbox_icon.svg | 102 +++++++++++ src/blackd/main.cpp | 31 ++++ src/blackd/qt_displayer.cpp | 78 ++++++++ src/blackd/qt_displayer.h | 31 ++++ src/blackmisc/CMakeLists.txt | 21 +++ src/blackmisc/com_client.cpp | 186 +++++++++++++++++++ src/blackmisc/com_client.h | 117 ++++++++++++ src/blackmisc/com_client_buffer.cpp | 60 ++++++ src/blackmisc/com_client_buffer.h | 53 ++++++ src/blackmisc/com_handler.cpp | 127 +++++++++++++ src/blackmisc/com_handler.h | 72 ++++++++ src/blackmisc/com_server.cpp | 136 ++++++++++++++ src/blackmisc/com_server.h | 104 +++++++++++ src/blackmisc/config.cpp | 240 ++++++++++++++++++++++++ src/blackmisc/config.h | 162 ++++++++++++++++ src/blackmisc/config_manager.cpp | 94 ++++++++++ src/blackmisc/config_manager.h | 59 ++++++ src/blackmisc/context.cpp | 113 ++++++++++++ src/blackmisc/context.h | 249 +++++++++++++++++++++++++ src/blackmisc/debug.cpp | 191 +++++++++++++++++++ src/blackmisc/debug.h | 147 +++++++++++++++ src/blackmisc/display.cpp | 264 +++++++++++++++++++++++++++ src/blackmisc/display.h | 95 ++++++++++ src/blackmisc/gui_messages.h | 115 ++++++++++++ src/blackmisc/log.cpp | 253 +++++++++++++++++++++++++ src/blackmisc/log.h | 204 +++++++++++++++++++++ src/blackmisc/logmessage.cpp | 54 ++++++ src/blackmisc/logmessage.h | 83 +++++++++ src/blackmisc/message.cpp | 15 ++ src/blackmisc/message.h | 73 ++++++++ src/blackmisc/message_dispatcher.cpp | 32 ++++ src/blackmisc/message_dispatcher.h | 59 ++++++ src/blackmisc/message_factory.cpp | 48 +++++ src/blackmisc/message_factory.h | 59 ++++++ src/blackmisc/message_handler.cpp | 25 +++ src/blackmisc/message_handler.h | 75 ++++++++ src/blackmisc/message_system.cpp | 17 ++ src/blackmisc/message_system.h | 26 +++ src/blackmisc/serialize.cpp | 5 + src/blackmisc/serialize.h | 21 +++ src/blackmisc/type_info.cpp | 21 +++ src/blackmisc/type_info.h | 27 +++ src/blackx/CMakeLists.txt | 0 src/driver/CMakeLists.txt | 3 + src/driver/fs9/driver_fs9.cpp | 33 ++++ src/driver/fs9/driver_fs9.h | 17 ++ src/driver/fsx/CMakeLists.txt | 20 ++ src/driver/fsx/driver_fsx.cpp | 50 +++++ src/driver/fsx/driver_fsx.h | 35 ++++ src/driver/xplane/driver_xplane.cpp | 23 +++ src/driver/xplane/driver_xplane.h | 17 ++ 118 files changed, 8297 insertions(+), 5 deletions(-) create mode 100644 samples/CMakeLists.txt create mode 100644 samples/Geodetic2Ecef/CMakeLists.txt create mode 100644 samples/Geodetic2Ecef/main.cpp create mode 100644 samples/Logging/CMakeLists.txt create mode 100644 samples/Logging/main.cpp create mode 100644 samples/com_client/CMakeLists.txt create mode 100644 samples/com_client/client.cpp create mode 100644 samples/com_client/client.h create mode 100644 samples/com_client/main.cpp create mode 100644 samples/com_server/CMakeLists.txt create mode 100644 samples/com_server/main.cpp create mode 100644 samples/com_server/server.cpp create mode 100644 samples/com_server/server.h create mode 100644 samples/config/CMakeLists.txt create mode 100644 samples/config/config/config.ini create mode 100644 samples/config/config/position.cfg create mode 100644 samples/config/config/test.cfg create mode 100644 samples/config/main.cpp create mode 100644 samples/interpolator/CMakeLists.txt create mode 100644 samples/interpolator/main.cpp create mode 100644 src/CMakeLists.txt create mode 100644 src/blackbox/CMakeLists.txt create mode 100644 src/blackbox/blackbox.cpp create mode 100644 src/blackbox/blackbox.h create mode 100644 src/blackbox/blackbox.ui create mode 100644 src/blackbox/dialog_chat.cpp create mode 100644 src/blackbox/dialog_chat.h create mode 100644 src/blackbox/dialog_chat.ui create mode 100644 src/blackbox/dialog_connect.cpp create mode 100644 src/blackbox/dialog_connect.h create mode 100644 src/blackbox/dialog_connect.ui create mode 100644 src/blackbox/main.cpp create mode 100644 src/blackcore/CMakeLists.txt create mode 100644 src/blackcore/constants.h create mode 100644 src/blackcore/ecef.cpp create mode 100644 src/blackcore/ecef.h create mode 100644 src/blackcore/fsd_client.cpp create mode 100644 src/blackcore/fsd_client.h create mode 100644 src/blackcore/fsd_messages.cpp create mode 100644 src/blackcore/fsd_messages.h create mode 100644 src/blackcore/fsd_protocol.h create mode 100644 src/blackcore/interpolator.cpp create mode 100644 src/blackcore/interpolator.h create mode 100644 src/blackcore/math.cpp create mode 100644 src/blackcore/math.h create mode 100644 src/blackcore/matrix_3d.cpp create mode 100644 src/blackcore/matrix_3d.h create mode 100644 src/blackcore/multiplayer.cpp create mode 100644 src/blackcore/multiplayer.h create mode 100644 src/blackcore/ned.cpp create mode 100644 src/blackcore/ned.h create mode 100644 src/blackcore/plane.cpp create mode 100644 src/blackcore/plane.h create mode 100644 src/blackcore/sim_callbacks.h create mode 100644 src/blackcore/simulator.cpp create mode 100644 src/blackcore/simulator.h create mode 100644 src/blackcore/vector_3d.cpp create mode 100644 src/blackcore/vector_3d.h create mode 100644 src/blackcore/vector_geo.cpp create mode 100644 src/blackcore/vector_geo.h create mode 100644 src/blackd/CMakeLists.txt create mode 100644 src/blackd/blackd.cpp create mode 100644 src/blackd/blackd.h create mode 100644 src/blackd/blackd.qrc create mode 100644 src/blackd/blackd.ui create mode 100644 src/blackd/images/blackbox.svg create mode 100644 src/blackd/images/blackbox_icon.svg create mode 100644 src/blackd/main.cpp create mode 100644 src/blackd/qt_displayer.cpp create mode 100644 src/blackd/qt_displayer.h create mode 100644 src/blackmisc/CMakeLists.txt create mode 100644 src/blackmisc/com_client.cpp create mode 100644 src/blackmisc/com_client.h create mode 100644 src/blackmisc/com_client_buffer.cpp create mode 100644 src/blackmisc/com_client_buffer.h create mode 100644 src/blackmisc/com_handler.cpp create mode 100644 src/blackmisc/com_handler.h create mode 100644 src/blackmisc/com_server.cpp create mode 100644 src/blackmisc/com_server.h create mode 100644 src/blackmisc/config.cpp create mode 100644 src/blackmisc/config.h create mode 100644 src/blackmisc/config_manager.cpp create mode 100644 src/blackmisc/config_manager.h create mode 100644 src/blackmisc/context.cpp create mode 100644 src/blackmisc/context.h create mode 100644 src/blackmisc/debug.cpp create mode 100644 src/blackmisc/debug.h create mode 100644 src/blackmisc/display.cpp create mode 100644 src/blackmisc/display.h create mode 100644 src/blackmisc/gui_messages.h create mode 100644 src/blackmisc/log.cpp create mode 100644 src/blackmisc/log.h create mode 100644 src/blackmisc/logmessage.cpp create mode 100644 src/blackmisc/logmessage.h create mode 100644 src/blackmisc/message.cpp create mode 100644 src/blackmisc/message.h create mode 100644 src/blackmisc/message_dispatcher.cpp create mode 100644 src/blackmisc/message_dispatcher.h create mode 100644 src/blackmisc/message_factory.cpp create mode 100644 src/blackmisc/message_factory.h create mode 100644 src/blackmisc/message_handler.cpp create mode 100644 src/blackmisc/message_handler.h create mode 100644 src/blackmisc/message_system.cpp create mode 100644 src/blackmisc/message_system.h create mode 100644 src/blackmisc/serialize.cpp create mode 100644 src/blackmisc/serialize.h create mode 100644 src/blackmisc/type_info.cpp create mode 100644 src/blackmisc/type_info.h create mode 100644 src/blackx/CMakeLists.txt create mode 100644 src/driver/CMakeLists.txt create mode 100644 src/driver/fs9/driver_fs9.cpp create mode 100644 src/driver/fs9/driver_fs9.h create mode 100644 src/driver/fsx/CMakeLists.txt create mode 100644 src/driver/fsx/driver_fsx.cpp create mode 100644 src/driver/fsx/driver_fsx.h create mode 100644 src/driver/xplane/driver_xplane.cpp create mode 100644 src/driver/xplane/driver_xplane.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 07550acb0..d483f9227 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -184,7 +184,7 @@ ENDIF() ############### Includes ############### INCLUDE_DIRECTORIES(${QT_INCLUDES}) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/blacklib/include) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/src) ############### Doxygen ############### @@ -202,7 +202,7 @@ ENDIF(DOXYGEN_FOUND) ############### build targets ############### -ADD_SUBDIRECTORY(blackd) -ADD_SUBDIRECTORY(blackbox) -ADD_SUBDIRECTORY(blacklib) -ADD_SUBDIRECTORY(blackx) \ No newline at end of file +ADD_SUBDIRECTORY(src) +IF(WITH_BLACK_SAMPLES) + ADD_SUBDIRECTORY(samples) +ENDIF(WITH_BLACK_SAMPLES) \ No newline at end of file diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt new file mode 100644 index 000000000..4ec2bec48 --- /dev/null +++ b/samples/CMakeLists.txt @@ -0,0 +1,6 @@ +ADD_SUBDIRECTORY(Logging) +ADD_SUBDIRECTORY(com_server) +ADD_SUBDIRECTORY(com_client) +ADD_SUBDIRECTORY(Geodetic2Ecef) +ADD_SUBDIRECTORY(interpolator) +ADD_SUBDIRECTORY(config) \ No newline at end of file diff --git a/samples/Geodetic2Ecef/CMakeLists.txt b/samples/Geodetic2Ecef/CMakeLists.txt new file mode 100644 index 000000000..b3afc69b1 --- /dev/null +++ b/samples/Geodetic2Ecef/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB SRC *.cpp) + +ADD_EXECUTABLE(sample_Geodetic2Ecef ${SRC}) + +TARGET_LINK_LIBRARIES(sample_Geodetic2Ecef blackmisc blackcore ${QT_LIBRARIES}) +SET_TARGET_PROPERTIES(sample_Geodetic2Ecef PROPERTIES PROJECT_LABEL "Samples - Geodetic to Ecef") \ No newline at end of file diff --git a/samples/Geodetic2Ecef/main.cpp b/samples/Geodetic2Ecef/main.cpp new file mode 100644 index 000000000..ef4db440a --- /dev/null +++ b/samples/Geodetic2Ecef/main.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + BlackMisc::CApplicationContext myApplicationContext; + + QElapsedTimer timer; + qint64 duration; + + double lat = 27.999999, lon = 86.999999, h = 8820.999999; // Mt Everest + + BlackCore::CEcef mediumvec; + BlackCore::CVectorGeo startVec(lat, lon, h); + startVec.print(); + + cout << std::endl; + cout << std::endl; + + BlackCore::CVectorGeo endVec; + + timer.start(); + mediumvec = startVec.toCartesian(); + + duration = timer.nsecsElapsed(); + + mediumvec.print(); + + cout << std::endl; + cout << std::endl; + + cout << "Needed " << duration << " nanoseconds for the calculation!" << std::endl << std::endl; + + timer.restart(); + endVec = mediumvec.toGeodetic(); + duration = timer.nsecsElapsed(); + + endVec.print(); + + cout << "Needed " << duration << " nanoseconds for the calculation!" << std::endl << std::endl; + + return a.exec(); +} diff --git a/samples/Logging/CMakeLists.txt b/samples/Logging/CMakeLists.txt new file mode 100644 index 000000000..ca4e75148 --- /dev/null +++ b/samples/Logging/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB SRC *.cpp) + +ADD_EXECUTABLE(sample_logging ${SRC}) + +TARGET_LINK_LIBRARIES(sample_logging blackmisc ${QT_LIBRARIES}) +SET_TARGET_PROPERTIES(sample_logging PROPERTIES PROJECT_LABEL "Samples - Logging") \ No newline at end of file diff --git a/samples/Logging/main.cpp b/samples/Logging/main.cpp new file mode 100644 index 000000000..73bd4d8be --- /dev/null +++ b/samples/Logging/main.cpp @@ -0,0 +1,18 @@ +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + BlackMisc::CApplicationContext myApplicationContext; + + bInfo << "This is a Info log message"; + bWarning << "This is a bWarning log message"; + bError << "This is a bError log message"; + bDebug << "This is a bDebug log message"; + + return a.exec(); +} diff --git a/samples/com_client/CMakeLists.txt b/samples/com_client/CMakeLists.txt new file mode 100644 index 000000000..e09876dd0 --- /dev/null +++ b/samples/com_client/CMakeLists.txt @@ -0,0 +1,9 @@ +FILE(GLOB sample_com_client_SOURCES *.cpp) +SET(sample_com_client_HEADERS client.h) + +QT4_WRAP_CPP(sample_com_client_HEADERS_MOC ${sample_com_client_HEADERS}) + +ADD_EXECUTABLE(sample_com_client ${sample_com_client_SOURCES} ${sample_com_client_HEADERS_MOC}) + +TARGET_LINK_LIBRARIES(sample_com_client blackmisc ${QT_LIBRARIES}) +SET_TARGET_PROPERTIES(sample_com_client PROPERTIES PROJECT_LABEL "Samples - Com client") \ No newline at end of file diff --git a/samples/com_client/client.cpp b/samples/com_client/client.cpp new file mode 100644 index 000000000..6858316f1 --- /dev/null +++ b/samples/com_client/client.cpp @@ -0,0 +1,36 @@ +#include +#include "client.h" +#include + +using namespace BlackMisc; + +Client::Client(QObject *parent) : QObject(parent) +{ + connect(&comclient, SIGNAL(doError(QAbstractSocket::SocketError,QString)), this, SLOT(onError(QAbstractSocket::SocketError,QString))); + connect(&comclient, SIGNAL(doConnected()), this, SLOT(onClientConnected())); + + QString address = "127.0.0.1"; + comclient.connectTo(address, 6809); +} + +Client::~Client() +{ +} + +void Client::onError(QAbstractSocket::SocketError error, QString message) +{ + bWarning << "Socket error!"; +} + +void Client::onClientConnected() +{ + QByteArray message_data; + QDataStream out(&message_data, QIODevice::WriteOnly); + + IMessage* testmsg = new TestMessage(); + + *testmsg >> out; + + comclient.sendMessage(testmsg->getID(), message_data); + delete testmsg; +} \ No newline at end of file diff --git a/samples/com_client/client.h b/samples/com_client/client.h new file mode 100644 index 000000000..64d759732 --- /dev/null +++ b/samples/com_client/client.h @@ -0,0 +1,19 @@ +#include +#include + +class Client : public QObject +{ + Q_OBJECT + +public: + explicit Client(QObject *parent = NULL); + ~Client(); + +protected slots: + + void onError(QAbstractSocket::SocketError,QString); + void onClientConnected(); + +private: + BlackMisc::CComClient comclient; +}; \ No newline at end of file diff --git a/samples/com_client/main.cpp b/samples/com_client/main.cpp new file mode 100644 index 000000000..31e808852 --- /dev/null +++ b/samples/com_client/main.cpp @@ -0,0 +1,16 @@ +#include + +#include +#include "client.h" + +using namespace BlackMisc; + +int main(int argc, char *argv[]) +{ + BlackMisc::CApplicationContext myApplicationContext; + QApplication a(argc, argv); + + Client client; + + return a.exec(); +} diff --git a/samples/com_server/CMakeLists.txt b/samples/com_server/CMakeLists.txt new file mode 100644 index 000000000..5df290a3a --- /dev/null +++ b/samples/com_server/CMakeLists.txt @@ -0,0 +1,9 @@ +FILE(GLOB sample_com_server_SOURCES *.cpp) +SET(sample_com_server_HEADERS server.h) + +QT4_WRAP_CPP(sample_com_server_HEADERS_MOC ${sample_com_server_HEADERS}) + +ADD_EXECUTABLE(sample_com_server ${sample_com_server_SOURCES} ${sample_com_server_HEADERS_MOC}) + +TARGET_LINK_LIBRARIES(sample_com_server blackmisc ${QT_LIBRARIES}) +SET_TARGET_PROPERTIES(sample_com_server PROPERTIES PROJECT_LABEL "Samples - Com Server") \ No newline at end of file diff --git a/samples/com_server/main.cpp b/samples/com_server/main.cpp new file mode 100644 index 000000000..65a0dbf7f --- /dev/null +++ b/samples/com_server/main.cpp @@ -0,0 +1,16 @@ +#include + +#include +#include "server.h" + +using namespace BlackMisc; + +int main(int argc, char *argv[]) +{ + BlackMisc::CApplicationContext myApplicationContext; + QApplication a(argc, argv); + + Server server; + + return a.exec(); +} diff --git a/samples/com_server/server.cpp b/samples/com_server/server.cpp new file mode 100644 index 000000000..5507f1610 --- /dev/null +++ b/samples/com_server/server.cpp @@ -0,0 +1,39 @@ +#include +#include "server.h" + +using namespace BlackMisc; + +Server::Server(QObject *parent) : QObject(parent) +{ + QHostAddress local = QHostAddress(QHostAddress::LocalHost); + + server.Host(local, 6809); + + connect(&server, SIGNAL(doMessageReceived(QString &, QByteArray&)), this, SLOT(onData(QString &, QByteArray&))); + + CMessageSystem myMessageSystem; + + bInfo << "Com Server running. \n"; +} + +Server::~Server() +{ +} + +void Server::onData(QString &messageID, QByteArray &message) +{ + BlackMisc::IMessage* test = BlackMisc::CMessageFactory::getInstance().create(messageID); + QDataStream stream(&message, QIODevice::ReadOnly); + + bAssert (test); + *test << stream; + + CMessageDispatcher::getInstance().append(test); + CMessageDispatcher::getInstance().dispatch(); + +} + +void TestMessageHandler::onTestMessage(const TestMessage *testmessage) +{ + bDebug << "Message ID: " << testmessage->getID() << " with text: " << testmessage->getTestString(); +} \ No newline at end of file diff --git a/samples/com_server/server.h b/samples/com_server/server.h new file mode 100644 index 000000000..1f503ba52 --- /dev/null +++ b/samples/com_server/server.h @@ -0,0 +1,32 @@ +#include +#include + +class TestMessageHandler : public BlackMisc::CMessageHandler +{ +public: + TestMessageHandler() + { + registerMessageFunction(this, &TestMessageHandler::onTestMessage); + } +private: + + void onTestMessage(const BlackMisc::TestMessage *testmessage); + +}; + +class Server : public QObject +{ + Q_OBJECT + +public: + explicit Server(QObject *parent = NULL); + ~Server(); + +protected slots: + + void onData(QString &messageID, QByteArray& message); + +private: + BlackMisc::CComServer server; + TestMessageHandler myHandler; +}; \ No newline at end of file diff --git a/samples/config/CMakeLists.txt b/samples/config/CMakeLists.txt new file mode 100644 index 000000000..4db634be2 --- /dev/null +++ b/samples/config/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB SRC *.cpp) + +ADD_EXECUTABLE(sample_config ${SRC}) + +TARGET_LINK_LIBRARIES(sample_config blackmisc ${QT_LIBRARIES}) +SET_TARGET_PROPERTIES(sample_config PROPERTIES PROJECT_LABEL "Samples - Config") \ No newline at end of file diff --git a/samples/config/config/config.ini b/samples/config/config/config.ini new file mode 100644 index 000000000..e69de29bb diff --git a/samples/config/config/position.cfg b/samples/config/config/position.cfg new file mode 100644 index 000000000..cd05ebc1a --- /dev/null +++ b/samples/config/config/position.cfg @@ -0,0 +1,3 @@ +Longitude=48.999999 +Latitude=11.9999999 +Altitude=300 \ No newline at end of file diff --git a/samples/config/config/test.cfg b/samples/config/config/test.cfg new file mode 100644 index 000000000..6b6b9ee37 --- /dev/null +++ b/samples/config/config/test.cfg @@ -0,0 +1,2 @@ +TestString = Hallo +TestString2 = Welt \ No newline at end of file diff --git a/samples/config/main.cpp b/samples/config/main.cpp new file mode 100644 index 000000000..33c32fa5f --- /dev/null +++ b/samples/config/main.cpp @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include +#include + +using namespace BlackMisc; + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + BlackMisc::CApplicationContext myApplicationContext; + + CConfigManager::getInstance().setConfigPath(QString("config")); + if (!CConfigManager::getInstance().readConfig()) + { + bWarning << "To run this sample, there must be a config folder"; + bWarning << "in the same directory, containing *.cfg files."; + } + + CConfig *myConfig = CConfigManager::getInstance().getConfig("position"); + bAssert(myConfig); + myConfig->display(); + + return a.exec(); +} diff --git a/samples/interpolator/CMakeLists.txt b/samples/interpolator/CMakeLists.txt new file mode 100644 index 000000000..d7983e57d --- /dev/null +++ b/samples/interpolator/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB SRC *.cpp) + +ADD_EXECUTABLE(sample_interpolator ${SRC}) + +TARGET_LINK_LIBRARIES(sample_interpolator blackmisc blackcore ${QT_LIBRARIES}) +SET_TARGET_PROPERTIES(sample_interpolator PROPERTIES PROJECT_LABEL "Samples - Interpolator") \ No newline at end of file diff --git a/samples/interpolator/main.cpp b/samples/interpolator/main.cpp new file mode 100644 index 000000000..5e3e2220e --- /dev/null +++ b/samples/interpolator/main.cpp @@ -0,0 +1,76 @@ +#include +#include + +#include + +#include + +#include +#include +#include +#include + +using namespace std; +using namespace BlackCore; + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + QElapsedTimer timer; + + CVectorGeo myGeo(48.123, 11.75, 400); + CVector3D vecNed(1, 0, 0); + CVector3D vecEcef; + + CInterpolator interpolator; + + interpolator.initialize(); + + CVectorGeo vecGeo(48.340733, 11.750565, 100); + CVectorGeo vecGeo2(48.344727, 11.805153, 100); + + cout << "Start position: " << endl; + vecGeo.print(); + + cout << "End position: " << endl; + vecGeo2.print(); + + timer.start(); + + // CVectorGeo pos, double groundVelocity, double heading, double pitch, double bank + interpolator.pushUpdate(vecGeo, 20, 80, 0, 0); + interpolator.pushUpdate(vecGeo2, 20, 250, 0, 0); + + double duration = timer.nsecsElapsed(); + + TPlaneState teststate; + + timer.restart(); + interpolator.stateNow(&teststate); + + CEcef pos = teststate.position; + CVector3D vel = teststate.velocity; + CNed ned = teststate.velNED; + + duration = timer.nsecsElapsed(); + timer.restart(); + + CVectorGeo resultGeo = pos.toGeodetic(); + duration = timer.nsecsElapsed(); + + cout << "End position: " << endl; + resultGeo.print(); + cout << endl; + + cout << "End velocity: " << endl; + vel.print(); + cout << endl; + + cout << "Heading: " << endl; + cout << teststate.orientation.heading << endl; + cout << endl; + + cout << duration << " nanoseconds" << endl; + + return a.exec(); +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 000000000..3214959c3 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,6 @@ +ADD_SUBDIRECTORY(blackbox) +ADD_SUBDIRECTORY(blackcore) +ADD_SUBDIRECTORY(blackd) +ADD_SUBDIRECTORY(blackmisc) +ADD_SUBDIRECTORY(blackx) +ADD_SUBDIRECTORY(driver) \ No newline at end of file diff --git a/src/blackbox/CMakeLists.txt b/src/blackbox/CMakeLists.txt new file mode 100644 index 000000000..03a3bee87 --- /dev/null +++ b/src/blackbox/CMakeLists.txt @@ -0,0 +1,29 @@ +FILE(GLOB blackbox_SOURCES *.cpp) +FILE(GLOB blackbox_HEADERS *.h) +SET(blackbox_HEADERS_QOBJECT + blackbox.h + dialog_connect.h + dialog_chat.h) + +SET(blackbox_FORMS blackbox.ui + dialog_connect.ui + dialog_chat.ui) +SET(blackbox_RESOURCES ) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) + +QT4_WRAP_CPP(blackbox_HEADERS_MOC ${blackbox_HEADERS_QOBJECT}) +QT4_WRAP_UI(blackbox_FORMS_HEADERS ${blackbox_FORMS}) +QT4_ADD_RESOURCES(blackbox_RESOURCES_RCC ${blackbox_RESOURCES}) + +SOURCE_GROUP(QtGeneratedMocSrc FILES ${blackbox_HEADERS_MOC}) +SOURCE_GROUP (QtResources FILES ${blackbox_RESOURCES_RCC}) +SOURCE_GROUP (QtForms FILES ${blackbox_FORMS_HEADERS}) + +ADD_EXECUTABLE(blackbox WIN32 MACOSX_BUNDLE ${blackbox_SOURCES} + ${blackbox_HEADERS_MOC} + ${blackbox_FORMS_HEADERS} + ${blackbox_RESOURCES_RCC}) + +TARGET_LINK_LIBRARIES(blackbox blackmisc ${QT_LIBRARIES} ${QT_QTMAIN_LIBRARY}) +SET_TARGET_PROPERTIES(blackbox PROPERTIES PROJECT_LABEL "BlackBox GUI - BlackBox") \ No newline at end of file diff --git a/src/blackbox/blackbox.cpp b/src/blackbox/blackbox.cpp new file mode 100644 index 000000000..4cddd2798 --- /dev/null +++ b/src/blackbox/blackbox.cpp @@ -0,0 +1,48 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#include "dialog_connect.h" +#include "dialog_chat.h" + +#include "blackbox.h" +#include "ui_blackbox.h" + +BlackBox::BlackBox(QWidget *parent) : + QDialog(parent), + ui(new Ui::BlackBox) +{ + ui->setupUi(this); + + m_dlg_connect = new CDialogConnect(); + m_dlg_connect->hide(); + + m_dlg_chat = new CDialogChat(); + m_dlg_chat->hide(); + + connect(ui->bt_Connect, SIGNAL(clicked()), this, SLOT(onConnect())); + connect(ui->bt_Chat, SIGNAL(clicked()), this, SLOT(onButtonChat())); +} + +BlackBox::~BlackBox() +{ + delete ui; +} + +void BlackBox::onConnect() +{ + if (m_dlg_connect->isHidden()) + { + m_dlg_connect->show(); + } + +} + +void BlackBox::onButtonChat() +{ + if (m_dlg_chat->isHidden()) + { + m_dlg_chat->show(); + } +} diff --git a/src/blackbox/blackbox.h b/src/blackbox/blackbox.h new file mode 100644 index 000000000..063b0ecae --- /dev/null +++ b/src/blackbox/blackbox.h @@ -0,0 +1,37 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef BLACKBOX_H +#define BLACKBOX_H + +#include + +class CDialogConnect; +class CDialogChat; + +namespace Ui { +class BlackBox; +} + +class BlackBox : public QDialog +{ + Q_OBJECT + +public: + explicit BlackBox(QWidget *parent = 0); + ~BlackBox(); + +protected slots: + void onConnect(); + void onButtonChat(); + +private: + Ui::BlackBox *ui; + + CDialogConnect *m_dlg_connect; + CDialogChat *m_dlg_chat; +}; + +#endif // BLACKBOX_H diff --git a/src/blackbox/blackbox.ui b/src/blackbox/blackbox.ui new file mode 100644 index 000000000..9072e879e --- /dev/null +++ b/src/blackbox/blackbox.ui @@ -0,0 +1,59 @@ + + + BlackBox + + + + 0 + 0 + 400 + 300 + + + + BlackBox + + + + + 40 + 40 + 75 + 23 + + + + Connect + + + + + + 130 + 40 + 75 + 23 + + + + Settings + + + + + + 40 + 80 + 75 + 23 + + + + Chat + + + + + + + diff --git a/src/blackbox/dialog_chat.cpp b/src/blackbox/dialog_chat.cpp new file mode 100644 index 000000000..1266eac00 --- /dev/null +++ b/src/blackbox/dialog_chat.cpp @@ -0,0 +1,21 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#include "dialog_chat.h" +#include "ui_dialog_chat.h" + +CDialogChat::CDialogChat(QWidget *parent) : + QDialog(parent), + ui(new Ui::CDialogChat) +{ + ui->setupUi(this); + ui->chatGeneral->textCursor().insertText("Testline"); + ui->chatGeneral->centerCursor(); +} + +CDialogChat::~CDialogChat() +{ + delete ui; +} diff --git a/src/blackbox/dialog_chat.h b/src/blackbox/dialog_chat.h new file mode 100644 index 000000000..3e72c1c4b --- /dev/null +++ b/src/blackbox/dialog_chat.h @@ -0,0 +1,27 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef DIALOG_CHAT_H +#define DIALOG_CHAT_H + +#include + +namespace Ui { +class CDialogChat; +} + +class CDialogChat : public QDialog +{ + Q_OBJECT + +public: + explicit CDialogChat(QWidget *parent = 0); + ~CDialogChat(); + +private: + Ui::CDialogChat *ui; +}; + +#endif // DIALOG_CHAT_H diff --git a/src/blackbox/dialog_chat.ui b/src/blackbox/dialog_chat.ui new file mode 100644 index 000000000..03acea211 --- /dev/null +++ b/src/blackbox/dialog_chat.ui @@ -0,0 +1,74 @@ + + + CDialogChat + + + + 0 + 0 + 400 + 300 + + + + Dialog + + + + + + QTabWidget::South + + + 1 + + + + General + + + + + 0 + 0 + 381 + 261 + + + + + + + Unicom + + + + + 0 + 0 + 381 + 261 + + + + + + + + + + Qt::Horizontal + + + + + PushButton + + + + + + + + + diff --git a/src/blackbox/dialog_connect.cpp b/src/blackbox/dialog_connect.cpp new file mode 100644 index 000000000..e12427805 --- /dev/null +++ b/src/blackbox/dialog_connect.cpp @@ -0,0 +1,61 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#include "dialog_connect.h" +#include "ui_dialog_connect.h" + +#include +#include +#include + +using namespace BlackMisc; + +CDialogConnect::CDialogConnect(QWidget *parent) : + QDialog(parent), m_hasComConnection(false), + ui(new Ui::CDialogConnect) +{ + ui->setupUi(this); + + connect(&comclient, SIGNAL(doError(QAbstractSocket::SocketError,QString)), this, SLOT(onError(QAbstractSocket::SocketError,QString))); + connect(&comclient, SIGNAL(doConnected()), this, SLOT(onClientConnected())); + connect(ui->bt_FSDConnect, SIGNAL(clicked()), this, SLOT(onFSDConnect())); + + QString address = "127.0.0.1"; + comclient.connectTo(address, 42000); +} + +CDialogConnect::~CDialogConnect() +{ + delete ui; +} + +void CDialogConnect::onFSDConnect() +{ + QByteArray message_data; + QDataStream out(&message_data, QIODevice::WriteOnly); + MSG_CONNECT_TO_VATSIM* msgConnect = new MSG_CONNECT_TO_VATSIM(); + + msgConnect->setHost(ui->m_host->text()); + msgConnect->setCallsign(ui->m_callsign->text()); + msgConnect->setUserID(ui->m_ID->text()); + msgConnect->setPassword(ui->m_password->text()); + msgConnect->setPort(ui->m_port->text().toUInt()); + msgConnect->setRealName(ui->m_name->text()); + + *msgConnect >> out; + + comclient.sendMessage(msgConnect->getID(), message_data); + delete msgConnect; +} + +void CDialogConnect::onError(QAbstractSocket::SocketError,QString) +{ + +} + +void CDialogConnect::onClientConnected() +{ + m_hasComConnection = true; +} diff --git a/src/blackbox/dialog_connect.h b/src/blackbox/dialog_connect.h new file mode 100644 index 000000000..c8f98001d --- /dev/null +++ b/src/blackbox/dialog_connect.h @@ -0,0 +1,36 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef DIALOG_CONNECT_H +#define DIALOG_CONNECT_H + +#include +#include + +namespace Ui { +class CDialogConnect; +} + +class CDialogConnect : public QDialog +{ + Q_OBJECT + +public: + explicit CDialogConnect(QWidget *parent = 0); + ~CDialogConnect(); + +protected slots: + void onFSDConnect(); + void onError(QAbstractSocket::SocketError, QString); + void onClientConnected(); + +private: + Ui::CDialogConnect *ui; + BlackMisc::CComClient comclient; + + bool m_hasComConnection; +}; + +#endif // DIALOG_CONNECT_H diff --git a/src/blackbox/dialog_connect.ui b/src/blackbox/dialog_connect.ui new file mode 100644 index 000000000..d6d1ba334 --- /dev/null +++ b/src/blackbox/dialog_connect.ui @@ -0,0 +1,171 @@ + + + CDialogConnect + + + + 0 + 0 + 286 + 279 + + + + Dialog + + + + + + Connect + + + + + + + 10 + + + + Host: + + + + + + + vatsim-germany.org + + + + + + + + 10 + + + + Port: + + + + + + + 6809 + + + + + + + + 10 + + + + Callsign: + + + + + + + DLH123 + + + + + + + + 10 + + + + ID: + + + + + + + Qt::Horizontal + + + + 31 + 20 + + + + + + + + 123456 + + + + + + + + 10 + + + + Password: + + + + + + + 123456 + + + + + + + + 10 + + + + Real Name: + + + + + + + Roland + + + + + + + + + + Connect + + + + + + + Cancel + + + + + + + + diff --git a/src/blackbox/main.cpp b/src/blackbox/main.cpp new file mode 100644 index 000000000..3957d6f65 --- /dev/null +++ b/src/blackbox/main.cpp @@ -0,0 +1,22 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#include "blackbox.h" +#include +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + BlackMisc::CApplicationContext myBlackApp; + BlackMisc::IContext::getInstance().getDebug()->create(); + + + BlackBox w; + w.show(); + + return a.exec(); +} diff --git a/src/blackcore/CMakeLists.txt b/src/blackcore/CMakeLists.txt new file mode 100644 index 000000000..13c37653c --- /dev/null +++ b/src/blackcore/CMakeLists.txt @@ -0,0 +1,18 @@ +FILE(GLOB blackcore_SOURCES *.cpp) +FILE(GLOB blackcore_HEADERS *.h) +SET(blackcore_HEADERS_QOBJECT + fsd_client.h) + +QT4_WRAP_CPP(blackcore_HEADERS_MOC ${blackcore_HEADERS_QOBJECT}) + +SOURCE_GROUP(QtGeneratedMocSrc FILES ${blackcore_HEADERS_MOC}) +SOURCE_GROUP (Headers FILES ${blackcore_HEADERS}) + +IF(WITH_STATIC) + ADD_LIBRARY(blackcore STATIC ${blackcore_SOURCES} ${blackcore_HEADERS_MOC}) +ELSE(WITH_STATIC) + ADD_LIBRARY(blackcore SHARED ${blackcore_SOURCES} ${blackcore_HEADERS_MOC}) +ENDIF(WITH_STATIC) + +TARGET_LINK_LIBRARIES(blackcore) +SET_TARGET_PROPERTIES(blackcore PROPERTIES PROJECT_LABEL "Library - BlackCore") \ No newline at end of file diff --git a/src/blackcore/constants.h b/src/blackcore/constants.h new file mode 100644 index 000000000..f26544b4f --- /dev/null +++ b/src/blackcore/constants.h @@ -0,0 +1,55 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef CONSTANTS_H +#define CONSTANTS_H + +#include "math.h" + +namespace BlackCore +{ + namespace Constants + { + //! Conversion from Degree to Radians + const double DegToRad = 4.0 * atan(1.0) / 180.0; + + //! Conversion from Radians to Degree + const double RadToDeg = 180.0 / (4.0 * atan(1.0)); + + //! Mathematical constant Pi + const double PI = 4.0 * atan(1.0); + + //! 2 * Pi + const double TwoPI = 2.0 * PI; + + //! Conversion from feet to meter + const double FeetToMeter = 0.3048; + + //! Conversion from meter to feed + const double MeterToFeet = 3.28084; + + //! Conversion from knots to meter/second + const double KnotsToMeterPerSecond = 0.5144444444; + + //! Equatorial radius of WGS84 ellipsoid (6378137 m) + const double EarthRadiusMeters = 6378137.0; + + //! Flattening of WGS84 ellipsoid (1/298.257223563). + const double Flattening = 1/298.257223563; + + //! First eccentricity squared + const double e2 = (Flattening * (2 - Flattening)); + + //! First eccentricity to the power of four + const double e4 = CMath::square(e2); + + const double e2m = CMath::square(1 - Flattening); + + const double e2absolute = abs(e2); + } + +} // namespace BlackCore + +#endif // CONSTANTS_H diff --git a/src/blackcore/ecef.cpp b/src/blackcore/ecef.cpp new file mode 100644 index 000000000..b36311e06 --- /dev/null +++ b/src/blackcore/ecef.cpp @@ -0,0 +1,250 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ +//! +//! This file incorporates work covered by the following copyright and +//! permission notice: +//! +//! Copyright (c) Charles Karney (2008-2011) and licensed +//! under the MIT/X11 License. For more information, see +//! http://geographiclib.sourceforge.net/ + +#include "blackcore/matrix_3d.h" +#include "blackcore/ned.h" +#include "blackcore/ecef.h" +#include "blackcore/math.h" +#include "blackcore/constants.h" + +namespace BlackCore +{ + +CEcef::CEcef() +{ +} + +CEcef::CEcef(double X, double Y, double Z) + : CVector3D(X, Y, Z) +{ +} + +CNed CEcef::toNED(const CVectorGeo &pos) +{ + CNed result; + + double angle = - ( pos.latitudeDegrees() * Constants::DegToRad ) - Constants::PI/2; + + CMatrix3D dcm1; + CMatrix3D dcm2; + CMatrix3D dcm3; + CMatrix3D DCM; + dcm1.zeros(); + dcm2.zeros(); + dcm3.zeros(); + DCM.zeros(); + + dcm1(0,0) = 1; + dcm1(1,1) = 1; + dcm1(1,2) = 0; + dcm1(2,1) = 0; + dcm1(2,2) = 1; + + dcm2(0,0) = cos( angle ); + dcm2(0,2) = -sin( angle ); + dcm2(1,1) = 1; + dcm2(2,0) = sin( angle ); + dcm2(2,2) = cos( angle ); + + angle = pos.longitudeDegrees() * Constants::DegToRad; + + dcm3(0,0) = cos(angle ); + dcm3(0,1) = sin(angle ); + dcm3(1,0) = -sin(angle ); + dcm3(1,1) = cos(angle ); + dcm3(2,2) = 1; + + DCM = dcm1 * dcm2 * dcm3; + + CVector3D tempResult = DCM * (*this); + + result.setNorth(tempResult.X()); + result.setEast(tempResult.Y()); + result.setDown(0); + result.setPosition(pos); + + return result; +} + +void CEcef::operator= (const CVector3D &rhs) +{ + v[0] = rhs.X(); + v[1] = rhs.Y(); + v[2] = rhs.Z(); +} + +CVectorGeo CEcef::toGeodetic() +{ + CVectorGeo result; + + double R = CMath::hypot(v[0], v[1]); + + double slam = 0; + double clam = 1; + + if (R) + { + slam = v[1] / R; + clam = v[0] / R; + } + + //! Calculate the distance to the earth + double h = CMath::hypot(R, v[2]); + + double sphi = 0; + double cphi = 0; + + double p = CMath::square(R / Constants::EarthRadiusMeters); + double q = Constants::e2m * CMath::square(v[2] / Constants::EarthRadiusMeters); + double r = (p + q - Constants::e4) / 6.0; + + if ( !(Constants::e4 * q == 0 && r <= 0) ) + { + //! Avoid possible division by zero when r = 0 by multiplying + //! equations for s and t by r^3 and r, resp. + + double S = Constants::e4 * p * q / 4; //! S = r^3 * s + double r2 = CMath::square(r); + double r3 = r * r2; + double disc = S * (2 * r3 + S); + double u = r; + + if (disc >= 0) + { + double T3 = S + r3; + /*! + Pick the sign on the sqrt to maximize abs(T3). This minimizes + loss of precision due to cancellation. The result is unchanged + because of the way the T is used in definition of u. + */ + T3 += T3 < 0 ? -sqrt(disc) : sqrt(disc); // T3 = (r * t)^3 + + //!N.B. cubicRootReal always returns the real root. cubicRootReal(-8) = -2. + double T = CMath::cubicRootReal(T3); + + //! T can be zero; but then r2 / T -> 0. + u += T + (T != 0 ? r2 / T : 0); + } + else + { + //! T is complex, but the way u is defined the result is real. + double ang = atan2(sqrt(-disc), -(S + r3)); + /*! + There are three possible cube roots. We choose the root which + avoids cancellation. Note that disc < 0 implies that r < 0. + */ + u += 2 * r * cos(ang / 3); + } + + //! This is garanteed positive + double V = sqrt(CMath::square(u) + Constants::e4 * q); + + /*! + Avoid loss of accuracy when u < 0. Underflow doesn't occur in + e4 * q / (v - u) because u ~ e^4 when q is small and u < 0. + */ + double uv = u < 0 ? Constants::e4 * q / (V - u) : u + V; //! u+v, guaranteed positive + + //! Need to guard against w going negative due to roundoff in uv - q. + double w = std::max(double(0), Constants::e2absolute * (uv - q) / (2 * V)); + + /*! + Rearrange expression for k to avoid loss of accuracy due to + subtraction. Division by 0 not possible because uv > 0, w >= 0. + */ + double k = uv / (sqrt(uv + CMath::square(w)) + w); + double k1 = k; + double k2 = k + Constants::e2; + double d = k1 * R / k2; + double H = CMath::hypot((v[2])/k1, R/k2); + + sphi = (v[2] / k1) / H; + cphi = (R / k2) / H; + + h = (1 - Constants::e2m/k1) * CMath::hypot(d, v[2]); + } + else //! e4 * q == 0 && r <= 0 + { + /*! + This leads to k = 0 (oblate, equatorial plane) and k + e^2 = 0 + (prolate, rotation axis) and the generation of 0/0 in the general + formulas for phi and h. using the general formula and division by 0 + in formula for h. So handle this case by taking the limits: + f > 0: z -> 0, k -> e2 * sqrt(q)/sqrt(e4 - p) + f < 0: R -> 0, k + e2 -> - e2 * sqrt(q)/sqrt(e4 - p) + */ + double zz = sqrt((Constants::e4 - p) / Constants::e2m); + double xx = sqrt( p ); + double H = CMath::hypot(zz,xx); + sphi = zz / H; + cphi = xx / H; + if (v[2] < 0) sphi = -sphi; // for tiny negative Z (not for prolate) + h = - Constants::EarthRadiusMeters * (Constants::e2m) * H / Constants::e2absolute; + } + + double lat = atan2(sphi, cphi) * Constants::RadToDeg; + + //! Negative signs return lon in [-180, 180). + double lon = -atan2(-slam, clam) * Constants::RadToDeg; + + result.setLongitudeDegrees(lon); + result.setLatitudeDegrees(lat); + result.setAltitude(h); + + return result; + + +/* + CVectorGeo result; + + double Xpow2plusYpow2 = CMath::square(v[0])+CMath::square(v[1]); + + if( Xpow2plusYpow2 + CMath::square(v[2]) < 25 ) { + + // This function fails near the geocenter region, so catch that special case here. + // Define the innermost sphere of small radius as earth center and return the + // coordinates 0/0/-EQURAD. It may be any other place on geoide's surface, + // the Northpole, Hawaii or Wentorf. This one was easy to code ;-) + + result.setLongitude( 0.0 ); + result.setLatitude( 0.0 ); + result.setAltitude( -Constants::EarthRadius ); + + return result; + + } + + double R = CMath::hypot(v[0], v[1]); + double p = CMath::square(R / Constants::EarthRadius); + double q = CMath::square(v[2] / Constants::EarthRadius)*(1-e2); + double r = 1/6.0*(p+q-e4); + double s = e4*p*q/(4*CMath::cubic(r)); + + if( s >= -2.0 && s <= 0.0 ) + s = 0.0; + + double t = pow(1+s+sqrt(s*(2+s)), 1/3.0); + double u = r*(1+t+1/t); + double vt = sqrt(u*u+e4*q); + double w = e2*(u+vt-q)/(2*vt); + double k = sqrt(u+vt+w*w)-w; + double D = k*R/(k+e2); + + result.setLongitude(2*atan2(v[1], v[0]+R)*RadToDeg); + double hypot = CMath::hypot(D, v[2]); //sqrt(D*D+v[2]*v[2]); + result.setLatitude(2*atan2(v[2], D+hypot)*RadToDeg); + result.setAltitude((k+e2-1)*hypot/k*M_TO_FT); + + return result;*/ +} + +} // namespace BlackCore diff --git a/src/blackcore/ecef.h b/src/blackcore/ecef.h new file mode 100644 index 000000000..d2b794851 --- /dev/null +++ b/src/blackcore/ecef.h @@ -0,0 +1,42 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef ECEF_H +#define ECEF_H + +#include "vector_3d.h" + +namespace BlackCore +{ + +class CNed; +class CVectorGeo; + +class CEcef : public CVector3D +{ +public: + CEcef(); + CEcef(double X, double Y, double Z); + + //! Converts this velocity vector into the NED format + /*! + \param pos This position is needed for correct calculation + \return velocity in NED coordinate system + */ + CNed toNED(const CVectorGeo &pos); + + //! Converts this position vector into the geodetic format + /*! + \return Position in latitude, longitude and altitude + */ + CVectorGeo toGeodetic(); + + //! Assignment operator + void operator= (const CVector3D &rhs); +}; + +} // namespace BlackCore + +#endif // ECEF_H diff --git a/src/blackcore/fsd_client.cpp b/src/blackcore/fsd_client.cpp new file mode 100644 index 000000000..9558d5681 --- /dev/null +++ b/src/blackcore/fsd_client.cpp @@ -0,0 +1,189 @@ +#include +#include + +#include +#include + +#include +#include + +namespace FSD +{ + + using namespace BlackMisc; + + + CFSDClient::CFSDClient() + : m_tcp_socket(NULL), m_port(0), m_simType(FSD::SIM_UNKNOWN) + { + init(); + } + + void CFSDClient::connectTo(const QString &host, quint16 port) + { + m_host = host; + m_port = port; + + if ( isConnected() ) + return; + + bDebug << "Connecting to FSD server: " << m_host << ":" << m_port; + + m_tcp_socket->connectToHost(m_host, m_port); + } + + void CFSDClient::disconnectFrom() + { + bDebug << "Disconnecting from host."; + + m_tcp_socket->disconnectFromHost(); + m_port = 0; + m_host.clear(); + } + + void CFSDClient::reconnect() + { + + } + + void CFSDClient::updateClientInfo(TClientInfo &clientInfo ) + { + m_host = clientInfo.m_host; + m_port = clientInfo.m_port; + m_password = clientInfo.m_password; + m_callsign = clientInfo.m_callsign; + m_userid = clientInfo.m_userid; + m_simType = clientInfo.m_simType; + m_realName = clientInfo.m_realName; + } + + bool CFSDClient::isConnected() + { + return m_tcp_socket->state() == QAbstractSocket::ConnectedState; + } + + QString CFSDClient::getErrorMessage(QAbstractSocket::SocketError error) + { + return QString("Unknown"); + } + + void CFSDClient::onConnected() + { + bDebug << "Connected successfully to remote host."; + bDebug << "Sending #AP now..."; + + QString line; + + FSD_MSG_AddPilot addPilot; + addPilot.setSource(m_callsign); + addPilot.setDest("SERVER"); + addPilot.setUserID(m_userid); + addPilot.setPassword(m_password); + addPilot.setSimulator((quint16)m_simType); + addPilot.setRealName(m_realName); + + QTextStream stream(&line); + addPilot >> stream; + + sendMessage(line); + + emit doConnected(); + } + + void CFSDClient::onDisconnected() + { + bDebug << "Disconnected successfully from remote host."; + emit doDisconnected(); + } + + void CFSDClient::onError(QAbstractSocket::SocketError error) + { + + if ( error != 0 ) + { + bError << "Received socket error: " << error << " - Disconnecting..."; + } + + disconnectFrom(); + emit doError(error, getErrorMessage(error) ); + } + + void CFSDClient::onReceivingData() + { + QTextStream input(m_tcp_socket); + QString line; + + do + { + line = input.readLine(); + if (!line.isNull()) + processLine(line); + } while(!line.isNull()); + } + + bool CFSDClient::sendMessage(const QString &message) + { + if (!isConnected()) + { + bError << "Cannot send data in disconnected state!"; + return false; + } + + qint64 message_size = message.size(); + + qint64 bytes = m_tcp_socket->write(message.toAscii()); + if (bytes < 0 || bytes != message_size) + { + bWarning << "Error writing to socket!"; + return false; + } + + return true; + } + + void CFSDClient::init() + { + m_tcp_socket = new QTcpSocket(this); + bAssert(m_tcp_socket); + + bAssert ( QObject::connect( m_tcp_socket, SIGNAL( connected() ), this, SLOT( onConnected() ) ) ); + bAssert ( QObject::connect( m_tcp_socket, SIGNAL( disconnected() ), this, SLOT( onDisconnected() ) ) ); + bAssert ( QObject::connect( m_tcp_socket, SIGNAL( error(QAbstractSocket::SocketError) ), this, SLOT( onError(QAbstractSocket::SocketError) ) ) ); + + bAssert ( QObject::connect( m_tcp_socket, SIGNAL( readyRead() ), this, SLOT( onReceivingData() ) ) ); + + registerMessages(); + } + + void CFSDClient::registerMessages() + { + REGISTER_MESSAGE(FSD::FSD_MSG_TextMessage, #TM); + } + + void CFSDClient::processLine(QString &line) + { + QString header; + for (int ii = 0; ii < MAX_FSD_HEADERS; ii++) + { + QString head = FSD::Headers[ii]; + if(line.startsWith( head )) + { + header = FSD::Headers[ii]; + line.remove(0, FSD::Headers[ii].length()); + } + } + + if (header.isEmpty()) + return; + + QTextStream stream(&line); + IMessage* fsd_message = CMessageFactory::getInstance().create(header); + bAssert(fsd_message); + *fsd_message << stream; + + CMessageDispatcher::getInstance().append(fsd_message); + } + + + +} // namespace FSD diff --git a/src/blackcore/fsd_client.h b/src/blackcore/fsd_client.h new file mode 100644 index 000000000..5cf8746a2 --- /dev/null +++ b/src/blackcore/fsd_client.h @@ -0,0 +1,126 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef FSD_CLIENT_H +#define FSD_CLIENT_H + +#include +#include +#include +#include + +#include + + +namespace FSD +{ + +typedef struct { + QString m_host; + quint16 m_port; + QString m_callsign; + QString m_userid; + QString m_password; + FSD::SimulatorType m_simType; + QString m_realName; +} TClientInfo; + +class CFSDClient : public QObject +{ + Q_OBJECT + +public: + CFSDClient(); + + void connectTo(const QString &host, quint16 port); + void disconnectFrom(); + void reconnect(); + + void updateClientInfo(TClientInfo &clientInfo ); + + TClientInfo& clientInfo(); + + bool isConnected(); + + //! Returns a human readable description of the last error that occurred. + QString getErrorMessage(QAbstractSocket::SocketError error); + + bool sendMessage(const QString &message); + + ////////////////////////////////// + // FSD specific senders functions + ////////////////////////////////// + + void sendText ( QString &message); + + void sendTextonRadios ( QList &frequencies, QString &message); + + void sendClientQuery ( TQueryType type, QString &callsign); + + void sendClientQueryReponse ( TQueryType type, QString &data); + + void sendPilotPosition ( TPositionMessage *posMessage ); + + void sendFlightPlan (); + +signals: + + //! emitted when new data were received + void doReceivedMessage(QString &messageID, QByteArray &message); + + //! emitted when cliebt connected + void doConnected(); + + //! emitted when client disconnected + void doDisconnected(); + + //! emitted when an error has occured + void doError(QAbstractSocket::SocketError error, const QString& error_message); + +protected slots: + + //! Call this slot . + /*! + \param data Reference to the raw byte data to be sent. + \return Returns true if sending was successfull, otherwise false. + */ + void onConnected(); + void onDisconnected(); + void onError(QAbstractSocket::SocketError error); + void onReceivingData(); + +protected: + + void sendAddPilot(); + + + +private: + + CFSDClient( const CFSDClient& other); + const CFSDClient& operator = ( const CFSDClient& other); + + void init(); + void registerMessages(); + + void processLine(QString &line); + + QTcpSocket* m_tcp_socket; + + QString m_host; + quint16 m_port; + QString m_callsign; + QString m_userid; + QString m_password; + FSD::SimulatorType m_simType; + QString m_realName; + + QString m_last_error; + +}; + +} // namespace FSD + +#endif // FSD_CLIENT_H diff --git a/src/blackcore/fsd_messages.cpp b/src/blackcore/fsd_messages.cpp new file mode 100644 index 000000000..6b4b59973 --- /dev/null +++ b/src/blackcore/fsd_messages.cpp @@ -0,0 +1,97 @@ +#include "blackmisc/debug.h" + +#include "blackcore/fsd_messages.h" + +using namespace BlackMisc; + +namespace FSD +{ + qint32 FSD_MSG::unpack(const QString &line, QStringVector &tokens) + { + const QString separator(":"); + + int begin = 0; + int end = 0; + int token_position = 0; + + qint32 count = line.count(separator); + tokens.resize(count+1); + + while ( (end = line.indexOf(separator, begin, Qt::CaseInsensitive)) != -1) + { + if (token_position < tokens.size()) + { + tokens.replace(token_position, line.mid(begin, end - begin)); + begin = end + separator.size(); + ++token_position; + } + else + { + bError << "Cannot split message. Vector is to small"; + return -1; + } + } + if (begin < line.size() && token_position < tokens.size()) + { + tokens.replace(token_position, line.mid(begin)); + } + else + return -1; + + return token_position + 1; + } + + QString FSD_MSG::pack(const QStringVector &tokens) const + { + QString line; + int length = 0; + const QString separator(":"); + const QString line_feed("\r\n"); + const int size = tokens.size(); + + // Calculate the total message length + for (int ii = 0; ii < size; ++ii) + length += tokens.at(ii).size(); + + // Add the size of the separator + length += separator.size() * (size - 1); + + // Add size of the line feed + length += line_feed.size(); + + // Add size of message ID + length += getID().size(); + + if (length == 0) + return line; + + line.reserve(length); + + line = getID(); + for (int ii = 0; ii < size; ++ii) + { + if (ii) + line += separator; + line += tokens.at(ii); + } + + line += line_feed; + + return line; + } + + QTextStream& FSD_MSG_Plane_Position::operator<< ( QTextStream& in) + { + QString message = in.readAll(); + qint32 size = unpack(message, m_message_tokens); + bAssert ( size == 10 ); + + return in; + } + + QTextStream& FSD_MSG_Plane_Position::operator>> (QTextStream& out) const + { + out << pack(m_message_tokens); + return out; + } +} diff --git a/src/blackcore/fsd_messages.h b/src/blackcore/fsd_messages.h new file mode 100644 index 000000000..8711b98fd --- /dev/null +++ b/src/blackcore/fsd_messages.h @@ -0,0 +1,157 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef FSD_MESSAGES_H +#define FSD_MESSAGES_H + +#include "blackmisc/message_system.h" + +#define VATSIM_PROTOCOL_REV 9 + +// Qt includes +#include +#include + +typedef QVector QStringVector; + +namespace FSD +{ + class FSD_MSG : public BlackMisc::IMessage + { + public: + FSD_MSG(QString& id) : IMessage(id) + { + + } + + void setSource(const QString &source) {m_source = source; } + void setDest(const QString &destination) {m_destination = destination; } + + protected: + qint32 unpack(const QString &line, QStringVector &tokens); + QString pack(const QStringVector &tokens) const; + + QString m_destination; + QString m_source; + }; + + class FSD_MSG_AddPilot : public FSD_MSG + { + public: + FSD_MSG_AddPilot() : FSD_MSG(QString("#AP")), m_revision(VATSIM_PROTOCOL_REV), + m_rating(1) + { + } + + void setUserID(const QString &userID) { m_userID = userID; } + void setPassword(const QString &password) { m_password = password; } + void setSimulator(const quint16 &simulator) { m_simulator = simulator; } + void setRealName(const QString &name) { m_realName = name; } + + virtual QDataStream& operator<< (QDataStream& in) { return in; } + virtual QDataStream& operator>> (QDataStream& out) const { return out; } + + virtual QTextStream& operator<< ( QTextStream& in) + { return in; } + virtual QTextStream& operator>> (QTextStream& out) const + { + QStringVector tokens; + tokens << m_source << m_destination << m_userID << m_password; + tokens << QString("%1").arg(m_rating) << QString("%1").arg(m_revision); + tokens << QString("%1").arg(m_simulator) << m_realName; + out << pack(tokens); + return out; + } + + private: + + QString m_userID; + QString m_password; + quint16 m_rating; + quint16 m_revision; + quint16 m_simulator; + QString m_realName; + }; + + class FSD_MSG_TextMessage : public FSD_MSG + { + public: + FSD_MSG_TextMessage() : FSD_MSG(QString("#TM")) + { + } + + virtual QDataStream& operator<< (QDataStream& in) { return in; } + virtual QDataStream& operator>> (QDataStream& out) const { return out;} + + virtual QTextStream& operator<< ( QTextStream& in) + { + QString message = in.readAll(); + QStringVector tokens; + + //tokens.resize(3); + unpack(message, tokens); + m_source = tokens.at(0); + m_destination = tokens.at(1); + int size = tokens.size(); + QString m_textmessage; + for ( int ii = 2; ii < tokens.size(); ++ii) + m_textmessage += tokens.at(ii); + bInfo << m_textmessage; + return in; + } + + virtual QTextStream& operator>> (QTextStream& out) const + { + QStringVector tokens; + tokens << m_source << m_destination; + out << pack(tokens); + return out; + } + }; + + class FSD_MSG_Plane_Position : public FSD_MSG + { + public: + + FSD_MSG_Plane_Position() : FSD_MSG(QString("@")) + { + m_message_tokens.resize(10); + } + + inline QString SquawkMode() const { return m_message_tokens.at(0); } + inline QString Callsign() const { return m_message_tokens.at(1); } + inline QString Squawk() const { return m_message_tokens.at(2); } + inline quint16 Rating() const { return m_message_tokens.at(3).toUInt(); } + inline double Latitude() const { return m_message_tokens.at(4).toDouble(); } + inline double Longitude() const { return m_message_tokens.at(5).toDouble(); } + inline double Altitude() const { return m_message_tokens.at(6).toDouble(); } + inline qint32 Speed() const { return m_message_tokens.at(7).toInt(); } + inline quint32 PBH() const { return m_message_tokens.at(8).toUInt(); } + inline qint32 AltDiff() const { return m_message_tokens.at(9).toInt(); } + + inline void setSquawkMode( const QString &squawk_mode) { m_message_tokens.replace(0, squawk_mode); } + inline void setCallsign ( const QString &callsign) { m_message_tokens.replace(1, callsign); } + inline void setSquawk ( const QString &squawk) { m_message_tokens.replace(2, squawk); } + inline void setRating ( const quint16 rating) { m_message_tokens.replace(3, QString("%1").arg(rating)); } + inline void setLatitude ( const double latitude) { m_message_tokens.replace(4, QString("%1").arg(latitude)); } + inline void setLongitude ( const double longitude) { m_message_tokens.replace(5, QString("%1").arg(longitude)); } + inline void setAltitude ( const double altitude) { m_message_tokens.replace(6, QString("%1").arg(altitude)); } + inline void setSpeed ( const qint32 speed) { m_message_tokens.replace(7, QString("%1").arg(speed)); } + inline void setPBH ( const quint32 pbh) { m_message_tokens.replace(8, QString("%1").arg(pbh)); } + inline void setAltDiff ( const qint32 altdiff) { m_message_tokens.replace(9, QString("%1").arg(altdiff)); } + + virtual QTextStream& operator<< ( QTextStream& in); + virtual QTextStream& operator>> (QTextStream& out) const; + + virtual QDataStream& operator<< (QDataStream& in) { return in; } + virtual QDataStream& operator>> (QDataStream& out) const { return out;} + + private: + QStringVector m_message_tokens; + }; + +} // namespace FSD + +#endif // FSD_MESSAGES_H diff --git a/src/blackcore/fsd_protocol.h b/src/blackcore/fsd_protocol.h new file mode 100644 index 000000000..dd877b1f4 --- /dev/null +++ b/src/blackcore/fsd_protocol.h @@ -0,0 +1,61 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef FSD_PROTOCOL_H +#define FSD_PROTOCOL_H + +#include + +namespace FSD +{ + enum SimulatorType { + SIM_UNKNOWN = -1, + }; + + typedef enum { + Query_FP, + Query_Frequency, + Query_Server, + Query_RealName, + Query_isATC, + Query_Capabilities, + Query_IP + } TQueryType; + + typedef enum { + TMode_Standby = 'S', + TMode_Charly = 'N', + TMode_Ident = 'Y' + } TTransponderMode; + + typedef struct { + TTransponderMode transponderMode; + quint16 squawk; + quint8 rating; + double latitude; + double longitude; + qint32 altitude; + qint32 groundSpeed; + double pitch; + double bank; + double heading; + qint32 diffPressureTrueAlt; + } TPositionMessage; + + + const QString Headers[] = { + "@", + "%", + "#AA", + "#AP", + "#DA", + "#DP", + "#TM" + }; + +#define MAX_FSD_HEADERS 7 +} + +#endif // FSD_PROTOCOL_H diff --git a/src/blackcore/interpolator.cpp b/src/blackcore/interpolator.cpp new file mode 100644 index 000000000..4f4a09040 --- /dev/null +++ b/src/blackcore/interpolator.cpp @@ -0,0 +1,155 @@ +#include +#include "blackcore/matrix_3d.h" +#include "blackcore/vector_geo.h" +#include "blackcore/math.h" +#include "blackcore/interpolator.h" +#include "blackcore/constants.h" + +namespace BlackCore +{ + +CInterpolator::CInterpolator() + : m_state_begin(NULL), m_state_end(NULL) +{ + m_time.start(); +} + +CInterpolator::~CInterpolator() +{ + delete m_state_begin; + delete m_state_end; +} + +void CInterpolator::initialize() +{ + +} + +void CInterpolator::pushUpdate(CVectorGeo pos, double groundVelocity, double heading, double pitch, double bank) +{ + CNed vNED; + + if ( m_state_begin == NULL ) + { + m_state_begin = new TPlaneState(); + + m_state_begin->position = pos.toCartesian(); + m_state_begin->orientation.heading = heading*Constants::DegToRad; + m_state_begin->orientation.pitch = pitch*Constants::DegToRad; + m_state_begin->orientation.bank = bank*Constants::DegToRad; + m_state_begin->groundspeed = groundVelocity * Constants::KnotsToMeterPerSecond; + + vNED.setNorth( cos(m_state_begin->orientation.heading)*m_state_begin->groundspeed ); + vNED.setEast( sin(m_state_begin->orientation.heading)*m_state_begin->groundspeed ); + vNED.setDown(0); + vNED.setPosition(pos); + + m_state_begin->velocity = vNED.toECEF(); + + + m_state_begin->timestamp = 0; + return; + } + else + { + stateNow(m_state_begin); + } + + if ( m_state_end == NULL ) + { + m_state_end = new TPlaneState(); + } + m_state_end->reset(); + + m_state_end->timestamp = m_time.elapsed(); + + m_state_end->position = pos.toCartesian(); + m_state_end->orientation.heading = normalizeRadians(heading*Constants::DegToRad); + m_state_end->orientation.pitch = normalizeRadians(pitch*Constants::DegToRad); + m_state_end->orientation.bank = normalizeRadians(bank*Constants::DegToRad); + m_state_end->groundspeed = groundVelocity*Constants::KnotsToMeterPerSecond; + + vNED.setNorth( cos(m_state_end->orientation.heading)*m_state_end->groundspeed ); + vNED.setEast( sin(m_state_end->orientation.heading)*m_state_end->groundspeed ); + vNED.setDown(0); + vNED.setPosition(pos); + m_state_end->velocity = vNED.toECEF(); + + std::cout << " Interpolator End velocity: " << std::endl; + vNED.print(); + std::cout << std::endl; + + m_timeEnd = 5; + + double m_TFpow4 = CMath::cubic(m_timeEnd) * m_timeEnd; + + m_a = m_state_begin->velocity * CMath::square(m_timeEnd); + m_a += m_state_end->velocity * CMath::square(m_timeEnd); + + m_a += m_state_begin->position * m_timeEnd * 2; + m_a -= m_state_end->position * m_timeEnd * 2; + m_a *= 6; + m_a /= m_TFpow4; + + m_b = m_state_begin->velocity * CMath::cubic(m_timeEnd) * (-2) - m_state_end->velocity * CMath::cubic(m_timeEnd); + m_b = m_b - m_state_begin->position * CMath::square(m_timeEnd) * 3 + m_state_end->position * CMath::square(m_timeEnd) * 3; + m_b = m_b * 2 / ( m_TFpow4 ); +} + +bool CInterpolator::isValid() +{ + return (m_state_begin && m_state_end); +} + +bool CInterpolator::stateNow(TPlaneState *state) +{ + if ( !isValid() ) + return false; + + double time = 5; + + /*! + Plane Position + */ + + double timePow2 = CMath::square(time); + double timePow3 = CMath::cubic(time); + + CEcef pos; + pos = m_b*3*timePow2*m_timeEnd + m_a * timePow3 * m_timeEnd - m_b * 3 * time * CMath::square(m_timeEnd) - m_a * time* CMath::cubic(m_timeEnd); + pos += m_state_begin->position*(-6)*time + m_state_begin->position*6*m_timeEnd + m_state_end->position*6*time; + pos /= 6*m_timeEnd; + + state->position = pos; + + CEcef vel; + vel.zeros(); + vel = m_a * ( 3 * m_timeEnd * CMath::square(time) - CMath::cubic(m_timeEnd)); + vel += m_b * ( 6 * m_timeEnd * time - 3 * CMath::square(m_timeEnd)) + (m_state_end->position - m_state_begin->position) * 6; + vel /= 6*m_timeEnd; + + state->velocity = vel; + state->velNED = vel.toNED(pos.toGeodetic()); + + /*! + Plane Orientation + */ + + double vEast = state->velNED.East(); + double vNorth = state->velNED.North(); + double fraction = vNorth / vEast; + + double heading = atan2 (vNorth, vEast); + + state->orientation.heading = heading * Constants::RadToDeg; + + return true; + +} + +double CInterpolator::normalizeRadians(double radian) +{ + return radian - Constants::TwoPI * floor(0.5 + radian / Constants::TwoPI); +} + +} // namespace BlackCore diff --git a/src/blackcore/interpolator.h b/src/blackcore/interpolator.h new file mode 100644 index 000000000..b19e41b9f --- /dev/null +++ b/src/blackcore/interpolator.h @@ -0,0 +1,79 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef INTERPOLATOR_H +#define INTERPOLATOR_H + +#include + +#include "blackcore/vector_geo.h" +#include +#include "blackcore/vector_3d.h" +#include "blackcore/ned.h" +#include "blackcore/ecef.h" +#include "blackcore/constants.h" + +namespace BlackCore +{ + +typedef struct +{ + double heading; + double pitch; + double bank; + +} TOrientation; + +typedef struct +{ + void reset() + { + } + + qint64 timestamp; + CEcef position; + TOrientation orientation; + double groundspeed; + CVector3D velocity; + CNed velNED; + +} TPlaneState; + +class CInterpolator +{ +public: + CInterpolator(); + virtual ~CInterpolator(); + + void initialize(); + + void pushUpdate(CVectorGeo pos, double groundVelocity, double heading, double pitch, double bank); + + bool isValid(); + + + + bool stateNow(TPlaneState *state); +private: + double normalizeRadians(double radian); + + + QElapsedTimer m_time; + TPlaneState *m_state_begin; + TPlaneState *m_state_end; + + bool m_valid; + + CVector3D m_a; + CVector3D m_b; + + double m_timeEnd; + double m_timeBegin; + +}; + +} // namespace BlackCore + +#endif // INTERPOLATOR_H diff --git a/src/blackcore/math.cpp b/src/blackcore/math.cpp new file mode 100644 index 000000000..c2b81dd94 --- /dev/null +++ b/src/blackcore/math.cpp @@ -0,0 +1,33 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#include // std::max + +#include "blackcore/math.h" + +namespace BlackCore { + +double CMath::hypot(double x, double y) +{ + x = abs(x); + y = abs(y); + + double max = std::max(x,y); + double min = std::min(x,y); + + double r = min/max; + + return max * sqrt(1 + r*r); +} + +double CMath::cubicRootReal(const double x) +{ + double result; + result = std::pow(std::abs(x), (double)1/3); + + return x < 0 ? -result : result; +} + +} // namespace BlackCore \ No newline at end of file diff --git a/src/blackcore/math.h b/src/blackcore/math.h new file mode 100644 index 000000000..e24db691d --- /dev/null +++ b/src/blackcore/math.h @@ -0,0 +1,56 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef MATH_H +#define MATH_H + +namespace BlackCore +{ + +class CMath +{ +public: + //! Calculates the hypotenuse of x and y without overflow + /*! + \param x + \param y + */ + static double hypot(double x, double y); + + //! Calculates the square of x + /*! + \param x + \return x^2 + */ + static inline double square(const double x) + { + return x*x; + } + + //! Calculates x to the power of three + /*! + \param x + \return x^3 + */ + static inline double cubic(const double x) + { + return x*x*x; + } + + //! Calculates the real cubic root + /*! + \param x + \param y + \return Returns the real part of the solution + */ + static double cubicRootReal(const double x); + +private: + CMath() {} +}; + +} // namespace BlackCore + +#endif // MATH_H diff --git a/src/blackcore/matrix_3d.cpp b/src/blackcore/matrix_3d.cpp new file mode 100644 index 000000000..7494e0a6c --- /dev/null +++ b/src/blackcore/matrix_3d.cpp @@ -0,0 +1,255 @@ +#include +#include "blackmisc/debug.h" +#include "blackcore/vector_3d.h" +#include "blackcore/matrix_3d.h" + +/* TODO + * +class Vector2D +{ +private: + Vector data;//der macht copy-ctor, dtor und op= +public: + class Zeilenproxy + { + private: + Vector2D& v2d; + int zeile; + public: + Zeilenproxy(Vector2D& _v2d,int _y) + :v2d(_v2d),y(_y) + { + } + double& operator[](int x) + { + return v2d.data[y*SIZEX+x];//kacke, nur demo + } + } + ZeilenProxy operator[](int y) + { + return Zeilenproxy(*this,y); + } +}; +*/ + +namespace BlackCore +{ + +CMatrix3D::CMatrix3D() +{ + zeros(); +} + +CMatrix3D::CMatrix3D(const CMatrix3D & other) +{ + zeros(); + for(int i=0; i<3; i++) + { + for(int j=0; j<3; j++) + { + m[i][j] = other.getElement(i, j); + } + } +} + +void CMatrix3D::random() +{ + +} + +double CMatrix3D::determinant() +{ + double determinant = m[0][0]*m[1][1]*m[2][2] + + m[0][1]*m[1][2]*m[2][0] + + m[0][2]*m[1][0]*m[2][1] - + m[0][1]*m[1][0]*m[2][2] - + m[0][2]*m[1][1]*m[2][0] - + m[0][0]*m[1][2]*m[2][1]; + + return determinant; +} + +CMatrix3D CMatrix3D::inverse() +{ + CMatrix3D result; + double det = determinant(); + + if (!det) + return result; + + double invdet = 1 / determinant(); + + result.m[0][0] = ( m[1][1]*m[2][2] - m[1][2]*m[2][1] ) * invdet; + result.m[0][1] = ( - m[0][1]*m[2][2] + m[0][2]*m[2][1] ) * invdet; + result.m[0][2] = ( m[0][1]*m[1][2] - m[0][2]*m[1][1] ) * invdet; + result.m[1][0] = ( - m[1][0]*m[2][2] + m[1][2]*m[2][0] ) * invdet; + result.m[1][1] = ( m[0][0]*m[2][2] - m[0][2]*m[2][0] ) * invdet; + result.m[1][2] = ( - m[0][0]*m[1][2] + m[0][2]*m[1][0] ) * invdet; + result.m[2][0] = ( m[1][0]*m[2][1] - m[1][1]*m[2][0] ) * invdet; + result.m[2][1] = ( - m[0][0]*m[2][1] + m[0][1]*m[2][0] ) * invdet; + result.m[2][2] = ( m[0][0]*m[1][1] - m[0][1]*m[1][0] ) * invdet; + + return result; +} + +void CMatrix3D::zeros() +{ + for(int i=0; i<3; ++i) + { + for(int j=0; j<3; ++j) + { + m[i][j] = 0; + } + } +} + +void CMatrix3D::print() +{ + std::cout << m[0][0] << " " << m[0][1] << " " << m[0][2] << std::endl; + std::cout << m[1][0] << " " << m[1][1] << " " << m[1][2] << std::endl; + std::cout << m[2][0] << " " << m[2][1] << " " << m[2][2] << std::endl; +} + +double CMatrix3D::getElement(qint8 row, qint8 column) const +{ + bAssert (row < 3 || column < 3); + + return m[row][column]; +} + +void CMatrix3D::setElement(qint8 row, qint8 column, double value) +{ + bAssert (row < 3 || column < 3); + + m[row][column] = value; +} + +CMatrix3D & CMatrix3D::operator +=(const CMatrix3D &rhs) +{ + for(int i=0; i<3; ++i) + { + for(int j=0; j<3; ++j) + { + m[i][j] += rhs.getElement(i, j); + } + } + return *this; +} + +CMatrix3D & CMatrix3D::operator -=(const CMatrix3D &rhs) +{ + for(int i=0; i<3; ++i) + { + for(int j=0; j<3; ++j) + { + m[i][j] -= rhs.getElement(i, j); + } + } + return *this; +} + +CMatrix3D& CMatrix3D::operator = (const CMatrix3D &rhs) +{ + if (this != &rhs) + { + for(int i=0; i<3; ++i) + { + for(int j=0; j<3; ++j) + { + m[i][j] = rhs.getElement(i, j); + } + } + } + return *this; +} + +CMatrix3D CMatrix3D::operator + (const CMatrix3D &rhs) +{ + CMatrix3D helper = *this; + helper += rhs; + return helper; +} + +CMatrix3D CMatrix3D::operator - (const CMatrix3D &rhs) +{ + CMatrix3D helper = *this; + helper -= rhs; + return helper; +} + +bool CMatrix3D::operator == (const CMatrix3D &rhs) +{ + bool isEqual = true; + for(int i=0; i<3 && isEqual; ++i) + { + for(int j=0; j<3 && isEqual; ++j) + { + isEqual = (m[i][j] == rhs.getElement(i, j)); + } + } + return isEqual; +} + +bool CMatrix3D::operator != (const CMatrix3D &rhs) +{ + return !(*this == rhs); +} + +CMatrix3D & CMatrix3D::operator *= (const CMatrix3D &rhs) +{ + CMatrix3D helper(*this); + for(qint32 column = 0; column < 3; ++column) + { + for(qint32 row = 0; row < 3; ++row ) + { + m[row][column] = helper.getElement(row,0) * rhs.getElement(0, column); + for(qint32 line = 1; line < 3; ++line) + { + m[row][column] += helper.getElement(row,line) * rhs.getElement(line, column); + } + } + } + return *this; +} + +CMatrix3D CMatrix3D::operator * (const CMatrix3D &rhs) +{ + CMatrix3D helper(*this); + helper *= rhs; + return helper; +} + +CVector3D CMatrix3D::operator * ( const CVector3D &rhs) +{ + CVector3D result; + for (qint32 i = 0; i < 3; ++i) + { + for (qint32 j = 0; j < 3; ++j) + { + result.v[i] += m[i][j] * rhs.v[j]; + } + } + + return result; +} + +CEcef CMatrix3D::operator * ( const CEcef &rhs) +{ + CEcef result; + for (qint32 i = 0; i < 3; ++i) + { + for (qint32 j = 0; j < 3; ++j) + { + result.v[i] += m[i][j] * rhs.v[j]; + } + } + + return result; +} + +double& CMatrix3D::operator() (const qint8 row, const qint8 column) +{ + return m[row][column]; +} + +} // namespace BlackCore diff --git a/src/blackcore/matrix_3d.h b/src/blackcore/matrix_3d.h new file mode 100644 index 000000000..fa66d8b91 --- /dev/null +++ b/src/blackcore/matrix_3d.h @@ -0,0 +1,86 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef MATRIX_3D_H +#define MATRIX_3D_H + +#include "blackcore/vector_3d.h" +#include "blackcore/ecef.h" + +namespace BlackCore +{ + +class CMatrix3D +{ +public: + CMatrix3D(); + + CMatrix3D(const CMatrix3D & other); + + /*! + Basic Matrix functions + */ + + //! Fills the matrix with random elements + void random(); + + //! Calculates the determinant of the matrix + double determinant(); + + //! Returns the inverse matrix + CMatrix3D inverse(); + + //! Sets all elements to zero + void zeros(); + + //! Prints the matrix to stdout + void print(); + + //! Returns an element + /*! + \param row Specifies elements row + \param column Specifies elements column + \return Returns element of [row, column] + */ + double getElement(qint8 row, qint8 column) const; + + //! Sets a matrix element + /*! + \param row Specifies elements row + \param column Specifies elements column + \param value Specifies the new elements value + */ + void setElement(qint8 row, qint8 column, double value); + + /*! + Operators + */ + + CMatrix3D & operator +=(const CMatrix3D &rhs); + CMatrix3D & operator -=(const CMatrix3D &rhs); + + CMatrix3D & operator = (const CMatrix3D &rhs); + + CMatrix3D operator +(const CMatrix3D &rhs); + CMatrix3D operator -(const CMatrix3D &rhs); + + bool operator ==(const CMatrix3D &rhs); + bool operator !=(const CMatrix3D &rhs); + + CMatrix3D & operator *=(const CMatrix3D &rhs); + CMatrix3D operator *(const CMatrix3D &rhs); + + CVector3D operator * ( const CVector3D &rhs); + CEcef operator * ( const CEcef &rhs); + + double& operator() (const qint8 row, const qint8 column); + +private: + double m[3][3]; +}; + +} // namespace BlackCore + +#endif // MATRIX_3D_H diff --git a/src/blackcore/multiplayer.cpp b/src/blackcore/multiplayer.cpp new file mode 100644 index 000000000..66f04026d --- /dev/null +++ b/src/blackcore/multiplayer.cpp @@ -0,0 +1,96 @@ +#include +#include +#include "blackcore/plane.h" +#include "blackcore/multiplayer.h" + +namespace BlackCore { + +CMultiPlayer::CMultiPlayer() + : m_isRunning(false) +{ + registerMessageFunction(this, &CMultiPlayer::onPositionUpdate); + + m_simulator = ISimulator::createDriver(ISimulator::FSX); +} + +void CMultiPlayer::start() +{ + if (m_isRunning) + return; + + m_isRunning = true; +} + +void CMultiPlayer::stop() +{ + if (!m_isRunning) + return; + + m_isRunning = false; +} + +void CMultiPlayer::run() +{ + TPlaneManager::iterator it; + for (it = m_multiplayer_planes.begin(); it != m_multiplayer_planes.end(); ++it) + { + if (needsToRemoved(it.value())) + { + removePlane(it.value()); + it = m_multiplayer_planes.erase(it); + } + + if (areAIPlanesEnabled()) + it.value()->render(); + } +} + +bool CMultiPlayer::isKnown(const QString &callsign) const +{ + return m_multiplayer_planes.contains(callsign); +} + +CPlane *CMultiPlayer::getPlane(const QString &callsign) +{ + return m_multiplayer_planes.value(callsign); +} + +void CMultiPlayer::onPositionUpdate(const FSD::FSD_MSG_Plane_Position *plane_position) +{ + QString callsign = plane_position->Callsign(); + CPlane *plane; + + plane = getPlane(callsign); + + CVectorGeo position(plane_position->Latitude(), plane_position->Longitude(), plane_position->Altitude()); + + FS_PBH pitchBankHeading; + pitchBankHeading.pbh = plane_position->PBH(); + + //! TODO: Pitch Bank Heading and a timestamp + + if (plane) + { + plane->addPosition(position, plane_position->Speed(), pitchBankHeading.hdg, pitchBankHeading.pitch, pitchBankHeading.bank); + } + else + { + plane = new CPlane(callsign, m_simulator); + addPlane(plane); + plane->addPosition(position, plane_position->Speed(), pitchBankHeading.hdg, pitchBankHeading.pitch, pitchBankHeading.bank); + } + +} + +void CMultiPlayer::addPlane(CPlane *plane) +{ + m_multiplayer_planes.insert(plane->Callsign(), plane); +} + +void CMultiPlayer::removePlane(CPlane *plane) +{ + qint32 id; + m_simulator->removePlane(id); +} + +} //! namespace BlackCore diff --git a/src/blackcore/multiplayer.h b/src/blackcore/multiplayer.h new file mode 100644 index 000000000..209ca0e9c --- /dev/null +++ b/src/blackcore/multiplayer.h @@ -0,0 +1,100 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef MULTIPLAYER_H +#define MULTIPLAYER_H + +#include +#include +#include +#include +#include + +namespace BlackCore { + + class CPlane; + class ISimulator; + + union FS_PBH { + quint32 pbh; + struct { + quint32 unused : 1; + quint32 onground : 1; + quint32 hdg : 10; + quint32 bank : 10; + quint32 pitch : 10; + }; + }; + + class CMultiPlayer : public BlackMisc::CMessageHandler + { + public: + CMultiPlayer(); + + //! Starts the multiplayer mode. + void start (); + + //! Stops the multiplayer mode. + void stop (); + + //! Returns true if the multiplayer mode has been started. Otherwise false. \sa start() + /*! + \return Return true if running, otherwise false. + */ + inline bool isRunning() const { return m_isRunning; } + + //! This is the trigger, to do all frequent calculations and send everything to the simulator. + //! CMultiPlayer does nothing by itself, the parent has to call this. + void run(); + + //! Returns true the plane is known, othwewise false. + /*! + \return Return true if the given plane is in the hash map, otherwise false. + */ + bool isKnown(const QString &callsign) const; + + //! Enables or disables the injection of AI planes + /*! + \param enable If enable is true, injection is enabled, otherwise it will be disabled + */ + void enableAIPlanes(bool enable); + + //! Returns true if rendering of AI planes is enabled + /*! + \return Return true if enabled, otherwise false. + */ + bool areAIPlanesEnabled() const; + + + //! Use this method if you need a specific plane object. + /*! + \param callsign Callsign of the players plane + \return Returns the pointer to the Plane object. + */ + CPlane *getPlane ( const QString &callsign); + + private: + + void onPositionUpdate(const FSD::FSD_MSG_Plane_Position *plane_position); + + void addPlane(CPlane *plane); + + void removePlane(CPlane *plane); + + bool needsToRemoved(CPlane *plane); + + typedef QHash TPlaneManager; + TPlaneManager m_multiplayer_planes; + + bool m_isRunning; + + bool m_enableAIPlanes; + + ISimulator *m_simulator; + }; + +} //! namespace BlackCore + +#endif // MULTIPLAYER_H diff --git a/src/blackcore/ned.cpp b/src/blackcore/ned.cpp new file mode 100644 index 000000000..253b9d73c --- /dev/null +++ b/src/blackcore/ned.cpp @@ -0,0 +1,74 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#include "blackcore/matrix_3d.h" +#include "blackcore/ecef.h" +#include "blackcore/ned.h" + +#include "blackcore/constants.h" + +namespace BlackCore +{ + + CNed::CNed() + { + zeros(); + } + + CNed::CNed(CVectorGeo &pos, double N, double E, double D) + : CVector3D(N, E, D), m_position(pos) + { + } + + CEcef CNed::toECEF() + { + double angle = - ( m_position.latitudeDegrees() * Constants::DegToRad ) - Constants::PI/2; + + CMatrix3D dcm1; + CMatrix3D dcm2; + CMatrix3D dcm3; + CMatrix3D DCM; + CMatrix3D invDCM; + dcm1.zeros(); + dcm2.zeros(); + dcm3.zeros(); + + dcm1(0,0) = 1; + dcm1(1,1) = 1; + dcm1(1,2) = 0; + dcm1(2,1) = 0; + dcm1(2,2) = 1; + + dcm2(0,0) = cos( angle ); + dcm2(0,2) = -sin( angle ); + dcm2(1,1) = 1; + dcm2(2,0) = sin( angle ); + dcm2(2,2) = cos( angle ); + + angle = m_position.longitudeDegrees() * Constants::DegToRad; + + dcm3(0,0) = cos(angle ); + dcm3(0,1) = sin(angle ); + dcm3(1,0) = -sin(angle ); + dcm3(1,1) = cos(angle ); + dcm3(2,2) = 1; + + DCM = dcm1 * dcm2 * dcm3; + + invDCM.zeros(); + invDCM = DCM.inverse(); + + CVector3D tempResult = invDCM * (*this); + CEcef result; + + result.setX(tempResult.X()); + result.setY(tempResult.Y()); + result.setZ(tempResult.Z()); + + return result; +} + +} // namespace BlackCore + diff --git a/src/blackcore/ned.h b/src/blackcore/ned.h new file mode 100644 index 000000000..f921f182f --- /dev/null +++ b/src/blackcore/ned.h @@ -0,0 +1,47 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef VECTOR_NED_H +#define VECTOR_NED_H + +#include "vector_3d.h" +#include "vector_geo.h" + +namespace BlackCore +{ + +class CEcef; + +class CNed : public CVector3D +{ +public: + CNed(); + CNed(CVectorGeo &pos, double N, double E, double D); + + double North() const {return v[0];} + + double East() const {return v[1];} + + double Down() const {return v[2];} + + CVectorGeo position() const { return m_position; } + + void setNorth(const double num) { v[0] = num; } + + void setEast(const double num) { v[1] = num; } + + void setDown(const double num) { v[2] = num; } + + void setPosition(const CVectorGeo &pos ) { m_position = pos; } + + CEcef toECEF(); + +private: + CVectorGeo m_position; +}; + +} // namespace BlackCore + +#endif // VECTOR_NED_H diff --git a/src/blackcore/plane.cpp b/src/blackcore/plane.cpp new file mode 100644 index 000000000..7a16741b4 --- /dev/null +++ b/src/blackcore/plane.cpp @@ -0,0 +1,36 @@ +#include +#include +#include +#include "blackcore/plane.h" + +namespace BlackCore { + + CPlane::CPlane() + : m_interpolator(NULL), m_driver(NULL) + { + } + + CPlane::CPlane(const QString &callsign, ISimulator *driver) + : m_callsign(callsign), m_interpolator(NULL), m_driver(driver) + { + m_interpolator = new CInterpolator(); + + bAssert(m_interpolator); + bAssert(driver); + } + + void CPlane::addPosition(const CVectorGeo &position, double groundVelocity, double heading, double pitch, double bank) + { + bAssert(m_interpolator); + + m_interpolator->pushUpdate(position, groundVelocity, heading, pitch, bank); + } + + void CPlane::render() + { + //m_driver->updatePositionAndSpeed(); + } + + + +} // namespace BlackCore diff --git a/src/blackcore/plane.h b/src/blackcore/plane.h new file mode 100644 index 000000000..998aa9e75 --- /dev/null +++ b/src/blackcore/plane.h @@ -0,0 +1,52 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef PLANE_H +#define PLANE_H + +#include + +namespace BlackCore { + + class ISimulator; + class CInterpolator; + + class CPlane + { + public: + + enum ESquawkMode {Standby = 'S', + Charlie = 'N', + Ident = 'Y'}; + + CPlane(); + CPlane(const QString &callsign, ISimulator *driver); + + + + void addPosition(const CVectorGeo &position, double groundVelocity, double heading, double pitch, double bank); + + //! Returns the callsign of the multiplayer plane + /*! + \return callsign. + */ + inline QString& Callsign() { return m_callsign; } + + void render(); + + double getLastUpdateTime(); + + private: + + QString m_callsign; + + CInterpolator *m_interpolator; + + ISimulator *m_driver; + }; + +} // namespace BlackCore + +#endif // PLANE_H diff --git a/src/blackcore/sim_callbacks.h b/src/blackcore/sim_callbacks.h new file mode 100644 index 000000000..e9e77684d --- /dev/null +++ b/src/blackcore/sim_callbacks.h @@ -0,0 +1,6 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +//TODO remove this file diff --git a/src/blackcore/simulator.cpp b/src/blackcore/simulator.cpp new file mode 100644 index 000000000..20f76662c --- /dev/null +++ b/src/blackcore/simulator.cpp @@ -0,0 +1,136 @@ +/*************************************************************************** + * Copyright (C) 2013 by Roland Winklmeier * + * roland.m.winklmeier@googlemail.com * + * * + * For license information see LICENSE in the root folder of the * + * source code. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + ***************************************************************************/ + +#include "blackcore/simulator.h" +#include "blackmisc/debug.h" + +#include +#include + +namespace BlackCore { + + const quint32 ISimulator::InterfaceVersionMajor = 0; + const quint32 ISimulator::InterfaceVersionMinor = 1; + + typedef ISimulator* (*createISimulatorInstance)(); + const char *IDRV_CREATE_SIM_INTERFACE = "BB_createISimulatorInstance"; + + typedef quint32 (*getDriverVersionMajor)(void); + const char *DRIVER_VERSION_MAJOR = "BB_InterfaceVersionMajor"; + + typedef quint32 (*getDriverVersionMinor)(void); + const char *DRIVER_VERSION_MINOR = "BB_InterfaceVersionMinor"; + + void ISimulator::setLibraryContext(BlackMisc::IContext *context) + { + m_libraryContext = context; + } + + ISimulator *ISimulator::createDriver(ESimulator sim) + { + QLibrary myLib; + ISimulator *result = NULL; + + getDriverVersionMajor driverVersionMajor; + getDriverVersionMinor driverVersionMinor; + createISimulatorInstance createDriver; + + switch (sim) + { + #ifdef Q_OS_WIN + case FS9: + { + myLib.setFileName(SHARED_LIBRARY_NAME_FS9); + bAssertstr(myLib.load(), myLib.errorString()); + driverVersionMajor = (getDriverVersionMajor) myLib.resolve(DRIVER_VERSION_MAJOR); + + if (driverVersionMajor != NULL) + { + bAssertstr(driverVersionMajor() == ISimulator::InterfaceVersionMajor, QString("Wrong version of the driver. Try to reinstall!")); + } + + createDriver = (createISimulatorInstance) myLib.resolve(IDRV_CREATE_SIM_INTERFACE); + if (createDriver) + { + bInfo << "Loaded successfully shared library 'bb_driver_fs9'"; + result = createDriver(); + } + } + break; + + case FSX: + myLib.setFileName(SHARED_LIBRARY_NAME_FSX); + bAssertstr(myLib.load(), myLib.errorString()); + + driverVersionMajor = (getDriverVersionMajor) myLib.resolve(DRIVER_VERSION_MAJOR); + + if (driverVersionMajor != NULL) + { + bAssertstr(driverVersionMajor() == ISimulator::InterfaceVersionMajor, QString("Wrong version of the driver. Try to reinstall!")); + } + + createDriver = (createISimulatorInstance) myLib.resolve(IDRV_CREATE_SIM_INTERFACE); + if (createDriver) + { + bInfo << "Loaded successfully shared library 'bb_driver_fsx'"; + result = createDriver(); + } + break; + #endif + case XPLANE: + myLib.setFileName(SHARED_LIBRARY_NAME_XPLANE); + bAssertstr(myLib.load(), myLib.errorString()); + + driverVersionMajor = (getDriverVersionMajor) myLib.resolve(DRIVER_VERSION_MAJOR); + + if (driverVersionMajor != NULL) + { + bAssertstr(driverVersionMajor() == ISimulator::InterfaceVersionMajor, QString("Wrong version of the driver. Try to reinstall!")); + } + + createDriver = (createISimulatorInstance) myLib.resolve(IDRV_CREATE_SIM_INTERFACE); + if (createDriver) + { + bInfo << "Loaded successfully shared library 'bb_driver_xplane'"; + result = createDriver(); + } + break; + default: + break; + } + + return result; + } + + void ISimulator::setcbSimStarted(const cbSimStarted &func) + { + m_cbSimStarted = func; + } + + void ISimulator::setcbChangedAvionicsState(const cbChangedAvionicsState &func) + { + m_cbChangedAvionicsState = func; + } + + void ISimulator::setcbChangedAnimationState(const cbChangedAnimationState &func) + { + m_cbChangedAnimationState = func; + } + + void ISimulator::setcbChangedModel(const cbChangedModel &func) + { + m_cbChangedModel = func; + } + +} //! namespace BlackCore diff --git a/src/blackcore/simulator.h b/src/blackcore/simulator.h new file mode 100644 index 000000000..63613e5a4 --- /dev/null +++ b/src/blackcore/simulator.h @@ -0,0 +1,168 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef SIMULATOR_H +#define SIMULATOR_H + +#include +#include + +#include "blackcore/sim_callbacks.h" +#include "blackcore/vector_geo.h" + +#define SHARED_LIBRARY_NAME_FS9 "bb_driver_fs9" +#define SHARED_LIBRARY_NAME_FSX "bb_driver_fsx" +#define SHARED_LIBRARY_NAME_XPLANE "bb_driver_xplane" + +namespace BlackMisc { + + class IContext; + +} + +namespace BlackCore { + + class CPlaneModel + { + public: + QString name; + QString typeCode; + QString airlineCode; + }; + + class CPhysicalState + { + public: + CPhysicalState() : headingDegrees(0), pitchDegrees(0), bankDegrees(0), groundSpeedKnots(0) + {} + CVectorGeo position; + float headingDegrees; + float pitchDegrees; + float bankDegrees; + float groundSpeedKnots; + }; + + class CAvionicsState + { + CAvionicsState() : squawkCode(0), squawkModeC(false), squawkIdent(false), + com1FreqHz(0), com2FreqHz(0) + {} + qint16 squawkCode; + bool squawkModeC; + bool squawkIdent; + qint32 com1FreqHz; + qint32 com2FreqHz; + }; + + class CAnimationState + { + public: + CAnimationState() : gearPercent(0), flapsPercent(0), landingLights(false), + taxiLights(false), navLights(false), strobeLights(false), beaconLights(false) + {} + qint8 gearPercent; + qint8 flapsPercent; + bool landingLights; + bool taxiLights; + bool navLights; + bool strobeLights; + bool beaconLights; + }; + + typedef std::tr1::function cbSimStarted; + typedef std::tr1::function cbChangedAvionicsState; + typedef std::tr1::function cbChangedAnimationState; + typedef std::tr1::function cbChangedModel; + typedef std::tr1::function cbSendTextMessage; + + class ISimulator + { + public: + + /// Version of the driver interface. To increment when the interface change. + static const quint32 InterfaceVersionMajor; + static const quint32 InterfaceVersionMinor; + + enum ESimulator { + FS9 = 0, + FSX, + XPLANE, + }; + + ISimulator() {} + virtual ~ISimulator() {} + + virtual void setLibraryContext(BlackMisc::IContext *context); + + static ISimulator *createDriver(ESimulator sim); + + //////////////////////////////// + // Global section + //////////////////////////////// + + virtual int init() = 0; + + virtual int connect() = 0; + + // Callback when the Simulation starts + virtual void setcbSimStarted(const cbSimStarted &func); + + virtual bool isConnected() = 0; + + virtual QString getLastErrorMessage() = 0; + + //////////////////////////////// + // User plane section + //////////////////////////////// + + // Callback avionics state + virtual void setcbChangedAvionicsState(const cbChangedAvionicsState &func); + + // Callback animation state + virtual void setcbChangedAnimationState(const cbChangedAnimationState &func); + + // Callback, when the Aircraft is set or gets changed + virtual void setcbChangedModel(const cbChangedModel &func); + + // Not const because it may need to mutate state in order to communicate with the sim + virtual bool isOnGround() = 0; + + // This might block - use QtConcurrent::run if that is a problem + virtual CPhysicalState getPhysicalState() = 0; + + //////////////////////////////// + // Remote plane section + //////////////////////////////// + + // This might block - use QtConcurrent::run if that is a problem + virtual qint32 addPlane(const QString &callsign) = 0; + + virtual bool removePlane(const qint32 planeID) = 0; + + virtual void setModel(const qint32 planeID, const CPlaneModel &model) = 0; + + virtual bool setPhysicalState(const qint32 planeID, const CPhysicalState &state) = 0; + + virtual bool setAnimationState(const qint32 planeID, const CAnimationState &state) = 0; + + // Calls the supplied visitor function once for every model available in the simulator. + virtual void visitAllModels(const std::tr1::function &visitor) = 0; + + // Fills container with all models. Works for any container that supports push_back. + template + void getAllModels(T &container) { visitAllModels(std::tr1::bind(T::push_back, container)); } + + protected: + BlackMisc::IContext *m_libraryContext; + + cbSimStarted m_cbSimStarted; + cbChangedAvionicsState m_cbChangedAvionicsState; + cbChangedAnimationState m_cbChangedAnimationState; + cbChangedModel m_cbChangedModel; + }; + +} //! namespace BlackCore + +#endif // SIMULATOR_H diff --git a/src/blackcore/vector_3d.cpp b/src/blackcore/vector_3d.cpp new file mode 100644 index 000000000..c25f0d8de --- /dev/null +++ b/src/blackcore/vector_3d.cpp @@ -0,0 +1,177 @@ +#include +#include + +#include "blackmisc/debug.h" + +#include "blackcore/matrix_3d.h" +#include "blackcore/vector_3d.h" +#include "blackcore/vector_geo.h" + +#include "blackcore/constants.h" + +namespace BlackCore +{ + +CVector3D::CVector3D() +{ + zeros(); +} + +CVector3D::CVector3D(double x, double y, double z) +{ + zeros(); + v[0] = x; + v[1] = y; + v[2] = z; +} + +CVector3D::CVector3D(const CVector3D &other) +{ + zeros(); + for (int i=0; i<3; ++i) + { + v[i] = other.getElement(i); + } +} + +void CVector3D::print() +{ + std::cout << "v = " << std::endl; + std::cout << std::fixed; + for (qint32 i = 0; i < 3; ++i) + { + std::cout << "[" << v[i] << "]" << std::endl; + } +} + +void CVector3D::zeros() +{ + for (qint32 i = 0; i < 3; ++i) + { + v[i] = 0; + } +} + +double CVector3D::magnitude() +{ + return sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); +} + +double CVector3D::getElement(qint8 row) const +{ + bAssert(row < 3); + + return v[row]; +} + +CVector3D &CVector3D::operator +=(const CVector3D &rhs) +{ + for (int i=0; i<3; ++i) + { + v[i] += rhs.getElement(i); + } + return *this; +} + +CVector3D &CVector3D::operator -=(const CVector3D &rhs) +{ + for (int i=0; i<3; ++i) + { + v[i] -= rhs.getElement(i); + } + return *this; +} + +CVector3D &CVector3D::operator =(const CVector3D &rhs) +{ + if (this != &rhs) + { + for (int i=0; i<3; ++i) + { + v[i] = rhs.getElement(i); + } + } + return *this; +} + +CVector3D CVector3D::operator + (const CVector3D &rhs) +{ + CVector3D helper = *this; + helper += rhs; + return helper; +} + +CVector3D CVector3D::operator - (const CVector3D &rhs) +{ + CVector3D helper = *this; + helper -= rhs; + return helper; +} + +bool CVector3D::operator == (const CVector3D &rhs) +{ + bool isEqual = true; + for(int i=0; i<3 && isEqual; ++i) + { + isEqual = (v[i] == rhs.getElement(i)); + } + return isEqual; +} + +bool CVector3D::operator != (const CVector3D &rhs) +{ + return !(*this == rhs); +} + +CVector3D & CVector3D::operator *= (const CVector3D &rhs) +{ + CVector3D helper(*this); + for(qint32 row = 0; row < 3; ++row ) + { + v[row] = helper.getElement(row) * rhs.getElement(row); + } + return *this; +} + +CVector3D CVector3D::operator * (const CVector3D &rhs) +{ + CVector3D helper(*this); + helper *= rhs; + return helper; +} + +CVector3D &CVector3D::operator *= ( const double rhs) +{ + CVector3D helper(*this); + for(qint32 row = 0; row < 3; ++row ) + { + v[row] = helper.getElement(row) * rhs; + } + return *this; +} + +CVector3D CVector3D::operator * (const double rhs) +{ + CVector3D helper(*this); + helper *= rhs; + return helper; +} + +CVector3D &CVector3D::operator /= ( const double rhs) +{ + CVector3D helper(*this); + for(qint32 row = 0; row < 3; ++row ) + { + v[row] = helper.getElement(row) / rhs; + } + return *this; +} + +CVector3D CVector3D::operator / (const double rhs) +{ + CVector3D helper(*this); + helper /= rhs; + return helper; +} + +} // namespace BlackCore diff --git a/src/blackcore/vector_3d.h b/src/blackcore/vector_3d.h new file mode 100644 index 000000000..1383d59c9 --- /dev/null +++ b/src/blackcore/vector_3d.h @@ -0,0 +1,73 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#include + +#ifndef VECTOR_3D_H +#define VECTOR_3D_H + +namespace BlackCore +{ + + class CMatrix3D; + + class CVector3D + { + public: + CVector3D(); + CVector3D(double x, double y, double z); + CVector3D( const CVector3D & other); + + double X() const {return v[0];} + + double Y() const {return v[1];} + + double Z() const {return v[2];} + + void setX(const double num) { v[0] = num; } + + void setY(const double num) { v[1] = num; } + + void setZ(const double num) { v[2] = num; } + + double getElement(qint8 row) const; + + void print(); + + void zeros(); + + CVector3D & operator +=(const CVector3D &rhs); + CVector3D & operator -=(const CVector3D &rhs); + + CVector3D & operator = (const CVector3D &rhs); + + CVector3D operator +(const CVector3D &rhs); + CVector3D operator -(const CVector3D &rhs); + + bool operator ==(const CVector3D &rhs); + bool operator !=(const CVector3D &rhs); + + //double crossProduct(qint32 ); + + CVector3D & operator *=(const CVector3D &rhs); + CVector3D operator *( const CVector3D &rhs); + + CVector3D & operator *=( const double rhs); + CVector3D operator *( const double rhs); + + CVector3D & operator /=( const double rhs); + CVector3D operator /( const double rhs); + + double magnitude(); + + protected: + double v[3]; + + friend class CMatrix3D; + }; + +} //! namespace BlackCore + +#endif // VECTOR_3D_H diff --git a/src/blackcore/vector_geo.cpp b/src/blackcore/vector_geo.cpp new file mode 100644 index 000000000..fb4f6c93d --- /dev/null +++ b/src/blackcore/vector_geo.cpp @@ -0,0 +1,86 @@ +#include +#include + +#include "blackcore/constants.h" +#include "blackcore/vector_geo.h" +#include "blackcore/ecef.h" + +namespace BlackCore +{ + + CVectorGeo::CVectorGeo() + : m_latitudeDegrees(0), m_longitudeDegrees(0), m_altitudeMeters(0) + {} + + CVectorGeo::CVectorGeo(double latitudeDegrees, double longitudeDegrees, double altitudeMeters) + : m_latitudeDegrees(latitudeDegrees), m_longitudeDegrees(longitudeDegrees), + m_altitudeMeters(altitudeMeters) + {} + + CVectorGeo::CVectorGeo(const CVectorGeo &other) + : m_latitudeDegrees(other.m_latitudeDegrees), m_longitudeDegrees(other.m_longitudeDegrees), + m_altitudeMeters(other.m_altitudeMeters) + {} + + CEcef CVectorGeo::toCartesian() + { + CEcef result; + + double phi = m_latitudeDegrees * Constants::DegToRad; + double lambda = m_longitudeDegrees * Constants::DegToRad; + double sphi = sin(phi); + double cphi = 0; + if (std::abs(m_latitudeDegrees) != 90) + cphi = cos(phi); + + double n = Constants::EarthRadiusMeters/sqrt(1-Constants::e2 * CMath::square(sphi)); + + double slambda = 0; + if (m_longitudeDegrees != -180) + slambda = sin(lambda); + + double clambda = 0; + if (std::abs(m_longitudeDegrees) != 90) + clambda = cos(lambda); + + double h = m_altitudeMeters; + + double X = (n + h) * cphi; + double Y = X * slambda; + X *= clambda; + double Z = (Constants::e2m * n + h)*sphi; + + result.setX(X); + result.setY(Y); + result.setZ(Z); + return result; + } + + void CVectorGeo::zeros() + { + m_latitudeDegrees = 0; + m_longitudeDegrees = 0; + m_altitudeMeters = 0; + } + + void CVectorGeo::print(std::ostream &stream) + { + stream << "v = " << std::endl; + stream << std::fixed; + stream << "[" << m_latitudeDegrees << "]" << std::endl; + stream << "[" << m_longitudeDegrees << "]" << std::endl; + stream << "[" << m_altitudeMeters << "]" << std::endl; + } + + CVectorGeo &CVectorGeo::operator =(const CVectorGeo &rhs) + { + if (this != &rhs) + { + m_latitudeDegrees = rhs.latitudeDegrees(); + m_longitudeDegrees = rhs.longitudeDegrees(); + m_altitudeMeters = rhs.altitudeMeters(); + } + return *this; + } + +} // namespace BlackCore diff --git a/src/blackcore/vector_geo.h b/src/blackcore/vector_geo.h new file mode 100644 index 000000000..21f328982 --- /dev/null +++ b/src/blackcore/vector_geo.h @@ -0,0 +1,58 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef VECTOR_GEO_H +#define VECTOR_GEO_H + +#include + +namespace BlackCore +{ + +class CEcef; + +class CVectorGeo +{ + public: + CVectorGeo(); + CVectorGeo(double latitudeDegrees, double longintudeDegrees, double altitudeMeters); + CVectorGeo(const CVectorGeo &other); + + void setLatitudeDegrees(double latitudeDegrees) + { + m_latitudeDegrees = latitudeDegrees; + } + + void setLongitudeDegrees(double longitudeDegrees) + { + m_longitudeDegrees = longitudeDegrees; + } + + void setAltitude(double altitudeMeters) + { + m_altitudeMeters = altitudeMeters; + } + + double latitudeDegrees() const { return m_latitudeDegrees; } + double longitudeDegrees() const { return m_longitudeDegrees; } + double altitudeMeters() const { return m_altitudeMeters; } + + CEcef toCartesian(); + + void zeros(); + + void print(std::ostream &stream = std::cout); + + CVectorGeo &operator=(const CVectorGeo &rhs); + + private: + double m_latitudeDegrees; + double m_longitudeDegrees; + double m_altitudeMeters; + }; + +} // namespace BlackCore + +#endif // VECTOR_GEO_H diff --git a/src/blackd/CMakeLists.txt b/src/blackd/CMakeLists.txt new file mode 100644 index 000000000..53762e858 --- /dev/null +++ b/src/blackd/CMakeLists.txt @@ -0,0 +1,25 @@ +FILE(GLOB blackd_SOURCES *.cpp) +FILE(GLOB blackd_HEADERS *.h) +SET(blackd_HEADERS_QOBJECT + blackd.h) + +SET(blackd_FORMS blackd.ui) +SET(blackd_RESOURCES blackd.qrc) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) + +QT4_WRAP_CPP(blackd_HEADERS_MOC ${blackd_HEADERS_QOBJECT}) +QT4_WRAP_UI(blackd_FORMS_HEADERS ${blackd_FORMS}) +QT4_ADD_RESOURCES(blackd_RESOURCES_RCC ${blackd_RESOURCES}) + +SOURCE_GROUP(QtGeneratedMocSrc FILES ${blackd_HEADERS_MOC}) +SOURCE_GROUP (QtResources FILES ${blackd_RESOURCES_RCC}) +SOURCE_GROUP (QtForms FILES ${blackd_FORMS_HEADERS}) + +ADD_EXECUTABLE(blackd WIN32 MACOSX_BUNDLE ${blackd_SOURCES} + ${blackd_HEADERS_MOC} + ${blackd_FORMS_HEADERS} + ${blackd_RESOURCES_RCC}) + +TARGET_LINK_LIBRARIES(blackd blackmisc blackcore ${QT_LIBRARIES} ${QT_QTMAIN_LIBRARY}) +SET_TARGET_PROPERTIES(blackd PROPERTIES PROJECT_LABEL "BlackBox Daemon - blackd") \ No newline at end of file diff --git a/src/blackd/blackd.cpp b/src/blackd/blackd.cpp new file mode 100644 index 000000000..a46f7f465 --- /dev/null +++ b/src/blackd/blackd.cpp @@ -0,0 +1,169 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#include + +#include +#include +#include +#include + +#include "qt_displayer.h" + +#include "blackd.h" +#include "ui_blackd.h" + +using namespace BlackMisc; +using namespace FSD; + + +BlackD::BlackD(QWidget *parent) : + QDialog(parent), + ui(new Ui::BlackD) +{ + ui->setupUi(this); + + createActions(); + createTrayIcon(); + + connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), + this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason))); + + setWindowTitle(tr("BlackD")); + + QIcon icon = QIcon(":/images/blackbox_icon.svg"); + trayIcon->setIcon(icon); + trayIcon->show(); + + setWindowIcon(icon); + + createLogging(); + + createComServer(); + + m_fsd_client = new CFSDClient(); + + bDebug << "BlackDaemon running..."; +} + +BlackD::~BlackD() +{ + delete ui; +} + +void BlackD::setVisible(bool visible) +{ + minimizeAction->setEnabled(visible); + maximizeAction->setEnabled(!isMaximized()); + restoreAction->setEnabled(isMaximized() || !visible); + QDialog::setVisible(visible); +} + +void BlackD::closeEvent(QCloseEvent *event) +{ + if (trayIcon->isVisible()) { + QMessageBox::information(this, tr("BlackD"), + tr("The program will keep running in the " + "system tray. To terminate the program, " + "choose Quit in the context menu " + "of the system tray entry.")); + hide(); + event->ignore(); + } +} + +void BlackD::iconActivated(QSystemTrayIcon::ActivationReason reason) +{ + switch (reason) { + case QSystemTrayIcon::DoubleClick: + setVisible(!isVisible()); + } +} + +void BlackD::createActions() +{ + minimizeAction = new QAction(tr("Mi&nimize"), this); + connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide())); + + maximizeAction = new QAction(tr("Ma&ximize"), this); + connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized())); + + restoreAction = new QAction(tr("&Restore"), this); + connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal())); + + quitAction = new QAction(tr("&Quit"), this); + connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); +} + +void BlackD::createTrayIcon() +{ + trayIconMenu = new QMenu(this); + trayIconMenu->addAction(minimizeAction); + trayIconMenu->addAction(maximizeAction); + trayIconMenu->addAction(restoreAction); + trayIconMenu->addSeparator(); + trayIconMenu->addAction(quitAction); + + trayIcon = new QSystemTrayIcon(this); + trayIcon->setContextMenu(trayIconMenu); +} + +void BlackD::createLogging() +{ + BlackMisc::IContext::getInstance().getDebug()->create(); + + m_displayer = new CQtDisplayer(ui->logginView); + bAssert(m_displayer); + BlackMisc::IContext::getInstance().getDebug()->getDebugLog()->attachDisplay (m_displayer); + BlackMisc::IContext::getInstance().getDebug()->getInfoLog()->attachDisplay (m_displayer); + BlackMisc::IContext::getInstance().getDebug()->getWarningLog()->attachDisplay (m_displayer); + BlackMisc::IContext::getInstance().getDebug()->getAssertLog()->attachDisplay (m_displayer); + BlackMisc::IContext::getInstance().getDebug()->getErrorLog()->attachDisplay (m_displayer); +} + +void BlackD::createComServer() +{ + CMessageFactory::getInstance().registerMessages(); + m_comserver = new CComServer(this); + + registerMessageFunction(this, &BlackD::onMSG_CONNECT_TO_VATSIM); + + QHostAddress local = QHostAddress(QHostAddress::LocalHost); + + m_comserver->Host(local, 42000); + connect(m_comserver, SIGNAL(doMessageReceived(QString &, QByteArray&)), this, SLOT(onData(QString &, QByteArray&))); +} + +void BlackD::onData(QString &messageID, QByteArray &message) +{ + bDebug << messageID; + BlackMisc::IMessage* test = BlackMisc::CMessageFactory::getInstance().create(messageID); + QDataStream stream(&message, QIODevice::ReadOnly); + + bAssert (test); + *test << stream; + + CMessageDispatcher::getInstance().append(test); + CMessageDispatcher::getInstance().dispatch(); +} + +void BlackD::onMSG_CONNECT_TO_VATSIM(const BlackMisc::MSG_CONNECT_TO_VATSIM *connect) +{ + bDebug << "Connecting to FSD server:"; + bDebug << connect->getHost() << ":" << connect->getPort(); + + FSD::TClientInfo clientinfo; + clientinfo.m_callsign = connect->getCallsign(); + clientinfo.m_host = connect->getHost(); + clientinfo.m_password = connect->getPassword(); + clientinfo.m_port = connect->getPort(); + clientinfo.m_realName = connect->getRealName(); + clientinfo.m_simType = FSD::SIM_UNKNOWN; + clientinfo.m_userid = connect->getUserID(); + + m_fsd_client->updateClientInfo(clientinfo); + + m_fsd_client->connectTo(connect->getHost(), connect->getPort()); +} diff --git a/src/blackd/blackd.h b/src/blackd/blackd.h new file mode 100644 index 000000000..608c495b9 --- /dev/null +++ b/src/blackd/blackd.h @@ -0,0 +1,73 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef BLACKD_H +#define BLACKD_H + +#include +#include +#include +#include + +#include + +namespace Ui { +class BlackD; +} + +namespace FSD { +class CFSDClient; +} + +class CQtDisplayer; +class CMultiPlayer; + +class BlackD : public QDialog, public BlackMisc::CMessageHandler +{ + Q_OBJECT + +public: + explicit BlackD(QWidget *parent = 0); + ~BlackD(); + + void setVisible(bool visible); + +protected: + void closeEvent(QCloseEvent *event); + +private slots: + void iconActivated(QSystemTrayIcon::ActivationReason reason); + void onData(QString &messageID, QByteArray &message); + +private: + + void createActions(); + void createTrayIcon(); + void createLogging(); + void createComServer(); + + //! Messages + void onMSG_CONNECT_TO_VATSIM(const BlackMisc::MSG_CONNECT_TO_VATSIM *connect); + + Ui::BlackD *ui; + + QAction *minimizeAction; + QAction *maximizeAction; + QAction *restoreAction; + QAction *quitAction; + + QSystemTrayIcon *trayIcon; + QMenu *trayIconMenu; + + CQtDisplayer *m_displayer; + + FSD::CFSDClient *m_fsd_client; + CMultiPlayer *m_multi_player; + + BlackMisc::CComServer *m_comserver; + +}; + +#endif // BLACKD_H diff --git a/src/blackd/blackd.qrc b/src/blackd/blackd.qrc new file mode 100644 index 000000000..b0808533e --- /dev/null +++ b/src/blackd/blackd.qrc @@ -0,0 +1,5 @@ + + + images/blackbox_icon.svg + + diff --git a/src/blackd/blackd.ui b/src/blackd/blackd.ui new file mode 100644 index 000000000..d3ae83267 --- /dev/null +++ b/src/blackd/blackd.ui @@ -0,0 +1,33 @@ + + + BlackD + + + + 0 + 0 + 400 + 300 + + + + Dialog + + + + false + + + + 10 + 10 + 381 + 281 + + + + + + + + diff --git a/src/blackd/images/blackbox.svg b/src/blackd/images/blackbox.svg new file mode 100644 index 000000000..f2953b8a6 --- /dev/null +++ b/src/blackd/images/blackbox.svg @@ -0,0 +1,101 @@ + + + + + + + + + + image/svg+xml + + + + + + + Layer 1 + + B + Box + + lack + + + diff --git a/src/blackd/images/blackbox_icon.svg b/src/blackd/images/blackbox_icon.svg new file mode 100644 index 000000000..923c9af2e --- /dev/null +++ b/src/blackd/images/blackbox_icon.svg @@ -0,0 +1,102 @@ + + + + + + + + + + image/svg+xml + + + + + + + + Layer 1 + + B + B + + + + + diff --git a/src/blackd/main.cpp b/src/blackd/main.cpp new file mode 100644 index 000000000..935fe50bc --- /dev/null +++ b/src/blackd/main.cpp @@ -0,0 +1,31 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#include + +#include "blackd.h" +#include +#include + +int main(int argc, char *argv[]) +{ + Q_INIT_RESOURCE(blackd); + + QApplication app(argc, argv); + BlackMisc::CApplicationContext myBlackApp; + + if (!QSystemTrayIcon::isSystemTrayAvailable()) { + QMessageBox::critical(0, QObject::tr("Systray"), + QObject::tr("I couldn't detect any system tray " + "on this system.")); + return 1; + } + QApplication::setQuitOnLastWindowClosed(false); + + BlackD w; + w.hide(); + + return app.exec(); +} diff --git a/src/blackd/qt_displayer.cpp b/src/blackd/qt_displayer.cpp new file mode 100644 index 000000000..fb0e02890 --- /dev/null +++ b/src/blackd/qt_displayer.cpp @@ -0,0 +1,78 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#include "qt_displayer.h" + +using namespace BlackMisc; + +CQtDisplayer::CQtDisplayer(QPlainTextEdit *debugWindow, const char *displayerName) + : ILogDisplay (displayerName), m_needHeader(true) +{ + setParam(debugWindow); +} + +CQtDisplayer::CQtDisplayer() + : ILogDisplay (""), m_needHeader(true) +{ + +} + +CQtDisplayer::~CQtDisplayer() { + +} + +void CQtDisplayer::setParam (QPlainTextEdit *debugWindow) +{ + m_DebugWindow=debugWindow; +} + +void CQtDisplayer::doPrint ( const BlackMisc::CLog::SLogInformation &logInformation, const QString &message) +{ + if (!m_DebugWindow) + return; + + bool needSpace = false; + QString line; + + if(m_DebugWindow==NULL) + return; + + QTextCharFormat format; + + if (logInformation.m_dateTime.isValid()) { + line += dateToString(logInformation.m_dateTime); + needSpace = true; + } + + if (logInformation.m_logType != CLog::OFF) + { + if (needSpace) { line += " "; needSpace = false; } + line += logTypeToString(logInformation.m_logType); + if (logInformation.m_logType == BlackMisc::CLog::WARNING) + format.setForeground(QBrush(QColor("red"))); + else + format.setForeground(QBrush(QColor("black"))); + needSpace = true; + } + + if (logInformation.m_methodName != NULL) + { + if (needSpace) + { + line += " "; needSpace = false; + } + line += logInformation.m_methodName; + needSpace = true; + } + + if (needSpace) + { + line += " : "; needSpace = false; + } + line += message; + + m_DebugWindow->textCursor().insertText(line, format); + m_DebugWindow->centerCursor(); +} diff --git a/src/blackd/qt_displayer.h b/src/blackd/qt_displayer.h new file mode 100644 index 000000000..d1a8494ea --- /dev/null +++ b/src/blackd/qt_displayer.h @@ -0,0 +1,31 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef QT_DISPLAYER_H +#define QT_DISPLAYER_H + +#include + +// Qt includes +#include + +class CQtDisplayer : virtual public BlackMisc::ILogDisplay +{ +public: + CQtDisplayer(QPlainTextEdit *debugWindow, + const char *displayerName = ""); + CQtDisplayer(); + ~CQtDisplayer (); + void setParam (QPlainTextEdit *debugWindow); + +protected: + virtual void doPrint(const BlackMisc::CLog::SLogInformation &logInformation, const QString &message); + +private: + QPlainTextEdit *m_DebugWindow; + bool m_needHeader; +}; + +#endif // QT_DISPLAYER_H diff --git a/src/blackmisc/CMakeLists.txt b/src/blackmisc/CMakeLists.txt new file mode 100644 index 000000000..b7e428cbe --- /dev/null +++ b/src/blackmisc/CMakeLists.txt @@ -0,0 +1,21 @@ +FILE(GLOB blackmisc_SOURCES *.cpp) +FILE(GLOB blackmisc_HEADERS *.h) +SET(blackmisc_HEADERS_QOBJECT + com_client.h + com_client_buffer.h + com_handler.h + com_server.h) + +QT4_WRAP_CPP(blackmisc_HEADERS_MOC ${blackmisc_HEADERS_QOBJECT}) + +SOURCE_GROUP(QtGeneratedMocSrc FILES ${blackmisc_HEADERS_MOC}) +SOURCE_GROUP (Headers FILES ${blackmisc_HEADERS}) + +IF(WITH_STATIC) + ADD_LIBRARY(blackmisc STATIC ${blackmisc_SOURCES} ${blackmisc_HEADERS_MOC}) +ELSE(WITH_STATIC) + ADD_LIBRARY(blackmisc SHARED ${blackmisc_SOURCES} ${blackmisc_HEADERS_MOC}) +ENDIF(WITH_STATIC) + +TARGET_LINK_LIBRARIES(blackmisc) +SET_TARGET_PROPERTIES(blackmisc PROPERTIES PROJECT_LABEL "Library - BlackMisc") \ No newline at end of file diff --git a/src/blackmisc/com_client.cpp b/src/blackmisc/com_client.cpp new file mode 100644 index 000000000..1ed90c6a9 --- /dev/null +++ b/src/blackmisc/com_client.cpp @@ -0,0 +1,186 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#include +#include + +#include "blackmisc/debug.h" +#include "blackmisc/com_client.h" + +namespace BlackMisc +{ + + CComClient::CComClient(QObject *parent) + : IComHandler(parent), m_tcp_socket(NULL), m_port(0) + { + init(); + } + + CComClient::~CComClient() + { + if ( isConnected() ) + disconnect(); + + if ( m_tcp_socket != NULL ) + delete m_tcp_socket; + + m_tcp_socket = NULL; + } + + bool CComClient::init() + { + m_tcp_socket = new QTcpSocket(this); + bAssert(m_tcp_socket); + + bAssert ( QObject::connect( m_tcp_socket, SIGNAL( connected() ), this, SLOT( onConnected() ) ) ); + bAssert ( QObject::connect( m_tcp_socket, SIGNAL( disconnected() ), this, SLOT( onDisconnected() ) ) ); + bAssert ( QObject::connect( m_tcp_socket, SIGNAL( error(QAbstractSocket::SocketError) ), this, SLOT( onError(QAbstractSocket::SocketError) ) ) ); + + bAssert ( QObject::connect( m_tcp_socket, SIGNAL( readyRead() ), this, SLOT( onReceivingData() ) ) ); + + return true; + } + + void CComClient::connectTo( const QString& hostName, quint16 port) + { + bAssert ( ! hostName.isEmpty() ); + bAssert ( port > 0 ); + + m_hostName = hostName; + m_port = port; + + if ( isConnected() ) + return; + + bDebug << "Connecting to host: " << hostName << ":" << port; + + m_receive_buffer.clear(); + + m_tcp_socket->connectToHost(hostName, port); + + } + + bool CComClient::isConnected() const + { + return m_tcp_socket->state() == QAbstractSocket::ConnectedState; + } + + void CComClient::disconnectFrom() + { + bDebug << "Disconnecting from host."; + + m_tcp_socket->disconnectFromHost(); + m_port = 0; + m_hostName.clear(); + } + + bool CComClient::sendMessage(const QString& messageID, const QByteArray &message) + { + if (!isConnected()) + { + bError << "Cannot send data in disconnected state!"; + return false; + } + + createFrame(messageID, message); + + qint64 sender_buffer_size = m_sender_buffer.size(); + + qint64 bytes = m_tcp_socket->write(m_sender_buffer); + if (bytes < 0 || bytes != sender_buffer_size) + { + bWarning << "Error writing to socket!"; + return false; + } + + return true; + } + + QString CComClient::getErrorMessage(QAbstractSocket::SocketError error) + { + QString message; + + /* + ConnectionRefusedError, + RemoteHostClosedError, + HostNotFoundError, + SocketAccessError, + SocketResourceError, + SocketTimeoutError, + DatagramTooLargeError, + NetworkError, + AddressInUseError, + SocketAddressNotAvailableError, + UnsupportedSocketOperationError, + UnfinishedSocketOperationError, + ProxyAuthenticationRequiredError, + SslHandshakeFailedError, + ProxyConnectionRefusedError, + ProxyConnectionClosedError, + ProxyConnectionTimeoutError, + ProxyNotFoundError, + ProxyProtocolError, + UnknownSocketError = -1 */ + + switch (error) + { + case QAbstractSocket::ConnectionRefusedError: + message = "Connection refused by host!"; + break; + + case QAbstractSocket::RemoteHostClosedError: + message = "Connection closed by host!"; + break; + + case QAbstractSocket::HostNotFoundError: + message = "Host not found!"; + break; + + default: + case QAbstractSocket::UnknownSocketError: + message = "Unknown error!"; + break; + } + + return message; + } + + void CComClient::onConnected() + { + bDebug << "Connected successfully to remote host."; + emit doConnected(); + } + + void CComClient::onDisconnected() + { + bDebug << "Disconnected successfully from remote host."; + emit doDisconnected(); + } + + void CComClient::onError(QAbstractSocket::SocketError error) + { + if ( error != 0 ) + { + bError << "Received socket error: " << error << " - Disconnecting..."; + } + + disconnect(); + emit doError(error, getErrorMessage(error) ); + } + + void CComClient::onReceivingData() + { + QString messageID; + QByteArray message; + m_receive_buffer.append(m_tcp_socket->readAll()); + while (parseFrame(messageID, message)) + { + emit doReceivedMessage(messageID, message); + } + } + +} // namespace BlackMisc + + diff --git a/src/blackmisc/com_client.h b/src/blackmisc/com_client.h new file mode 100644 index 000000000..f8fa60a6b --- /dev/null +++ b/src/blackmisc/com_client.h @@ -0,0 +1,117 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef COM_CLIENT_H +#define COM_CLIENT_H + +#include +#include + +#include "blackmisc/com_handler.h" + +class QTcpSocket; + +namespace BlackMisc +{ + +class CComClient : public IComHandler +{ + Q_OBJECT + +public: + + //! Constructor + /*! + \param parent Pointer to the parent QObject + */ + CComClient(QObject *parent = 0); + + //! Destructor + ~CComClient(); + + //! This method initializes the client + virtual bool init(); + + //! Connects to the host address. + /*! + \param host Host address of the remote host. + \param port Port number of the remote host. + \return Returns true if connecting was successfull, otherwise false. + */ + void connectTo (const QString& hostName, quint16 port); + + //! Returns the connection status + /*! + \return Returns true if connected, otherwise false + */ + bool isConnected() const; + + //! Disconnects from the current server + void disconnectFrom(); + + //! Sends a message to the remote host. + /*! + \param data Reference to the raw byte data to be sent. + \return Returns true if sending was successfull, otherwise false. + */ + bool sendMessage (const QString &messageID, const QByteArray &message); + + //! Returns a human readable description of the last error that occurred. + QString getErrorMessage(QAbstractSocket::SocketError error); + +signals: + + //! emitted when new data were received + void doReceivedMessage(QString &messageID, QByteArray &message); + + //! emitted when cliebt connected + void doConnected(); + + //! emitted when client disconnected + void doDisconnected(); + + //! emitted when an error has occured + void doError(QAbstractSocket::SocketError error, const QString& error_message); + +protected slots: + + //! Call this slot, when connected succesfully + void onConnected(); + + //! Call this slot, when disconnected succesfully + void onDisconnected(); + + //! Call this slot, when an error appeared + void onError(QAbstractSocket::SocketError error); + + //! Call this slot, when data has been received + void onReceivingData(); + +protected: + + //! TCP Socket + /*! + Pointer to the tcp socket. + */ + QTcpSocket* m_tcp_socket; + + //! Remote hostname + QString m_hostName; + + //! Remote host port + quint16 m_port; + + //! This variable holds the last appeared error + QString m_last_error; + +private: + + CComClient( const CComClient& other); + const CComClient& operator = ( const CComClient& other); +}; + +} // namespace BlackMisc + +#endif // COM_CLIENT_H diff --git a/src/blackmisc/com_client_buffer.cpp b/src/blackmisc/com_client_buffer.cpp new file mode 100644 index 000000000..412fa06d7 --- /dev/null +++ b/src/blackmisc/com_client_buffer.cpp @@ -0,0 +1,60 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#include + +#include "blackmisc/debug.h" + +#include "blackmisc/com_client_buffer.h" + +namespace BlackMisc +{ + + CComClientBuffer::CComClientBuffer(uint clientID, QTcpSocket *socket, QObject *parent) + : m_client_id(clientID), m_tcp_socket(socket), IComHandler(parent) + { + connect(m_tcp_socket, SIGNAL(readyRead()), this, SLOT(onReceivingData())); + connect(m_tcp_socket, SIGNAL(disconnected()), this, SLOT(onClientDisconnected())); + } + CComClientBuffer::~CComClientBuffer() + { + m_tcp_socket->deleteLater(); + } + + bool CComClientBuffer::sendMessage(const QString& id, const QByteArray &message) + { + createFrame(id, message); + + qint64 sender_buffer_size = m_sender_buffer.size(); + + qint64 bytes = m_tcp_socket->write(m_sender_buffer); + if (bytes < 0 || bytes != sender_buffer_size) + { + bWarning << "Error writing to socket!"; + return false; + } + + return true; + } + + void CComClientBuffer::onReceivingData() + { + QByteArray message; + QString messageID; + + m_receive_buffer.append(m_tcp_socket->readAll()); + while (parseFrame(messageID, message)) + { + emit doReceivedMessage(m_client_id, messageID, message); + } + } + + void CComClientBuffer::onClientDisconnected() + { + bInfo << "Client disconnected!"; + emit doDisconnected(m_client_id); + } + +} // namespace BlackMisc diff --git a/src/blackmisc/com_client_buffer.h b/src/blackmisc/com_client_buffer.h new file mode 100644 index 000000000..e83772835 --- /dev/null +++ b/src/blackmisc/com_client_buffer.h @@ -0,0 +1,53 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef COM_CLIENT_BUFFER_H +#define COM_CLIENT_BUFFER_H + +#include + +#include "blackmisc/com_handler.h" + +class QTcpSocket; + +namespace BlackMisc +{ + + class CComClientBuffer : public IComHandler + { + Q_OBJECT + + public: + CComClientBuffer(uint clientID, QTcpSocket *socket, QObject *parent = 0); + + virtual ~CComClientBuffer(); + + //! Sends a message to the remote host. + /*! + \param data Reference to the raw byte data to be sent. + \return Returns true if sending was successfull, otherwise false. + */ + bool sendMessage (const QString &id, const QByteArray &message); + + signals: + + void doReceivedMessage(uint clientID, QString& messageID, QByteArray &message); + void doDisconnected(uint clientID); + + protected slots: + + void onReceivingData(); + void onClientDisconnected(); + + protected: + + QTcpSocket* m_tcp_socket; + uint m_client_id; + + }; + +} // namespace BlackMisc + +#endif // COM_CLIENT_BUFFER_H diff --git a/src/blackmisc/com_handler.cpp b/src/blackmisc/com_handler.cpp new file mode 100644 index 000000000..f6d31e6b1 --- /dev/null +++ b/src/blackmisc/com_handler.cpp @@ -0,0 +1,127 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#include +#include + +#include "blackmisc/debug.h" + +#include "blackmisc/com_handler.h" + +namespace BlackMisc +{ + + IComHandler::IComHandler(QObject *parent) : + QObject(parent) + { + } + + void IComHandler::createFrame(const QString& messageID, const QByteArray &data) + { + m_sender_buffer.clear(); + + QDataStream stream(&m_sender_buffer, QIODevice::WriteOnly); + + qint32 message_size = data.size(); + quint16 crc = qChecksum(data.constData(), message_size); + + stream << (qint32)Sync_Marker + << (qint32)message_size + << (QString)messageID; + stream.writeRawData(data.constData(), message_size); + stream << (quint16)crc; + } + + bool IComHandler::parseFrame(QString &messageID, QByteArray &data) + { + if (m_receive_buffer.isEmpty()) + return false; + + qint32 total_length = 0; + qint32 min_size = 3 * (int)sizeof(qint32); + + if (m_receive_buffer.size() < min_size) + { + bDebug << "Received data is to small to read SYNC and frame length!"; + return false; + } + + bool found_sync = false; + QDataStream stream (m_receive_buffer); + + ///////////////////////////////////////////////// + // Read the Sync + ///////////////////////////////////////////////// + + do + { + qint32 sync = 0; + stream >> (qint32)sync; + if (sync == Sync_Marker) + found_sync = true; + } + while (!found_sync && !stream.atEnd()); + + if (!found_sync) + { + bWarning << "Could not find sync pattern in the stream. Discarding all data!"; + m_receive_buffer.clear(); + return false; + } + + total_length += (int)sizeof(qint32); // Sync + + ///////////////////////////////////////////////// + // Read size of the message itself + ///////////////////////////////////////////////// + + qint32 message_length = 0; + stream >> (qint32)message_length; + + total_length += (int)sizeof(qint32); // Length + total_length += message_length; // Data + + ///////////////////////////////////////////////// + // Read the message id + ///////////////////////////////////////////////// + + stream >> messageID; + total_length += sizeof(QChar) * messageID.length() + (int)sizeof(quint32); // ID + + if (m_receive_buffer.size() < (total_length + (int)sizeof (quint16))) + { + bDebug << "Received data is to small to read data block!"; + return false; + } + + ///////////////////////////////////////////////// + // Read the data + ///////////////////////////////////////////////// + + data.resize(message_length); + qint32 bytes = stream.readRawData(data.data(), message_length); + + bAssert (bytes == message_length); + bAssert (data.size() == message_length); + + quint16 crc_calc = qChecksum (data.constData(), data.size()); + quint16 crc_recv = 0; + stream >> (quint16)crc_recv; + + total_length += (int)sizeof(quint16); + + m_receive_buffer.remove(0, total_length); + + if (crc_calc != crc_recv) + { + bWarning << "Message CRC error!"; + data.clear(); + return false; + } + + return true; + } + +} // namespace BlackMisc diff --git a/src/blackmisc/com_handler.h b/src/blackmisc/com_handler.h new file mode 100644 index 000000000..913e50635 --- /dev/null +++ b/src/blackmisc/com_handler.h @@ -0,0 +1,72 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef COM_HANDLER_H +#define COM_HANDLER_H + +#include + +class QTcpSocket; + +const qint32 Sync_Marker = 0x1ACFFC1D; + +namespace BlackMisc +{ + //! IComHandler Interface. + /*! + This interface implements the basic class for every InterCommunikation + objects. It creates the frames in which the data is packed and + deframes it, when it receives something from the TCP socket. + \sa CComClient CComServer + */ + class IComHandler : public QObject + { + Q_OBJECT + + public: + //! Constructor + /*! + \param parent Pointer to the parent QObject + */ + explicit IComHandler(QObject *parent = 0); + + //! Virtual destructor + virtual ~IComHandler() {} + + protected: + + //! Creates a sendable frame containing some data. + /*! + \param messageID QString with the unique messageID + \param message The actual data + \sa IMessage + */ + void createFrame (const QString &messageID, const QByteArray &data); + + //! Parses a new frame and constructs messageID and data out of it + /*! + \param messageID Reference to the QString messageID + \param message Reference where the data will be stored in. + \sa IMessage + */ + bool parseFrame(QString &messageID, QByteArray &data); + + //! Receive Buffer + /*! + Data received from the TCP socket, will stored in here. + */ + QByteArray m_receive_buffer; + + //! Sender Buffer + /*! + Sending data via the TCP socket, should be stored in here. + */ + QByteArray m_sender_buffer; + + }; + +} // namespace BlackMisc + +#endif // COM_HANDLER_H diff --git a/src/blackmisc/com_server.cpp b/src/blackmisc/com_server.cpp new file mode 100644 index 000000000..85a7aee1c --- /dev/null +++ b/src/blackmisc/com_server.cpp @@ -0,0 +1,136 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#include +#include + +#include "blackmisc/debug.h" +#include "blackmisc/com_client_buffer.h" +#include "blackmisc/com_server.h" + +namespace BlackMisc +{ + +CComServer::CComServer(QObject *parent) + : QObject(parent), m_tcp_server(NULL), m_port(0) +{ + init(); +} + +CComServer::~CComServer() +{ + //QObject::disconnect(m_tcp_server, SIGNAL(newConnection()), this, SLOT(onIncomingConnection()) ); + + TClientBufferHash::iterator it = m_client_buffers.begin(); + while (it != m_client_buffers.end()) + { + it.value()->deleteLater(); + ++it; + } + + m_tcp_server->close(); + m_tcp_server->deleteLater(); +} + +bool CComServer::init() +{ + m_tcp_server = new QTcpServer(this); + bAssert (m_tcp_server); + bAssert ( QObject::connect(m_tcp_server, SIGNAL(newConnection()), this, SLOT(onIncomingConnection()) ) ); + + return true; +} + +void CComServer::Host(const QHostAddress &address, const quint16 port) +{ + if (isHosting()) return; + + bAssert ( ! address.isNull() ); + bAssert ( port > 0 ); + + if ( !m_tcp_server->listen(address, port) ) + { + bError << "Hosting failed"; + emit doHostClosed(); + } + else + { + bDebug << "Hosting successfull"; + emit doHosting(); + } +} + +bool CComServer::isHosting() const +{ + return m_tcp_server->isListening(); +} + +void CComServer::close() +{ + m_tcp_server->close(); +} + +void CComServer::sendToClient( const uint clientID, const QString &messageID, const QByteArray& data) +{ + if (!m_client_buffers.contains(clientID)) + { + bWarning << "Cannot send data to client - unknown client!"; + return; + } + m_client_buffers.value(clientID)->sendMessage(messageID, data); +} + +void CComServer::sendToAll(const QString &messageID, const QByteArray& data) +{ + TClientBufferHash::const_iterator it = m_client_buffers.constBegin(); + while (it != m_client_buffers.constEnd()) + { + it.value()->sendMessage(messageID, data); + ++it; + } +} + +QString CComServer::getErrorMessage( const QAbstractSocket::SocketError error ) +{ + return QString(); +} + +void CComServer::onIncomingConnection() +{ + while ( m_tcp_server->hasPendingConnections() ) + { + QTcpSocket* socket = m_tcp_server->nextPendingConnection(); + uint clientID = qHash(socket); + + // Create new ClientBuffer object. This new object gets the owner of the socket + CComClientBuffer* clientbuf = new CComClientBuffer (clientID, socket,this); + bAssert(clientbuf); + + connect(clientbuf, SIGNAL(doDisconnected(uint)), this, SLOT(onClientDisconnected(uint))); + connect(clientbuf, SIGNAL(doReceivedMessage(uint, QString&, QByteArray&)), this, SLOT(onClientMessageReceived(uint, QString&, QByteArray&))); + + m_client_buffers.insert(clientID, clientbuf); + + emit doClientConnected(); + } +} + +void CComServer::onClientDisconnected(uint clientID) +{ + if ( !m_client_buffers.contains(clientID)) + { + bWarning << "Disconnected unknown client!"; + return; + } + + m_client_buffers.take(clientID)->deleteLater(); +} + +void CComServer::onClientMessageReceived(uint clientID, QString &messageID, QByteArray &message) +{ + emit doMessageReceived(messageID, message); +} + +} // namespace BlackMisc diff --git a/src/blackmisc/com_server.h b/src/blackmisc/com_server.h new file mode 100644 index 000000000..4ca0cd3b4 --- /dev/null +++ b/src/blackmisc/com_server.h @@ -0,0 +1,104 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef TCP_SERVER_H +#define TCP_SERVER_H + +#include +#include +#include + +class QTcpServer; + +class CComClientBuffer; + +namespace BlackMisc +{ + + class CComServer : public QObject + { + Q_OBJECT + + public: + + //! Constructor + /*! + \param parent Pointer to the parent QObject + */ + CComServer(QObject *parent = 0); + + //! Destructor + ~CComServer(); + + //! This method initializes the server + /*! + \return Returns true, if successfull, otherwise false + */ + bool init (); + + //! Call this method to start hosting + void Host ( const QHostAddress & address, const quint16 port); + + //! Hosting status + /*! + \return Returns true if hosting, otherwise false + */ + bool isHosting () const; + + //! Closes the opened hosting session + void close(); + + //! Sends data to a client + /*! + \param clientID ID of the target client + \param messageID ID of the message, to be sent to the client + \param data The actual data/message + */ + void sendToClient(const quint32 clientID, const QString &messageID, const QByteArray& data); + + //! Sends data to all clients + /*! + \param messageID ID of the message, to be sent to the client + \param data The actual data/message + */ + void sendToAll(const QString &messageID, const QByteArray& data); + + //! Call this method to get last error + /*! + \return Returns a string representation of the last error. + */ + QString getErrorMessage( const QAbstractSocket::SocketError error); + + signals: + + void doHostClosed(); + void doHosting(); + void doClientConnected(); + void doClientDisconnected(); + void doMessageReceived(QString &, QByteArray &); + void doMessageReceived(); + + protected slots: + + void onIncomingConnection(); + + void onClientDisconnected(uint clientID); + + void onClientMessageReceived(uint clientHash, QString &messageID, QByteArray &message); + + protected: + + QTcpServer* m_tcp_server; + + QHostAddress m_address; + quint16 m_port; + + typedef QHash TClientBufferHash; + TClientBufferHash m_client_buffers; + }; + +} // namespace BlackMisc + +#endif // TCP_SERVER_H diff --git a/src/blackmisc/config.cpp b/src/blackmisc/config.cpp new file mode 100644 index 000000000..646d8d13b --- /dev/null +++ b/src/blackmisc/config.cpp @@ -0,0 +1,240 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#include +#include + +#include "blackmisc/debug.h" +#include "blackmisc/config.h" + +namespace BlackMisc +{ + CValue::CValue() : _type(CONFIG_UNKOWN), _value(""), _int_value(0), + _bool_value(false), _double_value(0.0) + { + + } + + CValue::CValue (const QString& value) : _type(CONFIG_UNKOWN), _value(value), _int_value(0), + _bool_value(false), _double_value(0.0) + { + init(); + } + + void CValue::init() + { + bool result = false; + qint32 int_value = 0; + double double_value = 0.0; + + int_value = _value.toInt( &result ); + if (result) + { + _type = CONFIG_INT; + _int_value = int_value; + _double_value = int_value; + _bool_value = false; + return; + } + + double_value = _value.toDouble( &result ); + if (result) + { + _type = CONFIG_DOUBLE; + _int_value = 0; + _double_value = double_value; + _bool_value = false; + return; + } + + if ( _value.compare("false", Qt::CaseInsensitive) == 0) + { + _type = CONFIG_BOOL; + _int_value = 0; + _double_value = 0.0; + _bool_value = false; + return; + } + + if ( _value.compare("true", Qt::CaseInsensitive) == 0) + { + _type = CONFIG_BOOL; + _int_value = 0; + _double_value = 0.0; + _bool_value = true; + return; + } + + _type = CONFIG_STRING; + _int_value = 0; + _double_value = 0.0; + _bool_value = false; + } + + qint32 CValue::asInt( bool* ok ) + { + bool result = true; + if ( _type != CONFIG_INT ) + { + result = false; + } + + if (ok != NULL) + *ok = result; + return _int_value; + } + + double CValue::asDouble( bool* ok ) + { + bool result = true; + if ( _type != CONFIG_DOUBLE ) + { + result = false; + } + + if (ok != NULL) + *ok = result; + return _double_value; + } + + bool CValue::asBool( bool* ok ) + { + bool result = true; + if ( _type != CONFIG_BOOL ) + { + result = false; + } + + if (ok != NULL) + *ok = result; + return _bool_value; + } + + CConfig::CConfig(const QString& filename, const QString& separator, bool isRelative) + { + m_configfile = filename; + m_separator = separator; + } + + bool CConfig::load() + { + return load(m_configfile); + } + + bool CConfig::load(const QString& filename) + { + m_configfile = filename; + + m_value_map.clear(); + + if (m_configfile.isEmpty()) + { + bError << "Can't open emtpy config file!"; + return false; + } + QFile input (m_configfile); + if ( !input.open(QIODevice::ReadOnly)) + { + bError << "Failed to open config file !" << m_configfile; + input.close(); + return false; + } + + bool error = false; + quint32 no_line = 0; + + QTextStream instream(&input); + + while ( !instream.atEnd() ) + { + ++no_line; + + QString line = instream.readLine(); + + // Remove any whitespace from the start and end + line = line.trimmed(); + + // Search for the comment operator and discard it + int pos = line.indexOf( QChar('#') ); + if ( pos != -1 ) + line = line.left(pos).trimmed(); + + // Check if we have a empty line + if ( line.isEmpty() ) + continue; + + // Separate between key and value + QStringList tags = line.split(m_separator); + if ( tags.count() != 2) + { + bWarning << "Could not parse line " << no_line << " in file " << m_configfile << "!"; + error = true; + continue; + } + QString key = tags[0].trimmed(); + CValue value = CValue( tags[1].trimmed() ); + + setValue (key, value); + } + + input.close(); + return !error; + } + + void CConfig::setValue(const QString &key, const CValue &value) + { + if ( contains(key) ) + update(key, value); + else + add(key, value); + } + + CValue CConfig::value(const QString &key) const + { + if (m_value_map.contains(key)) + return m_value_map.value(key); + else + return CValue(); + } + + bool CConfig::contains(const QString &key) const + { + return m_value_map.contains(key); + } + + void CConfig::remove(const QString &key) + { + m_value_map.remove(key); + } + + void CConfig::add(const QString &key, const CValue &value) + { + // Paranoid... + if ( contains(key) ) + { + update(key, value); + } + else + { + m_value_map.insert(key, value); + } + } + + void CConfig::update(const QString &key, const CValue &value) + { + + } + + void CConfig::display() + { + TValueMap::const_iterator it; + for (it = m_value_map.begin(); it != m_value_map.end(); ++it) + { + CValue value = it.value(); + bDebug << "Key: " << it.key() << " - Value: " << value.asString(); + } + } + +} //! namespace BlackMisc diff --git a/src/blackmisc/config.h b/src/blackmisc/config.h new file mode 100644 index 000000000..4661ef6c0 --- /dev/null +++ b/src/blackmisc/config.h @@ -0,0 +1,162 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef CONFIG_H +#define CONFIG_H + +#include +#include + +namespace BlackMisc +{ + + class CValue + { + public: + + //! Configuration type enum. + /*! This enum lists the three different values, used in the config file. */ + typedef enum { CONFIG_STRING = 0, /*!< Type String. */ + CONFIG_INT, /*!< Type Integer. */ + CONFIG_DOUBLE, /*!< Type Double. */ + CONFIG_BOOL, /*!< Type Bool. */ + CONFIG_UNKOWN /*!< Type Unknown. */ + } TConfigType; + + CValue (); + + CValue (const QString& value); + + void init(); + + QString& asString() { return _value; } + + qint32 asInt( bool* ok = NULL ); + + bool asBool(bool* ok = NULL ); + + double asDouble( bool* result ); + + inline bool isValid() {return _type != CONFIG_UNKOWN;} + + inline bool isInt() { return _type == CONFIG_INT; } + inline bool isDouble() { return _type == CONFIG_DOUBLE; } + inline bool isBool() { return _type == CONFIG_BOOL; } + + protected: + + QString _value; + TConfigType _type; + + qint32 _int_value; + double _double_value; + bool _bool_value; + + }; + + //! Configuration class. + /*! + This class implements the configuration part of the library. + */ + class CConfig + { + public: + + CConfig(const QString& filename, const QString& separator = "=", bool isRelative = false); + + //! Sets the value of the specified key. + /*! + \param key Key, which value should be set. + \param value The actual value as T. + */ + void setValue(const QString& key, const CValue& value); + + //! Returns the value from key. + /*! + \param key Specified key. + \return The value to key 'key' as T& + */ + CValue value(const QString& key) const; + + //! Function to check if the key is in the config. + /*! + \param key Specified key. + \return Returns true, if key is in the config. + */ + void add (const QString& key, const CValue& value); + + //! Function to check if the key is in the config. + /*! + \param key Specified key. + \return Returns true, if key is in the config. + */ + void update (const QString& key, const CValue& value); + + //! Function to check if the key is in the config. + /*! + \param key Specified key. + \return Returns true, if key is in the config. + */ + bool contains (const QString& key) const; + + //! Removes the key and its value from the config. + /*! + \param key Key, which has to be removed. + */ + void remove (const QString& key); + + //! Displays the configuration to the debug output. + /*! + More info. + */ + void display (); + + /*! + * Config File section + */ + + //! Returns the config filename of this config object. + /*! + \return filename of this config. + */ + const QString& configFile() const {return m_configfile; } + + //! Loads the config file. + /*! + \return Returns true if loading went well. + */ + bool load (); + + //! Loads the config file. + /*! + \param filename Specify a different filename. + \return Returns true if loading went well. + */ + bool load (const QString& filename); + + //! Saves the config to file. + /*! + \return Returns true if loading went well. + */ + bool save() {} // TODO + + //! Saves the config to file. + /*! + \param filename Specify a different filename. + \return Returns true if loading went well. + */ + bool save(const QString& filename) {} // TODO + + protected: + + QString m_configfile; + QString m_separator; + typedef QMap TValueMap; + TValueMap m_value_map; + + }; +} //! namespace BlackMisc + +#endif // CONFIG_H diff --git a/src/blackmisc/config_manager.cpp b/src/blackmisc/config_manager.cpp new file mode 100644 index 000000000..52eff6f37 --- /dev/null +++ b/src/blackmisc/config_manager.cpp @@ -0,0 +1,94 @@ +#include +#include + + +#include "blackmisc/config.h" +#include "blackmisc/debug.h" +#include "blackmisc/config_manager.h" + +namespace BlackMisc +{ + SINGLETON_CLASS_IMPLEMENTATION(CConfigManager) + + CConfigManager::CConfigManager() + { + } + + void CConfigManager::setConfigPath(QString &path) + { + m_config_path = QDir(path).absolutePath(); + + } + + int CConfigManager::readConfig(bool forceReload) + { + /*! + Foreach *.cfg file in the config path, + create a new CConfig object and parse it into. + Then append the pointer to this object into + the config map. + */ + + if (forceReload) + clear(); + + QDir directory(m_config_path); + QStringList filters; + filters << "*.cfg"; + directory.setNameFilters(filters); + + QStringList files = directory.entryList(); + + QStringList::const_iterator constIterator; + for (constIterator = files.constBegin(); constIterator != files.constEnd(); ++constIterator) + { + int index = (*constIterator).indexOf("."); + QString section = (*constIterator).left(index); + + if (!m_config_map.contains(section)) + { + QString filePath = m_config_path + QDir::separator() + (*constIterator); + CConfig *config = new CConfig(filePath); + config->load(); + + m_config_map.insert(section, config); + } + } + + return m_config_map.size(); + } + + int CConfigManager::writeConfig() + { + /*! + Foreach config object in the map, + create a file with all values, from + the object. Filename is created + from the section name + */ + return m_config_map.size(); + } + + void CConfigManager::clear() + { + TConfigMap::iterator iterator; + for (iterator = m_config_map.begin(); iterator != m_config_map.end(); ++iterator) + { + delete iterator.value(); + } + + m_config_map.clear(); + } + + CConfig *CConfigManager::getConfig(const QString §ion) + { + if (m_config_map.contains(section)) + return m_config_map.value(section); + else + { + bError << "Could not find config section: " << section; + return NULL; + } + } + +} // namespace BlackMisc \ No newline at end of file diff --git a/src/blackmisc/config_manager.h b/src/blackmisc/config_manager.h new file mode 100644 index 000000000..737cca67a --- /dev/null +++ b/src/blackmisc/config_manager.h @@ -0,0 +1,59 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef CONFIGMANAGER_H +#define CONFIGMANAGER_H + +#include +#include + +#include "blackmisc/context.h" + +namespace BlackMisc +{ + + class CConfig; + + class CConfigManager + { + // safe singleton declaration + SINGLETON_CLASS_DECLARATION(CConfigManager) + + CConfigManager(); + public: + + //! Configuration Manager error codes. + /*! This enum lists all errors, which can appear. If you need + * a readable output then consider using /sa getErrorString() + */ + typedef enum { UNKNOWN_PATH = 0, /*!< Type String. */ + + } TErrorCodes; + + //! Sets the global path, where all the config files are located + /*! + \param path absolute pathname + */ + void setConfigPath(QString &path); + + int readConfig(bool forceReload = false); + + int writeConfig(); + + void clear(); + + CConfig *getConfig(const QString §ion); + + private: + + typedef QMap TConfigMap; + TConfigMap m_config_map; + + QString m_config_path; + + }; +} // namespace BlackLib + +#endif // CONFIGMANAGER_H \ No newline at end of file diff --git a/src/blackmisc/context.cpp b/src/blackmisc/context.cpp new file mode 100644 index 000000000..5f107831f --- /dev/null +++ b/src/blackmisc/context.cpp @@ -0,0 +1,113 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#include "blackmisc/debug.h" +#include "blackmisc/context.h" + +namespace BlackMisc +{ + + IContext *IContext::m_context = NULL; + + IContext &IContext::getInstance() + { + if (m_context == NULL) + { + m_context = new CApplicationContext; + } + return *m_context; + } + + bool IContext::isInitialised() + { + return m_context != NULL; + } + + + IContext::~IContext() + { + m_context = NULL; + } + + void IContext::registerContext() + { + #ifdef Q_OS_WIN + bAssert(m_context == NULL); + #endif // Q_OS_WIN + m_context = this; + + m_debug = new CDebug; + } + + CApplicationContext::CApplicationContext() + { + registerContext(); + } + + void *CApplicationContext::singletonPointer(const QString &singletonName) + { + TSingletonMap::const_iterator it = m_singletonObjects.find(singletonName); + if (it != m_singletonObjects.end()) + return it.value(); + + return NULL; + } + + void CApplicationContext::setSingletonPointer(const QString &singletonName, void *object) + { + m_singletonObjects.insert(singletonName, object); + } + + void CApplicationContext::releaseSingletonPointer(const QString &singletonName, void *object) + { + bAssert (m_singletonObjects.find(singletonName).value() == object); + m_singletonObjects.remove(singletonName); + } + + CDebug *CApplicationContext::getDebug() + { + return m_debug; + } + + void CApplicationContext::setDebug(CDebug *debug) + { + m_debug = debug; + } + + CLibraryContext::CLibraryContext(IContext &applicationContext) + : m_applicationContext(&applicationContext) + { + registerContext(); + } + + void *CLibraryContext::singletonPointer(const QString &singletonName) + { + bAssert(m_applicationContext != NULL); + return m_applicationContext->singletonPointer(singletonName); + } + + void CLibraryContext::setSingletonPointer(const QString &singletonName, void *object) + { + bAssert(m_applicationContext != NULL); + m_applicationContext->setSingletonPointer(singletonName, object); + } + + void CLibraryContext::releaseSingletonPointer(const QString &singletonName, void *object) + { + bAssert(m_applicationContext != NULL); + m_applicationContext->releaseSingletonPointer(singletonName, object); + } + + CDebug *CLibraryContext::getDebug() + { + return m_applicationContext->getDebug(); + } + + void CLibraryContext::setDebug(CDebug *debug) + { + m_debug = debug; + } + +} // namespace BlackMisc diff --git a/src/blackmisc/context.h b/src/blackmisc/context.h new file mode 100644 index 000000000..8a3ffe2f9 --- /dev/null +++ b/src/blackmisc/context.h @@ -0,0 +1,249 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef CONTEXT_H +#define CONTEXT_H + +#include + +namespace BlackMisc +{ + class CLog; + class CDebug; + + //! IContext Interface. + /*! + This interface abstracts any application and library context. Use it to + add singleton classes and for application and library wide logging. + */ + class IContext + { + public: + + //! Reference to IConext. + /*! + This static function returns a reference to the singleton object. + Use always this method to retrieve the context, since you cannot + instantiate your own one. Before it can be used you have to create + either a CApplicationContext or a CLibraryContext in the very + beginning of the executable/libary. + */ + static IContext &getInstance(); + + //! Returns true if the context is initialized and ready. + /*! + \return Returns true if context is initialized, otherwise false. + */ + static bool isInitialised(); + + //! Destructor. + /*! + Destroys the context. + */ + virtual ~IContext(); + + //! Pure virtual method returns the pointer to singletone object by its name. + /*! + \param singletonName a reference to the singletones name. + \return Returns a pointer to the singleton object. + */ + virtual void *singletonPointer(const QString &singletonName) = NULL; + + //! Pure virtual method sets the singletone pointer, given by its name. + /*! + \param singletonName a reference to the singletones name. + \param object a pointer to the singletone object. + */ + virtual void setSingletonPointer(const QString &singletonName, void *object) = NULL; + + //! Deallocates the object and removes the singletone pointer from the context map. + /*! + \param singletonName a reference to the singletones name. + \param object a pointer to the singletone object. + */ + virtual void releaseSingletonPointer(const QString &singletonName, void *object) = NULL; + + //! Pure virtual method returns the pointer to debug object + /*! + \return Pointer to CDebug object + */ + virtual CDebug *getDebug() = NULL; + + //! Pure virtual function to set the global error log object + /*! + \param Pointer to CDebug object + */ + virtual void setDebug(CDebug *debug) = NULL; + + protected: + //! Method to register the context. + /*! This method should be called by the derived class. It sets the + context variable to the calling object.*/ + /*! + \param Pointer to CLog object + */ + void registerContext(); + + //! Pointer to the global context. + /*! + This variable holds a pointer to the application context. + */ + static IContext *m_context; + + //! Pointer to the global Debug object. + /*! + This member variable contains all logging types, not only debug. + */ + CDebug *m_debug; + + }; + + //! CApplicationContext. + /*! + This class implements the IContext interface for applications. + */ + class CApplicationContext : public IContext + { + public: + CApplicationContext(); + + //! This method returns the pointer to singletone object by its name. + /*! + \param singletonName a reference to the singletones name. + \return Returns a pointer to the singleton object. + */ + virtual void *singletonPointer(const QString &singletonName); + + //! Sets the singletone pointer, given by its name. + /*! + \param singletonName a reference to the singletones name. + \param object a pointer to the singletone object. + */ + virtual void setSingletonPointer(const QString &singletonName, void *object); + + //! Deallocates the object and removes the singletone pointer from the context map. + /*! + \param singletonName a reference to the singletones name. + \param object a pointer to the singletone object. + */ + virtual void releaseSingletonPointer(const QString &singletonName, void *ptr); + + //! Pure virtual method returns the pointer to debug object + /*! + \return Pointer to CDebug object + */ + virtual CDebug *getDebug(); + + //! Pure virtual function to set the global error log object + /*! + \param Pointer to CDebug object + */ + virtual void setDebug(CDebug *debug); + + private: + //! Typedef for the singleton map + typedef QMap TSingletonMap; + + //! Map of all registered objects inside the application. + /*! + This map holds associates all registered singleton objects to their names. + */ + TSingletonMap m_singletonObjects; + }; + + //! CApplicationContext. + /*! + This class implements the IContext interface for libraries. + */ + class CLibraryContext : public IContext + { + public: + CLibraryContext (IContext &application); + + //! This method returns the pointer to singletone object by its name. + /*! + \param singletonName a reference to the singletones name. + \return Returns a pointer to the singleton object. + */ + virtual void *singletonPointer(const QString &singletonName); + + //! Sets the singletone pointer, given by its name. + /*! + \param singletonName a reference to the singletones name. + \param object a pointer to the singletone object. + */ + virtual void setSingletonPointer(const QString &singletonName, void *ptr); + + //! Deallocates the object and removes the singletone pointer from the context map. + /*! + \param singletonName a reference to the singletones name. + \param object a pointer to the singletone object. + */ + virtual void releaseSingletonPointer(const QString &singletonName, void *ptr); + + //! Pure virtual method returns the pointer to debug object + /*! + \return Pointer to CDebug object + */ + virtual CDebug *getDebug(); + + //! Pure virtual function to set the global error log object + /*! + \param Pointer to CDebug object + */ + virtual void setDebug(CDebug *debug); + + private: + //! Pointer the application context. + /*! + Libraries do not have their own context, because they are using + the one from the linked application. + */ + IContext *m_applicationContext; + }; + + /*! + This macros helps to create the body of a singletone class, + which registers itself with the application context. + */ + #define SINGLETON_CLASS_DECLARATION(className) \ + private:\ + /* Singletone class constructor */ \ + className (const className &) {}\ + /* the local static pointer to the singleton instance */ \ + static className *m_instance; \ + public:\ + static className &getInstance() \ + { \ + if (m_instance == NULL) \ + { \ + /* We need a valid context.*/ \ + bAssertstr(BlackMisc::IContext::isInitialised(), QString("You are trying to access a singleton without having initialized a context. The simplest correction is to add 'BlackMisc::CApplicationContext myApplicationContext;' at the very beginning of your application.")); \ + \ + /* Get the singleton object from the context, if there is one */ \ + void *object = BlackMisc::IContext::getInstance().singletonPointer(#className); \ + if (object == NULL) \ + { \ + /* We have no allocated object yet, so do it now. */ \ + m_instance = new className; \ + BlackMisc::IContext::getInstance().setSingletonPointer(#className, m_instance); \ + } \ + else \ + { \ + /* Always use the c++ methods instead of casting the C way. */ \ + m_instance = reinterpret_cast(object); \ + } \ + } \ + return *m_instance; \ + } \ + private: + /* Put your class constructor directly after this makro and make sure it is private! */ + + + #define SINGLETON_CLASS_IMPLEMENTATION(className) className *className::m_instance = NULL; + +} // namespace BlackMisc + +#endif CONTEXT_H diff --git a/src/blackmisc/debug.cpp b/src/blackmisc/debug.cpp new file mode 100644 index 000000000..0dc869659 --- /dev/null +++ b/src/blackmisc/debug.cpp @@ -0,0 +1,191 @@ +#include +#include +#include "blackmisc/log.h" +#include "blackmisc/debug.h" +#include "blackmisc/display.h" + +namespace BlackMisc +{ + + CDebug::CDebug() + : m_isInitialized(false), m_errorLog(NULL), m_warningLog(NULL), + m_infoLog(NULL), m_debugLog(NULL), m_assertLog(NULL) + { + + } + + void CDebug::create (QString &logPath, bool logInFile, bool eraseLastLog) + { + if (!m_isInitialized) + { + setErrorLog(new CLog (CLog::ERROR)); + setWarningLog(new CLog (CLog::WARNING)); + setInfoLog(new CLog (CLog::INFO)); + setDebugLog(new CLog (CLog::DEBUG)); + setAssertLog(new CLog (CLog::ASSERT)); + + stdDisplayer = new CStdDisplay ("DEFAULT_SD"); + + if (logInFile) + { + QDir fileinfo(m_logPath); + QString fn; + if ( !m_logPath.isEmpty() ) + { + m_logPath = fileinfo.absolutePath(); + fn += m_logPath; + } + else + { + } + + fileDisplayer = new CFileDisplay ("", true, "DEFAULT_FD"); + fileDisplayer = new CFileDisplay ("", eraseLastLog, "DEFAULT_FD"); + } + + init(true); + m_isInitialized = true; + } + } + + void CDebug::init (bool logInFile) + { + m_debugLog->attachDisplay(stdDisplayer); + m_infoLog->attachDisplay (stdDisplayer); + m_warningLog->attachDisplay (stdDisplayer); + m_assertLog->attachDisplay (stdDisplayer); + m_errorLog->attachDisplay (stdDisplayer); + + if (logInFile) + { + m_debugLog->attachDisplay (fileDisplayer); + m_infoLog->attachDisplay (fileDisplayer); + m_warningLog->attachDisplay (fileDisplayer); + m_assertLog->attachDisplay (fileDisplayer); + m_errorLog->attachDisplay (fileDisplayer); + } + } + + QString CDebug::getLogDirectory() + { + return m_logPath; + } + + void CDebug::assertFailed(int line, const char *file, const char* function, const char *exp) + { + m_assertLog->setLogInformation (line, file, function); + BlackMisc::CLogMessage::getAssertMsgObj() << "ASSERT FAILED! STOP!"; + + #ifdef BB_GUI + QMessageBox::critical(0, "ASSERT FAILED", + QString("%1 %2 %3 () - failed assert: %4"). + arg(QString(file)).arg(line).arg(QString(function)).arg(QString(exp))); + + qApp->quit(); + exit(1); + #endif + + } + + CLog *CDebug::getErrorLog() + { + return m_errorLog; + } + + void CDebug::setErrorLog(CLog *errorLog) + { + m_errorLog = errorLog; + } + + CLog *CDebug::getWarningLog() + { + return m_warningLog; + } + + void CDebug::setWarningLog(CLog *warningLog) + { + m_warningLog = warningLog; + } + + CLog *CDebug::getInfoLog() + { + return m_infoLog; + } + + void CDebug::setInfoLog(CLog *infoLog) + { + m_infoLog = infoLog; + } + + CLog *CDebug::getDebugLog() + { + return m_debugLog; + } + + void CDebug::setDebugLog(CLog *debugLog) + { + m_debugLog = debugLog; + } + + CLog *CDebug::getAssertLog() + { + return m_assertLog; + } + + void CDebug::setAssertLog(CLog *assertLog) + { + m_assertLog = assertLog; + } + + void CDebug::assertFailedString(int line, const char *fileName, const char *methodName, const char* exp, const char* string) + { + m_assertLog->setLogInformation (line, fileName, methodName); + BlackMisc::CLogMessage::getAssertMsgObj() << "ASSERT FAILED: " << string; + #ifdef BB_GUI + QMessageBox::critical(0, "ASSERT FAILED", string); + #endif + } + + CLogMessage CDebug::blackInfo(int line, const char *fileName, const char *methodName) + { + create(); + m_infoLog->setLogInformation( line, fileName, methodName); + return BlackMisc::CLogMessage::getInfoMsgObj(); + } + + CLogMessage CDebug::blackWarning(int line, const char *fileName, const char *methodName) + { + create(); + m_warningLog->setLogInformation( line, fileName, methodName); + return BlackMisc::CLogMessage::getWarningMsgObj(); + } + + CLogMessage CDebug::blackDebug(int line, const char *fileName, const char *methodName) + { + create(); + m_debugLog->setLogInformation( line, fileName, methodName); + return BlackMisc::CLogMessage::getDebugMsgObj(); + } + + CLogMessage CDebug::blackError(int line, const char *fileName, const char *methodName) + { + create(); + m_errorLog->setLogInformation( line, fileName, methodName); + return BlackMisc::CLogMessage::getErrorMsgObj(); + } + + CLogMessage CDebug::blackAssert(int line, const char *fileName, const char *methodName) + { + create(); + m_assertLog->setLogInformation( line, fileName, methodName); + return BlackMisc::CLogMessage::getAssertMsgObj(); + } + + CLogMessage CDebug::blackAssertqstr(int line, const char *fileName, const char *methodName) + { + create(); + m_assertLog->setLogInformation( line, fileName, methodName); + return BlackMisc::CLogMessage::getAssertMsgObj(); + } + +} // namespace BlackMisc diff --git a/src/blackmisc/debug.h b/src/blackmisc/debug.h new file mode 100644 index 000000000..b21abc690 --- /dev/null +++ b/src/blackmisc/debug.h @@ -0,0 +1,147 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef DEBUG_H +#define DEBUG_H + +#include "blackmisc/context.h" +#include "blackmisc/log.h" +#include "blackmisc/display.h" +#include "blackmisc/logmessage.h" + +// This header contains debug macros + +namespace BlackMisc +{ + //! class CDebug + /*! This class implements the logging of the library. It holds a list of displays + takes care of any additional information needed, e.g. timestamps, filename etc. + To use the logging use the default displayer or implement your own one and + register it with this class. + */ + class CDebug + { + public: + + CDebug(); + + + // internal use only + void create (QString &logPath = QString(""), bool logInFile = true, bool eraseLastLog = false); + + // init Debug + void init(bool logInFile); + + /// Do not call this, unless you know what you're trying to do (it kills debug)! + void destroy() {} + + void changeLogDirectory(const QString &dir) {} + + QString getLogDirectory(); + + // Assert function + + //! Method returns the pointer to the global assert log object + /*! + \return Pointer to CLog object + */ + CLog *getAssertLog(); + + //! Pure virtual function to set the global assert log object + /*! + \param Pointer to CLog object + */ + void setAssertLog(CLog *assertLog); + + //! Pure virtual method returns the pointer to the global error log object + /*! + \return Pointer to CLog object + */ + CLog *getErrorLog(); + + //! Pure virtual function to set the global error log object + /*! + \param Pointer to CLog object + */ + void setErrorLog(CLog *errorLog); + + //! Pure virtual method returns the pointer to the global warning log object + /*! + \return Pointer to CLog object + */ + CLog *getWarningLog(); + + //! Pure virtual function to set the global warning log object + /*! + \param Pointer to CLog object + */ + void setWarningLog(CLog *warningLog); + + //! Pure virtual method returns the pointer to the global info log object + /*! + \return Pointer to CLog object + */ + CLog *getInfoLog(); + + //! Pure virtual function to set the global info log object + /*! + \param Pointer to CLog object + */ + void setInfoLog(CLog *infoLog); + + //! Pure virtual method returns the pointer to the global debug log object + /*! + \return Pointer to CLog object + */ + CLog *getDebugLog(); + + //! Pure virtual function to set the global debug log object + /*! + \param Pointer to CLog object + */ + void setDebugLog(CLog *debugLog); + + void assertFailed(int line, const char *file, const char* function, const char *exp); + void assertFailedString(int line, const char *fileName, const char *methodName, const char* exp, const char* string); + + CLogMessage blackInfo(int line, const char *fileName, const char *methodName); + CLogMessage blackWarning(int line, const char *fileName, const char *methodName); + CLogMessage blackDebug(int line, const char *fileName, const char *methodName); + CLogMessage blackError(int line, const char *fileName, const char *methodName); + CLogMessage blackAssert(int line, const char *fileName, const char *methodName); + CLogMessage blackAssertqstr(int line, const char *fileName, const char *methodName); + + private: + bool m_isInitialized; + + CStdDisplay *stdDisplayer; + CFileDisplay *fileDisplayer; + + QString m_logPath; + + CLog *m_errorLog; + CLog *m_warningLog; + CLog *m_infoLog; + CLog *m_debugLog; + CLog *m_assertLog; + }; + + /*! + Macro is not defined in VC6 + */ + #if _MSC_VER <= 1200 + # define __FUNCTION__ NULL + #endif + + #define bInfo ( BlackMisc::IContext::getInstance().getDebug()->blackInfo(__LINE__, __FILE__, __FUNCTION__ ) ) + #define bWarning ( BlackMisc::IContext::getInstance().getDebug()->blackWarning(__LINE__, __FILE__, __FUNCTION__ ) ) + #define bDebug ( BlackMisc::IContext::getInstance().getDebug()->blackDebug(__LINE__, __FILE__, __FUNCTION__ ) ) + #define bError ( BlackMisc::IContext::getInstance().getDebug()->blackError(__LINE__, __FILE__, __FUNCTION__ ) ) + #define bAssert(exp) if (!(exp)) BlackMisc::IContext::getInstance().getDebug()->assertFailed(__LINE__, __FILE__, __FUNCTION__, #exp) + #define bAssertstr(exp, str) if (!(exp)) BlackMisc::IContext::getInstance().getDebug()->assertFailedString(__LINE__, __FILE__, __FUNCTION__, #exp, #str) + +} // namespace BlackMisc + +#endif DEBUG_H // DEBUG_H diff --git a/src/blackmisc/display.cpp b/src/blackmisc/display.cpp new file mode 100644 index 000000000..1156578f3 --- /dev/null +++ b/src/blackmisc/display.cpp @@ -0,0 +1,264 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#include +#include + +#include "blackmisc/context.h" +#include "blackmisc/display.h" + +namespace BlackMisc +{ + + static const char *LogTypeToString[7] = + { "", "Error", "Warning", "Info", "Debug", "Assert", "Unknown" }; + + ILogDisplay::ILogDisplay(const QString &displayName) + { + m_mutex = new QMutex (); + DisplayName = displayName; + } + + ILogDisplay::~ILogDisplay() + { + delete m_mutex; + } + + const char *ILogDisplay::logTypeToString (CLog::TLogType logType) + { + if (logType < CLog::OFF || logType > CLog::UNKNOWN) + return "Not defined"; + + return LogTypeToString[logType]; + } + + QString ILogDisplay::currentDateToString () + { + QDateTime currentDateTime = QDateTime::currentDateTime(); + QString format("yyyy-MM-dd hh:mm:ss"); + return currentDateTime.toString(format); + } + + QString ILogDisplay::dateToString (const QDateTime &time) + { + QString format("yyyy-MM-dd hh:mm:ss"); + return time.toString(format); + } + + QString ILogDisplay::headLine () + { + QString header = QString("\n Logging started at %1\n").arg(currentDateToString()); + return header; + } + + /* + * Display the string where it does. + */ + void ILogDisplay::print (const CLog::SLogInformation &logInformation, const QString &message) + { + m_mutex->lock(); + doPrint( logInformation, message ); + m_mutex->unlock(); + } + + void CStdDisplay::doPrint (const CLog::SLogInformation &logInformation, const QString &message) + { + bool needSpace = false; + QString line; + + if (logInformation.m_logType != CLog::OFF) + { + line += logTypeToString(logInformation.m_logType); + needSpace = true; + } + + // Write thread identifier + if ( logInformation.m_threadId != 0 ) + { + if (needSpace) { line += " "; needSpace = false; } + line += QString("%1").arg(logInformation.m_threadId); + } + + if (logInformation.m_sourceFile != NULL) + { + if (needSpace) { line += " "; needSpace = false; } + line += QFileInfo (logInformation.m_sourceFile).fileName(); + needSpace = true; + } + + if (logInformation.m_line != -1) + { + if (needSpace) { line += " "; needSpace = false; } + line += QString("%1").arg(logInformation.m_line); + needSpace = true; + } + + if (logInformation.m_methodName != NULL) + { + if (needSpace) { line += " "; needSpace = false; } + line += logInformation.m_methodName; + needSpace = true; + } + + if (logInformation.m_applicationName != NULL) + { + if (needSpace) { line += " "; needSpace = false; } + line += logInformation.m_applicationName; + needSpace = true; + } + + if (needSpace) { line += " : "; needSpace = false; } + + line += message; + + static bool consoleMode = true; + + QTextStream out(stdout); + out << line; + } + + CFileDisplay::CFileDisplay (const QString &filename, bool eraseLastLog, const QString &displayName) : + ILogDisplay (displayName), m_needHeader(true) + { + setParam (filename, eraseLastLog); + + } + + CFileDisplay::CFileDisplay () : + ILogDisplay (""), m_needHeader(true) + { + + } + + CFileDisplay::~CFileDisplay () + { + if ( m_file->handle() != -1 ) + { + m_file->close(); + } + + delete m_file; + } + + void CFileDisplay::setParam (const QString &filename, bool eraseLastLog) + { + m_fileName = filename; + + if (filename.isEmpty()) + { + // Call this first, otherwise the Singleton pointer is NULL + CLog::setDefaultApplicationName(); + + // Read the process name and name the log accordingly + QString *processName = (QString *)IContext::getInstance().singletonPointer("BlackMisc::CLog::m_applicationName"); + + // Just in case + if ( processName != NULL ) + m_fileName = QFileInfo(*processName).baseName() + ".log"; + else + printf("Cannot create log file without a filename!"); + } + + m_file = new QFile(m_fileName); + + if (eraseLastLog) + { + // Erase all the derived log files + int i = 0; + bool fileExist = true; + while (fileExist) + { + QFileInfo info(m_fileName); + QString fileToDelete = info.absolutePath() + "/" + info.baseName() + QString("%1").arg(i, 3, 10, QChar('0')) + info.completeSuffix(); + if ( QFile::exists(fileToDelete) ) + QFile(fileToDelete).remove(); + else + fileExist = false; + i++; + } + } + + if ( m_file->handle() != -1 ) + { + m_file->close(); + } + } + + void CFileDisplay::doPrint (const CLog::SLogInformation &logInformation, const QString &message) + { + bool needSpace = false; + QString line; + + // if the filename is not set, don't log + if ( m_fileName.isEmpty() ) return; + + if (logInformation.m_dateTime.isValid()) + { + line += dateToString(logInformation.m_dateTime); + needSpace = true; + } + + if (logInformation.m_logType != CLog::OFF) + { + if (needSpace) { line += " "; needSpace = false; } + line += logTypeToString(logInformation.m_logType); + needSpace = true; + } + + if (!logInformation.m_applicationName.isEmpty()) + { + if (needSpace) { line += " "; needSpace = false; } + line += logInformation.m_applicationName; + needSpace = true; + } + + if (logInformation.m_sourceFile != NULL) + { + if (needSpace) { line += " "; needSpace = false; } + line += QFileInfo (logInformation.m_sourceFile).fileName(); + needSpace = true; + } + + if (logInformation.m_line != -1) + { + if (needSpace) { line += " "; needSpace = false; } + line += QString("%1").arg(logInformation.m_line); + needSpace = true; + } + + if (logInformation.m_methodName != NULL) + { + if (needSpace) { line += " "; needSpace = false; } + line += logInformation.m_methodName; + needSpace = true; + } + + if (needSpace) { line += " : "; needSpace = false; } + + line += message; + + // Try to open the file if the handle is invalid + if (m_file->handle() == -1) + { + if ( !m_file->open(QIODevice::WriteOnly) ) + printf ("Can't open log file '%s': %s\n", m_fileName.toLatin1(), strerror (errno)); + } + + if (m_file->handle() != -1) + { + QTextStream out(m_file); + + if (m_needHeader) + { + const QString hs = headLine(); + out << hs; + m_needHeader = false; + } + + if(!line.isEmpty()) + out << line; + } + } +} diff --git a/src/blackmisc/display.h b/src/blackmisc/display.h new file mode 100644 index 000000000..1a98eb617 --- /dev/null +++ b/src/blackmisc/display.h @@ -0,0 +1,95 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef DISPLAY_H +#define DISPLAY_H + +#include +#include + +#include "blackmisc/log.h" + +namespace BlackMisc +{ + class ILogDisplay + { + public: + /// Constructor + ILogDisplay(const QString &displayName ); + + /// Destructor + virtual ~ILogDisplay(); + + /// Display the string where it does. + void print( const CLog::SLogInformation &logInformation, const QString &message ); + + /// This is the identifier for a displayer, it is used to find or remove a displayer + QString DisplayName; + + protected: + /// Method to implement in the derived class + virtual void doPrint(const CLog::SLogInformation &logInformation, const QString &message) = NULL; + + // Return the header string with date (for the first line of the log) + static QString headLine (); + + public: + + /// Convert log type to string + static const char *logTypeToString (CLog::TLogType logType); + + /// Convert the current date to human string + static QString currentDateToString (); + + /// Convert date to "2000/01/14 10:05:17" string + static QString dateToString (const QDateTime &time); + + private: + + QMutex *m_mutex; + + }; + + class CStdDisplay : virtual public ILogDisplay + { + public: + CStdDisplay ( const QString &displayerName = QString("")) : ILogDisplay (displayerName) {} + + protected: + + /// Display the string to stdout and OutputDebugString on Windows + virtual void doPrint (const CLog::SLogInformation &logInformation, const QString &message); + + }; + + class CFileDisplay : virtual public ILogDisplay + { + public: + + /// Constructor + CFileDisplay (const QString &filename, bool eraseLastLog = false, const QString &displayName = ""); + + CFileDisplay (); + + ~CFileDisplay (); + + /// Set Parameter of the displayer if not set at the ctor time + void setParam (const QString &filename, bool eraseLastLog = false); + + protected: + /// Put the string into the file. + virtual void doPrint (const CLog::SLogInformation &logInformation, const QString &message); + + private: + QString m_fileName; + + QFile *m_file; + + bool m_needHeader; + }; +} // BlackMisc + + +#endif // DISPLAY_H diff --git a/src/blackmisc/gui_messages.h b/src/blackmisc/gui_messages.h new file mode 100644 index 000000000..e1041e2d6 --- /dev/null +++ b/src/blackmisc/gui_messages.h @@ -0,0 +1,115 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef GUI_MESSAGES_H +#define GUI_MESSAGES_H + +#include + +namespace BlackMisc +{ + class MSG_CONNECT_TO_VATSIM : public IMessage + { + public: + MSG_CONNECT_TO_VATSIM() : IMessage(QString("MSG_ID_CONNECT_TO_VATSIM")) + { + } + + QString getHost () const { return m_host; } + quint16 getPort () const { return m_port; } + QString getCallsign () const { return m_callsign; } + QString getUserID () const { return m_userid; } + QString getPassword () const { return m_password; } + QString getRealName () const { return m_realName; } + + void setHost (const QString &host) { m_host = host; } + void setPort (const quint16 &port) { m_port = port; } + void setCallsign (const QString &callsign) { m_callsign = callsign; } + void setUserID (const QString &id) { m_userid = id; } + void setPassword (const QString &password) { m_password = password; } + void setRealName (const QString &realname) { m_realName = realname; } + + virtual QDataStream& operator<< ( QDataStream& in) + { + in >> m_message_id; + in >> m_host; + in >> m_port; + in >> m_callsign; + in >> m_userid; + in >> m_password; + in >> m_realName; + return in; + } + + virtual QDataStream& operator>> (QDataStream& out) const + { + out << m_message_id; + out << m_host; + out << m_port; + out << m_callsign; + out << m_userid; + out << m_password; + out << m_realName; + return out; + } + + virtual QTextStream& operator<< ( QTextStream& in) { return in; } + virtual QTextStream& operator>> (QTextStream& out) const { return out; } + + protected: + + private: + QString m_host; + quint16 m_port; + QString m_callsign; + QString m_userid; + QString m_password; + QString m_realName; + }; + + class MSG_CHAT_MESSAGE : public IMessage + { + public: + MSG_CHAT_MESSAGE() : IMessage(QString("MSG_ID_CHAT_MESSAGE")) + { + } + + void setSource (const QString &source) { m_source = source; } + void setDestination (const QString &destination) { m_destination = destination; } + void setText (const QString &text) { m_source = text; } + + QString getSource() const {return m_source;} + QString getDestination() const {return m_destination;} + QString getText() const {return m_text;} + + virtual QDataStream& operator<< ( QDataStream& in) + { + in >> m_message_id; + in >> m_source; + in >> m_destination; + return in; + } + + virtual QDataStream& operator>> (QDataStream& out) const + { + out << m_message_id; + out << m_source; + out << m_destination; + return out; + } + + virtual QTextStream& operator<< ( QTextStream& in) { return in; } + virtual QTextStream& operator>> (QTextStream& out) const { return out; } + + protected: + + private: + QString m_source; + QString m_destination; + QString m_text; + }; +} + +#endif // GUI_MESSAGES_H \ No newline at end of file diff --git a/src/blackmisc/log.cpp b/src/blackmisc/log.cpp new file mode 100644 index 000000000..ce8e54354 --- /dev/null +++ b/src/blackmisc/log.cpp @@ -0,0 +1,253 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#include +#include +#include + +#include "blackmisc/log.h" +#include "blackmisc/display.h" +#include "blackmisc/debug.h" + +#ifdef Q_OS_WIN +# define NOMINMAX +# include +# include +#else +# include +#endif + +namespace BlackMisc +{ + QString *CLog::m_applicationName = NULL; + + CLog::CLog(TLogType logType) : m_logType (logType) + { + } + + CLog::~CLog(void) + { + } + + void CLog::setDefaultApplicationName() + { + //! Get the object from the singleton context and create a new one if not already done + if (m_applicationName == NULL) + { + m_applicationName = static_cast(IContext::getInstance().singletonPointer("BlackMisc::CLog::m_applicationName")); + if (m_applicationName == NULL) + { + m_applicationName = new QString; + IContext::getInstance().setSingletonPointer("BlackMisc::CLog::m_applicationName", m_applicationName); + } + } + +#ifdef Q_OS_WIN + //! By default, we use the executables name. + if ((*m_applicationName).isEmpty()) + { + char name[1024]; + int size = GetModuleFileName (NULL, name, 1023); + QString applicationPath = QString::fromUtf8(name,size); + (*m_applicationName) = QFileInfo ( applicationPath ).fileName(); + } +#else + //! Todo: Check if there a corresponding API in Linux and Mac + //! For the time being, set it to unknown. + if ((*m_applicationName).empty()) + { + *m_applicationName = ""; + } +#endif + } + + void CLog::printWithNewLine( QString &message ) + { + //! If we have no displays, we have nothing to do. + if ( hasNoDisplays() ) + { + return; + } + + QChar newLine = '\n'; + + //! We should print the message with a new line. So check + //! if one is already there. If not append it. + if (!message.endsWith(newLine, Qt::CaseInsensitive)) + message.append(newLine); + + printString (message); + } + + void CLog::print( QString &message ) + { + //! If we have no displays, we have nothing to do. + if ( hasNoDisplays() ) + { + return; + } + + printString (message); + } + + void CLog::printString( QString &message ) + { + QString logDisplay; + + //! Just in case, lets set the default name + setDefaultApplicationName (); + + //! If the current line is empty, then put some information as + //! the prefix. + //! Be aware: This information must be set by the \sa setLogInformation() + //! before. + if ( m_logLine.isEmpty() ) + { + m_logInformation.m_dateTime = QDateTime::currentDateTime(); + m_logInformation.m_logType = m_logType; + m_logInformation.m_applicationName = *m_applicationName; + m_logInformation.m_threadId = 0; //getThreadId(); + m_logInformation.m_sourceFile = m_sourceFile; + m_logInformation.m_line = m_line; + m_logInformation.m_methodName = m_methodName; + + m_logLine = message; + } + else + { + m_logLine += message; + } + + //! If this is not the end of the line, we are done for now. + if ( ! message.contains('\n') ) + { + return; + } + + for ( TLogDisplayList::iterator it = m_logDisplays.begin(); it != m_logDisplays.end(); ++it) + { + (*it)->print(m_logInformation, m_logLine); + } + + //! Reset everything for the next line + m_logLine.clear(); + resetLogInformation(); + } + + void CLog::attachDisplay(ILogDisplay *display) + { + //! Display must be a valid pointer + if (display == NULL) + { + printf ("Trying to add a NULL pointer\n"); + return; + } + + //! Check if it is already attached + if ( !m_logDisplays.contains(display) ) + { + m_logDisplays.push_back (display); + } + else + { + bWarning << "Couldn't attach the display - already in the list!"; + } + } + + ILogDisplay* CLog::getDisplay(const QString &displayName) + { + //! Must be a valid name + if (displayName.isEmpty()) + { + bWarning << "Cannot return a display with empty name!"; + return NULL; + } + + TLogDisplayList::const_iterator it; + + //! Loop through the list and find the candidate + for ( it = m_logDisplays.constBegin(); it != m_logDisplays.constEnd(); ++it) + { + //! Does it have the desired name? + if ( (*it)->DisplayName == displayName ) + { + return *it; + } + } + } + + void CLog::dettachDisplay (ILogDisplay *logDisplay) + { + //! Must be a valid pointer + if (logDisplay == NULL) + { + bWarning << "Cannot remove a NULL displayer!"; + return; + } + + //! We should have only one, but just in case. + m_logDisplays.removeAll(logDisplay); + + } + + void CLog::dettachDisplay (const QString &displayName) + { + //! Must be a valid name + if (displayName.isEmpty()) + { + bWarning << "Cannot remove displayer with empty name!"; + return; + } + + TLogDisplayList::iterator it; + + for ( it = m_logDisplays.begin(); it != m_logDisplays.end(); ) + { + if ( (*it)->DisplayName == displayName ) + { + it = m_logDisplays.erase(it); + } + else + { + ++it; + } + } + } + + bool CLog::isAttached (ILogDisplay *logDisplay) const + { + return m_logDisplays.contains(logDisplay); + } + + void CLog::setLogInformation (int line, const char *sourceFile, const char *methodName) + { + //! We have to make sure, we at least one display. + if ( !hasNoDisplays() ) + { + m_mutex.lock(); + m_posSet++; + m_sourceFile = sourceFile; + m_line = line; + m_methodName = methodName; + } + } + + void CLog::resetLogInformation() + { + //! It should be impossible that this gets called, withoud + //! having a attached display. + bAssert( !hasNoDisplays() ); + + if ( m_posSet > 0 ) + { + m_sourceFile = NULL; + m_line = -1; + m_methodName = NULL; + m_posSet--; + m_mutex.unlock(); + } + } + +} // namespace BlackMisc diff --git a/src/blackmisc/log.h b/src/blackmisc/log.h new file mode 100644 index 000000000..b184f96fd --- /dev/null +++ b/src/blackmisc/log.h @@ -0,0 +1,204 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef LOG_H +#define LOG_H + +#include +#include +#include +#include + +namespace BlackMisc { + + class ILogDisplay; + + //! Logging class + /*! This class implements the logging of the library. It holds a list of displays + takes care of any additional information needed, e.g. timestamps, filename etc. + To use the logging use the default displayer or implement your own one and + register it with this class. + */ + class CLog + { + public: + //! Logging type. + /*! This enum holds all different available log types. */ + typedef enum { OFF = 0, + ERROR, + WARNING, + INFO, + DEBUG, + ASSERT, + UNKNOWN } TLogType; + + //! SLogParameter + /*! + This structs capsulates all information needed to output a log line. + */ + struct SLogInformation + { + SLogInformation() : m_logType(CLog::OFF), m_threadId(0), m_line(-1), m_sourceFile(NULL), m_methodName(NULL) {} + + QDateTime m_dateTime; + TLogType m_logType; + QString m_applicationName; + quint32 m_threadId; + const char *m_sourceFile; + qint32 m_line; + const char *m_methodName; + }; + + CLog (TLogType logType = OFF); + + //! CLog destructor. + virtual ~CLog(void); + + /*! + * Display + */ + + //! This method adds a Displayer to the Log object + /*! CLog does not own the pointer. It is the callers responsibility + to allocate the displayer and remove it after using. */ + /*! + \param display A pointer to a display. + \sa ILogDisplay + */ + void attachDisplay (BlackMisc::ILogDisplay *display); + + //! This method returns the pointer to a registered display. + /*! + \return display A pointer to a display. + */ + ILogDisplay *getDisplay (const QString &displayName); + + //! Removes a display + /*! + \param logDisplay Pointer to the display. + */ + void dettachDisplay (ILogDisplay *logDisplay); + + //! Removes a display by its name. + /*! + \param displayName Name of the display. + */ + void dettachDisplay (const QString& displayName); + + //! Checks if the displayer is added + /*! + \param logDisplay Pointer to a display. + \return Returns true if display is attached, otherwise false. + */ + bool isAttached (ILogDisplay *logDisplay) const; + + //! Checks if the object has any attached displays + /*! + \return Returns true if no display is attached, otherwise false. + */ + bool hasNoDisplays () const { return m_logDisplays.empty(); } + + //! Sets the name of the application process + /*! + \param displayName Name of the application. + */ + static void setApplicationName (const QString &displayName); + + //! Sets the default application name. This is the name + //! of the executable. + static void setDefaultApplicationName (); + + //! Sets any additional information as prefix to the log message + /*! + \param fileName This is the name of the corresponding source file. + \param methodName This is the name of calling method. + */ + void setLogInformation (int line, const char *fileName, const char *methodName = NULL); + + //! Prints the message and adds an new line character at the end + /*! + \param message Message string, which has to be logged + */ + void printWithNewLine( QString &message ); + + //! Prints the message as is and appends no additional characters + /*! + \param message Message string, which has to be logged + */ + void print( QString &message ); + + void printString ( QString &message ); + + protected: + + /// Display a string in decorated form to all attached displayers. + void displayString (const char *str); + + /// Symetric to setPosition(). Automatically called by display...(). Do not call if noDisplayer(). + void resetLogInformation(); + + //! Logging Type. + /*! + Specifies which logging type should be used. + Possible are: Error, Warning, Info, Debug and Assert. + */ + TLogType m_logType; + + //! Application name. + /*! + Specifies the name of the application to put it into the log line + */ + static QString *m_applicationName; + + //! Source file name. + /*! + Specifies the name of the source file, log message was called from. + */ + const char *m_sourceFile; + + //! Code line. + /*! + Specifies the line in the source file, log message was called from. + */ + qint32 m_line; + + //! Method name. + /*! + Specifies the method in the source file, log message was called from. + */ + const char *m_methodName; + + /*! + \typedef TLogDisplayerMap + QList container holding pointers to ILogDisplay objects + \sa ArrayList::GetEnumerator, \sa List::GetEnumerator + */ + typedef QList TLogDisplayList; + + //! List of all attached displays. + TLogDisplayList m_logDisplays; + + //! Mutex object + /*! + This makes our class thread safe. + */ + QMutex m_mutex; + + //! Position + quint32 m_posSet; + + //! Log message string + /*! + This variable is used, if a log line consists of two or more + calls. The first ones are then stored temporary in this variable + until one message ends with a line feed. + */ + QString m_logLine; + SLogInformation m_logInformation; + }; + +} // namespace BlackMisc + +#endif LOG_H diff --git a/src/blackmisc/logmessage.cpp b/src/blackmisc/logmessage.cpp new file mode 100644 index 000000000..07a42ba71 --- /dev/null +++ b/src/blackmisc/logmessage.cpp @@ -0,0 +1,54 @@ +#include "blackmisc/logmessage.h" +#include "blackmisc/debug.h" + +namespace BlackMisc +{ + + CLogMessage::LogStream::LogStream(CLog::TLogType type) + : output(&buffer, QIODevice::WriteOnly), reference(1), + type(type), needSpace(true), enableOutput(true) + {} + + CLogMessage::CLogMessage(CLog::TLogType type) + : logStream(new LogStream(type)) + { + } + + CLogMessage::CLogMessage(const CLogMessage &other) + : logStream(other.logStream) + { + ++logStream->reference; + } + + CLogMessage::~CLogMessage() { + if (!--logStream->reference) { + if(logStream->enableOutput) { + switch (logStream->type) + { + case CLog::WARNING: + BlackMisc::IContext::getInstance().getDebug()->getWarningLog()->printWithNewLine(logStream->buffer); + break; + + case CLog::INFO: + BlackMisc::IContext::getInstance().getDebug()->getInfoLog()->printWithNewLine(logStream->buffer); + break; + + case CLog::DEBUG: + BlackMisc::IContext::getInstance().getDebug()->getDebugLog()->printWithNewLine(logStream->buffer); + break; + + case CLog::ERROR: + BlackMisc::IContext::getInstance().getDebug()->getErrorLog()->printWithNewLine(logStream->buffer); + break; + + case CLog::ASSERT: + BlackMisc::IContext::getInstance().getDebug()->getAssertLog()->printWithNewLine(logStream->buffer); + break; + } + + } + delete logStream; + } + } + +} // namespace Blackib diff --git a/src/blackmisc/logmessage.h b/src/blackmisc/logmessage.h new file mode 100644 index 000000000..26945b753 --- /dev/null +++ b/src/blackmisc/logmessage.h @@ -0,0 +1,83 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef LOGMESSAGE_H +#define LOGMESSAGE_H + +// Qt includes + +#include + +#include "blackmisc/context.h" +#include "blackmisc/log.h" + +namespace BlackMisc +{ + class CLogMessage + { + struct LogStream { + + //! Constructor + LogStream(CLog::TLogType type); + + + QTextStream output; + + //! Message Buffer + QString buffer; + + //! Logging type + CLog::TLogType type; + bool needSpace; + bool enableOutput; + + //! Reference count + quint32 reference; + + } *logStream; + + public: + CLogMessage( CLog::TLogType type ); + CLogMessage(const CLogMessage &other); + + ~CLogMessage(); + + inline CLogMessage &maybeSpace() { if (logStream->needSpace) logStream->output << ' '; return *this; } + + inline CLogMessage &operator<<(QChar t) { logStream->output << '\'' << t << '\''; return maybeSpace(); } + inline CLogMessage &operator<<(QBool t) { logStream->output << (bool(t != 0) ? "true" : "false"); return maybeSpace(); } + inline CLogMessage &operator<<(bool t) { logStream->output << (t ? "true" : "false"); return maybeSpace(); } + inline CLogMessage &operator<<(char t) { logStream->output << t; return maybeSpace(); } + inline CLogMessage &operator<<(signed short t) { logStream->output << t; return maybeSpace(); } + inline CLogMessage &operator<<(unsigned short t) { logStream->output << t; return maybeSpace(); } + inline CLogMessage &operator<<(signed int t) { logStream->output << t; return maybeSpace(); } + inline CLogMessage &operator<<(unsigned int t) { logStream->output << t; return maybeSpace(); } + inline CLogMessage &operator<<(signed long t) { logStream->output << t; return maybeSpace(); } + inline CLogMessage &operator<<(unsigned long t) { logStream->output << t; return maybeSpace(); } + inline CLogMessage &operator<<(qint64 t) + { logStream->output << QString::number(t); return maybeSpace(); } + inline CLogMessage &operator<<(quint64 t) + { logStream->output << QString::number(t); return maybeSpace(); } + inline CLogMessage &operator<<(float t) { logStream->output << t; return maybeSpace(); } + inline CLogMessage &operator<<(double t) { logStream->output << t; return maybeSpace(); } + inline CLogMessage &operator<<(const char* t) { logStream->output << QString::fromAscii(t); return maybeSpace(); } + inline CLogMessage &operator<<(const QString & t) { logStream->output << '\"' << t << '\"'; return maybeSpace(); } + inline CLogMessage &operator<<(const QByteArray & t) { logStream->output << '\"' << t << '\"'; return maybeSpace(); } + + static CLogMessage getWarningMsgObj() { return CLogMessage(CLog::WARNING); } + static CLogMessage getInfoMsgObj() { return CLogMessage(CLog::INFO); } + static CLogMessage getDebugMsgObj() { return CLogMessage(CLog::DEBUG); } + static CLogMessage getErrorMsgObj() { return CLogMessage(CLog::ERROR); } + static CLogMessage getAssertMsgObj() { return CLogMessage(CLog::ASSERT); } + + inline CLogMessage &operator<<(QTextStreamManipulator m) + { logStream->output << m; return *this; } + + + }; + +} // BlackMisc + +#endif LOGMESSAGE_H// LOGMESSAGE_H diff --git a/src/blackmisc/message.cpp b/src/blackmisc/message.cpp new file mode 100644 index 000000000..a81a8769b --- /dev/null +++ b/src/blackmisc/message.cpp @@ -0,0 +1,15 @@ +#include "blackmisc/message.h" + +namespace BlackMisc +{ + IMessage::IMessage(QString& id) + { + m_message_id = id; + } + + QString IMessage::getID() const + { + return m_message_id; + } + +} // namespace BlackMisc diff --git a/src/blackmisc/message.h b/src/blackmisc/message.h new file mode 100644 index 000000000..58c9a2061 --- /dev/null +++ b/src/blackmisc/message.h @@ -0,0 +1,73 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef MESSAGE_H +#define MESSAGE_H + +#include +#include +#include +#include "blackmisc/serialize.h" + +namespace BlackMisc +{ + + class IMessage : public ISerialize + { + public: + IMessage(QString& id); + + QString getID() const; + + virtual QDataStream& operator<< ( QDataStream& in) = 0; + virtual QDataStream& operator>> (QDataStream& out) const = 0; + + virtual QTextStream& operator<< ( QTextStream& in) = 0; + virtual QTextStream& operator>> (QTextStream& out) const = 0; + + + protected: + + QString m_message_id; + }; + + class TestMessage : public IMessage + { + public: + TestMessage() : IMessage(QString("MSG_ID_TestMessage")) + { + testString = "This is a test message!"; + } + + QString getTestString () const { return testString; } + + //QDataStream &operator>>(qint8 &i); + + virtual QDataStream& operator<< ( QDataStream& in) + { + in >> m_message_id; + in >> testString; + return in; + } + + virtual QDataStream& operator>> (QDataStream& out) const + { + out << m_message_id; + out << testString; + return out; + } + + virtual QTextStream& operator<< ( QTextStream& in) { return in; } + virtual QTextStream& operator>> (QTextStream& out) const { return out; } + + protected: + + private: + QString testString; + }; + +} // namespace BlackMisc + +#endif // MESSAGE_H diff --git a/src/blackmisc/message_dispatcher.cpp b/src/blackmisc/message_dispatcher.cpp new file mode 100644 index 000000000..580881ccc --- /dev/null +++ b/src/blackmisc/message_dispatcher.cpp @@ -0,0 +1,32 @@ +#include "blackmisc/message_handler.h" +#include "blackmisc/message_dispatcher.h" + +namespace BlackMisc +{ + SINGLETON_CLASS_IMPLEMENTATION(CMessageDispatcher) + + void CMessageDispatcher::append(IMessage *message) + { + m_messageQueue.enqueue(message); + } + + void CMessageDispatcher::dispatch() + { + IMessage* message = NULL; + + if (m_messageQueue.isEmpty()) + return; + + message = m_messageQueue.dequeue(); + + if (message != NULL) + { + CTypeInfo typeinfo = CTypeInfo(typeid(*message)); + QList neededHandlers = m_messageHander.values(typeinfo); + int testsize = neededHandlers.size(); + for (int i = 0; i < neededHandlers.size(); ++i) + neededHandlers.at(i)->handleMessage(message); + } + } + +} // namespace BlackMisc diff --git a/src/blackmisc/message_dispatcher.h b/src/blackmisc/message_dispatcher.h new file mode 100644 index 000000000..820b16eae --- /dev/null +++ b/src/blackmisc/message_dispatcher.h @@ -0,0 +1,59 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef MESSAGE_DISPATCHER_H +#define MESSAGE_DISPATCHER_H + +#include +#include + +#include "blackmisc/message.h" + +#include "blackmisc/context.h" +#include "blackmisc/type_info.h" + +namespace BlackMisc +{ + class CMessageHandler; + + class CMessageDispatcher + { + + // safe singleton declaration + SINGLETON_CLASS_DECLARATION(CMessageDispatcher) + + CMessageDispatcher() {} + + public: + virtual ~CMessageDispatcher() {} + + void dispatch (); + void append ( IMessage* message); + + bool empty () + { + return m_messageQueue.size() == 0; + } + + template + void registerClass(T*, CTypeInfo); + + private: + typedef QQueue TMessageQueue; + TMessageQueue m_messageQueue; + + typedef QMultiMap TMessageHandlerMap; + TMessageHandlerMap m_messageHander; + }; + + template + void CMessageDispatcher::registerClass( T* object, CTypeInfo typeinfo) + { + m_messageHander.insert(typeinfo, object); + } + +} // namespace BlackMisc + +#endif // MESSAGE_DISPATCHER_H diff --git a/src/blackmisc/message_factory.cpp b/src/blackmisc/message_factory.cpp new file mode 100644 index 000000000..0f28a3b96 --- /dev/null +++ b/src/blackmisc/message_factory.cpp @@ -0,0 +1,48 @@ +#include "blackmisc/message_factory.h" + +namespace BlackMisc +{ + SINGLETON_CLASS_IMPLEMENTATION(CMessageFactory) + + IMessageCreator::IMessageCreator(const QString &messageID) + { + CMessageFactory::getInstance().registerMessage(messageID, this); + } + + IMessage* CMessageFactory::create(const QString &messageID) + { + if (m_creators.contains(messageID)) + { + IMessageCreator* creator = m_creators.value(messageID); + IMessage* msg = creator->create(); + return msg; + } + else + return (IMessage*)NULL; + } + + CMessageFactory::~CMessageFactory() + { + TMessageCreatorHash::iterator it = m_creators.begin(); + while (it != m_creators.end()) + { + IMessageCreator* creator = it.value(); + if (creator) + delete creator; + ++it; + } + } + + void CMessageFactory::registerMessage(const QString &messageID, IMessageCreator *creator) + { + m_creators.insert(messageID, creator); + } + + void CMessageFactory::registerMessages() + { + REGISTER_MESSAGE(TestMessage, MSG_ID_TestMessage); + REGISTER_MESSAGE(MSG_CONNECT_TO_VATSIM, MSG_ID_CONNECT_TO_VATSIM); + REGISTER_MESSAGE(MSG_CHAT_MESSAGE, MSG_ID_CHAT_MESSAGE); + } + +} // namespace BlackMisc diff --git a/src/blackmisc/message_factory.h b/src/blackmisc/message_factory.h new file mode 100644 index 000000000..e76b1d321 --- /dev/null +++ b/src/blackmisc/message_factory.h @@ -0,0 +1,59 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef MESSAGE_FACTORY_H +#define MESSAGE_FACTORY_H + +#include +#include "blackmisc/message.h" +#include "blackmisc/gui_messages.h" +#include "blackmisc/debug.h" +#include "blackmisc/context.h" + +#define REGISTER_MESSAGE(classname, msgName) new MessageCreatorImpl(#msgName); + + +namespace BlackMisc +{ + class IMessageCreator + { + public: + IMessageCreator(const QString& messageID); + + virtual IMessage* create() = 0; + }; + + template + class MessageCreatorImpl : public IMessageCreator + { + public: + MessageCreatorImpl(const QString& messageID) : IMessageCreator(messageID) {} + virtual IMessage* create() { return new T; } + }; + + class CMessageFactory + { + // safe singleton declaration + SINGLETON_CLASS_DECLARATION(CMessageFactory) + + CMessageFactory() { } + public: + + virtual ~CMessageFactory(); + + IMessage* create (const QString &messageID); + + void registerMessage(const QString &messageID, IMessageCreator* creator); + static void registerMessages(); + + private: + + typedef QHash TMessageCreatorHash; + TMessageCreatorHash m_creators; + }; + +} // namespace BlackMisc + +#endif // MESSAGE_FACTORY_H diff --git a/src/blackmisc/message_handler.cpp b/src/blackmisc/message_handler.cpp new file mode 100644 index 000000000..c5fb6c5e1 --- /dev/null +++ b/src/blackmisc/message_handler.cpp @@ -0,0 +1,25 @@ +#include "blackmisc/message_handler.h" + +namespace BlackMisc +{ + CMessageHandler::~CMessageHandler() + { + TFunctionHandlerMap::iterator it = m_messagehandler.begin(); + while (it != m_messagehandler.end()) + { + delete it.value(); + ++it; + } + m_messagehandler.clear(); + } + + void CMessageHandler::handleMessage(const IMessage * message) + { + TFunctionHandlerMap::iterator it = m_messagehandler.find(CTypeInfo(typeid(*message))); + if (it != m_messagehandler.end()) + { + it.value()->exec(message); + } + } + +} // namespace BlackMisc diff --git a/src/blackmisc/message_handler.h b/src/blackmisc/message_handler.h new file mode 100644 index 000000000..07c785ee8 --- /dev/null +++ b/src/blackmisc/message_handler.h @@ -0,0 +1,75 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef MESSAGE_HANDLER_H +#define MESSAGE_HANDLER_H + +#include +#include "blackmisc/message.h" +#include "blackmisc/debug.h" +#include "blackmisc/type_info.h" +#include "blackmisc/message_dispatcher.h" + +namespace BlackMisc +{ + + class IFunctionHandler + { + public: + virtual ~IFunctionHandler() {} + void exec (const IMessage* message) + { + call (message); + } + + private: + virtual void call (const IMessage*) = 0; + }; + + template + class MemberFunctionHandler : public IFunctionHandler + { + public: + typedef void (T::*MemberFunction)(MessageT*); + MemberFunctionHandler(T* instance, MemberFunction memfunc) : m_instance(instance), m_function(memfunc) {} + + void call(const IMessage* message) + { + (m_instance->*m_function)(static_cast(message)); + } + + private: + T* m_instance; + MemberFunction m_function; + }; + + + class CMessageHandler + { + public: + ~CMessageHandler(); + + void handleMessage(const IMessage* message); + + template + void registerMessageFunction(T*, void (T::*memfunc)(MessageT*)); + + private: + typedef QMap TFunctionHandlerMap; + TFunctionHandlerMap m_messagehandler; + }; + + template + void CMessageHandler::registerMessageFunction(T* obj, void (T::*memfunc)(MessageT*)) + { + CTypeInfo typeinfo = CTypeInfo(typeid(MessageT)); + m_messagehandler[typeinfo]= new MemberFunctionHandler(obj, memfunc); + CMessageDispatcher::getInstance().registerClass(obj, typeinfo); + } + + +} // namespace BlackMisc + +#endif // MESSAGE_HANDLER_H diff --git a/src/blackmisc/message_system.cpp b/src/blackmisc/message_system.cpp new file mode 100644 index 000000000..f236119d0 --- /dev/null +++ b/src/blackmisc/message_system.cpp @@ -0,0 +1,17 @@ +#include "blackmisc/message_system.h" + +namespace BlackMisc +{ + + +CMessageSystem::CMessageSystem() +{ + init(); +} + +void CMessageSystem::init() +{ + CMessageFactory::registerMessages(); +} + +} // namespace BlackMisc diff --git a/src/blackmisc/message_system.h b/src/blackmisc/message_system.h new file mode 100644 index 000000000..003e35e9c --- /dev/null +++ b/src/blackmisc/message_system.h @@ -0,0 +1,26 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef MESSAGE_SYSTEM_H +#define MESSAGE_SYSTEM_H + +#include "blackmisc/message_handler.h" +#include "blackmisc/message_dispatcher.h" +#include "blackmisc/message_factory.h" + +namespace BlackMisc +{ + +class CMessageSystem +{ +public: + CMessageSystem(); + + static void init(); +}; + +} // namespace BlackMisc + +#endif // MESSAGE_SYSTEM_H diff --git a/src/blackmisc/serialize.cpp b/src/blackmisc/serialize.cpp new file mode 100644 index 000000000..7a864449e --- /dev/null +++ b/src/blackmisc/serialize.cpp @@ -0,0 +1,5 @@ +#include "blackmisc/serialize.h" + +ISerialize::ISerialize() +{ +} diff --git a/src/blackmisc/serialize.h b/src/blackmisc/serialize.h new file mode 100644 index 000000000..eeac22247 --- /dev/null +++ b/src/blackmisc/serialize.h @@ -0,0 +1,21 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef SERIALIZE_H +#define SERIALIZE_H + +class QDataStream; + +class ISerialize +{ +public: + ISerialize(); + virtual ~ISerialize() {}; + + virtual QDataStream& operator<< (QDataStream& in) = 0; + virtual QDataStream& operator>> (QDataStream& out) const = 0; +}; + +#endif // SERIALIZE_H diff --git a/src/blackmisc/type_info.cpp b/src/blackmisc/type_info.cpp new file mode 100644 index 000000000..d9fb8dcc8 --- /dev/null +++ b/src/blackmisc/type_info.cpp @@ -0,0 +1,21 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#include "blackmisc/type_info.h" + +namespace BlackMisc +{ + + CTypeInfo::CTypeInfo(const type_info& info) + : m_typeinfo(info) + { + } + + bool CTypeInfo::operator <(const CTypeInfo& rhs) const + { + return m_typeinfo.before(rhs.m_typeinfo) != 0; + } + +} // namespace BlackMisc diff --git a/src/blackmisc/type_info.h b/src/blackmisc/type_info.h new file mode 100644 index 000000000..7061bd9c7 --- /dev/null +++ b/src/blackmisc/type_info.h @@ -0,0 +1,27 @@ +//! Copyright (C) 2013 Roland Winklmeier +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef TYPE_INFO_H +#define TYPE_INFO_H + +#include + +namespace BlackMisc +{ + + class CTypeInfo + { + public: + explicit CTypeInfo(const type_info& info); + + bool operator < (const CTypeInfo& rhs) const; + + private: + const type_info& m_typeinfo; + }; + +} // namespace BlackMisc + +#endif // TYPE_INFO_H diff --git a/src/blackx/CMakeLists.txt b/src/blackx/CMakeLists.txt new file mode 100644 index 000000000..e69de29bb diff --git a/src/driver/CMakeLists.txt b/src/driver/CMakeLists.txt new file mode 100644 index 000000000..397430dc9 --- /dev/null +++ b/src/driver/CMakeLists.txt @@ -0,0 +1,3 @@ +IF(WITH_DRIVER_FSX) + ADD_SUBDIRECTORY(fsx) +ENDIF(WITH_DRIVER_FSX) diff --git a/src/driver/fs9/driver_fs9.cpp b/src/driver/fs9/driver_fs9.cpp new file mode 100644 index 000000000..3e6096209 --- /dev/null +++ b/src/driver/fs9/driver_fs9.cpp @@ -0,0 +1,33 @@ +#include "driver_fs9.h" + +extern "C" +{ + Q_DECL_EXPORT ISimulator* BB_createISimulatorInstance () + { + return new CDriverFSX; + } + + Q_DECL_EXPORT quint32 BB_InterfaceVersionMajor () + { + return ISimulator::InterfaceVersionMajor; + } + + Q_DECL_EXPORT quint32 BB_InterfaceVersionMinor () + { + return ISimulator::InterfaceVersionMinor; + } +} + + +CDriverFS9::CDriverFS9() +{ +} + +void CDriverFS9::setLibraryContext(BlackMisc::IContext *context) +{ +#ifdef Q_OS_WIN + bAssert(!BlackMisc::IContext::isContextInitialised()); +#endif + + m_libraryContext = new BlackMisc::CLibraryContext(*context); +} diff --git a/src/driver/fs9/driver_fs9.h b/src/driver/fs9/driver_fs9.h new file mode 100644 index 000000000..a77a39c5e --- /dev/null +++ b/src/driver/fs9/driver_fs9.h @@ -0,0 +1,17 @@ +#ifndef DRIVER_FS9_H +#define DRIVER_FS9_H + +#include + +class CDriverFS9 : public ISimulator +{ +public: + CDriverFS9(); + virtual int init() { return 1;} + +protected: + + BlackMisc::CLibraryContext *m_libraryContext; +}; + +#endif // DRIVER_FS9_H diff --git a/src/driver/fsx/CMakeLists.txt b/src/driver/fsx/CMakeLists.txt new file mode 100644 index 000000000..bb9a16c8d --- /dev/null +++ b/src/driver/fsx/CMakeLists.txt @@ -0,0 +1,20 @@ +FILE(GLOB driver_fsx_SOURCES *.cpp) +FILE(GLOB driver_fsx_HEADERS *.h) +SET(driver_fsx_HEADERS_QOBJECT ) + +QT4_WRAP_CPP(driver_fsx_HEADERS_MOC ${driver_fsx_HEADERS_QOBJECT}) + +SOURCE_GROUP(QtGeneratedMocSrc FILES ${driver_fsx_HEADERS_MOC}) +SOURCE_GROUP (Headers FILES ${driver_fsx_HEADERS}) + +INCLUDE_DIRECTORIES(${SIMCONNECT_INCLUDE_DIR}) +LINK_DIRECTORIES(${SIMCONNECT_LIBRARY_DIR}) + +IF(WITH_STATIC_DRIVERS) + ADD_LIBRARY(bb_driver_fsx STATIC ${driver_fsx_SOURCES} ${driver_fsx_HEADERS_MOC} ) +ELSE(WITH_STATIC_DRIVERS) + ADD_LIBRARY(bb_driver_fsx SHARED ${driver_fsx_SOURCES} ${driver_fsx_HEADERS_MOC} ) +ENDIF(WITH_STATIC_DRIVERS) + +TARGET_LINK_LIBRARIES(bb_driver_fsx blackmisc blackcore SimConnect.lib ${QT_LIBRARIES}) +SET_TARGET_PROPERTIES(bb_driver_fsx PROPERTIES PROJECT_LABEL "Driver - FSX") \ No newline at end of file diff --git a/src/driver/fsx/driver_fsx.cpp b/src/driver/fsx/driver_fsx.cpp new file mode 100644 index 000000000..ebafa7710 --- /dev/null +++ b/src/driver/fsx/driver_fsx.cpp @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (C) 2013 by Roland Winklmeier * + * roland.m.winklmeier@googlemail.com * + * * + * For license information see LICENSE in the root folder of the * + * source code. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + ***************************************************************************/ + +#include + +#include +#include "driver_fsx.h" + +extern "C" +{ + Q_DECL_EXPORT ISimulator* BB_createISimulatorInstance () + { + return new CDriverFSX; + } + + Q_DECL_EXPORT quint32 BB_InterfaceVersionMajor () + { + return ISimulator::InterfaceVersionMajor; + } + + Q_DECL_EXPORT quint32 BB_InterfaceVersionMinor () + { + return ISimulator::InterfaceVersionMinor; + } +} + +CDriverFSX::CDriverFSX() +{ + +} + +void CDriverFSX::setLibraryContext(BlackMisc::IContext *context) +{ +#ifdef Q_OS_WIN + bAssert(!BlackMisc::IContext::isContextInitialised()); +#endif + + m_libraryContext = new BlackMisc::CLibraryContext(*context); +} diff --git a/src/driver/fsx/driver_fsx.h b/src/driver/fsx/driver_fsx.h new file mode 100644 index 000000000..e2eda0ace --- /dev/null +++ b/src/driver/fsx/driver_fsx.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2013 by Roland Winklmeier * + * roland.m.winklmeier@googlemail.com * + * * + * For license information see LICENSE in the root folder of the * + * source code. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + ***************************************************************************/ + +#ifndef DRIVER_FSX_H +#define DRIVER_FSX_H + +#include +#include + +class CDriverFSX : public BlackCore::ISimulator +{ +public: + CDriverFSX(); + + virtual void setLibraryContext(BlackMisc::IContext *context); + + virtual int init() { return 0; } + +protected: + + BlackMisc::CLibraryContext *m_libraryContext; +}; + +#endif // DRIVER_FSX_H diff --git a/src/driver/xplane/driver_xplane.cpp b/src/driver/xplane/driver_xplane.cpp new file mode 100644 index 000000000..386307757 --- /dev/null +++ b/src/driver/xplane/driver_xplane.cpp @@ -0,0 +1,23 @@ +#include "driver_xplane.h" + +extern "C" +{ + Q_DECL_EXPORT ISimulator* BB_createISimulatorInstance () + { + return new CDriverXPlane; + } +} + + +CDriverXPlane::CDriverXPlane() +{ +} + +void CDriverFSX::setLibraryContext(BlackMisc::IContext *context) +{ +#ifdef Q_OS_WIN + bAssert(!BlackMisc::IContext::isContextInitialised()); +#endif + + m_libraryContext = new BlackMisc::CLibraryContext(*context); +} diff --git a/src/driver/xplane/driver_xplane.h b/src/driver/xplane/driver_xplane.h new file mode 100644 index 000000000..b648a7053 --- /dev/null +++ b/src/driver/xplane/driver_xplane.h @@ -0,0 +1,17 @@ +#ifndef DRIVER_XPLANE_H +#define DRIVER_XPLANE_H + +#include + +class CDriverXPlane : public ISimulator +{ +public: + CDriverXPlane(); + virtual int init() {return 1;} + +protected: + + BlackMisc::CLibraryContext *m_libraryContext; +}; + +#endif // DRIVER_XPLANE_H