Test session

Dependencies:   FatFileSystem MCP23017 WattBob_TextLCD mbed

Fork of Assignment_2_herpe by Xavier Herpe

task_manager.cpp

Committer:
xouf2114
Date:
2017-03-14
Revision:
4:48761259552a

File content as of revision 4:48761259552a:

/**
 * This class manages all the tasks and ensures they are correctly executed.
 * It contains various error reporting for schedule issues.
 * 
 * Currently it checks for tasks inside the called interrupt, delaying the tasks
 * execution slightly. This gets worse with an increasing number of tasks.
 * As such this should only used with a small number of tasks.
 * 
 * Author: Jacob Baungard Hansen
 */

#include "task_manager.h"

/**
 *
 * @param ticker_freq_ms        how often we should check for tasks
 */
TaskManager::TaskManager(int ticker_freq_ms) {
    this->current_time=0;
    this->ticker_freq_ms = ticker_freq_ms;
}

/**
 *
 * @param ticker_freq_ms        how often we should check for tasks
 * @param lcd                               pointer to LCDHelper object, used to display errors
 */
TaskManager::TaskManager(int ticker_freq_ms, LCDHelper * lcd) {
    this->current_time=0;
    this->ticker_freq_ms = ticker_freq_ms;
    this->lcd = lcd;
}

// empty
TaskManager::~TaskManager() {}

/**
 * Checks if any tasks needs to run, and if so run them.
 * Also checks for any scheduling conflicts, and ensures
 * the tasks execution time is not too long.
 */
void TaskManager::find_and_run(){
    // start timer
    t.start();
    
    // increase current time
    this->current_time += this->ticker_freq_ms;
    
    // if no tasks, give an error
    if (this->tasks.empty()) {
        this->schedule_error("No tasks");
        this->stop();
    }
    
    Task * task_to_run = NULL;
    // check if there's any tasks to run this timetamp
    for (unsigned int i=0; i<this->tasks.size(); i++) {
        if (this->tasks[i]->get_next_run_ms() == this->current_time) {
            if (task_to_run == NULL ) {
                task_to_run = this->tasks[i];
            } else { // if more than one task this timestamp, it is an error
                this->schedule_error("Conflict");
                this->stop();
                break;
            }
        }
    }
    
    // run the found task, if any
    if (task_to_run != NULL) {
        task_to_run->increment_next_run();
        task_to_run->action();
    } 
    
    // Ensure task didn't take too long
    // asume messuring code taskes at least 2ms.
    t.stop();
    if (t.read_ms() > (this->ticker_freq_ms)-2) {
        this->schedule_error("Task too long");
        this->stop();
    }
    // reset timer for next timeaaround
    t.reset();
    
}

/**
 * Prints a scheduling error
 * 
 * @param msg       message to print on line2 of lcd display
 */
void TaskManager::schedule_error(std::string msg) {
    if (this->lcd != NULL) {
        this->lcd->print("Schedule error:", msg);
    }
    this->stop();
}

/**
 * Adds a task to the exeuction cycle
 * 
 * @param task      pointer to the task to add
 */
void TaskManager::add_task(Task * task) {
    // we need to ensure that the frequency for the task
    // and the ticker frequency is a match
    if (task->get_frequency_ms() % this->ticker_freq_ms != 0) {
        this->schedule_error("Bad task freq");
    } 
    // first possible slot for a task to run is at ticker_freq_ms (maybe this should be changed)
    // ensure tasks do not start earlier
    else if (task->get_next_run_ms() < this->ticker_freq_ms) {
        this->schedule_error("start<tickerfreq");
    } 
    // add task 
    else {
        this->tasks.push_back(task);
    }
}

/**
 * Removes a task to the exeuction cycle
 * 
 * @param task      pointer to the task to remove
 */
void TaskManager::remove_task(Task * task) {
    for (unsigned int i=0; i<this->tasks.size(); i++) {
        if (this->tasks[i] == task) {
            this->tasks.erase(this->tasks.begin()+i);
            break;
        }
    }
}

/** 
 * Starts running
 */
void TaskManager::start() {
    timestamp_t in_us = this->ticker_freq_ms*1000.0;
    // need to change priority in case of using
    // interupts in the activities.
    // a bit nasty
    NVIC_SetPriority(TIMER3_IRQn, 200);
    this->ticker.attach_us<TaskManager>(this, &TaskManager::find_and_run, in_us);
    
    while(1) {} 
}

/**
 * Stops running
 */
void TaskManager::stop() {
    this->ticker.detach();
    // might not want this in a general case (not sure)
    // although for this case it seems appropiate. 
    while(1) {}
}