Compare commits
10 Commits
268c270a4d
...
render
Author | SHA1 | Date | |
---|---|---|---|
c9d2c05b73 | |||
c07c47385e | |||
68fd8440fc | |||
c1b4baeb2e | |||
09ea237a13 | |||
26ef097d86 | |||
9b56357770 | |||
57720e50f7 | |||
05f186188f | |||
20fd0631c6 |
BIN
UML/event.png
Normal file
BIN
UML/event.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
55
UML/event.puml
Normal file
55
UML/event.puml
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
@startuml
|
||||||
|
|
||||||
|
participant Behavior as b
|
||||||
|
participant Dispatcher as d
|
||||||
|
entity Event as e
|
||||||
|
participant EventQueue as eq
|
||||||
|
queue "EventQueue::queue_" as q
|
||||||
|
|
||||||
|
== Create an Event ==
|
||||||
|
|||
|
||||||
|
?->> b ++ : GEN
|
||||||
|
b -> e ** : new
|
||||||
|
b -> b --++ : pushEvent
|
||||||
|
e -> b : getBehavior
|
||||||
|
b --> e ++: setBehavior
|
||||||
|
e --> b --
|
||||||
|
b -> d ++ : getDispatcher
|
||||||
|
d --> b
|
||||||
|
b -> d -- : pushEvent
|
||||||
|
d ->? -- : push
|
||||||
|
|
||||||
|
|
||||||
|
|||
|
||||||
|
|||
|
||||||
|
== Push Event ==
|
||||||
|
|||
|
||||||
|
?->> d ++: pushEvent
|
||||||
|
d -> eq--++: push
|
||||||
|
eq -> q ++
|
||||||
|
q --> eq
|
||||||
|
eq -> q -- : pushEndQueue
|
||||||
|
|
||||||
|
|||
|
||||||
|
|||
|
||||||
|
== Dispatch ==
|
||||||
|
|||
|
||||||
|
?->> d ++: executeOnce
|
||||||
|
d -> q : getFront
|
||||||
|
q -> e ++
|
||||||
|
e --> q
|
||||||
|
q --> d : event
|
||||||
|
d -> q : pop
|
||||||
|
deactivate q
|
||||||
|
d -> d --++ : dispatchEvent
|
||||||
|
d -> b ++ : getBehavior
|
||||||
|
b --> d
|
||||||
|
d -> b -- : process
|
||||||
|
b -> b--: processEvent
|
||||||
|
|
||||||
|
destroy e
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@enduml
|
BIN
UML/timeAlgorithme.png
Normal file
BIN
UML/timeAlgorithme.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
27
UML/timeAlgorithme.puml
Normal file
27
UML/timeAlgorithme.puml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
@startuml
|
||||||
|
|
||||||
|
start
|
||||||
|
:newTime = 0
|
||||||
|
totalTime = 0
|
||||||
|
isEnd = it == list.end()
|
||||||
|
lastTime = 0;
|
||||||
|
|
||||||
|
#tomato:if (!isEnd) then (not end)
|
||||||
|
#tomato:totalTime += it.getRelTicks();
|
||||||
|
endif
|
||||||
|
|
||||||
|
while ( !isEnd && (totalTime <= newTime) ) is (goForward)
|
||||||
|
:isEnd = (++it == list.end());
|
||||||
|
:lastTime = totalTime;
|
||||||
|
#tomato:if (!isEnd) then (not end)
|
||||||
|
#tomato:totalTime += it.getRelTicks();
|
||||||
|
endif
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
#tomato:if (!isEnd) then (not end)
|
||||||
|
#tomato:subRelTicks(newTime- lastTime);
|
||||||
|
endif
|
||||||
|
:it.setRelTicks(newTime - lastTime);
|
||||||
|
:insert(it, newTimeout);
|
||||||
|
|
||||||
|
@enduml
|
BIN
UML/timeout.png
Normal file
BIN
UML/timeout.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 63 KiB |
62
UML/timeout.puml
Normal file
62
UML/timeout.puml
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
@startuml
|
||||||
|
|
||||||
|
participant "Behavior::StateMachine" as sm
|
||||||
|
participant Dispatcher as d
|
||||||
|
participant TimeoutManager as tm
|
||||||
|
entity "Event::Timeout" as t
|
||||||
|
queue "TimeoutManager::timeouts_" as timeouts
|
||||||
|
|
||||||
|
autoactivate off
|
||||||
|
|||
|
||||||
|
|||
|
||||||
|
== Schedule timeout ==
|
||||||
|
|||
|
||||||
|
sm -> sm++ : scheduleTimeout
|
||||||
|
sm -> d ++: getDispatcher
|
||||||
|
d --> sm --: dispatcher
|
||||||
|
sm -> d --++ : scheduleTimeout
|
||||||
|
d -> tm ++: getTimeoutManager
|
||||||
|
tm --> d --: timeoutManager
|
||||||
|
d -> tm --++ : scheduleTimeout
|
||||||
|
tm -> t ** : new
|
||||||
|
t --> tm
|
||||||
|
tm -> timeouts --++: insert
|
||||||
|
|
||||||
|
|||
|
||||||
|
|||
|
||||||
|
== Decrement timeout (and dispatch) ==
|
||||||
|
|||
|
||||||
|
loop every tickInterval
|
||||||
|
?->> tm ++: tick
|
||||||
|
tm -> timeouts : getFront
|
||||||
|
timeouts -> t ++
|
||||||
|
t --> timeouts
|
||||||
|
timeouts --> tm : timeout
|
||||||
|
tm -> t --: decrement
|
||||||
|
end
|
||||||
|
|||
|
||||||
|
note left t
|
||||||
|
When timeout is 0,
|
||||||
|
dispatch event
|
||||||
|
end note
|
||||||
|
t -> timeouts : pop
|
||||||
|
deactivate timeouts
|
||||||
|
t ->? --: pushEvent
|
||||||
|
|
||||||
|
|||
|
||||||
|
|||
|
||||||
|
== Unschedule timeout ==
|
||||||
|
|||
|
||||||
|
sm -> sm++ : unscheduleTimeout
|
||||||
|
sm -> d ++: getDispatcher
|
||||||
|
d --> sm --: dispatcher
|
||||||
|
sm -> d --++ : unscheduleTimeout
|
||||||
|
d -> tm ++: getTimeoutManager
|
||||||
|
tm --> d --: timeoutManager
|
||||||
|
d -> tm --++ : unscheduleTimeout
|
||||||
|
tm -> timeouts --: erase
|
||||||
|
timeouts -> t !!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@enduml
|
49
readme.md
49
readme.md
@ -8,34 +8,17 @@
|
|||||||
|
|
||||||
# Time Algorithm
|
# Time Algorithm
|
||||||
|
|
||||||
```plantuml
|
|
||||||
|
|
||||||
@startuml
|
<img src="./UML/timeAlgorithme.png">
|
||||||
|
|
||||||
start
|
# Sequence Diagrams
|
||||||
:rTime = 0
|
## Timeout
|
||||||
relInterval = 0
|
|
||||||
isEnd = it == list.end();
|
|
||||||
if (!isEnd) then (not end)
|
|
||||||
:relInterval = it.getRelTicks()
|
|
||||||
rTime += relInterval;
|
|
||||||
|
|
||||||
while ( !isEnd && ( relInterval <= 0 || (rTime < dTime) ) is (goForward)
|
<img src="./UML/timeout.png">
|
||||||
:isEnd = (++it == list.end());
|
|
||||||
if (!isEnd) then (not end)
|
|
||||||
:relInterval = it.getRelTicks()
|
|
||||||
rTime += relInterval;
|
|
||||||
endif
|
|
||||||
endwhile
|
|
||||||
|
|
||||||
endif
|
## Event
|
||||||
: insert ;
|
|
||||||
|
|
||||||
@enduml
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
<img src="./UML/event.png">
|
||||||
|
|
||||||
# Tests
|
# Tests
|
||||||
## Test 1
|
## Test 1
|
||||||
@ -48,7 +31,7 @@ The Test Factory (TestFactory01) instantiates 2 objects:
|
|||||||
<details>
|
<details>
|
||||||
<summary>QT result ✅</summary>
|
<summary>QT result ✅</summary>
|
||||||
|
|
||||||

|
<img src="./test-bench/test1/ide-qtcreator-test1-idf/result.PNG">
|
||||||
|
|
||||||
This test is successfully passed
|
This test is successfully passed
|
||||||
|
|
||||||
@ -56,7 +39,7 @@ This test is successfully passed
|
|||||||
<details>
|
<details>
|
||||||
<summary>STM result ✅</summary>
|
<summary>STM result ✅</summary>
|
||||||
|
|
||||||

|
<img src="./test-bench/test1/ide-cubeide-test1-idf/result.png">
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
@ -68,7 +51,7 @@ Weather or not the state machine should be deleted is handled with the 'deleteOn
|
|||||||
<details>
|
<details>
|
||||||
<summary>QT result ✅</summary>
|
<summary>QT result ✅</summary>
|
||||||
|
|
||||||

|
<img src="./test-bench/test2/ide-qtcreator-test2-idf/result.PNG">
|
||||||
|
|
||||||
This test is successfully passed
|
This test is successfully passed
|
||||||
|
|
||||||
@ -76,7 +59,7 @@ This test is successfully passed
|
|||||||
<details>
|
<details>
|
||||||
<summary>STM result ✅</summary>
|
<summary>STM result ✅</summary>
|
||||||
|
|
||||||

|
<img src="./test-bench/test2/ide-cubeide-test2-idf/result.png">
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
@ -86,7 +69,7 @@ This test checks basic event handling in state machines. In this example the Sta
|
|||||||
<details>
|
<details>
|
||||||
<summary>QT result ✅</summary>
|
<summary>QT result ✅</summary>
|
||||||
|
|
||||||

|
<img src="./test-bench/test3/ide-qtcreator-test3-idf/result.PNG">
|
||||||
|
|
||||||
This test is successfully passed
|
This test is successfully passed
|
||||||
|
|
||||||
@ -94,7 +77,7 @@ This test is successfully passed
|
|||||||
<details>
|
<details>
|
||||||
<summary>STM result ✅</summary>
|
<summary>STM result ✅</summary>
|
||||||
|
|
||||||

|
<img src="./test-bench/test3/ide-cubeide-test3-idf/result.png">
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
@ -104,7 +87,7 @@ Tests if timeouts are correctly cancelled. When leaving a state with a transitio
|
|||||||
<details>
|
<details>
|
||||||
<summary>QT result ✅</summary>
|
<summary>QT result ✅</summary>
|
||||||
|
|
||||||

|
<img src="./test-bench/test4/ide-qtcreator-test4-idf/result.PNG">
|
||||||
|
|
||||||
This test is successfully passed
|
This test is successfully passed
|
||||||
|
|
||||||
@ -112,7 +95,7 @@ This test is successfully passed
|
|||||||
<details>
|
<details>
|
||||||
<summary>STM result ✅</summary>
|
<summary>STM result ✅</summary>
|
||||||
|
|
||||||

|
<img src="./test-bench/test4/ide-cubeide-test4-idf/result.png">
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
@ -122,7 +105,7 @@ With this test multiple timeouts are added to the XFTimeoutManager list at the s
|
|||||||
<details>
|
<details>
|
||||||
<summary>QT result ✅</summary>
|
<summary>QT result ✅</summary>
|
||||||
|
|
||||||

|
<img src="./test-bench/test5/ide-qtcreator-test5-idf/result.PNG">
|
||||||
|
|
||||||
This test is successfully passed
|
This test is successfully passed
|
||||||
|
|
||||||
@ -130,7 +113,7 @@ This test is successfully passed
|
|||||||
<details>
|
<details>
|
||||||
<summary>STM result ✅</summary>
|
<summary>STM result ✅</summary>
|
||||||
|
|
||||||

|
<img src="./test-bench/test5/ide-cubeide-test5-idf/result.png">
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
@ -16,6 +16,12 @@ void XFBehavior::startBehavior() {
|
|||||||
GEN(XFInitialEvent());
|
GEN(XFInitialEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pushes the given event to the dispatcher.
|
||||||
|
*
|
||||||
|
* If the event has no behavior assigned, the behavior of this object is assigned.
|
||||||
|
* @param pEvent Event to push to the dispatcher.
|
||||||
|
*/
|
||||||
void XFBehavior::pushEvent(XFEvent *pEvent) {
|
void XFBehavior::pushEvent(XFEvent *pEvent) {
|
||||||
if(pEvent->getBehavior()==nullptr) {
|
if(pEvent->getBehavior()==nullptr) {
|
||||||
pEvent->setBehavior(this);
|
pEvent->setBehavior(this);
|
||||||
@ -39,6 +45,13 @@ interface::XFDispatcher *XFBehavior::getDispatcher() {
|
|||||||
return interface::XFDispatcher::getInstance();
|
return interface::XFDispatcher::getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a reference to the actually processed timeout.
|
||||||
|
*
|
||||||
|
* Will work only if the current event is of type IXFEvent::Timeout.
|
||||||
|
*
|
||||||
|
* @return Pointer to the currently processed timeout or nullptr if the current event is not a timeout.
|
||||||
|
*/
|
||||||
const XFTimeout *XFBehavior::getCurrentTimeout() {
|
const XFTimeout *XFBehavior::getCurrentTimeout() {
|
||||||
if(pCurrentEvent_->getEventType() == XFEvent::Timeout) {
|
if(pCurrentEvent_->getEventType() == XFEvent::Timeout) {
|
||||||
return (XFTimeout*) this->pCurrentEvent_;
|
return (XFTimeout*) this->pCurrentEvent_;
|
||||||
@ -51,13 +64,33 @@ void XFBehavior::setCurrentEvent(const XFEvent *pEvent) {
|
|||||||
this->pCurrentEvent_ = pEvent;
|
this->pCurrentEvent_ = pEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Processes the given event.
|
||||||
|
*
|
||||||
|
* The dispatcher calls this method every time a new event
|
||||||
|
* or timeout arrives. The process method stores the actual
|
||||||
|
* event using the #_pCurrentEvent and then calls
|
||||||
|
* processEvent().
|
||||||
|
*
|
||||||
|
* In case you intend to call process() inside your state machine you
|
||||||
|
* are doing something wrong! Call GEN() or pushEvent() instead!
|
||||||
|
*
|
||||||
|
* @param pEvent Event to process
|
||||||
|
* @return if the behavior is terminated (basically a boolean)
|
||||||
|
*/
|
||||||
XFBehavior::TerminateBehavior XFBehavior::process(const XFEvent *pEvent) {
|
XFBehavior::TerminateBehavior XFBehavior::process(const XFEvent *pEvent) {
|
||||||
this->setCurrentEvent(pEvent);
|
this->setCurrentEvent(pEvent);
|
||||||
|
|
||||||
|
// Get status of the event processing
|
||||||
XFEventStatus status = XFEventStatus::Unknown;
|
XFEventStatus status = XFEventStatus::Unknown;
|
||||||
status = this->processEvent();
|
status = this->processEvent();
|
||||||
|
|
||||||
|
// Check if event was consumed and if it should be deleted
|
||||||
if(status == XFEventStatus::Consumed && pEvent->deleteAfterConsume()) {
|
if(status == XFEventStatus::Consumed && pEvent->deleteAfterConsume()) {
|
||||||
delete pEvent;
|
delete pEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the behavior is terminated and return the result
|
||||||
XFBehavior::TerminateBehavior terminateBehavior = false;
|
XFBehavior::TerminateBehavior terminateBehavior = false;
|
||||||
if(status == XFEventStatus::Terminate) {
|
if(status == XFEventStatus::Terminate) {
|
||||||
terminateBehavior = true;
|
terminateBehavior = true;
|
||||||
|
@ -34,37 +34,29 @@ XFTimeoutManager::~XFTimeoutManager() {
|
|||||||
|
|
||||||
void XFTimeoutManager::addTimeout(XFTimeout *pNewTimeout) {
|
void XFTimeoutManager::addTimeout(XFTimeout *pNewTimeout) {
|
||||||
|
|
||||||
const int dTime = pNewTimeout->getInterval();
|
const int newTime = pNewTimeout->getInterval();
|
||||||
int rTime = 0;
|
int totalTime = 0;
|
||||||
int relInterval = 0;
|
|
||||||
bool isEnd = true;
|
bool isEnd = true;
|
||||||
int interval = dTime;
|
int lastTime = 0;
|
||||||
|
|
||||||
this->pMutex_->lock();
|
this->pMutex_->lock();
|
||||||
TimeoutList::iterator it = this->timeouts_.begin();
|
TimeoutList::iterator it = this->timeouts_.begin();
|
||||||
isEnd = (it == this->timeouts_.end());
|
isEnd = (it == this->timeouts_.end());
|
||||||
|
|
||||||
if(!isEnd){
|
if(!isEnd) totalTime += (*it)->getRelTicks();
|
||||||
relInterval = (*it)->getInterval();
|
|
||||||
rTime += relInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(!isEnd && ( relInterval <= 0 || (rTime > dTime) )) {
|
while(!isEnd && (totalTime <= newTime)) {
|
||||||
isEnd = (++it == this->timeouts_.end());
|
isEnd = (++it == this->timeouts_.end());
|
||||||
interval = rTime - dTime;
|
lastTime = totalTime;
|
||||||
if(!isEnd) {
|
if(!isEnd) totalTime += (*it)->getRelTicks();
|
||||||
relInterval = (*it)->getRelTicks();
|
|
||||||
rTime += relInterval;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if(it == this->timeouts_.begin())
|
|
||||||
|
|
||||||
if(!isEnd) (*it)->substractFromRelTicks(interval);
|
if(!isEnd) (*it)->substractFromRelTicks(newTime-lastTime);
|
||||||
it--;
|
|
||||||
pNewTimeout->setRelTicks(interval);
|
pNewTimeout->setRelTicks(newTime-lastTime);
|
||||||
this->timeouts_.insert(it, pNewTimeout);
|
this->timeouts_.insert(it, pNewTimeout);
|
||||||
|
|
||||||
this->pMutex_->unlock();
|
this->pMutex_->unlock();
|
||||||
return;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,12 +104,12 @@ void XFTimeoutManager::tick() {
|
|||||||
|
|
||||||
while (!isEmpty && (rTime <= 0) ) {
|
while (!isEmpty && (rTime <= 0) ) {
|
||||||
|
|
||||||
rTime = timeout->getRelTicks();
|
|
||||||
|
|
||||||
XFDispatcher::getInstance()->pushEvent(timeout);
|
XFDispatcher::getInstance()->pushEvent(timeout);
|
||||||
this->timeouts_.pop_front();
|
this->timeouts_.pop_front();
|
||||||
|
|
||||||
timeout = this->timeouts_.front();
|
timeout = this->timeouts_.front();
|
||||||
isEmpty = this->timeouts_.empty();
|
isEmpty = this->timeouts_.empty();
|
||||||
|
if(!isEmpty) rTime = timeout->getRelTicks();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user