@@ -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