-
Notifications
You must be signed in to change notification settings - Fork 1
/
Executor.cpp
126 lines (103 loc) · 2.01 KB
/
Executor.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "Executor.h"
#include "Timer.h"
#include "driverlib.h"
using namespace openpal;
Executor* gpExecutor = nullptr;
void SYSTICK_ISR()
{
if(gpExecutor)
{
gpExecutor->Tick();
}
}
Executor::Executor(uint8_t maxQueueSize, uint8_t maxtimers)
:m_ticks(0),
m_timers(maxtimers),
m_work(maxQueueSize),
m_idleTimers(maxtimers),
m_activeTimers(maxtimers)
{
for(uint8_t i = 0; i < m_timers.Size(); ++i)
{
m_idleTimers.Enqueue(&m_timers[i]);
}
}
MonotonicTimestamp Executor::GetTime()
{
return MonotonicTimestamp(m_ticks);
}
ITimer* Executor::Start(const TimeDuration& duration, const action_t& action)
{
return Start(GetTime().Add(duration), action);
}
ITimer* Executor::Start(const MonotonicTimestamp& expiration, const action_t& action)
{
assert(m_idleTimers.IsNotEmpty());
Timer** pTimer = m_idleTimers.Pop();
(*pTimer)->Set(this, action, expiration);
m_activeTimers.Add(*pTimer);
return *pTimer;
}
void Executor::Post(const action_t& action)
{
assert(!m_work.IsFull());
m_work.Enqueue(action);
}
void Executor::OnCancel(Timer* pTimer)
{
auto matches = [pTimer](Timer* pItem){ return pTimer == pItem; };
m_activeTimers.RemoveFirst(matches);
m_idleTimers.Enqueue(pTimer);
}
void Executor::Init()
{
gpExecutor = this;
MAP_SysTick_enableModule();
MAP_SysTick_setPeriod(1500); // 100 kHz
MAP_SysTick_registerInterrupt(&SYSTICK_ISR);
MAP_SysTick_enableInterrupt();
}
void Executor::Run()
{
while(RunOne());
}
void Executor::Tick()
{
++m_ticks;
}
bool Executor::RunOne()
{
if(RunOneTimer())
{
return true;
}
else
{
if(m_work.IsNotEmpty())
{
(*m_work.Peek())();
m_work.Pop();
return true;
}
else
{
return false;
}
}
}
bool Executor::RunOneTimer()
{
MonotonicTimestamp time = GetTime();
auto expired = [time](Timer* pTimer) { return pTimer->ExpiresAt().milliseconds < time.milliseconds; };
auto pNode = m_activeTimers.RemoveFirst(expired);
if(pNode)
{
m_idleTimers.Enqueue(pNode->value);
(pNode->value->GetAction())();
return true;
}
else
{
return false;
}
}