├── .gitignore ├── DigitalInputEvent.cpp ├── DigitalInputEvent.h ├── Event.cpp ├── Event.h ├── Examples └── StateMachineExample │ └── StateMachineExample.ino ├── Log.h ├── README.md ├── Runtime.cpp ├── Runtime.h ├── SoftTimer.cpp ├── SoftTimer.h ├── StackArray.h ├── StateMachine.cpp └── StateMachine.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Compiled Dynamic libraries 7 | *.so 8 | *.dylib 9 | 10 | # Compiled Static libraries 11 | *.lai 12 | *.la 13 | *.a 14 | -------------------------------------------------------------------------------- /DigitalInputEvent.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloud-rocket/arduino-essentials/83f1d19423345e2dc2b9f7a52b949bcda96ce215/DigitalInputEvent.cpp -------------------------------------------------------------------------------- /DigitalInputEvent.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloud-rocket/arduino-essentials/83f1d19423345e2dc2b9f7a52b949bcda96ce215/DigitalInputEvent.h -------------------------------------------------------------------------------- /Event.cpp: -------------------------------------------------------------------------------- 1 | #include "Event.h" 2 | 3 | #include "Log.h" 4 | #include 5 | 6 | 7 | Event::Event() { 8 | 9 | #ifdef DEBUG 10 | _listeners.setPrinter(Serial); 11 | #endif 12 | } 13 | 14 | void Event::Attach(EventListener* listener) { 15 | 16 | // Check if event already attached 17 | if (IsAttached(listener)) return; 18 | 19 | _listeners.push(listener); 20 | } 21 | 22 | 23 | byte Event::IsAttached(EventListener* listener) { 24 | 25 | if (!_listeners.isEmpty()) { 26 | 27 | for (_listeners.first(); !_listeners.isDone(); _listeners.next()) { 28 | 29 | if (_listeners.currentItem() == listener) { 30 | return 1; 31 | } 32 | } 33 | } 34 | 35 | return 0; 36 | } 37 | 38 | 39 | void Event::Detach(EventListener* listener) { 40 | 41 | 42 | _listeners.remove(listener); 43 | } 44 | 45 | 46 | 47 | void Event::Notify(uint16_t type) { 48 | 49 | if (!_listeners.isEmpty()) { 50 | 51 | for (_listeners.first(); !_listeners.isDone(); _listeners.next()) { 52 | 53 | _listeners.currentItem()->onEvent(this, type); 54 | 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Event.h: -------------------------------------------------------------------------------- 1 | #ifndef _EVENT_H 2 | #define _EVENT_H 3 | 4 | #include "StackArray.h" 5 | 6 | class Event; 7 | 8 | class EventListener { 9 | protected: 10 | virtual void onEvent(Event* o, uint16_t eventType, uint32_t param1 = 0, uint32_t param2 = 0) = 0; 11 | 12 | friend class Event; 13 | }; 14 | 15 | class Event { 16 | 17 | public: 18 | 19 | Event(); 20 | 21 | virtual uint8_t type() = 0; 22 | 23 | void Attach(EventListener* listener); 24 | void Detach(EventListener* listener); 25 | byte IsAttached(EventListener* listener); 26 | 27 | protected: 28 | virtual void Notify(uint16_t type); 29 | 30 | StackArray _listeners; 31 | }; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /Examples/StateMachineExample/StateMachineExample.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | StateMachine stateMachine; 9 | 10 | // MODE A 11 | 12 | class ModeA : public StateMachineMode { 13 | DECLARE_STATE(ModeA, State1); 14 | DECLARE_STATE(ModeA, EndlessLoop); 15 | 16 | BEGIN_STATES_REGISTRATION 17 | ADD_STATE(stateMachine, State1); 18 | ADD_STATE(stateMachine, EndlessLoop); 19 | END_STATES_REGISTRATION 20 | }; 21 | 22 | 23 | SM_COMMAND ModeA::State1(uint16_t eventType, uint32_t param1, uint32_t param2) { 24 | Serial.println("in State1"); 25 | 26 | return SM_NEXT_STATE; 27 | } 28 | 29 | SM_COMMAND ModeA::EndlessLoop(uint16_t eventType, uint32_t param1, uint32_t param2) { 30 | Serial.println("in EndlessLoop"); 31 | 32 | while(1) ; 33 | 34 | return SM_DO_NOTHING; 35 | } 36 | 37 | 38 | ModeA modeA; 39 | 40 | 41 | // MODE B 42 | 43 | 44 | class ModeB : public StateMachineMode { 45 | DECLARE_STATE(ModeB, StateOfB1); 46 | DECLARE_STATE(ModeB, StateOfB2); 47 | 48 | BEGIN_STATES_REGISTRATION 49 | ADD_STATE(stateMachine, StateOfB1); 50 | ADD_STATE(stateMachine, StateOfB2); 51 | END_STATES_REGISTRATION 52 | 53 | public: 54 | void begin(); 55 | void end(); 56 | 57 | 58 | }; 59 | 60 | 61 | SM_COMMAND ModeB::StateOfB1(uint16_t eventType, uint32_t param1, uint32_t param2) { 62 | Serial.println("in StateOfB1"); 63 | 64 | return SM_NEXT_STATE; 65 | } 66 | 67 | SM_COMMAND ModeB::StateOfB2(uint16_t eventType, uint32_t param1, uint32_t param2) { 68 | Serial.println("in StateOfB2"); 69 | 70 | stateMachine.setMode(modeA); 71 | 72 | return SM_DO_NOTHING; 73 | } 74 | 75 | void ModeB::begin() { 76 | Serial.println("ModeB::begin"); 77 | } 78 | 79 | void ModeB::end() { 80 | Serial.println("ModeB::end"); 81 | } 82 | 83 | 84 | ModeB modeB; 85 | 86 | 87 | 88 | void setup() { 89 | 90 | Serial.begin(115200); 91 | Serial.println("Initializing State Machine:"); 92 | 93 | modeA.init(stateMachine); 94 | modeB.init(stateMachine); 95 | 96 | RUNTIME.Attach(&stateMachine); 97 | 98 | stateMachine.setMode(modeB); 99 | 100 | Serial.println("State Machine initialized!"); 101 | } 102 | 103 | 104 | 105 | void loop() { 106 | RUNTIME.exec(); 107 | } 108 | 109 | int main(void) { 110 | 111 | init(); 112 | setup(); 113 | 114 | while (true) { 115 | loop(); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /Log.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_H_ 2 | #define LOG_H_ 3 | 4 | #define DEBUG 5 | 6 | #define DEBUG_INFO 1 7 | #define DEBUG_TEST 2 8 | 9 | #ifdef DEBUG 10 | 11 | #define LOG_INIT() Serial.begin(115200) 12 | #define LOG_PRINT(TYPE, MSG) if (TYPE == DEBUG_INFO) Serial.print(MSG) 13 | #define LOG_PRINTLN(TYPE, MSG) if (TYPE == DEBUG_INFO) Serial.println(MSG) 14 | //#define LOG_PRINTLN(TYPE, ...) if (TYPE == DEBUG_INFO) Serial.println(__VA_ARGS__) 15 | 16 | #else 17 | 18 | #define LOG_INIT() 19 | #define LOG_PRINT(TYPE, MSG) 20 | #define LOG_PRINTLN(TYPE, MSG) 21 | //#define LOG_PRINTLN(TYPE, ...) 22 | 23 | #endif 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | arduino-design-patterns 2 | ======================= 3 | 4 | Useful design patterns (C/C++) implemented for Arduino (Linked List, Event, Soft Timer Event, Debug Prints, State Machine) -------------------------------------------------------------------------------- /Runtime.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloud-rocket/arduino-essentials/83f1d19423345e2dc2b9f7a52b949bcda96ce215/Runtime.cpp -------------------------------------------------------------------------------- /Runtime.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SoftTimer.h 3 | * 4 | * Created on: 30 June 2012 5 | * Author: Miro 6 | */ 7 | 8 | #ifndef RUNTIME_H_ 9 | #define RUNTIME_H_ 10 | 11 | #include "Event.h" 12 | 13 | const extern uint8_t EVENT_TYPE_RUNTIME; 14 | 15 | extern class Runtime : public Event { 16 | 17 | public: 18 | 19 | void exec(); 20 | 21 | uint8_t type() {return EVENT_TYPE_RUNTIME;} 22 | 23 | } RUNTIME; 24 | 25 | 26 | #endif /* RUNTIME_H_ */ 27 | -------------------------------------------------------------------------------- /SoftTimer.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloud-rocket/arduino-essentials/83f1d19423345e2dc2b9f7a52b949bcda96ce215/SoftTimer.cpp -------------------------------------------------------------------------------- /SoftTimer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SoftTimer.h 3 | * 4 | * Created on: 30 June 2012 5 | * Author: Miro 6 | */ 7 | 8 | #ifndef SOFTTIMER_H_ 9 | #define SOFTTIMER_H_ 10 | 11 | #include "Event.h" 12 | 13 | class TimerListener : public Event, public EventListener { 14 | public: 15 | TimerListener() : lastTimestamp(0) {} 16 | 17 | private: 18 | unsigned long timerPeriod; 19 | unsigned long lastTimestamp; 20 | 21 | friend class SoftTimer; 22 | }; 23 | 24 | const extern uint8_t EVENT_TYPE_SOFT_TIMER; 25 | 26 | extern class SoftTimer : public Event, public EventListener { 27 | 28 | public: 29 | void init(); 30 | void Attach(TimerListener* listener, unsigned long timerPeriod); 31 | 32 | uint8_t type() {return EVENT_TYPE_SOFT_TIMER;} 33 | 34 | 35 | protected: 36 | void onEvent(Event* o, uint16_t eventType = 0, uint32_t param1 = 0, uint32_t param2 = 0); 37 | void Notify(uint16_t type); 38 | 39 | } TIMER; 40 | 41 | 42 | #endif /* SOFTTIMER_H_ */ 43 | -------------------------------------------------------------------------------- /StackArray.h: -------------------------------------------------------------------------------- 1 | /* 2 | * StackArray.h 3 | * 4 | * Library implementing a generic, dynamic stack (array version). 5 | * 6 | * --- 7 | * 8 | * Copyright (C) 2010 Efstathios Chatzikyriakidis (contact@efxa.org) 9 | * 10 | * This program is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation, either version 3 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program. If not, see . 22 | * 23 | * --- 24 | * 25 | * Version 1.0 26 | * 27 | * 2010-09-25 Efstathios Chatzikyriakidis 28 | * 29 | * - added resize(): for growing, shrinking the array size. 30 | * 31 | * 2010-09-23 Efstathios Chatzikyriakidis 32 | * 33 | * - added exit(), blink(): error reporting and handling methods. 34 | * 35 | * 2010-09-20 Alexander Brevig 36 | * 37 | * - added setPrinter(): indirectly reference a Serial object. 38 | * 39 | * 2010-09-15 Efstathios Chatzikyriakidis 40 | * 41 | * - initial release of the library. 42 | * 43 | * --- 44 | * 45 | * For the latest version see: http://www.arduino.cc/ 46 | */ 47 | 48 | // header defining the interface of the source. 49 | #ifndef _STACKARRAY_H 50 | #define _STACKARRAY_H 51 | 52 | // include Arduino basic header. 53 | #include 54 | 55 | // the definition of the stack class. 56 | template 57 | class StackArray { 58 | public: 59 | // init the stack (constructor). 60 | StackArray (); 61 | 62 | // clear the stack (destructor). 63 | ~StackArray (); 64 | 65 | // push an item to the stack. 66 | void push (const T i); 67 | 68 | // pop an item from the stack. 69 | T pop (); 70 | 71 | // get an item from the stack. 72 | T peek () const; 73 | 74 | // check if the stack is empty. 75 | bool isEmpty () const; 76 | 77 | // get the number of items in the stack. 78 | int count () const; 79 | 80 | // check if the stack is full. 81 | bool isFull () const; 82 | 83 | // set the printer of the stack. 84 | void setPrinter (Print & p); 85 | 86 | 87 | void remove(const T i); 88 | 89 | // Init iterator on first element 90 | void first(); 91 | 92 | void next(); 93 | 94 | bool isDone() const; 95 | 96 | T currentItem() const; 97 | 98 | 99 | private: 100 | // resize the size of the stack. 101 | void resize (const int s); 102 | 103 | // exit report method in case of error. 104 | void exit (const char * m) const; 105 | 106 | // led blinking method in case of error. 107 | void blink () const; 108 | 109 | // the initial size of the stack. 110 | static const int initialSize = 2; 111 | 112 | // the pin number of the on-board led. 113 | static const int ledPin = 13; 114 | 115 | Print * printer; // the printer of the stack. 116 | T * contents; // the array of the stack. 117 | int size; // the size of the stack. 118 | int top; // the top index of the stack. 119 | 120 | int current; // Iterator index 121 | }; 122 | 123 | // init the stack (constructor). 124 | template 125 | StackArray::StackArray () { 126 | size = 0; // set the size of stack to zero. 127 | top = 0; // set the initial top index of the stack. 128 | printer = NULL; // set the printer of stack to point nowhere. 129 | 130 | // allocate enough memory for the array. 131 | contents = (T *) malloc (sizeof (T) * initialSize); 132 | 133 | // if there is a memory allocation error. 134 | if (contents == NULL) 135 | exit ("STACK: insufficient memory to initialize stack."); 136 | 137 | // set the initial size of the stack. 138 | size = initialSize; 139 | } 140 | 141 | // clear the stack (destructor). 142 | template 143 | StackArray::~StackArray () { 144 | free (contents); // deallocate the array of the stack. 145 | 146 | contents = NULL; // set stack's array pointer to nowhere. 147 | printer = NULL; // set the printer of stack to point nowhere. 148 | size = 0; // set the size of stack to zero. 149 | top = 0; // set the initial top index of the stack. 150 | } 151 | 152 | // resize the size of the stack. 153 | template 154 | void StackArray::resize (const int s) { 155 | // defensive issue. 156 | if (s <= 0) 157 | exit ("STACK: error due to undesirable size for stack size."); 158 | 159 | // reallocate enough memory for the array. 160 | contents = (T *) realloc (contents, sizeof (T) * s); 161 | 162 | // if there is a memory allocation error. 163 | if (contents == NULL) 164 | exit ("STACK: insufficient memory to resize stack."); 165 | 166 | // set the new size of the stack. 167 | size = s; 168 | } 169 | 170 | // push an item to the stack. 171 | template 172 | void StackArray::push (const T i) { 173 | // check if the stack is full. 174 | if (isFull ()) 175 | // double size of array. 176 | resize (size * 2); 177 | 178 | // store the item to the array. 179 | contents[top++] = i; 180 | } 181 | 182 | // pop an item from the stack. 183 | template 184 | T StackArray::pop () { 185 | // check if the stack is empty. 186 | if (isEmpty ()) 187 | exit ("STACK: can't pop item from stack: stack is empty."); 188 | 189 | // fetch the top item from the array. 190 | T item = contents[--top]; 191 | 192 | // shrink size of array if necessary. 193 | if (!isEmpty () && (top <= size / 4)) 194 | resize (size / 2); 195 | 196 | // return the top item from the array. 197 | return item; 198 | } 199 | 200 | // get an item from the stack. 201 | template 202 | T StackArray::peek () const { 203 | // check if the stack is empty. 204 | if (isEmpty ()) 205 | exit ("STACK: can't peek item from stack: stack is empty."); 206 | 207 | // get the top item from the array. 208 | return contents[top - 1]; 209 | } 210 | 211 | // check if the stack is empty. 212 | template 213 | bool StackArray::isEmpty () const { 214 | return top == 0; 215 | } 216 | 217 | // check if the stack is full. 218 | template 219 | bool StackArray::isFull () const { 220 | return top == size; 221 | } 222 | 223 | // get the number of items in the stack. 224 | template 225 | int StackArray::count () const { 226 | return top; 227 | } 228 | 229 | // set the printer of the stack. 230 | template 231 | void StackArray::setPrinter (Print & p) { 232 | printer = &p; 233 | } 234 | 235 | // exit report method in case of error. 236 | template 237 | void StackArray::exit (const char * m) const { 238 | // print the message if there is a printer. 239 | if (printer) 240 | printer->println (m); 241 | 242 | // loop blinking until hardware reset. 243 | blink (); 244 | } 245 | 246 | // led blinking method in case of error. 247 | template 248 | void StackArray::blink () const { 249 | // set led pin as output. 250 | pinMode (ledPin, OUTPUT); 251 | 252 | // continue looping until hardware reset. 253 | while (true) { 254 | digitalWrite (ledPin, HIGH); // sets the LED on. 255 | delay (250); // pauses 1/4 of second. 256 | digitalWrite (ledPin, LOW); // sets the LED off. 257 | delay (250); // pauses 1/4 of second. 258 | } 259 | 260 | // solution selected due to lack of exit() and assert(). 261 | } 262 | 263 | template 264 | void StackArray::remove(const T o) { 265 | 266 | 267 | // Find the item 268 | for (int i = 0; i < top; i++) { 269 | if (contents[i] == o) { 270 | 271 | // Check if we have items afterwards 272 | if (i < top - 1) { 273 | 274 | // Remove this item 275 | memcpy(&contents[i], &contents[i+1], sizeof(T) * (top-i-1)); 276 | } 277 | 278 | top--; 279 | } 280 | } 281 | 282 | // Item not found 283 | exit ("STACK: Item not found in the array."); 284 | 285 | } 286 | 287 | 288 | template 289 | void StackArray::first() { 290 | 291 | // check if the stack is empty. 292 | if (isEmpty ()) 293 | exit ("STACK: can't initialize iterator: stack is empty."); 294 | 295 | current = 0; 296 | } 297 | 298 | template 299 | void StackArray::next() { 300 | 301 | // check if the stack is empty. 302 | if (isDone ()) 303 | exit ("STACK: no more items in the array."); 304 | 305 | 306 | current++; 307 | } 308 | 309 | template 310 | bool StackArray::isDone() const { 311 | return current == top; 312 | } 313 | 314 | template 315 | T StackArray::currentItem() const { 316 | 317 | // check if the stack is empty. 318 | if (isEmpty ()) 319 | exit ("STACK: can't get current item from stack: stack is empty."); 320 | 321 | // check if the stack is empty. 322 | if (isDone ()) 323 | exit ("STACK: no more items in the array."); 324 | 325 | // get the top item from the array. 326 | return contents[current]; 327 | 328 | } 329 | 330 | 331 | 332 | #endif // _STACKARRAY_H 333 | -------------------------------------------------------------------------------- /StateMachine.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloud-rocket/arduino-essentials/83f1d19423345e2dc2b9f7a52b949bcda96ce215/StateMachine.cpp -------------------------------------------------------------------------------- /StateMachine.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloud-rocket/arduino-essentials/83f1d19423345e2dc2b9f7a52b949bcda96ce215/StateMachine.h --------------------------------------------------------------------------------