From b84e6f7bc7c543a46da6424224a5b63888b38bdd Mon Sep 17 00:00:00 2001 From: Nicholas Wiersma Date: Fri, 2 Sep 2016 11:20:27 +0200 Subject: [PATCH] Initial commit --- LICENSE | 21 +++++++++++ README.md | 90 +++++++++++++++++++++++++++++++++++++++++++++ examples/simple.ino | 62 +++++++++++++++++++++++++++++++ keywords.txt | 22 +++++++++++ library.json | 13 +++++++ library.properties | 9 +++++ src/Scheduler.cpp | 40 ++++++++++++++++++++ src/Scheduler.h | 29 +++++++++++++++ src/Task.h | 66 +++++++++++++++++++++++++++++++++ 9 files changed, 352 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 examples/simple.ino create mode 100644 keywords.txt create mode 100644 library.json create mode 100644 library.properties create mode 100644 src/Scheduler.cpp create mode 100644 src/Scheduler.h create mode 100644 src/Task.h diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6d50192 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Nicholas Wiersma + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..fe6dd7d --- /dev/null +++ b/README.md @@ -0,0 +1,90 @@ +# ESP8266Scheduler + +ESP8266 Co-operative Multitasking + +# Quick Start + +## Installing + +You can install through the Arduino Library Manager. The package name is +**ESP8266Scheduler**. + +## Usage + +Include the library in your sketch + +```cpp +#include +``` + +In your setup function start the scheduler + +```cpp +Scheduler.start(&task); + +Scheduler.begin(); +``` + +The scheduler blocks once begun, so the loop function is never called. You should instead create tasks. + +# Creating a Task + +Tasks are classes that should inherit the ```Task``` class. A task can define a ```loop()``` and ```setup()``` function +much as the normal Arduino standard. + +```cpp +class BlinkTask : public Task { +protected: + void setup() { + state = HIGH; + + pinMode(2, OUTPUT); + pinMode(2, state); + } + + void loop() { + state = state == HIGH ? LOW : HIGH; + pinMode(2, state); + + delay(1000); + } + +private: + uint8_t state; +} blink_task; +``` + +**IMPORTANT: Tasks must be declared globally on the stack (not a pointer). Failure to do so will crash your device.** + +### Advanced Task Functions + +The ```Task``` also exposes a ```bool shouldRun()``` method that is used determine if the task loop +should be be resumed. This can be inherited to add your own logic to determine if your code should be resumed. + +```cpp +bool shouldRun() { + bool run = Task::shouldRun(); + + // Your code here + + return run; +} +``` + +**This function handles the ```delay()``` logic. The parent method should be called.** + +# Documentation + +## Methods + +### start +``` +static void start(Task *task) +``` +> Adds a task to the multitasking queue. + +### begin +``` +static void begin() +``` +> Starts the scheduler. This function is "blocking". It should be the last call the ```setup``` function. diff --git a/examples/simple.ino b/examples/simple.ino new file mode 100644 index 0000000..1267667 --- /dev/null +++ b/examples/simple.ino @@ -0,0 +1,62 @@ +#include +#include + +class PrintTask : public Task { +protected: + void loop() { + Serial.println("Print Loop Start"); + + delay(5000); + + Serial.println("Print Loop End"); + + delay(5000); + } +} print_task; + +class BlinkTask : public Task { +protected: + void setup() { + state = HIGH; + + pinMode(2, OUTPUT); + pinMode(2, state); + } + + void loop() { + state = state == HIGH ? LOW : HIGH; + pinMode(2, state); + + delay(1000); + } + +private: + uint8_t state; +} blink_task; + +class MemTask : public Task { +public: + void loop() { + Serial.print("Free Heap: "); + Serial.print(ESP.getFreeHeap()); + Serial.println(" bytes"); + + delay(10000); + } +} mem_task; + +void setup() { + Serial.begin(115200); + + Serial.println(""); + + delay(1000); + + Scheduler.start(&print_task); + Scheduler.start(&blink_task); + Scheduler.start(&mem_task); + + Scheduler.begin(); +} + +void loop() {} diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 0000000..a911aa5 --- /dev/null +++ b/keywords.txt @@ -0,0 +1,22 @@ +####################################### +# Syntax Coloring Map For ESP8266Scheduler +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Scheduler KEYWORD1 +Task KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +start KEYWORD2 +begin KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +# LITERAL1 diff --git a/library.json b/library.json new file mode 100644 index 0000000..d426bdf --- /dev/null +++ b/library.json @@ -0,0 +1,13 @@ +{ + "name": "ESP8266Scheduler", + "keywords": "multitasking", + "description": "ESP8266 Co-operative Multitasking", + "repository": + { + "type": "git", + "url": "https://github.com/nrwiersma/ESP8266Scheduler.git" + }, + "frameworks": "arduino", + "platforms": "espressif", + "version": "0.1" +} diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..a10c698 --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=ESP8266Scheduler +version=0.1 +author=Nick Wiersma +maintainer=Nick Wiersma +sentence=ESP8266 Co-operative Multitasking +paragraph=Co-operative multitasking for ESP8266 modules. +category=Other +url=https://github.com/nrwiersma/ESP8266Scheduler.git +architectures=esp8266 diff --git a/src/Scheduler.cpp b/src/Scheduler.cpp new file mode 100644 index 0000000..05d98f8 --- /dev/null +++ b/src/Scheduler.cpp @@ -0,0 +1,40 @@ +#include "Scheduler.h" + +extern "C" { + #include "cont.h" + + void yield(); +} + +SchedulerClass Scheduler; + +Task SchedulerClass::main; +Task *SchedulerClass::current = &SchedulerClass::main; + +SchedulerClass::SchedulerClass() { + main.next = &main; + main.prev = &main; +} + +void SchedulerClass::start(Task *task) { + task->next = &main; + task->prev = main.prev; + + main.prev->next = task; + main.prev = task; +} + +void SchedulerClass::begin() { + while (1) { + if (current->shouldRun()) + cont_run(¤t->context, task_tramponline); + + yield(); + + current = current->next; + } +} + +void task_tramponline() { + SchedulerClass::current->loopWrapper(); +} diff --git a/src/Scheduler.h b/src/Scheduler.h new file mode 100644 index 0000000..6d64365 --- /dev/null +++ b/src/Scheduler.h @@ -0,0 +1,29 @@ +#ifndef SCHEDULER_H +#define SCHEDULER_H + +// #include +#include "Task.h" + +extern "C" void loop(); +extern void task_tramponline(); + +class SchedulerClass { +public: + SchedulerClass(); + + static void start(Task *task); + + static void begin(); + +private: + friend void task_tramponline(); + + // class MainTask : public Task {}; + + static Task main; + static Task *current; +}; + +extern SchedulerClass Scheduler; + +#endif diff --git a/src/Task.h b/src/Task.h new file mode 100644 index 0000000..4a59152 --- /dev/null +++ b/src/Task.h @@ -0,0 +1,66 @@ +#ifndef TASK_H +#define TASK_H + +#include +#include "Scheduler.h" + +extern "C" { + #include "cont.h" +} + +class Task { +public: + Task() { + cont_init(&context); + } + +protected: + virtual void setup() {} + + virtual void loop() {} + + void delay(unsigned long ms) { + if (ms) { + delay_time = millis(); + delay_ms = ms; + } + + yield(); + } + + void yield() { + cont_yield(&context); + } + + virtual bool shouldRun() { + unsigned long now = millis(); + + return !delay_ms || now >= delay_time + delay_ms; + } + +private: + friend class SchedulerClass; + friend void task_tramponline(); + + Task *next; + Task *prev; + cont_t context; + + bool setup_done = false; + unsigned long delay_time; + unsigned long delay_ms; + + void loopWrapper() { + if (!setup_done) { + setup(); + setup_done = true; + } + + while(1) { + loop(); + yield(); + } + } +}; + +#endif