Commit 5143e53a authored by Leander Schulten's avatar Leander Schulten
Browse files

Changed LoopProgramm API, so that the context switching has its own api and...

Changed LoopProgramm API, so that the context switching has its own api and must not be implemented with boost(and the module compiler need no boost libs)
parent decb8f76
......@@ -42,7 +42,6 @@ SOURCES += \
programm.cpp \
programmprototype.cpp \
programms/dmxconsumer.cpp \
programms/loopprogramm.cpp \
test/testloopprogramm.cpp \
settings.cpp \
syncservice.cpp \
......@@ -62,7 +61,8 @@ SOURCES += \
programblockeditor.cpp \
audio/sample.cpp \
test/testsampleclass.cpp \
audio/audiocapturemanager.cpp
audio/audiocapturemanager.cpp \
programms/boostloopprogramcontextswitcher.cpp
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
......@@ -108,7 +108,6 @@ HEADERS += \
graph.h \
oscillogram.h \
programms/types.h \
programms/loopprogramm.h \
programms/dmxconsumer.h \
programms/module.h \
test/testloopprogramm.h \
......@@ -132,7 +131,9 @@ HEADERS += \
audio/sample.h \
test/testsampleclass.h \
audio/audiocapturemanager.h \
programms/fftoutput.hpp
programms/fftoutput.hpp \
programms/loopprogram.hpp \
programms/boostloopprogramcontextswitcher.h
# Default rules for deployment.
......
......@@ -117,7 +117,7 @@ int main(int argc, char *argv[])
//#warning Dont use IDBase<xxxxx>::getAllIDBases() in this file. It will crash the aplication when its closing
std::thread t(test);
std::thread t(Test::testLoopProgramm);
t.join();
auto after = ApplicationData::loadData(file);
......
#include "boostloopprogramcontextswitcher.h"
#include <QDebug>
namespace Modules {
BoostLoopProgramContextSwitcher::BoostLoopProgramContextSwitcher():m_coro([this](Coro::push_type &y){
m_yield = &y;
y();
startLoopProgram();
}){
}
bool BoostLoopProgramContextSwitcher::resume(){
m_coro();
return !m_coro;
}
void BoostLoopProgramContextSwitcher::yield(){
(*m_yield)();
}
}
#ifndef LOOPPROGRAMM_H
#define LOOPPROGRAMM_H
#ifndef BOOSTLOOPPROGRAMCONTEXTSWITCHER_H
#define BOOSTLOOPPROGRAMCONTEXTSWITCHER_H
#include "program.hpp"
#include "types.h"
#include "loopprogram.hpp"
#include "boost/coroutine2/all.hpp"
#include <qdebug.h>
#include <boost/config.hpp>
#if defined(BOOST_NO_CXX11_AUTO_DECLARATIONS) || \
......@@ -23,58 +20,20 @@
defined(BOOST_NO_HDR_TUPLE)
#error "execution_context is prevented to be included in this compiler";
#endif
namespace Modules {
template<typename BaseClass>
class LoopProgramm : public BaseClass
{
/**
* Address : 0 ... 100 101 102 103 ... 1000
* eg: ^ ^
* | + Stackbuttom
* + Stacktop
* Stacktop have smaller address then stackbuttom.
*/
using Coro = boost::coroutines2::coroutine<void>;
Coro::pull_type coro;
Coro::push_type *yield;
namespace Modules {
bool first=true;
bool finished = false;
bool show_=false;
time_diff_t currentWaitTime = 0;
time_diff_t timeToWait = 0;
static_assert (std::is_base_of<Program,BaseClass>::value,"BaseClass must be an Subclass of Programm or the clas Programm.");
protected:
void wait(time_diff_t time){
currentWaitTime = 0;
timeToWait = time;
(*yield)();
}
virtual void loopProgramm() = 0;
public:
LoopProgramm():coro([this](Coro::push_type &y){
yield = &y;
y();
loopProgramm();
finished = true;}){}
virtual ~LoopProgramm(){}
virtual ProgramState doStep(time_diff_t t)override{
if(first){
first = false;
}
if(finished)
return {true,false};
currentWaitTime+=t;
if(currentWaitTime>=timeToWait){
currentWaitTime = 0;
coro();
return {finished,true};
}
return {false,false};
}
};
class BoostLoopProgramContextSwitcher : public LoopProgramContextSwitcher
{
using Coro = boost::coroutines2::coroutine<void>;
Coro::pull_type m_coro;
Coro::push_type *m_yield;
public:
BoostLoopProgramContextSwitcher();
virtual void yield()override;
virtual bool resume()override;
};
}
#endif // LOOPPROGRAMM_H
#endif // BOOSTLOOPPROGRAMCONTEXTSWITCHER_H
#ifndef LOOPPROGRAMM_H
#define LOOPPROGRAMM_H
#include "program.hpp"
#include "types.h"
#include <memory>
namespace Modules {
class LoopProgram;
/**
* @brief The LoopProgramContextSwitcher class is responsible for the context switching in the LoopProgramm
*/
class LoopProgramContextSwitcher{
void (LoopProgram::*startFunction)() = nullptr;
LoopProgram * loopProgram = nullptr;
protected:
void startLoopProgram(){
if(loopProgram && startFunction)
(loopProgram->*startFunction)();
}
public:
/**
* @brief yield The function should stop the execution of the startfunction and give the control back to the resume caller
*/
virtual void yield()=0;
/**
* @brief resume the function should resume the execution of the function wich called the yield function
* @return true if the startFunction is finished
*/
virtual bool resume()=0;
/**
* @brief setStartFunction set the function wich contain the aktual loopProgramm
* @param loopProgram the function that the contextSwitcher should call the first time when starts
*/
void setStartFunction(LoopProgram * loopProgram, void (LoopProgram::*startFunction)()){
this->loopProgram = loopProgram;
this->startFunction = startFunction;
}
virtual ~LoopProgramContextSwitcher() = default;
};
/**
* @brief Subklassen der LoopPogramm Klasse müssen nicht die doStep Methode implementieren, um einen Schritt
* in ihrem Programm zu machen, sie können einfach die loopProgram Methode implementieren und um pausen zu machen
* die wait Methode benutzen.
* @note Die Klasse nimmt Kontextwechsel vor, um das loopProgramm zu simulieren. Das LoopProgramm wird in der doStep
* funktion gestartet, dann ruft dieses irgendwann wait auf, dort geht dann der Programmablauf zu der doStep funktion über.
* Wird diese wieder aufgerufen, wird in der wait funktion ab dem letztem befehl dort weitergemacht, bis die wait funktion
* wieder aufgerufen wird.
*/
class LoopProgram : public Program
{
std::unique_ptr<LoopProgramContextSwitcher> contextSwitcher;
bool finished = false;
time_diff_t currentWaitTime = 0;
time_diff_t timeToWait = 0;
protected:
/**
* @brief wait the wait funktion "waits" ms millisecends. it brings the control flow back to the doStep method
* @param ms the time to wait in ms
*/
void wait(time_diff_t ms){
currentWaitTime = 0;
timeToWait = ms;
if(contextSwitcher)
contextSwitcher->yield();
}
/**
* @brief loopProgram the subclasses implement here there program
*/
virtual void loopProgram() = 0;
public:
/**
* @brief setContextSwitcher sets the context switcher used by the LoopProgram, should be set before the program starts
* @param contextSwitcher the contextSwitcher object
*/
void setContextSwitcher(std::unique_ptr<LoopProgramContextSwitcher> contextSwitcher){
this->contextSwitcher = std::move(contextSwitcher);
if(this->contextSwitcher){
this->contextSwitcher->setStartFunction(this,&LoopProgram::loopProgram);
}
}
LoopProgram(const ValueType valueType):Program (valueType){}
virtual ProgramState doStep(time_diff_t t)final override{
if(finished)
return {true,false};
currentWaitTime+=t;
if(currentWaitTime>=timeToWait){
currentWaitTime = 0;
if(contextSwitcher)
finished = contextSwitcher->resume();
return {finished,true};
}
return {false,false};
}
};
template<typename OutputType>
using TypedLoopProgram = TypedProgram<OutputType,LoopProgram>;
}/*Modules namespace end*/
#endif // LOOPPROGRAMM_H
#include "loopprogramm.h"
......@@ -45,13 +45,14 @@ public:
}
};
template<typename OutputType>
class TypedProgram : public Program{
template<typename OutputType, typename Base = Program>
class TypedProgram : public Base{
static_assert (std::is_base_of<Program,Base>::value,"The Base class must be an subclass of the Program class!");
protected:
OutputType *output = nullptr;
unsigned int outputLength = 0;
public:
TypedProgram():Program(typeToEnum<OutputType>()){}
TypedProgram():Base(typeToEnum<OutputType>()){}
virtual void setOutputLength(unsigned int l) override{
outputLength = l;
if(output)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment