diff --git a/lib/task/fnTask.cpp b/lib/task/fnTask.cpp new file mode 100644 index 000000000..fa473758f --- /dev/null +++ b/lib/task/fnTask.cpp @@ -0,0 +1,79 @@ +#ifndef ESP_PLATFORM + +#include "fnTask.h" +#include "debug.h" + +fnTask::fnTask() +{ + Debug_println("fnTask::fnTask"); + _id = 0; + _state = TASK_READY; + _reason = TASK_COMPLETED; + _callback = nullptr; +} + + +fnTask::~fnTask() +{ + Debug_printf("fnTask::~fnTask #%d\n", _id); +} + + +fnTestTask::fnTestTask(int count) +{ + Debug_printf("fnTestTask::fnTestTask(%d)\n", count); + _count = count; + _i = 0; +} + +fnTestTask::~fnTestTask() +{ + Debug_printf("fnTestTask::~fnTestTask #%d\n", _id); +} + +int fnTestTask::get_progress() +{ + Debug_printf("fnTestTask::get_progress #%d\n", _id); + return 0; +} + +void * fnTestTask::get_result() +{ + Debug_printf("fnTestTask::get_result #%d\n", _id); + return nullptr; +} + + +int fnTestTask::start() +{ + Debug_printf("fnTestTask::start #%d\n", _id); + return 0; +} + +int fnTestTask::pause() +{ + Debug_printf("fnTestTask::pause #%d\n", _id); + return 0; +} + +int fnTestTask::resume() +{ + Debug_printf("fnTestTask::resume #%d\n", _id); + return 0; +} + +int fnTestTask::abort() +{ + Debug_printf("fnTestTask::abort #%d\n", _id); + return 0; +} + +int fnTestTask::step() +{ + Debug_printf("fnTestTask::step #%d - %d\n", _id, _i); + if (++_i<_count) + return 0; // continue + return 1; // done +} + +#endif // !ESP_PLATFORM \ No newline at end of file diff --git a/lib/task/fnTask.h b/lib/task/fnTask.h new file mode 100644 index 000000000..c9a25fde5 --- /dev/null +++ b/lib/task/fnTask.h @@ -0,0 +1,75 @@ +#ifndef _FN_TASK_H +#define _FN_TASK_H + +#include + +class fnTaskManager; + +class fnTask +{ +public: + enum task_state + { + TASK_READY = 0, + TASK_RUNNING, + TASK_PAUSED, + TASK_DONE + }; + + enum done_reason + { + TASK_COMPLETED = 0, + TASK_ABORTED + }; + + fnTask(); + virtual ~fnTask() = 0; + + // state, progress and results + task_state get_state() {return _state;}; + done_reason get_done_reason() {return _reason;}; + virtual int get_progress() {return 0;}; // optional + virtual void * get_result() {return nullptr;}; // optional + +protected: + // task state management + // READY -> RUNNING + virtual int start() = 0; // mandatory, must be implemented in sub-class + // RUNNING -> PAUSED + virtual int pause() {return 0;}; // optional + // PAUSED -> RUNNING + virtual int resume() {return 0;}; // optional + // -> DONE/ABORTED, result is not available + virtual int abort() {return 0;}; // optional + // do some work + virtual int step() = 0; // mandatory, must be implemented in sub-class + + friend fnTaskManager; + + uint8_t _id; // task ID 1..255, 0 is invalid / not yet assigned ID + task_state _state; + done_reason _reason; + void (*_callback)(fnTask *t, task_state new_state); +}; + +class fnTestTask : public fnTask +{ +public: + fnTestTask(int count); + virtual ~fnTestTask() override; + virtual int get_progress() override; + virtual void * get_result() override; + +protected: + virtual int start() override; + virtual int pause() override; + virtual int resume() override; + virtual int abort() override; + virtual int step() override; + +private: + int _count; + int _i; +}; + +#endif // _FN_TASK_H diff --git a/lib/task/fnTaskManager.cpp b/lib/task/fnTaskManager.cpp new file mode 100644 index 000000000..3ae265db2 --- /dev/null +++ b/lib/task/fnTaskManager.cpp @@ -0,0 +1,213 @@ +#ifndef ESP_PLATFORM + +#include + +#include "fnTaskManager.h" +#include "debug.h" + +// global task manager object +fnTaskManager taskMgr; + + +fnTaskManager::fnTaskManager() +{ + // Debug_println("fnTaskManager::fnTaskManager"); + _next_tid = 1; + _task_count = 0; +} + +fnTaskManager::~fnTaskManager() +{ + // Debug_println("fnTaskManager::~fnTaskManager"); + shutdown(); +} + +void fnTaskManager::shutdown() +{ + // abort tasks, if any + for (auto it = _task_map.begin(); it != _task_map.end(); ++it) + { + Debug_printf("Aborting task %d\n", it->first); + it->second->abort(); + delete it->second; + } + _task_map.clear(); + _task_count = 0; +} + +int fnTaskManager::submit_task(fnTask * t) +{ + Debug_println("submit_task"); + + for (auto it = _task_map.begin(); it != _task_map.end(); ++it) + { + if (it->second == t) + { + Debug_printf(" alredy submitted (task %d)!\n", it->first); + return 0; + } + } + + uint8_t tid = get_free_tid(); + if (tid == 0) + { + Debug_println(" failed to get free task ID"); + } + else + { + // store task + t->_id = tid; + _task_count += 1; + _task_map[tid] = t; + _next_tid = tid+1; + Debug_printf(" submitted #%d\n", tid); + } + return tid; +} + +uint8_t fnTaskManager::get_free_tid() +{ + uint8_t stop = _next_tid; + uint8_t tid = _next_tid; + while(_task_map.find(tid) != _task_map.end()) + { + // try next ID, skip ID 0 + if (++tid == 0) ++tid; + if(tid == stop) + { + // wrapped around, no free ID + tid = 0; + break; + } + } + return tid; +} + +fnTask * fnTaskManager::get_task(uint8_t tid) +{ + Debug_printf("get_task %d\n", tid); + std::map::iterator it = _task_map.find(tid); + if (it == _task_map.end()) + return nullptr; + return it->second; +} + +int fnTaskManager::pause_task(uint8_t tid) +{ + Debug_printf("pause_task %d\n", tid); + fnTask *task = get_task(tid); + if (task == nullptr) + return -1; + if (task->_state != fnTask::TASK_RUNNING) + return -1; + int result = task->pause(); + task->_state = fnTask::TASK_PAUSED; + // TODO callback + return result; +} + +int fnTaskManager::resume_task(uint8_t tid) +{ + Debug_printf("resume_task %d\n", tid); + fnTask *task = get_task(tid); + if (task == nullptr) + return -1; + if (task->_state != fnTask::TASK_PAUSED) + return -1; + int result = task->resume(); + task->_state = fnTask::TASK_RUNNING; + // TODO callback + return result; +} + +int fnTaskManager::abort_task(uint8_t tid) +{ + Debug_printf("abort_task %d\n", tid); + fnTask *task = get_task(tid); + if (task == nullptr) + return -1; + int result = task->abort(); + task->_state = fnTask::TASK_DONE; + task->_reason = fnTask::TASK_ABORTED; + // TODO callback + // remove aborted task + _task_count -= 1; + _task_map.erase(tid); + delete task; + return result; +} + +int fnTaskManager::complete_task(uint8_t tid) +{ + Debug_printf("complete_task %d\n", tid); + fnTask *task = get_task(tid); + if (task == nullptr) + return -1; + task->_state = fnTask::TASK_DONE; + task->_reason = fnTask::TASK_COMPLETED; + // TODO callback + // remove completed task + _task_count -= 1; + _task_map.erase(tid); + delete task; + return 0; +} + +bool fnTaskManager::service() +{ + if (_task_count == 0) + return true; // idle + + bool idle = true; // was service() idle? + int result; + fnTask *task; + std::list failed; + std::list completed; + + // update READY and RUNNING tasks + for (auto it = _task_map.begin(); it != _task_map.end(); ++it) + { + task = it->second; + switch (task->_state) + { + case fnTask::TASK_READY: + idle = false; + result = task->start(); + if (result < 0) + // failed to start task + failed.push_back(it->first); + else + task->_state = fnTask::TASK_RUNNING; + break; + + case fnTask::TASK_RUNNING: + idle = false; + result = task->step(); + if (result < 0) + // failure in task execution + failed.push_back(it->first); + else if (result > 0) + { + // task completed + completed.push_back(it->first); + } + break; + default: + ; + } + } + + if (!idle) + { + // handle failed tasks, if any + for (auto it = failed.begin(); it != failed.end(); ++it) + abort_task(*it); + // handle completed tasks, if any + for (auto it = completed.begin(); it != completed.end(); ++it) + complete_task(*it); + } + + return idle; +} + +#endif // !ESP_PLATFORM \ No newline at end of file diff --git a/lib/task/fnTaskManager.h b/lib/task/fnTaskManager.h new file mode 100644 index 000000000..62e5fb797 --- /dev/null +++ b/lib/task/fnTaskManager.h @@ -0,0 +1,36 @@ +#ifndef _FN_TASKMANAGER_H +#define _FN_TASKMANAGER_H + +#include +#include + +#include "fnTask.h" + + +class fnTaskManager +{ + +public: + fnTaskManager(); + ~fnTaskManager(); + int submit_task(fnTask * t); + fnTask * get_task(uint8_t tid); + int pause_task(uint8_t tid); + int resume_task(uint8_t tid); + int abort_task(uint8_t tid); + bool service(); + +private: + int complete_task(uint8_t tid); + uint8_t get_free_tid(); + void shutdown(); + + std::map _task_map; + uint8_t _next_tid; + uint8_t _task_count; +}; + +// global task manager +extern fnTaskManager taskMgr; + +#endif // _FN_TASKMANAGER_H