From cd40bef84459b87ab7cc93b31a08d19193a04cca Mon Sep 17 00:00:00 2001 From: Ivan Seidel Date: Mon, 28 Dec 2015 02:09:18 -0200 Subject: [PATCH 01/16] Update LICENSE.txt --- LICENSE.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.txt b/LICENSE.txt index 38c6bf2..5c02604 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) [year] [fullname] +Copyright (c) 2015 Ivan Seidel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 85695c05a2ee32276459a2ac36ed8e2819455240 Mon Sep 17 00:00:00 2001 From: Ivan Seidel Date: Thu, 21 Apr 2016 16:48:05 -0300 Subject: [PATCH 02/16] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 910e107..acf4e15 100644 --- a/README.md +++ b/README.md @@ -173,7 +173,7 @@ interrupts(); // This will enable the interrupts egain. DO NOT FORGET! - `void ThreadController::remove(Thread* _thread)` - This will remove the Thread from the ThreadController. - `void ThreadController::remove(int index)` - This will remove the thread on the position `index`. - `void ThreadController::clear()` - This will remove ALL threads from the ThreadController array. -- `void ThreadController::size(bool cached = true)` - Returns how many Threads are allocated +- `int ThreadController::size(bool cached = true)` - Returns how many Threads are allocated inside the ThreadController. If cached is `false`, will force the calculation of threads. - `Thread* ThreadController::get(int index)` - Returns the Thread on the position `index`. From 0acb70abce149d29fd6209abe1ef38e1a1cfd90a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nico=20B=C3=B6ckhoff?= Date: Mon, 11 Jul 2016 00:08:46 +0200 Subject: [PATCH 03/16] fixed typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index acf4e15..bf3c1de 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ ArduinoThreads is designed to simplify programs that need to perform multiple pe It should be noted that these are not “threads” in the real computer-science meaning of the term: tasks are implemented as functions that are periodically run to completion. On the one hand, this means that the only way a task can “yield” the CPU is by returning to the caller, and it is thus inadvisable to delay() or do long waits inside a task. On the other hand, this makes ArduinoThreads memory friendly, as no stack needs to be allocated per task. -## Instalation +## Installation 1. "Download":https://github.com/ivanseidel/ArduinoThread/archive/master.zip the Master branch from gitHub. 2. Unzip and modify the Folder name to "ArduinoThread" (Remove the '-master') From 29b2db495d37080a6b280165b96373c0e5e3d4bc Mon Sep 17 00:00:00 2001 From: CAHEK7 Date: Fri, 2 Sep 2016 15:55:01 +0300 Subject: [PATCH 04/16] add StaticThreadController --- StaticThreadController.h | 65 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 StaticThreadController.h diff --git a/StaticThreadController.h b/StaticThreadController.h new file mode 100644 index 0000000..7ee66bf --- /dev/null +++ b/StaticThreadController.h @@ -0,0 +1,65 @@ +/* + StaticThreadController.h - Controlls a list of Threads with different timings + + Basicaly, what it does is to keep track of current Threads and run when + necessary. + + StaticThreadController is an extended class of Thread, because of that, + it allows you to add a StaticThreadController inside another kind of ThreadController... + + It works exact as ThreadController except you can't add or remove treads dynamically. + + Created by Alex Eremin, September, 2016. + Released into the public domain. +*/ + +#ifndef StaticThreadController_h +#define StaticThreadController_h + +#include "Thread.h" + +template +class StaticThreadController: public Thread{ +protected: + Thread thread[N]; +public: + template + StaticThreadController(T&&... params) : + Thread(), + thread{params...} + { + #ifdef USE_THREAD_NAMES + // Overrides name + ThreadName = "StaticThreadController "; + ThreadName = ThreadName + ThreadID; + #endif + }; + + // run() Method is overrided + void run() override + { + for(int i = 0; i < N; i++){ + // Is enabled? Timeout exceeded? + if(thread[i].shouldRun()){ + thread[i].run(); + } + } + + // StaticThreadController extends Thread, so we should flag as runned thread + runned(); + } + + // Return the quantity of Threads + static constexpr int size() { return N; }; + + // Return the I Thread on the array + // Returns nullptr if index is out of bounds + Thread* get(int index) { return (index >= 0 && index < N) ? &thread[index] : nullptr; }; + + // Return the I Thread on the array + // Doesn't perform any bounds checks and behaviour is + // unpredictable in case of index > N + Thread& operator[](int index) { return thread[index]; }; +}; + +#endif From 0c405f390c4efd52b0816867f83af3e9fffacc16 Mon Sep 17 00:00:00 2001 From: CAHEK7 Date: Fri, 2 Sep 2016 15:55:34 +0300 Subject: [PATCH 05/16] update all additional stuff like README or examples --- README.md | 24 ++++++++++++++++++++++-- keywords.txt | 3 ++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bf3c1de..4487a5c 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,8 @@ if(myThread.shouldRun()){ Now that you got the idea, let's think a little bit: What if i have 3, 5, 100 Threads. Do I need to check EACH one?!? -* The answer is: NO. Create a `ThreadController`, and put all your boring-complex Threads inside it! +* The answer is: NO. Create a `ThreadController` or `StaticThreadController`, +and put all your boring-complex Threads inside it! ```c++ // Instantiate a new ThreadController @@ -90,11 +91,18 @@ controller.add(&hisThread); controller.add(&sensorReadings); ... ``` +or +```c++ +// Instantiate a new StaticThreadController +StaticThreadController<2> controller (Thread(my_callback, my_interval), Thread(his_callback, his_interval)); +// You don't need to do anything else, the treads will be created and kept inside controller +... +``` * You have created, configured, grouped it. What is missing? Yes, whe should RUN it! ```c++ -// call run on a Thread or a ThreadController to run it +// call run on a Thread, a ThreadController or a StaticThreadController to run it controller.run(); ``` @@ -126,6 +134,11 @@ or disable a GROUP of Threads, think about putting all of them inside a ThreadCo and adding this ThreadController to another ThreadController (YES! One ThreadController inside another). Check `ControllerInController` example. +* There is a `StaticThreadController` which is better to use when you know exact number of +threads to run. You cannot add or remove threads in runtime, but `StaticThreadController` +doesn't have any memory overhead to keep all the treads together, also the code may be slighly +more optimized because all the threads always exist and no need to do any runtime checks. + * Check the full example `CustomTimedThread` for a cool application of Threads that runs for a period, after a button is pressed. @@ -177,5 +190,12 @@ interrupts(); // This will enable the interrupts egain. DO NOT FORGET! inside the ThreadController. If cached is `false`, will force the calculation of threads. - `Thread* ThreadController::get(int index)` - Returns the Thread on the position `index`. + +- `void StaticThreadController::run()` - This will run the all `Threads` within the `StaicThreadController`, + only if needed (if shouldRun returns true); +- `int StaticThreadController::size()` - Returns how many Threads are allocated inside the StaticThreadController. +- `Thread* ThreadController::get(int index)` - Returns the Thread on the position `index` and `nullptr` if `index` + is out of bounds. + ### You don't need to know: - Nothing, yet ;) diff --git a/keywords.txt b/keywords.txt index d0cc5ca..09b104d 100644 --- a/keywords.txt +++ b/keywords.txt @@ -8,6 +8,7 @@ Thread KEYWORD1 ThreadController KEYWORD1 +StaticThreadController KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) @@ -19,7 +20,7 @@ shouldRun KEYWORD2 onRun KEYWORD2 run KEYWORD2 -# Specific of ThreadController +# Specific of ThreadController or StaticThreadController add KEYWORD2 remove KEYWORD2 clear KEYWORD2 From b271e7dbb84bc1694a54fbc09ca70dc634d8a919 Mon Sep 17 00:00:00 2001 From: CAHEK7 Date: Mon, 5 Sep 2016 01:03:43 +0300 Subject: [PATCH 06/16] hold pointer, not objects in the container --- StaticThreadController.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/StaticThreadController.h b/StaticThreadController.h index 7ee66bf..3af8c6a 100644 --- a/StaticThreadController.h +++ b/StaticThreadController.h @@ -21,10 +21,12 @@ template class StaticThreadController: public Thread{ protected: - Thread thread[N]; + //since this is a static controller, the pointers themselves can be const + //it should be distinguished from 'const Thread* thread[N]' + Thread * const thread[N]; public: template - StaticThreadController(T&&... params) : + StaticThreadController(T... params) : Thread(), thread{params...} { @@ -40,8 +42,8 @@ class StaticThreadController: public Thread{ { for(int i = 0; i < N; i++){ // Is enabled? Timeout exceeded? - if(thread[i].shouldRun()){ - thread[i].run(); + if(thread[i]->shouldRun()){ + thread[i]->run(); } } @@ -54,12 +56,16 @@ class StaticThreadController: public Thread{ // Return the I Thread on the array // Returns nullptr if index is out of bounds - Thread* get(int index) { return (index >= 0 && index < N) ? &thread[index] : nullptr; }; + Thread* get(int index) { + return (index >= 0 && index < N) ? thread[index] : nullptr; + }; // Return the I Thread on the array // Doesn't perform any bounds checks and behaviour is // unpredictable in case of index > N - Thread& operator[](int index) { return thread[index]; }; + Thread& operator[](int index) { + return *thread[index]; + }; }; #endif From 1c59599dba1e0b2b5db7480022a3176059cd84a3 Mon Sep 17 00:00:00 2001 From: CAHEK7 Date: Mon, 5 Sep 2016 01:46:23 +0300 Subject: [PATCH 07/16] update README.md and example --- README.md | 16 ++++-- .../StaticThreadController.ino | 56 +++++++++++++++++++ 2 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 examples/StaticThreadController/StaticThreadController.ino diff --git a/README.md b/README.md index 4487a5c..bca7ee5 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,8 @@ It should be noted that these are not “threads” in the real computer-science There are many examples showing many ways to use it. Here, we will explain Class itself, what it does and "how" it does. -There are basicaly, two Classes included in this Library: -`Thread` and `ThreadController` (that inherits from Thread). +There are basicaly, three Classes included in this Library: +`Thread`, `ThreadController` and `StaticThreadController` (both controllers inherit from Thread). - `Thread class`: This is the basic class, witch contains methods to set and run callbacks, check if the Thread should be runned, and also creates a unique ThreadID on the instantiation. @@ -41,6 +41,9 @@ There are basicaly, two Classes included in this Library: - `ThreadController class`: Responsable for "holding" multiple Threads. Can also be called as "a group of Threads", and is used to perform run in every Thread ONLY when needed. +- `StaticThreadController class`: Slighly faster and smaller version of `ThreadController`. + It works similar to `ThreadController`, but once constructed it can't add or remove threads to run. + * The instantiation of a Thread class is very simple: ```c++ @@ -93,9 +96,9 @@ controller.add(&sensorReadings); ``` or ```c++ -// Instantiate a new StaticThreadController -StaticThreadController<2> controller (Thread(my_callback, my_interval), Thread(his_callback, his_interval)); -// You don't need to do anything else, the treads will be created and kept inside controller +// Instantiate a new StaticThreadController with the number of threads to be supplied as template parameter +StaticThreadController<3> controller (&myThread, &hisThread, &sensorReadings); +// You don't need to do anything else, controller now contains all the threads. ... ``` @@ -136,7 +139,8 @@ inside another). Check `ControllerInController` example. * There is a `StaticThreadController` which is better to use when you know exact number of threads to run. You cannot add or remove threads in runtime, but `StaticThreadController` -doesn't have any memory overhead to keep all the treads together, also the code may be slighly +doesn't have additional memory overhead to keep all the treads together, doesn't have any +limitations how many threads to store (except of available memory) and also the code may be slighly more optimized because all the threads always exist and no need to do any runtime checks. * Check the full example `CustomTimedThread` for a cool application of Threads that runs diff --git a/examples/StaticThreadController/StaticThreadController.ino b/examples/StaticThreadController/StaticThreadController.ino new file mode 100644 index 0000000..bb4155a --- /dev/null +++ b/examples/StaticThreadController/StaticThreadController.ino @@ -0,0 +1,56 @@ +#include +#include + +//My Thread (as a pointer) +Thread* myThread = new Thread(); +//His Thread (not pointer) +Thread hisThread = Thread(); + +// callback for myThread +void niceCallback(){ + Serial.print("COOL! I'm running on: "); + Serial.println(millis()); +} + +// callback for hisThread +void boringCallback(){ + Serial.println("BORING..."); +} + +// callback for theThread +void justCallback(){ + Serial.println("executing..."); +} + +//The Thread (as a pointer) with justCallback initialized +Thread* theThread = new Thread(justCallback); + +// StaticThreadController that will controll all threads +// All non-pointers go with '&', but pointers go without '&', +StaticThreadController<3> controll (myThread, &hisThread, theThread); + +void setup(){ + Serial.begin(9600); + + // Configure myThread + myThread->onRun(niceCallback); + myThread->setInterval(500); + + // Configure hisThread + hisThread.onRun(boringCallback); + hisThread.setInterval(250); + + // Set interval for theThread using StaticThreadController interface + controll[3].setInterval(375); +} + +void loop(){ + // run StaticThreadController + // this will check every thread inside ThreadController, + // if it should run. If yes, he will run it; + controll.run(); + + // Rest of code + float h = 3.1415; + h/=2; +} From 7854b3aa61f4cc3b47e3f618980cd5ba4954aa2b Mon Sep 17 00:00:00 2001 From: CAHEK7 Date: Tue, 6 Sep 2016 15:50:35 +0300 Subject: [PATCH 08/16] add missed '_onRun' for StaticThreadController callback --- StaticThreadController.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/StaticThreadController.h b/StaticThreadController.h index 3af8c6a..6e316ea 100644 --- a/StaticThreadController.h +++ b/StaticThreadController.h @@ -40,6 +40,10 @@ class StaticThreadController: public Thread{ // run() Method is overrided void run() override { + // Run this thread before + if(_onRun != nullptr && shouldRun()) + _onRun(); + for(int i = 0; i < N; i++){ // Is enabled? Timeout exceeded? if(thread[i]->shouldRun()){ From 2ffb25b4aa25f354b0f5f5494ef1ac7c4d1e523b Mon Sep 17 00:00:00 2001 From: Ivan Seidel Date: Tue, 6 Sep 2016 12:51:45 -0300 Subject: [PATCH 09/16] Update library.properties --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index b710ea2..1494795 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ArduinoThread -version=2.0.3 +version=2.1.0 author=Ivan Seidel maintainer=Ivan Seidel sentence=A simple way to run Threads on Arduino From 1c43b8d54c4166d9f8ee8f3fea28700cbc4f6a32 Mon Sep 17 00:00:00 2001 From: wellington castro Date: Thu, 11 May 2017 22:39:00 -0400 Subject: [PATCH 10/16] Correcao na condicao do laco da funcao ThreadController::run() --- ThreadController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ThreadController.cpp b/ThreadController.cpp index af5f1d9..e247b59 100644 --- a/ThreadController.cpp +++ b/ThreadController.cpp @@ -24,7 +24,7 @@ void ThreadController::run(){ unsigned long time = millis(); int checks = 0; - for(int i = 0; i < MAX_THREADS && checks <= cached_size; i++){ + for(int i = 0; i < MAX_THREADS && checks < cached_size; i++){ // Object exists? Is enabled? Timeout exceeded? if(thread[i]){ checks++; From 55b9855b1b99f38002b1a1bfe607ac92ae7a81b4 Mon Sep 17 00:00:00 2001 From: Awaking Date: Mon, 15 May 2017 23:09:50 +0700 Subject: [PATCH 11/16] Fixes #21 --- Thread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Thread.cpp b/Thread.cpp index 8d5d8ee..cd29d98 100644 --- a/Thread.cpp +++ b/Thread.cpp @@ -4,7 +4,7 @@ Thread::Thread(void (*callback)(void), unsigned long _interval){ enabled = true; onRun(callback); _cached_next_run = 0; - last_run = 0; + last_run = millis(); ThreadID = (int)this; #ifdef USE_THREAD_NAMES From ce6fea25629ff3b900d709ff98d26ee26cf358ba Mon Sep 17 00:00:00 2001 From: Ivan Seidel Date: Mon, 15 May 2017 22:47:22 -0300 Subject: [PATCH 12/16] 2.1.1 --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 1494795..59eed7a 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ArduinoThread -version=2.1.0 +version=2.1.1 author=Ivan Seidel maintainer=Ivan Seidel sentence=A simple way to run Threads on Arduino From 652d3a55125ea1134ef026af67205406f2e669d6 Mon Sep 17 00:00:00 2001 From: Josenivaldo Benito Jr Date: Wed, 2 Aug 2017 15:15:12 -0300 Subject: [PATCH 13/16] Cleanup: Silence warning about anused variable Signed-off-by: Josenivaldo Benito Jr --- ThreadController.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/ThreadController.cpp b/ThreadController.cpp index af5f1d9..36923c9 100644 --- a/ThreadController.cpp +++ b/ThreadController.cpp @@ -65,7 +65,6 @@ bool ThreadController::add(Thread* _thread){ void ThreadController::remove(int id){ // Find Threads with the id, and removes - bool found = false; for(int i = 0; i < MAX_THREADS; i++){ if(thread[i]->ThreadID == id){ thread[i] = NULL; From 48bb21a195151c2a72203547989cdde0b25a5436 Mon Sep 17 00:00:00 2001 From: Marco D'Agostini Date: Wed, 21 Mar 2018 19:22:35 -0500 Subject: [PATCH 14/16] Typo - Synce -> Since --- examples/CustomTimedThread/CustomTimedThread.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/CustomTimedThread/CustomTimedThread.ino b/examples/CustomTimedThread/CustomTimedThread.ino index 9d2d7d8..e0f1545 100644 --- a/examples/CustomTimedThread/CustomTimedThread.ino +++ b/examples/CustomTimedThread/CustomTimedThread.ino @@ -49,7 +49,7 @@ =============== WHAT YO LEARN WITH THIS ================= 1) Threads are actually running in 'parallel'. - Synce each thread process time is very tiny, they appear + Since each thread process time is very tiny, they appear as being runned in parallel. Because of that, clicking multiple buttons at any time, @@ -254,4 +254,4 @@ void setup(){ void loop(){ // Here we just run the main thread controller controll.run(); -} \ No newline at end of file +} From 165d6545793a47989dbef0eddffea4f5739629c7 Mon Sep 17 00:00:00 2001 From: Mischa Date: Thu, 26 Jul 2018 07:11:20 +0200 Subject: [PATCH 15/16] fix bug in example CustomTimedThread when overriding shouldRun --- examples/CustomTimedThread/CustomTimedThread.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/CustomTimedThread/CustomTimedThread.ino b/examples/CustomTimedThread/CustomTimedThread.ino index e0f1545..146715d 100644 --- a/examples/CustomTimedThread/CustomTimedThread.ino +++ b/examples/CustomTimedThread/CustomTimedThread.ino @@ -113,7 +113,7 @@ public: "Old" default Thread method 'shouldRun' return if it should run. */ - bool shouldRun(long time){ + bool shouldRun(unsigned long time){ // Override enabled on thread when pin goes LOW. if(digitalRead(pin) == LOW){ enabled = true; From 44d0c57f920eeba832b0f2c26901d2b261756419 Mon Sep 17 00:00:00 2001 From: jediz Date: Fri, 5 Oct 2018 21:52:16 +0200 Subject: [PATCH 16/16] fixed spelling, grammar, section organisation, markup, added links to wiki, removed boilerplate, better readable while preserving the original spirit and code example --- README.md | 229 +++++++++++++++++++++++++++--------------------------- 1 file changed, 116 insertions(+), 113 deletions(-) diff --git a/README.md b/README.md index bca7ee5..b866337 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,61 @@ ![ArduinoThread Logo](https://raw.githubusercontent.com/ivanseidel/ArduinoThread/master/extras/ArduinoThread.png) -Arduino does not support "REAL" parallel tasks (aka Threads), but we can make use of this Library to -improve our code, and easily schedule tasks with fixed (or variable) time between runs. - -This Library helps to maintain organized and to facilitate the use of multiple tasks. We can -use Timers Interrupts, and make it really powerfull, running "pseudo-background" tasks under the rug. - -For example, I personaly use it for all my projects, and put all sensor aquisition and -filtering inside it, leaving the main loop, just for logic and "cool" part. - -#### ArduinoThreads is a library for managing the periodic execution of multiple tasks. - -Blinking an LED is often the very first thing an Arduino user learns. And this demonstrates that periodically performing one single task, like toggling the LED state, is really easy. However, one may quickly discover that managing multiple periodic tasks is not so simple if the tasks have different execution periods. - -ArduinoThreads is designed to simplify programs that need to perform multiple periodic tasks. The user defines a Thread object for each of those tasks, then lets the library manage their scheduled execution. - -It should be noted that these are not “threads” in the real computer-science meaning of the term: tasks are implemented as functions that are periodically run to completion. On the one hand, this means that the only way a task can “yield” the CPU is by returning to the caller, and it is thus inadvisable to delay() or do long waits inside a task. On the other hand, this makes ArduinoThreads memory friendly, as no stack needs to be allocated per task. +## ArduinoThreads Motivation +Arduino does not support isolated parallel tasks ([Threads](https://en.wikipedia.org/wiki/Thread_(computing))), +but we can make the main `loop` switch function execution conditionally and +thus simulate threading with [Protothread](https://en.wikipedia.org/wiki/Protothread) mechanism. +This library implements it and helps you to: + +- schedule, manage and simplify parallel, periodic tasks +- define fixed or variable time between runs +- organize the code in any type of project + - put all sensor readings in a thread + - keep the main loop clean +- hide the complexity of thread management +- run "pseudo-background" tasks using Timer interrupts + +Blinking an LED is often the very first thing an Arduino user learns. +And this demonstrates that periodically performing one single task, like toggling the LED state, is really easy. +However, one may quickly discover that managing multiple periodic tasks is not so simple +if the tasks have different schedule. + +The user defines a Thread object for each of those tasks, then lets the library manage their scheduled execution. + +It should be noted that these are not “threads” in the real computer-science meaning of the term: +tasks are implemented as functions that are run periodically. +On the one hand, this means that the only way a task can *yield* the CPU is by returning to the caller, +and it is thus inadvisable to `delay()` or do long waits inside any task. +On the other hand, this makes ArduinoThreads memory friendly, as no stack need to be allocated per task. ## Installation -1. "Download":https://github.com/ivanseidel/ArduinoThread/archive/master.zip the Master branch from gitHub. -2. Unzip and modify the Folder name to "ArduinoThread" (Remove the '-master') +1. Download [the Master branch](https://github.com/ivanseidel/ArduinoThread/archive/master.zip) from gitHub. +2. Unzip and modify the Folder name to "ArduinoThread" (Remove the '-master' suffix) 3. Paste the modified folder on your Library folder (On your `Libraries` folder inside Sketchbooks or Arduino software). -4. Restart Arduino IDE +4. Restart the Arduino IDE -**If you are here, because another Library requires this class, just don't waste time reading bellow. Install and ready.** +**If you are here just because another library requires a class from ArduinoThread, then you are done now +.** ## Getting Started -There are many examples showing many ways to use it. Here, we will explain Class itself, -what it does and "how" it does. +There are many examples showing many ways to use it. We will explain Class itself, +what it does and how it does. -There are basicaly, three Classes included in this Library: -`Thread`, `ThreadController` and `StaticThreadController` (both controllers inherit from Thread). +There are three main classes included in the library: +`Thread`, `ThreadController` and `StaticThreadController` (both controllers inherit from `Thread`). -- `Thread class`: This is the basic class, witch contains methods to set and run callbacks, - check if the Thread should be runned, and also creates a unique ThreadID on the instantiation. +- `Thread`: Basic class, witch contains methods to set and run callbacks, + check if the Thread should be run, and also creates a unique ThreadID on the instantiation. -- `ThreadController class`: Responsable for "holding" multiple Threads. Can also be called - as "a group of Threads", and is used to perform run in every Thread ONLY when needed. +- `ThreadController`: Responsible for managing multiple Threads. Can also be thought of + as "a group of Threads", and is used to perform `run` in every Thread ONLY when needed. -- `StaticThreadController class`: Slighly faster and smaller version of `ThreadController`. +- `StaticThreadController`: Slightly faster and smaller version of the `ThreadController`. It works similar to `ThreadController`, but once constructed it can't add or remove threads to run. -* The instantiation of a Thread class is very simple: +#### Create Thread instance: ```c++ Thread myThread = Thread(); @@ -52,8 +63,8 @@ Thread myThread = Thread(); Thread* myThread = new Thread(); ``` - -* Setting up a thread is essential. You can configure many things: +#### Setup thread behaviour +You can configure many things: ```c++ myThread.enabled = true; // Default enabled value is true @@ -68,28 +79,26 @@ myThread.ThreadName = "myThread tag"; myThread.onRun(callback_function); // callback_function is the name of the function ``` -Ok, creating Threads are not so hard. But what do we do with them now? - -* First, let's see how Threads should work, to understand what a `ThreadController` is and does +#### Running threads manually +Ok, creating threads isn't too hard, but what do we do with them? ```c++ -// First check if our Thread "should" be runned +// First check if our Thread should be run if(myThread.shouldRun()){ - // Yes, the Thread should be runned, let's run it + // Yes, the Thread should run, let's run it myThread.run(); } ``` -Now that you got the idea, let's think a little bit: What if i have 3, 5, 100 Threads. Do I need to check EACH one?!? - -* The answer is: NO. Create a `ThreadController` or `StaticThreadController`, -and put all your boring-complex Threads inside it! +#### Running threads via a controller +If you had 3, 5 or 100 threads, managing them manually could become tedious. +That's when `ThreadController` or `StaticThreadController` comes into play and saves you the repetitive thread management parts of code. ```c++ -// Instantiate a new ThreadController +// Instantiate new ThreadController ThreadController controller = ThreadController(); -// Now, put a bunch of Threads inside it, FEED it! -controller.add(&myThread); // Notice the & before the thread, IF it's not instantied as a pointer. +// Now, put bunch of Threads inside it, FEED it! +controller.add(&myThread); // Notice the '&' sign before the thread, IF it's not instantied as a pointer. controller.add(&hisThread); controller.add(&sensorReadings); ... @@ -102,58 +111,56 @@ StaticThreadController<3> controller (&myThread, &hisThread, &sensorReadings); ... ``` -* You have created, configured, grouped it. What is missing? Yes, whe should RUN it! +You have created, configured, grouped it. What is missing? Yes, whe should RUN it! +The following will run all the threads that NEED to run. ```c++ // call run on a Thread, a ThreadController or a StaticThreadController to run it controller.run(); ``` -This will run all the Threads that NEED to be runned. - -Congratulations, you have learned the basics of `ArduinoThread`. If you want some TIPS, see bellow. +Congratulations, you have learned the basics of the `ArduinoThread` library. If you want to learn more, see bellow. +### Tips and Warnings -### TIPs and Warnings +* `ThreadController` is not of a dynamic size (like a `LinkedList`). The maximum number of threads that it can manage + is defined in `ThreadController.h` (default is 15) -* ThreadController is not a `LinkedList`. It's "MAXIMUM" size (the maximum Threads that it can - store) is defined on ThreadController.h (default is 15) +* ☢ When extending the `Thread` class and overriding the `run()` function, + remember to always call `runned();` at the end, otherwise the thread will hang forever. -* !!!! VERY IMPORTANT !!!! When extending `Thread` class and implementing the function - `run()`, always remember to put `runned();` after all, otherwhise the `Thread` will ALWAYS run. - -* It's a good idea, to create a Timer interrupt and call a ThreadController.run() there. +* It's a good idea, to create a `Timer` interrupt and call a `ThreadController.run()` there. That way, you don't need to worry about reading sensors and doing time-sensitive stuff -on your main code (loop). Check `ControllerWithTimer` example. +in your main code (`loop`). Check `ControllerWithTimer` example. * Inheriting from `Thread` or even `ThreadController` is always a good idea. For example, I always create base classes of sensors that extends `Thread`, -so that I can "register" the sensors inside a ThreadController, and forget -about really reading sensors, just getting theirs values within my main code. -Checkout `SensorThread` example. - -* Remember that `ThreadController` is in fact, a Thread. If you want to enable -or disable a GROUP of Threads, think about putting all of them inside a ThreadController, -and adding this ThreadController to another ThreadController (YES! One ThreadController -inside another). Check `ControllerInController` example. - -* There is a `StaticThreadController` which is better to use when you know exact number of -threads to run. You cannot add or remove threads in runtime, but `StaticThreadController` -doesn't have additional memory overhead to keep all the treads together, doesn't have any -limitations how many threads to store (except of available memory) and also the code may be slighly -more optimized because all the threads always exist and no need to do any runtime checks. - -* Check the full example `CustomTimedThread` for a cool application of Threads that runs +so that I can "register" the sensors inside a `ThreadController`, and forget +about reading sensors, just having the values available in my main code. +Check the `SensorThread` example. + +* Remember that `ThreadController` is in fact, a `Thread` itself. If you want to group threads and +manage them together (enable or disable), think about putting all of them inside a `ThreadController`, +and adding this `ThreadController` to another `ThreadController` (YES! One inside another). +Check `ControllerInController` example. + +* `StaticThreadController` is optimal when you know the exact number of +threads to run. You cannot add or remove threads at runtime, but it +doesn't require additional memory to keep all the treads together, doesn't limit the number of thread +(except for available memory) and the code may be slightly +better optimized because all the threads always exist and no need to do any runtime checks. + +* Check the full example `CustomTimedThread` for a cool application of threads that run for a period, after a button is pressed. -* Running tasks on the Timer interrupts must be tought REALLY carefully +* Running tasks on the `Timer` interrupts must be thought though REALLY carefully - You cannot use "sleep()" inside a interrupt, because it will get into a infinite loop. + - You mustn't use `sleep()` inside an interrupt, because it would cause an infinite loop. - Things must do stuff quickly. Waiting too loooong on a interrupt, means waiting too - loooong on the main code (loop) + - Things execute quickly. Waiting too loooong on a interrupt, means waiting too + loooong on the main code (`loop`) - Things might get "scrambled". Since Timers interrupts actualy "BREAK" your code in half + - Things might get "scrambled". Since Timers interrupts actually "BREAK" your code in half and start running the interrupt, you might want to call `noInterrupts` and `interrupts` on places where cannot be interrupted: @@ -162,44 +169,40 @@ noInterrupts(); // Put the code that CANNOT be interrupted... interrupts(); // This will enable the interrupts egain. DO NOT FORGET! ``` - - ## Library Reference -### You should know: - -- `bool Thread::enabled` - Enables or disables the Thread. (do not stop it from running, but will - return false when shouldRun() is called) -- `void Thread::setInterval()` - Setts the desired interval for the Thread (in Ms). -- `bool Thread::shouldRun()` - Returns true, if the Thread should be runned. - (Basicaly,the logic is: (reached time AND is enabled?). +### Configuration options +#### Thread +- `bool Thread::enabled` - Enables or disables the thread. (doesn't prevent it from running, but will + return `false` when `shouldRun()` is called) +- `void Thread::setInterval()` - Schedules the thread run interval in milliseconds +- `bool Thread::shouldRun()` - Returns true, if the thread should be run. + (Basically,the logic is: (reached time AND is enabled?). - `void Thread::onRun()` - The target callback function to be called. -- `void Thread::run()` - This will run the Thread (call the callback function). -- `int Thread::ThreadID` - Theoretically, it's the address of memory. It's unique, and can +- `void Thread::run()` - Runs the thread (executes the callback function). +- `int Thread::ThreadID` - Theoretically, it's the memory address. It's unique, and can be used to compare if two threads are identical. -- `int Thread::ThreadName` - A human-redable thread name. Default is "Thread ThreadID" - eg.: "Thread 141515"; Note that to enable this attribute, you must uncomment the line that disables it on 'Thread.h'; -- protected: `void Thread::runned()` - Used to reset internal timer of the Thread. - This is automaticaly called AFTER a call to `run()`. - - -- `void ThreadController::run()` - This will run the all `Threads` within the `ThreadController`, - only if needed (if shouldRun returns true); -- `bool ThreadController::add(Thread* _thread)` - This will add a the thread to the ThreadController, - and return `true` if suceeded (it the array is full, returns false). -- `void ThreadController::remove(Thread* _thread)` - This will remove the Thread from the ThreadController. -- `void ThreadController::remove(int index)` - This will remove the thread on the position `index`. -- `void ThreadController::clear()` - This will remove ALL threads from the ThreadController array. -- `int ThreadController::size(bool cached = true)` - Returns how many Threads are allocated - inside the ThreadController. If cached is `false`, will force the calculation of threads. -- `Thread* ThreadController::get(int index)` - Returns the Thread on the position `index`. - - -- `void StaticThreadController::run()` - This will run the all `Threads` within the `StaicThreadController`, - only if needed (if shouldRun returns true); -- `int StaticThreadController::size()` - Returns how many Threads are allocated inside the StaticThreadController. -- `Thread* ThreadController::get(int index)` - Returns the Thread on the position `index` and `nullptr` if `index` +- `int Thread::ThreadName` - A human-readable thread name. + Default is "Thread ThreadID", eg.: "Thread 141515". + Note that to enable this attribute, you must uncomment the line that disables it on `Thread.h` +- protected: `void Thread::runned()` - Used to reset internal timer of the thread. + This is automatically called AFTER a call to `run()`. + +#### ThreadController +- `void ThreadController::run()` - Runs the all threads grouped by the controller, + but only if needed (if `shouldRun()` returns true); +- `bool ThreadController::add(Thread* _thread)` - Adds a the thread to the controller, + and returns `true` if succeeded (returns false if the array is full). +- `void ThreadController::remove(Thread* _thread)` - Removes the thread from the controller +- `void ThreadController::remove(int index)` - Removes the thread at the `index` position +- `void ThreadController::clear()` - Removes ALL threads from the controller +- `int ThreadController::size(bool cached = true)` - Returns number of threads allocated + in the ThreadController. Re-calculates thread count if `cached` is `false` +- `Thread* ThreadController::get(int index)` - Returns the thread at the `index` position + +#### StaticThreadController +- `void StaticThreadController::run()` - Runs all the threads within the controller, + but only if needed (if `shouldRun()` returns true); +- `int StaticThreadController::size()` - Returns how many Threads are allocated inside the controller. +- `Thread* ThreadController::get(int index)` - Returns the thread at the `index` position - or `nullptr` if `index` is out of bounds. - -### You don't need to know: -- Nothing, yet ;)