1+ #pragma once
2+ #include " olcConsoleGameEngine.h"
3+
4+ // Danilo's Arduino Simulation namespace
5+
6+ namespace das
7+ {
8+ void Swap (int &x, int &y) {
9+ x ^= y;
10+ y ^= x;
11+ x ^= y;
12+ }
13+
14+ /* *
15+ Rounds 'value' to closed interval ['lowerBoundary', 'higherBoundary']
16+ */
17+ void Clip (int &value, int lowerBoundary, int higherBoundary) {
18+ if (lowerBoundary > higherBoundary) {
19+ Swap (lowerBoundary, higherBoundary);
20+ }
21+ if (value < lowerBoundary) {
22+ value = lowerBoundary;
23+ }
24+ else if (value > higherBoundary) {
25+ value = higherBoundary;
26+ }
27+ }
28+
29+ const int RUN_SKETCH_ON_BOOT (0 ), ENTER_BOOTLOADER_ON_BOOT(1 );
30+
31+ const int LOW (0 );
32+ const int HIGH (5 ); // approx 5 volts
33+
34+ // Feel free to add more pins if you like, for my needs L01-L08, SW1-SW4 and BTN1-BTN4 are enough
35+ const int MAX_UC32_BASIC_IO_PIN (37 );
36+ const int NUM_SW (4 );
37+ const int NUM_LED (8 );
38+ const int NUM_BTN (4 );
39+
40+ enum PIN
41+ {
42+ L01 = 26 , L02, L03, L04, L05, L06, L07, L08,
43+ SW1 = 2 , SW2 = 7 , SW3 = 8 , SW4 = 35 ,
44+ BTN1 = 4 , BTN2 = 34 , BTN3 = 36 , BTN4 = 37
45+ };
46+
47+ enum PIN_MODE {
48+ INPUT = 0 , OUTPUT, INPUT_PULLUP
49+ };
50+
51+ /* *
52+ Simulation of Arduino uC32 - Basic IO Shield, used for educational purposes.
53+
54+ @note1: This is an abstract class with abstract methods 'void setup()' and 'void loop()'
55+ you MUST implement these. Also you need to call method Start() which is protected
56+ and inherited from olcConsoleGameEngine.h to start the simulation.
57+
58+ @note2: New Console window is created in ArduinoSimulation_uC32 constructor
59+ with default parameters that can potentionally cause exception depending on your
60+ settings. To change these, class that ihnerits ArduinoSimulation_uC32 will have
61+ to call its constructor with different parameters.
62+
63+ @author Danilo Novakoviæ
64+ @version 0.1 4/25/2018
65+ */
66+ class ArduinoSimulation_uC32 : protected olcConsoleGameEngine
67+ {
68+ protected:
69+ // You MUST implement these!!!
70+ virtual void setup () = 0;
71+ virtual void loop () = 0;
72+ private:
73+ struct sRectangleObject
74+ {
75+ short width, height;
76+ sRectangleObject (short width = 1 , short height = 2 ) {
77+ set (width, height);
78+ }
79+ void set (short width, short height) {
80+ this ->width = width;
81+ this ->height = height;
82+ }
83+ };
84+
85+ // fields
86+ bool m_bPins[MAX_UC32_BASIC_IO_PIN + 1 ];
87+ PIN_MODE m_PinModes[MAX_UC32_BASIC_IO_PIN + 1 ];
88+ sRectangleObject m_swModel, m_btnModel, m_ledModel;
89+ private:
90+ /* *
91+ @note: Set 'm_bLearningMode' to off if you don't wish to be thrown unecessary exceptions
92+ or/and possible warnings aimed to serve as reminder to not forget to, for example, set
93+ pinModes to on/off. (Even though simulation will work withouth doing it)
94+ */
95+ bool m_bLearningMode;
96+ public:
97+ ArduinoSimulation_uC32 (int width = 80 , int height = 60 , int fontw = 6 , int fonth = 6 ) {
98+ m_sAppName = L" ArduinoSimulation_uC32 by Danilo Novakovic" ;
99+ try {
100+ ConstructConsole (width, height, fontw, fonth);
101+ }
102+ catch (...) {
103+ printf_s (" \n Error: Unable to construct console window with width=%d, height=%d, fotnw=%d, fonth=%d\n " ,
104+ width, height, fontw, fonth);
105+ exit (EXIT_FAILURE);
106+ }
107+ m_bLearningMode = true ;
108+ }
109+ ~ArduinoSimulation_uC32 () {}
110+
111+ private:
112+ // Inherited via olcConsoleGameEngine
113+ virtual bool OnUserCreate () override
114+ {
115+ m_swModel.set (5 , 15 );
116+ m_btnModel.set (5 , 5 );
117+ m_ledModel.set (4 , 8 );
118+
119+ executeSoftReset (RUN_SKETCH_ON_BOOT);
120+ setup ();
121+ return true ;
122+ }
123+ virtual bool OnUserUpdate (float fElapsedTime ) override
124+ {
125+ // HANDLE INPUT
126+ if (m_keys[VK_ESCAPE].bReleased == true ) {
127+ return false ;
128+ }
129+
130+ for (int i = 1 ; i <= NUM_SW; ++i) {
131+ // keyboard nums 1-4 are reserved for SW flips (on-off)
132+ if (m_keys[i + ' 0' ].bReleased == true ) {
133+ int index = swIndex (NUM_SW - i + 1 );
134+ m_bPins[index] = !m_bPins[index];
135+ }
136+ }
137+
138+ for (int i = 0 ; i < NUM_BTN; ++i) {
139+ // keyboard chars Q,W,E,R are reserved for BTN flips (on-off)
140+ if (m_keys[" QWER" [i]].bHeld || m_keys[" qwer" [i]].bHeld ) {
141+ m_bPins[btnIndex (NUM_BTN - i)] = true ;
142+ }
143+ else {
144+ m_bPins[btnIndex (NUM_BTN - i)] = false ;
145+ }
146+ }
147+
148+ // USER FUNCTION
149+ loop ();
150+
151+ // UPDATE SCREEN
152+ DrawChipKIT ();
153+
154+ return true ;
155+ }
156+
157+ /* *
158+ Helper function that allows me to iterate through sw pins in a loop
159+ by returning their actual value. (SW1 == swIndex(1))
160+ @example: swIndex(1) will return value 2 (check enum das::PIN)
161+ */
162+ int swIndex (int i) {
163+ das::Clip (i, 1 , NUM_SW);
164+ switch (i) {
165+ case 1 :
166+ return (int )SW1;
167+ case 2 :
168+ return (int )SW2;
169+ case 3 :
170+ return (int )SW3;
171+ case 4 :
172+ return (int )SW4;
173+ default :
174+ return -1 ; // not found
175+ }
176+ }
177+ /* *
178+ Helper function that allows me to iterate through btn pins in a loop
179+ by returning their actual value. (BTN1 == btnIndex(1))
180+ @example: btnIndex(1) will return value 4 (check enum das::PIN)
181+ */
182+ int btnIndex (int i) {
183+ das::Clip (i, 1 , NUM_BTN);
184+ switch (i) {
185+ case 1 :
186+ return (int )BTN1;
187+ case 2 :
188+ return (int )BTN2;
189+ case 3 :
190+ return (int )BTN3;
191+ case 4 :
192+ return (int )BTN4;
193+ default :
194+ return -1 ; // not found
195+ }
196+ }
197+
198+ /* *
199+ Updates simulated chipkit (pins) on the console screen.
200+ */
201+ void DrawChipKIT ()
202+ {
203+ // Draw SW's
204+ int y = 2 , x = 1 , i;
205+ static const int SPACE_BETWEEN_PINS (1 );
206+ COLOUR colour;
207+
208+ for (i = 1 , x = 1 ; x < ScreenWidth () && i <= NUM_SW; ++i)
209+ {
210+ colour = m_bPins[swIndex (i)] == true ? FG_GREEN : FG_RED;
211+ Fill (x, y, x + m_swModel.width , y + m_swModel.height , PIXEL_SOLID, colour);
212+ x += m_swModel.width + SPACE_BETWEEN_PINS;
213+ }
214+ y += m_swModel.height + SPACE_BETWEEN_PINS * 3 ;
215+
216+ // Draw BTNs
217+ for (i = 0 , x = 1 ; x < ScreenWidth () && i < NUM_BTN; ++i)
218+ {
219+ PIXEL_TYPE type = m_bPins[btnIndex (NUM_BTN - i)] == true ? PIXEL_SOLID : PIXEL_QUARTER;
220+ Fill (x, y, x + m_btnModel.width , y + m_btnModel.height , type, FG_GREY);
221+ x += m_btnModel.width + SPACE_BETWEEN_PINS;
222+ }
223+
224+ // Draw LEDs
225+ for (i = 0 , x += m_btnModel.width ; x < ScreenWidth () && i < NUM_LED; ++i)
226+ {
227+ colour = m_bPins[(int )PIN::L08 - i] == true ? FG_GREEN : FG_RED;
228+ Fill (x, y, x + m_ledModel.width , y + m_ledModel.height , PIXEL_SOLID, colour);
229+ x += m_ledModel.width + SPACE_BETWEEN_PINS;
230+ }
231+
232+ }
233+ public:
234+ /* *
235+ Resets arduino chipset with specific options
236+ @params supported : RUN_SKETCH_ON_BOOT - resets chipset
237+ note: ENTER_BOOTLOADER_ON_BOOT is not yet implemented
238+ */
239+ void executeSoftReset (uint32_t options) {
240+ if (options == RUN_SKETCH_ON_BOOT) {
241+ for (int i = 0 ; i < MAX_UC32_BASIC_IO_PIN; ++i) {
242+ m_bPins[i] = false ;
243+ }
244+ }
245+ else if (options == ENTER_BOOTLOADER_ON_BOOT) {
246+ // ...
247+ }
248+ }
249+
250+ /* *
251+ Sets pin to certain mode (INPUT, OUTPUT, INPUT_PULLUP)
252+ @note: INPUT_PULLUP support is not yet implemented.
253+ It doesn't do anything in this current state of simulation class.
254+ */
255+ void pinMode (PIN pin, PIN_MODE mode) {
256+ m_PinModes[(int )pin] = mode;
257+ }
258+
259+ /* *
260+ Sets given 'pin' to 'value' (LOW, HIGH)
261+ @note: 'pin' given in params must be previously set to OUTPUT before
262+ calling this method. If it wasn't set on OUTPUT mode method will throw exception.
263+ (exception won't be thrown if m_bLearningMode is set to off)
264+ */
265+ void digitalWrite (PIN pin, int value)
266+ {
267+ if (m_bLearningMode && m_PinModes[(int )pin] != PIN_MODE::OUTPUT)
268+ {
269+ exit (Error (L" error: you called digital write on pin that had no OUTPUT mode set!" ));
270+ }
271+ m_bPins[(int )pin] = value > 0 ;
272+ }
273+
274+ /* *
275+ Reads the state of pin. (ON/OFF)
276+ */
277+ int digitalRead (PIN pin) {
278+ return m_bPins[(int )pin] == true ? LOW : HIGH;
279+ }
280+ void delay (unsigned int ms)
281+ {
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 ();
287+ }
288+
289+ };
290+
291+
292+
293+ }
0 commit comments