Commit 32d0ade1 authored by Leander Schulten's avatar Leander Schulten
Browse files

Weitergearbeitet, alles mögliche geändert

parent ea18ad76
...@@ -51,7 +51,11 @@ SOURCES += \ ...@@ -51,7 +51,11 @@ SOURCES += \
programms/modulemanager.cpp \ programms/modulemanager.cpp \
programms/programblock.cpp \ programms/programblock.cpp \
programms/compiler.cpp \ programms/compiler.cpp \
test/testmodulsystem.cpp test/testmodulsystem.cpp \
programms/controller.cpp \
programms/dmxprogram.cpp \
programms/dmxprogramblock.cpp \
programms/json_storage.cpp
# The following define makes your compiler emit warnings if you use # The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings # any feature of Qt which as been marked deprecated (the exact warnings
...@@ -108,7 +112,12 @@ HEADERS += \ ...@@ -108,7 +112,12 @@ HEADERS += \
programms/filter.hpp \ programms/filter.hpp \
programms/consumer.hpp \ programms/consumer.hpp \
programms/compiler.h \ programms/compiler.h \
test/testmodulsystem.h test/testmodulsystem.h \
programms/controller.h \
programms/dmxprogram.h \
programms/dmxprogramblock.h \
programms/storage.hpp \
programms/json_storage.h
# Default rules for deployment. # Default rules for deployment.
...@@ -118,6 +127,11 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin ...@@ -118,6 +127,11 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
DISTFILES += DISTFILES +=
QMAKE_CXXFLAGS += -fsanitize=address
# QMAKE_CXXFLAGS += -fno-omit-frame-pointer
QMAKE_CXXFLAGS += -Wshadow
#QMAKE_CXXFLAGS += -lasan
LIBS += -lasan
win32-g++{ win32-g++{
LIBS += -L$$PWD/'lib/boost' -lboost_coroutine -lboost_context LIBS += -L$$PWD/'lib/boost' -lboost_coroutine -lboost_context
......
...@@ -10,7 +10,7 @@ namespace Modules{ ...@@ -10,7 +10,7 @@ namespace Modules{
* @brief The Consumer class represents a Consumer like a driver for dmx or leds * @brief The Consumer class represents a Consumer like a driver for dmx or leds
* Treiber erben von dieser Klasse und zeigen die Entsprechenden Daten an. * Treiber erben von dieser Klasse und zeigen die Entsprechenden Daten an.
*/ */
class Consumer:public PropertyBase, public InputDataConsumer{ class Consumer:public PropertyBase, public InputDataConsumer, public Named{
public: public:
Consumer(const ValueType inputDataType):InputDataConsumer(inputDataType){} Consumer(const ValueType inputDataType):InputDataConsumer(inputDataType){}
virtual void setInputLength(unsigned int)=0; virtual void setInputLength(unsigned int)=0;
......
#include "controller.h"
#include <mutex>
namespace Modules {
Controller::Controller()
{
}
void Controller::run() noexcept{
while (run_) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
}
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <atomic>
#include <thread>
namespace Modules {
class Controller
{
std::atomic_bool run_;
std::thread thread;
std::mutex mutex;
std::condition_variable wait;
void run() noexcept;
public:
Controller();
void start(){
if(!run_){
run_=true;
thread = std::thread([this](){
run();
});
}
}
void stop(){run_=false;}
~Controller(){run_ = false;thread.join();}
};
}
#endif // CONTROLLER_H
...@@ -14,7 +14,9 @@ namespace Modules { ...@@ -14,7 +14,9 @@ namespace Modules {
virtual void setInputLength(unsigned int) override; virtual void setInputLength(unsigned int) override;
virtual void start()override; virtual void start()override;
virtual void show() override; virtual void show() override;
virtual void doStep(time_diff_t)override{}
const std::vector<short> & getChannelAssoziatfion()const{return channel;} const std::vector<short> & getChannelAssoziatfion()const{return channel;}
virtual const char * getName()const override{return "DMXConsumer";}
}; };
} }
......
#include "dmxprogram.h"
#include "dmxchannelfilter.h"
#include "programm.h"
#include <cstring>
namespace Modules {
DMXProgram::DMXProgram()
{
}
ProgrammState DMXProgram::doStep(time_diff_t diff) {
time += diff;
std::memset(values,0,getOutputLength());
DMXChannelFilter::initValues(values,getOutputLength());
::Programm::fill(values,getOutputLength(),time/1000.);
DMXChannelFilter::filterValues(values,getOutputLength());
return {false,true};
}
}
#ifndef DMXPROGRAM_H
#define DMXPROGRAM_H
#include "programm.hpp"
namespace Modules {
class DMXProgram : public BrightnessProgramm
{
time_diff_t time;
public:
DMXProgram();
virtual const char* getName()const override{return "DMXProgramm";}
virtual void start()override{time = 0;}
virtual ProgrammState doStep(time_diff_t)override;
virtual int getProgrammLengthInMS()override {return INFINITE;}
};
}
#endif // DMXPROGRAM_H
#include "dmxprogramblock.h"
namespace Modules {
DMXProgramBlock::DMXProgramBlock()
{
prog = new DMXProgram();
addProgramm(prog);
consumer = std::make_shared<DMXConsumer>();
prog->setOutputLength(512);
consumer->setInputLength(512);
detail::Connection c(consumer);
c.addTarget(512,prog,0);
addConsumer(std::move(c));
}
}
#ifndef DMXPROGRAMBLOCK_H
#define DMXPROGRAMBLOCK_H
#include "programblock.h"
#include "dmxprogram.h"
#include "dmxconsumer.h"
namespace Modules {
class DMXProgramBlock : public ProgramBlock
{
DMXProgram * prog = nullptr;
std::shared_ptr<DMXConsumer> consumer;
public:
DMXProgramBlock();
~DMXProgramBlock(){}
};
}
#endif // DMXPROGRAMBLOCK_H
...@@ -9,7 +9,7 @@ namespace Modules { ...@@ -9,7 +9,7 @@ namespace Modules {
/** /**
* @brief The Filter class filters input data and write the filtered data in the outpur array * @brief The Filter class filters input data and write the filtered data in the outpur array
*/ */
class Filter : public PropertyBase, public OutputDataProducer, public InputDataConsumer{ class Filter : public PropertyBase, public OutputDataProducer, public InputDataConsumer, public Named{
public: public:
Filter(const ValueType inputDataType,const ValueType outputDataType):OutputDataProducer(outputDataType),InputDataConsumer(inputDataType){} Filter(const ValueType inputDataType,const ValueType outputDataType):OutputDataProducer(outputDataType),InputDataConsumer(inputDataType){}
virtual void setInputLength(unsigned int length) = 0; virtual void setInputLength(unsigned int length) = 0;
......
#include "json_storage.h"
namespace Modules {
}
#ifndef JSON_STORAGE_H
#define JSON_STORAGE_H
#include "storage.hpp"
#include <QJsonObject>
#include <functional>
namespace Modules {
class JsonLoadObject : public LoadObject
{
const QJsonObject &o;
public:
JsonLoadObject(const QJsonObject &o):o(o){}
virtual int loadInt(const char*name) const override{return o[name].toInt();}
virtual float loadFloat(const char*name) const override {return static_cast<float>(o[name].toDouble());}
virtual double loadDouble(const char*name) const override{return o[name].toDouble();}
virtual bool loadBool(const char*name) const override{return o[name].toBool();}
virtual long loadLong(const char*name) const override{return static_cast<float>(o[name].toDouble());}
virtual char* loadStringOwn(const char*name) const override{
const auto data = o[name].toString().toLatin1();
char * d = new char[data.size()+1];
std::memcpy(d,data.constData(),data.size()+1);
return d;
}
};
class JsonSaveObject : public SaveObject{
QJsonObject &o;
public:
JsonSaveObject(QJsonObject &o):o(o){}
virtual void saveInt(const char*name,int i) override{
o[name] = i;
}
virtual void saveFloat(const char*name,float f) override{
o[name] = f;
}
virtual void saveDouble(const char*name,double d) override{
o[name] = d;
}
virtual void saveBool(const char*name,bool b) override{
o[name] = b;
}
virtual void saveLong(const char*name,long l) override{
o[name] = static_cast<double>(l);
}
virtual void saveString(const char*name,const char * c) override{
o[name] = c;
}
};
}
#endif // JSON_STORAGE_H
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <QDir> #include <QDir>
#include <QLibrary> #include <QLibrary>
#include <iostream> #include <iostream>
#include <memory>
namespace Modules { namespace Modules {
...@@ -23,7 +24,7 @@ namespace Modules { ...@@ -23,7 +24,7 @@ namespace Modules {
CreateFunction createFunc; CreateFunction createFunc;
public: public:
Entry(const std::string& name,const std::string& description):name(name),description(description){} Entry(const std::string& name,const std::string& description):name(name),description(description){}
Entry(const std::string& name,const std::string& description,CreateFunction func):name(name),description(description),createFunc(func){} Entry(const std::string& name,const std::string& description,CreateFunction func):createFunc(func),name(name),description(description){}
const std::string name; const std::string name;
const std::string description; const std::string description;
T* create()const{ T* create()const{
...@@ -54,15 +55,15 @@ namespace Modules { ...@@ -54,15 +55,15 @@ namespace Modules {
const ProgrammModulContainer & getProgrammModules(){return programms;} const ProgrammModulContainer & getProgrammModules(){return programms;}
const FilterModulContainer & getFilterModules(){return filter;} const FilterModulContainer & getFilterModules(){return filter;}
const ConsumerModulContainer & getConsumerModules(){return consumer;} const ConsumerModulContainer & getConsumerModules(){return consumer;}
Programm * createProgramm(const std::string & name){return createByName(programms,name);} std::shared_ptr<Programm> createProgramm(const std::string & name){return createByName(programms,name);}
Filter * createFilter (const std::string & name){return createByName(filter ,name);} std::shared_ptr<Filter> createFilter (const std::string & name){return createByName(filter ,name);}
Consumer * createConsumer(const std::string & name){return createByName(consumer ,name);} std::shared_ptr<Consumer> createConsumer(const std::string & name){return createByName(consumer ,name);}
protected: protected:
template<typename T> template<typename T>
static T * createByName(const std::vector<detail::Entry<T>> & c, const std::string &name){ static std::shared_ptr<T> createByName(const std::vector<detail::Entry<T>> & c, const std::string &name){
for(auto i = c.cbegin() ; i != c.cend();++i){ for(auto i = c.cbegin() ; i != c.cend();++i){
if(i->name == name) if(i->name == name)
return i->create(); return std::shared_ptr<T>(i->create());
} }
return nullptr; return nullptr;
} }
......
#include "programblock.h" #include "programblock.h"
#include <QJsonArray> #include <QJsonArray>
#include <stdexcept>
#include "modulemanager.h"
namespace Modules { namespace Modules {
namespace detail { namespace detail {
template<typename PointerType>
class SharedPtrComperator{
public:
bool operator()(const PointerType *l,const PointerType *r)const{
return l<r;
}
bool operator()(const std::shared_ptr<PointerType> &l,const std::shared_ptr<PointerType> &r)const{
return l.get()<r.get();
}
bool operator()(const PointerType*l,const std::shared_ptr<PointerType> &r)const{
return l<r.get();
}
bool operator()(const std::shared_ptr<PointerType> &l,const PointerType*r)const{
return l.get()<r;
}
};
} }
ProgramBlock::ProgramBlock() ProgramBlock::ProgramBlock()
...@@ -14,11 +32,124 @@ namespace Modules { ...@@ -14,11 +32,124 @@ namespace Modules {
} }
ProgramBlock::ProgramBlock(const QJsonObject& o){ ProgramBlock::ProgramBlock(const QJsonObject& o){
QJsonArray a; // Wir erstellen erstmal alle objecte mit passendem Typ und ID
/*for(const auto & i : programs){ std::map<QString,std::shared_ptr<Programm>> programs;
a.push_back(i->get) std::map<QString,std::shared_ptr<Filter>> filter;
}*/ std::map<QString,std::shared_ptr<Consumer>> consumer;
//TODO {
const auto progs = o["programs"].toArray();
for(const auto & v_ : progs){
QJsonObject obj = v_.toObject();
const auto qstr = obj["typename"].toString();
const auto str = qstr.toStdString();
auto p = ModuleManager::singletone()->createProgramm(str);
if(!p){
throw std::runtime_error(std::string("Program with name '") + str + "' does not exist.");
}
programs.insert(std::make_pair(qstr,p));
}
}
{
const auto progs = o["filter"].toArray();
for(const auto & v_ : progs){
QJsonObject obj = v_.toObject();
const auto qstr = obj["typename"].toString();
const auto str = qstr.toStdString();
auto p = ModuleManager::singletone()->createFilter(str);
if(!p){
throw std::runtime_error(std::string("Filter with name '") + str + "' does not exist.");
}
filter.insert(std::make_pair(qstr,p));
}
}
{
const auto progs = o["consumer"].toArray();
for(const auto & v_ : progs){
QJsonObject obj = v_.toObject();
const auto qstr = obj["typename"].toString();
const auto str = qstr.toStdString();
auto p = ModuleManager::singletone()->createConsumer(str);
if(!p){
throw std::runtime_error(std::string("Consumer with name '") + str + "' does not exist.");
}
consumer.insert(std::make_pair(qstr,p));
}
}
// Wir haben schon alle benötogten Objecte erstellt und wissen zu welcher ID welches Object gehört.
{
const auto filterCon = o["filterConnections"].toArray();
for(const auto & i : filterCon){
const auto iter = filter.find(i["source"].toString());
if(iter == filter.cend()){
throw std::runtime_error("Connection has invalid source.");
}
detail::Connection c(iter->second);
const auto targets = i["targets"].toArray();
for(const auto & t : targets){
OutputDataProducer * outputDataProducer;
const auto targetName = t["target"].toString();
const auto pIter = programs.find(targetName);
if(pIter != programs.cend()){
outputDataProducer = pIter->second.get();
}else{
const auto fIter = filter.find(targetName);
if(fIter != filter.cend()){
outputDataProducer = fIter->second.get();
}else{
throw std::runtime_error("Connection target not found :" + targetName.toStdString());
}
}
c.addTarget(t["length"].toInt(),outputDataProducer,t["targetStartIndex"].toInt());
}
this->filter.insert(std::make_pair(i["level"].toInt(),c));
}
}
{
const auto consumerCon = o["consumerConnections"].toArray();
for(const auto & i : consumerCon){
const auto iter = consumer.find(i["source"].toString());
if(iter == consumer.cend()){
throw std::runtime_error("Connection has invalid source.");
}
detail::Connection c(iter->second);
const auto targets = i["targets"].toArray();
for(const auto & t : targets){
OutputDataProducer * outputDataProducer;
const auto targetName = t["target"].toString();
const auto pIter = programs.find(targetName);
if(pIter != programs.cend()){
outputDataProducer = pIter->second.get();
}else{
const auto fIter = filter.find(targetName);
if(fIter != filter.cend()){
outputDataProducer = fIter->second.get();
}else{
throw std::runtime_error("Connection target not found :" + targetName.toStdString());
}
}
c.addTarget(t["length"].toInt(),outputDataProducer,t["targetStartIndex"].toInt());
}
this->consumer.push_back(c);
}
}
}
void ProgramBlock::addFilter(detail::Connection c, int layer){
for(const auto & con : c.targeds){
if(!haveOutputDataProducer(con.second.targed)){
throw std::runtime_error("one outputdataproducer is unknown");
}
}
filter.emplace(layer,std::move(c));
}
void ProgramBlock::addConsumer(detail::Connection c){
for(const auto & con : c.targeds){
if(!haveOutputDataProducer(con.second.targed)){
throw std::runtime_error("one outputdataproducer is unknown");
}
}
consumer.push_back(std::move(c));
} }
...@@ -27,23 +158,96 @@ namespace Modules { ...@@ -27,23 +158,96 @@ namespace Modules {
for(auto & p : programs){ for(auto & p : programs){
const auto state = p->doStep(diff); const auto state = p->doStep(diff);
finished |= state.finished; finished |= state.finished;
dataChanged[p] = state.outputDataChanged; dataChanged[p.get()] = state.outputDataChanged;
} }
for(auto i = filter.cbegin(); i!= filter.cend();++i){ for(auto i = filter.cbegin(); i!= filter.cend();++i){
if(doConnection(i->second)){ if(doConnection(i->second)){
static_cast<Filter*>(i->second.source)->filter(); static_cast<Filter*>(i->second.source.get())->filter();
} }
dataChanged[i->second.source] |= static_cast<Filter*>(i->second.source)->doStep(diff); dataChanged[i->second.source.get()] |= static_cast<Filter*>(i->second.source.get())->doStep(diff);
} }
for(auto i = consumer.cbegin(); i != consumer.cend();++i){ for(auto i = consumer.cbegin(); i != consumer.cend();++i){
if(doConnection(*i)){ if(doConnection(*i)){
static_cast<Consumer*>(i->source)->show(); static_cast<Consumer*>(i->source.get())->show();
} }
} }
return finished; return finished;
} }
void ProgramBlock::writeJsonObject(QJsonObject &o){
// Wir speichern zu jedem Programm/Filter/Consumer ein Object ab, das den Typnamen und eine ID, wir nehmen die Adresse im Arbeitsspeicher.
// Wir speichern die Connections, indem wir für die Source und die Targets die Adressen(IDs) der jeweiligen Pointer speichern.
// --- Programs ---
{QJsonArray progs;
for(auto i = programs.cbegin();i!=programs.cend();++i){
QJsonObject p;
p["typename"] = (*i)->getName();
p["id"] = QString::number(reinterpret_cast<size_t>(i->get()));
static_assert (sizeof (size_t) == sizeof (Programm*), "Pointer must have same size as size_t");
progs.push_back(p);
}
o["programs"] = progs;
}
// --- Filter ---
{
QJsonArray filter;
QJsonArray filterCon;
for(const auto & i : this->filter){
QJsonObject e;
QJsonObject con;
con["source"] = QString::number(reinterpret_cast<size_t>(i.second.source.get()));
e["typename"] = reinterpret_cast<Named*>(i.second.source.get())->getName();
e["id"] = QString::number(reinterpret_cast<size_t>(i.second.source.get()));
con["level"] = i.first;
static_assert (sizeof (size_t) == sizeof (Filter*), "Pointer must have same size as size_t");
filter.push_back(e);
QJsonArray targets;
for(const auto & c : i.second.targeds){
QJsonObject target;
target["target"] = QString::number(reinterpret_cast<size_t>(c.second.targed));
target["length"] = static_cast<int>(c.first);
target["targetStartIndex"] = static_cast<int>(c.second.startIndex);
targets.push_back(target);
}
con["targets"] = targets;
}
o["filter"] = filter;
o["filterConnections"] = filterCon;
}
// --- Consumer ---
{
QJsonArray consumer;