Skip to content
This repository was archived by the owner on Aug 21, 2019. It is now read-only.

Commit 2594c27

Browse files
DAS_v0.4
- Added multi-thread support - Program now works on 3 seperate deamon threads and scheduler that manages these threads (decides which is active, ready or in wait state)
1 parent aac2c03 commit 2594c27

2 files changed

Lines changed: 254 additions & 110 deletions

File tree

das.h

Lines changed: 143 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ namespace das
4747
enum PIN_MODE {
4848
INPUT = 0, OUTPUT, INPUT_PULLUP
4949
};
50+
const int NUM_DEAMON_THREADS = 3;
5051

5152
/**
5253
Simulation of Arduino uC32 - Basic IO Shield, used for educational purposes.
@@ -83,9 +84,16 @@ namespace das
8384
};
8485

8586
// fields
86-
bool m_bPins[MAX_UC32_BASIC_IO_PIN + 1];
87-
PIN_MODE m_PinModes[MAX_UC32_BASIC_IO_PIN + 1];
87+
std::atomic<bool> m_bPins[MAX_UC32_BASIC_IO_PIN + 1];
88+
std::atomic<PIN_MODE> m_PinModes[MAX_UC32_BASIC_IO_PIN + 1];
8889
sRectangleObject m_swModel, m_btnModel, m_ledModel;
90+
91+
const int THREAD_INPUT_ID = 0, THREAD_LOOP_ID = 1, THREAD_OUTPUT_ID = 2;
92+
std::atomic<int> m_activeThread;
93+
std::atomic<int> m_readyThreads[NUM_DEAMON_THREADS];
94+
condition_variable m_cvDeamonThreads[NUM_DEAMON_THREADS];
95+
condition_variable m_cvScheduler;
96+
mutex m_muxPin;
8997
private:
9098
/**
9199
@note: Set 'm_bLearningMode' to off if you don't wish to be thrown unecessary exceptions
@@ -116,15 +124,101 @@ namespace das
116124
m_btnModel.set(5, 5);
117125
m_ledModel.set(4, 8);
118126

127+
m_activeThread = -1;
128+
for (int i = 0; i < NUM_DEAMON_THREADS; ++i) {
129+
m_readyThreads[i] = 0;
130+
}
131+
119132
executeSoftReset(RUN_SKETCH_ON_BOOT);
120133
setup();
134+
135+
thread{ [&]() {HandleInput(); } }.detach();
136+
thread{ [&]() {HandleLoop(); } }.detach();
137+
thread{ [&]() {HandleOutput(); } }.detach();
138+
121139
return true;
122140
}
123141
virtual bool OnUserUpdate(float fElapsedTime) override
124142
{
143+
Scheduler();
144+
145+
return true;
146+
}
147+
void Scheduler()
148+
{
149+
unique_lock<mutex> ulock(m_muxPin);
150+
while (1)
151+
{
152+
m_activeThread = modRobin(m_activeThread + 1);
153+
if (m_readyThreads[m_activeThread] > 0) {
154+
m_cvDeamonThreads[m_activeThread].notify_one();
155+
m_cvScheduler.wait(ulock);
156+
}
157+
}
158+
159+
}
160+
const int TESTING_WAIT_TIME = 100;
161+
void HandleInput()
162+
{
163+
unique_lock<mutex> ulock(m_muxPin);
164+
while (1)
165+
{
166+
do
167+
{
168+
++m_readyThreads[THREAD_INPUT_ID];
169+
m_cvDeamonThreads[THREAD_INPUT_ID].wait(ulock);
170+
--m_readyThreads[THREAD_INPUT_ID];
171+
} while (m_activeThread != THREAD_INPUT_ID);
172+
173+
HandleKeyboardInput();
174+
//HandleMouseInput();
175+
HandleInputChipKit();
176+
177+
m_cvScheduler.notify_one();
178+
179+
}
180+
}
181+
void HandleOutput()
182+
{
183+
unique_lock<mutex> ulock(m_muxPin);
184+
while (1)
185+
{
186+
do
187+
{
188+
++m_readyThreads[THREAD_OUTPUT_ID];
189+
m_cvDeamonThreads[THREAD_OUTPUT_ID].wait(ulock);
190+
--m_readyThreads[THREAD_OUTPUT_ID];
191+
} while (m_activeThread != THREAD_OUTPUT_ID);
192+
193+
DrawChipKIT();
194+
UpdateScreen();
195+
196+
m_cvScheduler.notify_one();
197+
}
198+
}
199+
void HandleLoop()
200+
{
201+
unique_lock<mutex> ulock(m_muxPin);
202+
while (1)
203+
{
204+
do
205+
{
206+
++m_readyThreads[THREAD_LOOP_ID];
207+
m_cvDeamonThreads[THREAD_LOOP_ID].wait(ulock);
208+
--m_readyThreads[THREAD_LOOP_ID];
209+
} while (m_activeThread != THREAD_LOOP_ID);
210+
211+
ulock.unlock();
212+
loop();
213+
ulock.lock();
214+
215+
m_cvScheduler.notify_one();
216+
}
217+
}
218+
void HandleInputChipKit() {
125219
// HANDLE INPUT
126220
if (m_keys[VK_ESCAPE].bReleased == true) {
127-
return false;
221+
exit(EXIT_SUCCESS);
128222
}
129223

130224
for (int i = 1; i <= NUM_SW; ++i) {
@@ -144,16 +238,31 @@ namespace das
144238
m_bPins[btnIndex(NUM_BTN - i)] = false;
145239
}
146240
}
241+
}
147242

148-
// USER FUNCTION
149-
loop();
243+
void delayTest(unique_lock<mutex>& ulock, unsigned int ms, const wchar_t* debugMsg)
244+
{
245+
DrawString(0, m_activeThread, debugMsg);
246+
UpdateScreen();
247+
248+
int thread_id = m_activeThread;
150249

151-
// UPDATE SCREEN
152-
DrawChipKIT();
250+
ulock.unlock();
251+
m_cvScheduler.notify_one();
153252

154-
return true;
253+
this_thread::sleep_for(chrono::milliseconds(ms));
254+
ulock.lock();
255+
256+
while(m_activeThread != thread_id) {
257+
++m_readyThreads[thread_id];
258+
m_cvDeamonThreads[thread_id].wait(ulock);
259+
--m_readyThreads[thread_id];
260+
}
155261
}
156262

263+
int modRobin(int x, const int size = NUM_DEAMON_THREADS) {
264+
return x >= size ? 0 : x;
265+
}
157266
/**
158267
Helper function that allows me to iterate through sw pins in a loop
159268
by returning their actual value. (SW1 == swIndex(1))
@@ -277,13 +386,33 @@ namespace das
277386
int digitalRead(PIN pin) {
278387
return m_bPins[(int)pin] == true ? LOW : HIGH;
279388
}
280-
void delay(unsigned int ms)
389+
390+
/**
391+
@note: this function will attempt to lock(m_muxPin), so if you already hold
392+
that mutex you will have to unlock it first before calling this function
393+
*/
394+
void delay(unsigned int ms) {
395+
delay(ms, nullptr);
396+
}
397+
void delay(unsigned int ms, const wchar_t* debug_msg)
281398
{
282-
// I need to optimize this to work a bit better
283-
DrawChipKIT();
284-
thread t([this](){ this->UpdateScreen(); });
285-
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
286-
t.join();
399+
unique_lock<mutex> ulock(m_muxPin);
400+
int thread_id = m_activeThread;
401+
402+
if (debug_msg != nullptr) {
403+
DrawString(0, m_activeThread, debug_msg);
404+
}
405+
ulock.unlock();
406+
m_cvScheduler.notify_one();
407+
408+
this_thread::sleep_for(chrono::milliseconds(ms));
409+
ulock.lock();
410+
411+
while (m_activeThread != thread_id) {
412+
++m_readyThreads[thread_id];
413+
m_cvDeamonThreads[thread_id].wait(ulock);
414+
--m_readyThreads[thread_id];
415+
}
287416
}
288417

289418
};

0 commit comments

Comments
 (0)