Commit 6a4584c9 authored by Leander Schulten's avatar Leander Schulten

Merge branch 'controllerInQThread'

parents 56fe6ae7 ef5c692d
Pipeline #272788 passed with stage
in 13 minutes and 2 seconds
......@@ -63,6 +63,7 @@ SOURCES += \
dmx/programmprototype.cpp \
modules/dmxconsumer.cpp \
modules/ledconsumer.cpp \
modules/mqttimpl.cpp \
scanner.cpp \
settingsfilewrapper.cpp \
slideshow.cpp \
......@@ -136,6 +137,8 @@ HEADERS += \
dmx/dmxchannelfilter.h \
modules/controlpoint.hpp \
modules/ledconsumer.h \
modules/mqtt.hpp \
modules/mqttimpl.h \
modules/scanner.hpp \
scanner.h \
settingsfilewrapper.h \
......@@ -290,3 +293,9 @@ linux{
# needed for the SystemVolume class
LIBS += -lasound
}
# Qt MQTT
INCLUDEPATH += $$PWD/lib/qtmqtt/include
LIBS += -L$$PWD/lib/qtmqtt/lib -lQt5Mqtt
#include "codeeditorhelper.h"
#include <QTextCursor>
#include <QtQuick>
#include "settings.h"
#include "modules/compiler.h"
#include <QTextCursor>
#include <QtQuick>
QString toName(Modules::Module::Type t){
switch (t) {
......@@ -264,10 +264,27 @@ void addCompletionsForType(PossibleCodeCompletions & model, QString type){
model.push_back(new CodeCompletionEntry("setDmxValueForRotation(float rotation, unsigned char dmxValue)","void","Für den Motor der die Rotation nach links oder rechts des Spiegels bestimmt. Wenn der Spiegel nicht nach links oder rechts gedreht ist entspricht dies einenm dmxWert von 128 und einer Rotation von 0 Grad. Rotation nach rechts entspricht positiven graden und nach links negativen. Aus einem Winkel und den dazugehörigen DMX-Wert lassen sich alle anderen DMX-Werte berechnen."));
model.push_back(new CodeCompletionEntry("computeDmxValuesForPointTo(float x, float y, float z = 0)","PointToResult","Diese Methode bestimmt die DMX-Werte für die beiden Motoren wenn der Scanner auf einen bestimmten Pnkte auf der Karte zeigen soll. Diese Funktion gibt ein PointToResult Objekt zurück."));
}
if(type=="PointToResult"){
model.push_back(new CodeCompletionEntry("dmxValueForTilt","brightness_t","Der DMX-Wert den der Motor der für die Neigung zuständig ist annehmen soll, um auf den Punkt zu leuchtet, wenn canBeReached true ist."));
model.push_back(new CodeCompletionEntry("dmxValueForRotation","brightness_t","Der DMX-Wert den der Motor der für die Rotation zuständig ist annehmen soll, um auf den Punkt zu leuchtet, wenn canBeReached true ist."));
model.push_back(new CodeCompletionEntry("canBeReached","bool","Dieser Boolean gibt an, ob der Punkt vom Scanner überhaupt erreicht werden kann."));
if (type == "PointToResult") {
model.push_back(new CodeCompletionEntry("dmxValueForTilt", "brightness_t",
"Der DMX-Wert den der Motor der für die Neigung zuständig ist annehmen soll, um auf den Punkt zu leuchtet, wenn canBeReached true ist."));
model.push_back(new CodeCompletionEntry("dmxValueForRotation", "brightness_t",
"Der DMX-Wert den der Motor der für die Rotation zuständig ist annehmen soll, um auf den Punkt zu leuchtet, wenn canBeReached true ist."));
model.push_back(new CodeCompletionEntry("canBeReached", "bool", "Dieser Boolean gibt an, ob der Punkt vom Scanner überhaupt erreicht werden kann."));
}
if (type == "MqttClient" || type == "Mqtt") {
model.push_back(new CodeCompletionEntry("connect(\"example.com\", 1883 /*port*/);", "void", "Verbindet sich mit dem Server host am angegebenen Port."));
model.push_back(new CodeCompletionEntry("publishMessage(\"your/topic\", message);", "void", "Veröffentlicht unter der gegebenen Topic einen Wert."));
model.push_back(new CodeCompletionEntry("publishValue(\"your/topic\", value);", "void", "Veröffentlicht unter der gegebenen Topic einen Wert. Der Wert wird auf dem Mqtt Server gespeichert."));
model.push_back(new CodeCompletionEntry("status()", "MqttClientStatus",
"Gibt den Status der Verbindung zurück. Werte sind MqttClientStatus::Connected, MqttClientStatusDisconected und MqttClientStatus::Connecting"));
model.push_back(new CodeCompletionEntry("subscribe(\"your/topic\", [this](auto message){\n \n });", "void",
"Abboniert eine Topic, jedes mal, wenn dort eine Nachricht veröffentlich wird, wird das Callback aufgerufen"));
model.push_back(new CodeCompletionEntry("subscribe<int /* or float or bool */>(\"your/topic\", [this](auto value){\n \n });", "void",
"Abboniert eine Topic, jedes mal, wenn dort eine Nachricht veröffentlich wird, wird das Callback aufgerufen. Das Callback wird mit dem angegeben Typ "
"aufgerufen. Kann die Nachricht nicht zu diesem konvertiert werden, wird das Callback nicht aufgerufen."));
model.push_back(new CodeCompletionEntry("subscribe<int /* or float or bool */>(\"your/topic\", [this](auto message, bool hasValue, auto value){\n \n });", "void",
"Abboniert eine Topic, jedes mal, wenn dort eine Nachricht veröffentlich wird, wird das Callback aufgerufen. Das Callback wird mit dem angegeben Typ "
"aufgerufen. hasValue ist wahr, wenn die Konvertierung erfolgreich war."));
}
//model.push_back(new CodeCompletionEntry("","float",""));
......@@ -285,8 +302,16 @@ void addDefaultVariables(PossibleCodeCompletions & model, Modules::Module * m){
model.push_back(new CodeCompletionEntry("spotify->","SpotifyState","Ein Object, dass alle zu Spotify gehörigen Daten enthält."));
model.push_back(new CodeCompletionEntry("controlPoint->","ControlPoint","Der ControlPoint der in dem Map View gesetzt werden kann."));
model.push_back(new CodeCompletionEntry("Scanner::getByName(\"yourName\")","IScanner","Mit dieser Funktion kann man sich ein Scanner Objekt für einen bestimmten Name geben lassen. Dieses ist über alle Modules das Selbe."));
model.push_back(new CodeCompletionEntry("Scanner::getByNameOrCreate(\"yourName\")","IScanner","Mit dieser Funktion kann man sich ein Scanner Objekt für einen bestimmten Name geben lassen, bzw. wenn es dieses nicht gibt, wird eins erzeugt. Dieses ist dann über alle Modules das Selbe."));
model.push_back(new CodeCompletionEntry("IScanner * scanner = Scanner::getByName(\"yourName\")","IScanner","Deklariert eine Scanner Variable die einen per Namen referenzierten Scanner speichert."));
model.push_back(new CodeCompletionEntry("Scanner::getByNameOrCreate(\"yourName\")", "IScanner",
"Mit dieser Funktion kann man sich ein Scanner Objekt für einen bestimmten Name geben lassen, bzw. wenn es dieses nicht gibt, wird eins erzeugt. Dieses "
"ist dann über alle Modules das Selbe."));
model.push_back(
new CodeCompletionEntry("IScanner * scanner = Scanner::getByName(\"yourName\")", "IScanner", "Deklariert eine Scanner Variable die einen per Namen referenzierten Scanner speichert."));
model.push_back(new CodeCompletionEntry("MqttClient mqtt{\"test.com\", 1883}", "MqqtClient", "Deklariert einen Mqtt Klienten der sich mit dem Server test.com auf dem Port 1883 verbindet."));
model.push_back(new CodeCompletionEntry("MqttClient mqtt{\"lastWillTopic\", \"lastWillMessage\", bool retainOnServer}", "MqqtClient",
"Deklariert einen Mqtt Klienten mit einer last will message, diese wird gesendet, falls die Verbindung verloren geht. Mit der connnect Methode kann man "
"sich dann später mit den Server verbinden."));
}
void skipWhitespaces(int & cursor, QTextDocument * d){
......@@ -582,10 +607,10 @@ QString CodeEditorHelper::getType(QString variable, int pos){
return "SegmentObject";
if(variable == "spotify")
return "SpotifyState";
if(variable == "controlPoint")
return "ControlPoint";
if(variable.toLower().contains("scanner"))
return "IScanner";
if (variable == "controlPoint") return "ControlPoint";
const auto lower = variable.toLower();
if (lower.contains("scanner")) return "IScanner";
if (lower.contains("client") || lower.contains("mqtt")) return "MqttClient";
{
QString text = document->toPlainText();
auto index = text.lastIndexOf(QRegularExpression(variable + " *="),pos);
......@@ -1036,6 +1061,7 @@ void CodeEditorHelper::compile(){
stream << "#define HAVE_SPOTIFY" << endl;
stream << "#define HAVE_CONTROL_POINT" << endl;
stream << "#define HAVE_ISCANNER" << endl;
stream << "#define HAVE_MQTT" << endl;
switch (module->getType()) {
case Modules::Module::Filter:
stream << "#define HAVE_FILTER" << endl;
......@@ -1057,7 +1083,7 @@ void CodeEditorHelper::compile(){
stream << "using namespace Modules;" << endl;
stream << "using namespace std;" << endl;
stream << "" << endl;
lineCounter += 15;
lineCounter += 16;
stream << externCode << endl;
lineCounter += externCode.count("\n") + 1;
stream << "" << endl;
......
......@@ -27,4 +27,9 @@ cd RtAudio
./build_rtAudio.sh
cd ..
echo $'\n\nUpdate Qt MQTT'
cd qtmqtt
./getAndUpdate.sh
cd ..
echo "Lib installation complete"
#!/bin/bash
set -e
if [[ "$OSTYPE" == "msys" ]]; then # windows
# on windows we have to install perl first :(
if [[ $(cmd "/c perl -v") == *"is not recognized"* ]]; then
echo "########################################"
echo "################## ERROR ###############"
echo "########################################"
echo "Perl is not installed on your system (in cmd). You have to install Perl!"
echo "Visit http://strawberryperl.com and download and install Perl."
exit 3
fi
fi
# first we have to find the Qt dir
if [ ! -z "${QT_DIR}" ]; then # from env variable
QT="${QT_DIR}"
if [ ! -d "$QT" ]; then
echo "The dir saved in env variable QT_DIR does not exists: '$QT'"
echo "Execute 'export QT_DIR=your/path/to/qt' bevor execute this script to set the QT dir."
exit 2
fi
elif [ -d "/c/Qt" ]; then # windows
QT="/c/Qt"
elif [ -d ~/Qt ]; then # mainly mac and linux
QT=~/Qt
elif [ -d "/opt/Qt" ]; then # some stackoverflow answers recommends that
QT="/opt/Qt"
elif [ ! -z "$GITLAB_CI" ]; then
echo "Use Gitlab CI"
else
if [ ! -z "${QT_DIR}" ]; then
QT="${QT_DIR}"
if [ ! -d "$QT" ]; then
echo "The dir saved in env variable QT_DIR does not exists: '$QT'"
exit 2
fi
else
echo "No Qt installation found."
echo "Execute 'export QT_DIR=your/path/to/qt' bevor execute this script to set the QT dir."
exit 1
fi
fi
if [ ! -z "$GITLAB_CI" ]; then # in gitlab CI
LATEST=$(/usr/src/mxe/usr/x86_64-w64-mingw32.shared.posix/qt5/bin/qmake --version | grep -oh '5\.[0-9]\+.[0-9]\+')
else
LATEST=$(ls "$QT" | grep 5. | tail -1)
if [ -z $LATEST ]; then
echo "No installed Qt Version like 5.xx.x found in '$QT'"
echo "Execute 'export QT_DIR=your/path/to/qt' bevor execute this script to set the QT dir."
exit 1
fi
fi
echo "Use QT Version $LATEST"
GIT_DIR="mqtt"
CUR_DIR=$(pwd)
# add or update git
if [ ! -d "$GIT_DIR" ]; then # if folder "GIT_DIR" does not exists
git clone https://github.com/qt/qtmqtt.git "$GIT_DIR"
cd "$GIT_DIR"
else
cd "$GIT_DIR"
if [[ $(git pull) = "Already up to date." ]]; then
# we can skip copying
echo "Already up to date."
exit 0
fi
fi
# we are in the "$GIT_DIR" now.
# get the latest 5.x branch, but we now use the latest installed qt version
# last=$(git branch -a | grep -oh '5\.[0-9]\+.[0-9]\+' | tail -1)
git checkout "$LATEST"
cd ..
# to build there must be no space in th path.
# copy to different dir to change files
TEMP_DIR=$(mktemp) # creates empty file
rm $TEMP_DIR
mkdir $TEMP_DIR
cp -r $GIT_DIR $TEMP_DIR/$GIT_DIR
cd $TEMP_DIR/$GIT_DIR
# we have to change the includes.
for file in ./src/mqtt/*
do
[ -d "$file" ] && continue
echo "Process $file";
sed "s/<QtMqtt\/\([a-z]\+\)\.h>/\"\1.h\"/" "$file" > "temp";
cp "temp" "$file";
done
# build the project
if [ ! -z "$GITLAB_CI" ]; then # in gitlab CI
/usr/src/mxe/usr/x86_64-w64-mingw32.shared.posix/qt5/bin/qmake
else
BUILD=$(ls "$QT/$LATEST/" | grep _64)
"$QT/$LATEST/$BUILD/bin/qmake"
fi
make -j$(getconf _NPROCESSORS_ONLN)
# go back and copy the relevant files
cd "$CUR_DIR"
[ -d include ] && rm -rf include
cp -r $TEMP_DIR/$GIT_DIR/include include
cp $GIT_DIR/src/mqtt/*.h include/QtMqtt
[ -d lib ] && rm -rf lib
cp -r $TEMP_DIR/$GIT_DIR/lib lib
rm -rf $TEMP_DIR
echo "Installation complete"
\ No newline at end of file
......@@ -2,15 +2,17 @@
#include "compiler.h"
#include "errornotifier.h"
#include "system_error_handler.h"
#include <QAbstractEventDispatcher>
#include <QDebug>
#include <QProcess>
#include <mutex>
namespace Modules {
Controller::Controller():run_(false)
{
Controller::Controller() {
moveToThread(&thread);
QObject::connect(&thread, &QThread::started, [this]() { timerId = startTimer(1); });
}
void Controller::setSpotify(Spotify::Spotify *spotify){
......@@ -50,10 +52,16 @@ void Controller::setSpotify(Spotify::Spotify *spotify){
}
}
bool Controller::haveAnalysis()const{
return spotify&&spotify->getCurrentAudioAnalysis()&&spotify->getCurrentPlayingObject()&&spotify->getCurrentPlayingObject()->item;
Controller::~Controller() {
shouldRun = false;
if (thread.isRunning()) {
thread.exit();
thread.wait();
}
}
bool Controller::haveAnalysis() const { return spotify && spotify->getCurrentAudioAnalysis() && spotify->getCurrentPlayingObject() && spotify->getCurrentPlayingObject()->item; }
void Controller::updateSpotifyState(){
if(haveAnalysis()){
spotifyState.enabled = true;
......@@ -101,21 +109,31 @@ void Controller::updateSpotifyState(){
}
void Controller::run() noexcept{
void Controller::run() noexcept {
killTimer(timerId);
timerId = -1;
using namespace std::chrono;
const auto start = steady_clock::now();
long lastElapsedMilliseconds = 0;
while (run_) {
std::this_thread::sleep_for(milliseconds(1));
auto elapsedMilliseconds = duration_cast<milliseconds>(steady_clock::now() - start).count();
const auto time_diff = elapsedMilliseconds - lastElapsedMilliseconds;
startPoint = steady_clock::now();
lastElapsedMilliseconds = 0;
while (shouldRun) {
thread.msleep(1);
thread.eventDispatcher()->processEvents(QEventLoop::ExcludeUserInputEvents);
auto elapsedMilliseconds = duration_cast<duration<double, std::milli>>(steady_clock::now() - startPoint).count();
const int time_diff = static_cast<int>(std::round(elapsedMilliseconds)) - lastElapsedMilliseconds;
lastElapsedMilliseconds = elapsedMilliseconds;
if (!run_) {
break;
}
std::unique_lock<std::mutex> l(vectorLock);
for (auto &i : runnables)
i();
runnables.clear();
for (auto &i : mustBeStartedPrograms)
i->runStartMethods();
mustBeStartedPrograms.clear();
updateSpotifyState();
for(auto pb = runningProgramms.begin() ; pb != runningProgramms.end();){
for (auto pb = runningProgramms.begin(); pb != runningProgramms.end();) {
try {
if ((*pb)->doStep(time_diff)) {
deletingProgramBlock = (*pb).get();
......@@ -205,7 +223,8 @@ void Controller::run() noexcept{
void Controller::runProgramm(std::shared_ptr<ProgramBlock> pb){
std::unique_lock<std::mutex> l(vectorLock);
runningProgramms.push_back(pb);
runningProgramms.push_back(pb);
mustBeStartedPrograms.push_back(pb);
}
void Controller::stopProgramm(std::shared_ptr<ProgramBlock> pb){
......@@ -213,16 +232,18 @@ void Controller::stopProgramm(std::shared_ptr<ProgramBlock> pb){
if(deletingProgramBlock == pb.get())
return;
std::unique_lock<std::mutex> l(vectorLock);
runningProgramms.erase(std::remove(runningProgramms.begin(),runningProgramms.end(),pb),runningProgramms.end());
runningProgramms.erase(std::remove(runningProgramms.begin(), runningProgramms.end(), pb), runningProgramms.end());
mustBeStartedPrograms.erase(std::remove(runningProgramms.begin(), runningProgramms.end(), pb), runningProgramms.end());
}
void Controller::stopProgramm(ProgramBlock* pb){
std::unique_lock<std::mutex> l(vectorLock);
runningProgramms.erase(std::remove_if(runningProgramms.begin(),runningProgramms.end(),[&](const auto &v){return v.get()==pb;}),runningProgramms.end());
runningProgramms.erase(std::remove_if(runningProgramms.begin(), runningProgramms.end(), [&](const auto &v) { return v.get() == pb; }), runningProgramms.end());
mustBeStartedPrograms.erase(std::remove_if(runningProgramms.begin(), runningProgramms.end(), [&](const auto &v) { return v.get() == pb; }), runningProgramms.end());
}
bool Controller::isProgramRunning(ProgramBlock * pb){
std::unique_lock<std::mutex> l(vectorLock);
return std::any_of(runningProgramms.cbegin(),runningProgramms.cend(),[=](const auto & p){return p.get()==pb;});
return std::any_of(runningProgramms.cbegin(), runningProgramms.cend(), [=](const auto &p) { return p.get() == pb; });
}
}
} // namespace Modules
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <atomic>
#include <thread>
#include <mutex>
#include <condition_variable>
#include "controlpoint.hpp"
#include "programblock.h"
#include "spotify.hpp"
#include "spotify/spotify.h"
#include "controlpoint.hpp"
#include <QPointF>
#include <QThread>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <mutex>
namespace Modules {
/**
* @brief The Controller class controlls the whole Module system. Its load and execute it
*/
class Controller
{
std::atomic_bool run_;
std::thread thread;
class Controller : public QObject {
Q_OBJECT
QThread thread;
std::atomic_bool shouldRun;
int timerId = -1;
std::mutex mutex;
std::condition_variable wait;
std::vector<std::shared_ptr<ProgramBlock>> runningProgramms;
std::vector<std::shared_ptr<ProgramBlock>> mustBeStartedPrograms;
std::vector<std::function<void()>> runnables;
std::mutex vectorLock;
ProgramBlock * deletingProgramBlock = nullptr;
// Variables for Spotify:
......@@ -34,6 +38,9 @@ class Controller
int lastIndexOfCurrentTatum = -1;
int lastIndexOfCurrentSection = -1;
int lastIndexOfCurrentSegment = -1;
std::chrono::steady_clock::time_point startPoint;
long lastElapsedMilliseconds = -1;
// Control Point
ControlPoint controlPoint;
......@@ -64,20 +71,34 @@ public:
controlPoint.positionChanged = true;
}
void start(){
if(!run_){
run_=true;
thread = std::thread([this](){
run();
});
if (!thread.isRunning()) {
shouldRun = true;
thread.start();
}
}
void stop(){run_=false;}
~Controller(){run_ = false;if(thread.joinable())thread.join();}
void stop() {
shouldRun = false;
thread.exit();
lastElapsedMilliseconds = -1;
}
/**
* @brief runInController executes the func in the controller thread, if the controller thread is stopped, the controller thread must be started to execute the function
*/
void runInController(std::function<void()> func) {
std::unique_lock<std::mutex> l(vectorLock);
runnables.push_back(func);
}
~Controller();
private:
void runProgramm(std::shared_ptr<ProgramBlock> pb);
void stopProgramm(std::shared_ptr<ProgramBlock> pb);
void stopProgramm(ProgramBlock* pb);
bool isProgramRunning(ProgramBlock * pb);
bool isProgramRunning(ProgramBlock *pb);
protected:
void timerEvent(QTimerEvent *event) override { run(); }
private:
/**
* @brief haveAnalysis checks if currently a spotify analysis exists
......
......@@ -9,6 +9,7 @@
//#define HAVE_SPOTIFY
//#define HAVE_CONTROL_POINT
//#define HAVE_ISCANNER
//#define HAVE_MQTT
#ifdef HAVE_PROGRAM
#include "program.hpp"
......@@ -44,6 +45,10 @@
#include <functional>
#endif
#ifdef HAVE_MQTT
#include "mqtt.hpp"
#endif
#include <string>
//disable Warning for char * as return type in extern "C" Block with clang
......@@ -60,7 +65,7 @@
#endif
extern "C" {
enum class MODUL_TYPE{Program, LoopProgram,Filter,Consumer,Audio,Spotify,ControlPoint, IScanner};
enum class MODUL_TYPE { Program, LoopProgram, Filter, Consumer, Audio, Spotify, ControlPoint, IScanner, Mqtt };
#ifdef MODULE_LIBRARY
......@@ -110,9 +115,15 @@ MODULE_EXPORT bool have(MODUL_TYPE t){
#endif
case MODUL_TYPE::IScanner:
#ifdef HAVE_ISCANNER
return true;
return true;
#else
return false;
return false;
#endif
case MODUL_TYPE::Mqtt:
#ifdef HAVE_MQTT
return true;
#else
return false;
#endif
}
return false; // Vielleicht wird das enum in einer weiteren Version erweitert.
......@@ -170,26 +181,31 @@ MODULE_EXPORT void _setControlPoint(Modules::ControlPoint const * s){controlPoin
#endif
#ifdef HAVE_ISCANNER
std::function<Modules::IScanner*(const std::string &)> getScannerByNameCallback;
std::function<Modules::IScanner*(const std::string &)> getScannerByNameOrCreateCallback;
MODULE_EXPORT void _setGetScannerByNameCallback(std::function<Modules::IScanner*(const std::string &)> callback){getScannerByNameCallback = callback;}
MODULE_EXPORT void _setGetScannerByNameOrCreateCallback(std::function<Modules::IScanner*(const std::string &)> callback){getScannerByNameOrCreateCallback = callback;}
std::function<Modules::IScanner *(const std::string &)> getScannerByNameCallback;
std::function<Modules::IScanner *(const std::string &)> getScannerByNameOrCreateCallback;
MODULE_EXPORT void _setGetScannerByNameCallback(std::function<Modules::IScanner *(const std::string &)> callback) { getScannerByNameCallback = callback; }
MODULE_EXPORT void _setGetScannerByNameOrCreateCallback(std::function<Modules::IScanner *(const std::string &)> callback) { getScannerByNameOrCreateCallback = callback; }
namespace Scanner {
Modules::IScanner * getByName(const std::string & name){
if(getScannerByNameCallback){
Modules::IScanner *getByName(const std::string &name) {
if (getScannerByNameCallback) {
return getScannerByNameCallback(name);
}
return nullptr;
}
Modules::IScanner * getByNameOrCreate(const std::string & name){
if(getScannerByNameOrCreateCallback){
Modules::IScanner *getByNameOrCreate(const std::string &name) {
if (getScannerByNameOrCreateCallback) {
return getScannerByNameOrCreateCallback(name);
}
return nullptr;
}
}
} // namespace Scanner
#endif
#ifdef HAVE_MQTT
std::function<Modules::detail::IMqttClientImpl *()> createMqttClientCallback;
MODULE_EXPORT void _setCreateMqttClientCallback(std::function<Modules::detail::IMqttClientImpl *()> callback) { createMqttClientCallback = callback; }
Modules::detail::IMqttClientImpl *_createMqttClientImpl() { return createMqttClientCallback ? createMqttClientCallback() : nullptr; }
#endif
}
#endif // MODULES_GLOBAL_H
......@@ -2,6 +2,7 @@
#include "dmxconsumer.h"
#include "ledconsumer.h"
#include "module.h"
#include "mqttimpl.h"
#include "scanner.h"
#include "scanner.hpp"
#include "settings.h"
......@@ -220,24 +221,34 @@ typedef Modules::Program* (*CreateProgramm)(unsigned int index);
func(&controller_.getControlPoint());
}
}
if(f(MODUL_TYPE::IScanner)){
typedef void (*SetGetScannerByNameCallback)(std::function<IScanner*(const std::string &)>);
typedef void (*SetGetScannerByNameOrCreateCallback)(std::function<IScanner*(const std::string &)>);
if (f(MODUL_TYPE::IScanner)) {
typedef void (*SetGetScannerByNameCallback)(std::function<IScanner *(const std::string &)>);
typedef void (*SetGetScannerByNameOrCreateCallback)(std::function<IScanner *(const std::string &)>);
SetGetScannerByNameCallback getFunc = reinterpret_cast<SetGetScannerByNameCallback>(lib.resolve("_setGetScannerByNameCallback"));
SetGetScannerByNameOrCreateCallback getOrCreateFunc = reinterpret_cast<SetGetScannerByNameOrCreateCallback>(lib.resolve("_setGetScannerByNameOrCreateCallback"));
if(getFunc){
getFunc([](const std::string &name){return Scanner::getByName(name);});
}else{
if (getFunc) {
getFunc([](const std::string &name) { return Scanner::getByName(name); });
} else {
qDebug() << "getFunc is null, abort loading lib";
return;
}
if(getOrCreateFunc){
getOrCreateFunc([](const std::string &name){return Scanner::getByNameOrCreate(name);});
}else{
if (getOrCreateFunc) {
getOrCreateFunc([](const std::string &name) { return Scanner::getByNameOrCreate(name); });
} else {
qDebug() << "getOrCreateFunc is null, abort loading lib";
return;
}
}
if (f(MODUL_TYPE::Mqtt)) {
using SetCreateMqttClientCallback = void (*)(std::function<detail::IMqttClientImpl *()>);
SetCreateMqttClientCallback getFunc = reinterpret_cast<SetCreateMqttClientCallback>(lib.resolve("_setCreateMqttClientCallback"));
if (getFunc) {
getFunc([] { return new MqttImpl; });
} else {
qWarning() << "Modules MqttClient: getFunc is null";
return;
}
}
if(f(MODUL_TYPE::Program)){
loadType(lib,programms,"Program",lastLibraryIdentifier,[&](const auto p){
if(replaceOldModulesInProgramBlocks){
......
#ifndef MQTT_HPP
#define MQTT_HPP
#include <functional>
#include <memory>
#include <string>
namespace Modules {
enum class MqttClientStatus { Disconnected, Connecting, Connected, NotAvailible };
namespace detail {
class IMqttClientImpl {
public:
virtual void setLastWillMessage(const std::string &topic, const std::string &message, bool retain) = 0;
virtual void connect(const std::string &host, int port) = 0;
virtual void publishMessage(const std::string &topic, const std::string &message) = 0;
virtual void publishValue(const std::string &topic, const std::string &message) = 0;
virtual void subscribe(const std::string &topic, std::function<void(std::string)> callback) = 0;
virtual MqttClientStatus status() = 0;
virtual ~IMqttClientImpl() {}
};