Test session

Dependencies:   FatFileSystem MCP23017 WattBob_TextLCD mbed

Fork of Assignment_2_herpe by Xavier Herpe

Files at this revision

API Documentation at this revision

Comitter:
xouf2114
Date:
Tue Mar 14 14:46:43 2017 +0000
Parent:
3:5883d1a2c5b0
Commit message:
Test of Assignment 2

Changed in this revision

XG_2.cpp Show annotated file Show diff for this revision Revisions of this file
check_task.cpp Show annotated file Show diff for this revision Revisions of this file
counting_task.cpp Show annotated file Show diff for this revision Revisions of this file
freq_task.cpp Show annotated file Show diff for this revision Revisions of this file
lcd_helper.cpp Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
sdcard.cpp Show annotated file Show diff for this revision Revisions of this file
state.cpp Show annotated file Show diff for this revision Revisions of this file
task.cpp Show annotated file Show diff for this revision Revisions of this file
task_manager.cpp Show annotated file Show diff for this revision Revisions of this file
update_analog_task.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/XG_2.cpp	Tue Mar 07 17:20:46 2017 +0000
+++ b/XG_2.cpp	Tue Mar 14 14:46:43 2017 +0000
@@ -31,7 +31,7 @@
 PwmOut servo(p21); // Servo output
 DigitalOut TestPin(p20); // Pin only used to test program and measure time
 SDFileSystem sd(p5, p6, p7, p8, "sd"); // The pinout on the mbed Cool Components workshop board
-
+DigitalIn  switch_pin(p14, PullDown);
 
 //=====================================================================================
 // Internal objects declaration
@@ -47,7 +47,6 @@
 //=====================================================================================
 const int SampFreq = 100; // Sampling frequency is 10kHz (100us)
 
-
 //=====================================================================================
 // Variables declaration
 //=====================================================================================
@@ -196,38 +195,17 @@
 // Tasks
 //=====================================================================================
 
-// Task 1: Measure TTL input frequency
+// Task 1: Measure the freqeuncy of a 3.3v square wave signal
 void Task1()
 {
+task 1
+
     timer.reset();
-    
-    // If the input signal is low, wait for a rising edge to start counting
-    if (TTL == 0)
-    {
-        WaitRisEdge(); // Call subroutine to wait for rising edge
-        timer.start(); // Start timer
-        while(TTL == 1) // Keep counting as long as signal is high
-        {
-            wait_us(SampFreq);
-        }
-    }
-    
-    // If the input signal is high, wait for a falling edge to start counting
-    else if (TTL == 1)
-    {
-        WaitFalEdge(); // Call subroutine to wait for falling edge
-        timer.start(); // Start timer
-        while(TTL == 0) // Keep counting as long as signal is high
-        {
-            wait_us(SampFreq);
-        }
-    }
-
-    timer.stop(); // Stop counting when signal changes
-    period = timer.read_us()*2; // Convert the time into a period
-    frequency = 1000000/period; // Convert the period into a frequency
-}
-
+    while(freqCountPin == 0) {}
+    timer.start();      
+    while(freqCountPin == 1) {}
+    timer.stop();
+    frequency =  2000000 / timer.read_us()
 
 
 // Task 2: display the measured frequency on LCD screen
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/check_task.cpp	Tue Mar 14 14:46:43 2017 +0000
@@ -0,0 +1,73 @@
+/**
+ * The following task checks the digital inputs on pin11 and pin12
+ * it also checks for "errors" and save the error code to the state.
+ * If pin12 is 1, it schedules the counting task.
+ *
+ * Author: Jacob Baungard Hansen
+ */
+
+#include "check_task.h"
+
+/**
+ *
+ * @param starting_offset       when the task should but run first
+ * @param frequency_ms          the frequency in ms of how often the task should run
+ */
+CheckTask::CheckTask(int starting_offset, int frequency_ms,
+                                                                     State * state, TaskManager * tm)
+                                    : Task(starting_offset, frequency_ms) {
+                                        
+    this->state = state;
+    this->tm = tm;
+    this->counting_task = new CountingTask(0, 1800);
+    this->counting_scheduled = 0;
+    this->digital_in_1 = new DigitalIn(p11);
+    this->digital_in_2 = new DigitalIn(p12);
+    
+}
+
+/*
+ * Simple destructor
+ */
+CheckTask::~CheckTask() {
+    delete this->counting_task;
+    delete this->digital_in_1;
+    delete this->digital_in_2;
+}
+
+/** 
+ * The function that is run at the specified frequency.
+ */
+void CheckTask::action() {
+    
+    // get the digital values
+    int switch_1 = digital_in_1->read();
+    int switch_2 = digital_in_2->read();
+    
+    // save to the state
+    this->state->set_digital_1(switch_1);
+    this->state->set_digital_2(switch_2);
+
+    // check possible error codes
+    if (switch_1 == 1 && (this->state->get_avg_analog_1() > this->state->get_avg_analog_2() ) ) {
+        this->state->set_error(3);
+    } else {
+        this->state->set_error(0);
+    }
+    
+    // schedule or deschedule counting task as appropriate
+    if (switch_2 == 1 && this->counting_scheduled == 0) {
+        // schedule binary LED task
+        this->counting_scheduled = 1;
+        // set the binary LED task next run
+        int next_run = this->get_next_run_ms()+300;
+        this->counting_task->set_next_run_ms(next_run);
+        // add task to task manager
+        this->tm->add_task(this->counting_task);
+    } else if (switch_2 == 0) {
+        // delete task from task manager
+        this->tm->remove_task(this->counting_task);
+        this->counting_scheduled = 0;
+    }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/counting_task.cpp	Tue Mar 14 14:46:43 2017 +0000
@@ -0,0 +1,51 @@
+/**
+ * This task do a binary count on the 4 mbed LEDs
+ *
+ * Author: Jacob Baungard Hansen
+ */
+
+#include "counting_task.h"
+
+/**
+ *
+ * @param starting_offset       when the task should but run first
+ * @param frequency_ms          the frequency in ms of how often the task should run
+ */
+CountingTask::CountingTask(int starting_offset, int frequency_ms)
+                                    : Task(starting_offset, frequency_ms) {
+                                        
+  this->count = 0;
+
+    this->led1 = new DigitalOut(LED1);
+    this->led2 = new DigitalOut(LED2);
+    this->led3 = new DigitalOut(LED3);
+    this->led4 = new DigitalOut(LED4);
+    
+
+}
+
+CountingTask::~CountingTask() {
+    delete this->led1;
+    delete this->led2;
+    delete this->led3;
+    delete this->led4;
+}
+
+/** 
+ * The function that is run at the specified frequency.
+ */
+void CountingTask::action() {
+
+  // simple way to get the bits
+    std::bitset<4> bits(this->count);
+    
+    // set the result
+    this->led1->write(bits[3]);
+    this->led2->write(bits[2]);
+    this->led3->write(bits[1]);
+    this->led4->write(bits[0]);
+    
+    // don't overflow
+    this->count = (this->count+1) % 16;
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/freq_task.cpp	Tue Mar 14 14:46:43 2017 +0000
@@ -0,0 +1,47 @@
+/**
+ * Task for getting the frequency from digital input on pin13. 
+ * The frequency is calculated by counting the number of rises
+ * on the pin. This is done using an interupt handler.
+ *
+ * Author: Jacob Baungard Hansen
+ */
+#include "freq_task.h"
+
+FrequencyTask::FrequencyTask(int starting_offset, int frequency_ms,
+                                                                     State * state)
+                                    : Task(starting_offset, frequency_ms) {
+                                        
+    this->state = state;
+    this->count = 0;
+    this->interrupt = new InterruptIn(p13); 
+
+}
+
+FrequencyTask::~FrequencyTask() {
+    delete this->interrupt;
+}
+
+/**
+ * This is called by the interupt, simply adds one to the count
+ */
+void FrequencyTask::counter() {
+    this->count++;
+}
+
+void FrequencyTask::action() {
+    // reset the count
+    this->count=0;
+    // Enable the iterrupt
+    this->interrupt->rise<FrequencyTask>(this, &FrequencyTask::counter);
+    // wait for a specied amout of time
+    wait_ms(SAMPLE_LENGTH_MS);
+    // disable interrupts
+    this->interrupt->rise(NULL);
+    //interupt.rise<FrequencyTask>(this, NULL); This crashes, should report bug to ARM
+    int freq = 0;
+    if (this->count > 0) {
+        freq = count/(SAMPLE_LENGTH_MS*0.001);
+    }
+    
+    this->state->set_freq(freq);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lcd_helper.cpp	Tue Mar 14 14:46:43 2017 +0000
@@ -0,0 +1,85 @@
+/**
+ * Mostly just a wrapper around the LCD display.
+ *
+ * Author: Jacob Baungard Hansen
+ */
+
+#include "lcd_helper.h"
+
+/**
+ * Constructor setups the LCD Display
+ * and writes initial values needed for this project.
+ */
+LCDHelper::LCDHelper() {
+
+  this->par_port = new MCP23017(p9, p10, 0x40); // initialise 16-bit I/O chip
+  this->lcd = new WattBob_TextLCD(par_port); // initialise 2*26 char display 
+  par_port->write_bit(1,BL_BIT); // turn LCD backlight ON 
+  
+    lcd->cls(); // clear display
+    
+    this->print("Fr     d1   d2  ", "a1   a2   e  ");
+
+}
+
+LCDHelper::~LCDHelper() {
+    delete this->par_port;
+    delete this->lcd;
+}
+
+/**
+ * Clears the display and prints one line
+ */
+void LCDHelper::print(std::string line1) {
+    this->print(line1, std::string());
+}
+
+/**
+ * Clears the display and prints two lines
+ */
+void LCDHelper::print(std::string line1, std::string line2) {
+    lcd->cls(); // clear display
+    
+  lcd->locate(0,0); // set cursor to location (0,0) - top left corner
+  lcd->printf(line1.c_str()); 
+    
+    // only print line2 if it contains data
+    if (!line2.empty()) {
+    lcd->locate(1,0); // set cursor to location (1,0) - bottom left corner
+    lcd->printf(line2.c_str()); 
+    }
+}
+
+void LCDHelper::clear() {
+    lcd->cls(); // clear display
+}
+
+/**
+ *
+ *
+ * @Param   state       pointer to state object
+ */
+void LCDHelper::print_state(State * state) {
+    lcd->locate(0,3);
+    lcd->printf("%d", state->get_freq());
+    
+    lcd->locate(0,10);
+    lcd->printf("%d", state->get_digital_1());
+    
+    lcd->locate(0,15);
+    lcd->printf("%d", state->get_digital_2());
+    
+    lcd->locate(1,3);
+    // printf is very slow at converting from float to int
+    int avg_analog_1 = (int) floor( state->get_avg_analog_1() + 0.5);
+    lcd->printf("%d", avg_analog_1);
+        
+    lcd->locate(1,8);
+    // printf is very slow at converting from float to int
+    int avg_analog_2 = (int) floor( state->get_avg_analog_2() + 0.5);
+  lcd->printf("%d", avg_analog_2);
+    
+    lcd->locate(1,12);
+    lcd->printf("%d", state->get_error() );
+    
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Mar 14 14:46:43 2017 +0000
@@ -0,0 +1,66 @@
+/**
+ * Main class for the project.
+ * The main class instantiates all the tasks and schedules them
+ * correctly using the TaskManager object.
+ *
+ * As writing to the SDCard occasionally hits +50ms in timing, there was several issue
+ * with the schedule purposed in the original assignment. As a result the timings have changed.
+ * 
+ * Action 2 (reading digital values) have been discarded. The values are only used
+ * in the Action 5, as a result we might as well read them "Just In Time". 
+ * However if desired it could have been scheduled starting at 600ms with a freqency of 600ms
+ * 
+ * The schedule is as follows:
+ * Action 1 (frequency)           1200ms
+ * Action 2 (get digital input)   disabled, see above
+ * Action 3 (read analog in)      600ms
+ * Action 4 (Print to LCD)        1200ms
+ * Action 5 (checks)              600ms
+ * Action 5.1 (binary counting)   1800ms
+ * Action 6 (SDCard)              4800ms
+ *
+ * Author: Jacob Baungard Hansen
+ */
+
+#include "task.h"
+#include "lcd_helper.h"
+#include "demo_task.h"
+#include "task_manager.h"
+#include "state.h"
+#include "lcd_task.h"
+#include "update_analog_task.h"
+#include "check_task.h"
+#include "freq_task.h"
+#include "SDFileSystem.h"
+#include "sdcard_task.h"
+
+int main() {
+
+    LCDHelper * lcd_helper = new LCDHelper();
+    
+    State * state = new State(); 
+    
+    TaskManager * tm = new TaskManager(100, lcd_helper);
+    
+    UpdateAnalogTask * analog_task  = new UpdateAnalogTask(100, 600, state);
+    CheckTask * check_task = new CheckTask(200, 600, state, tm);
+    FrequencyTask * freq_task = new FrequencyTask(300, 1200, state);
+    LCDTask * lcd_task = new LCDTask(400, 2400, lcd_helper, state);
+    SDCardTask * sd_task = new SDCardTask(4800, 4800, state);
+    
+    tm->add_task(check_task);
+    tm->add_task(analog_task);
+    tm->add_task(lcd_task);
+    tm->add_task(freq_task);
+    tm->add_task(sd_task);
+    
+    tm->start();
+    
+    delete lcd_helper;
+    delete lcd_task;
+    delete analog_task;
+    delete freq_task;
+    delete sd_task;
+    delete tm;  
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sdcard.cpp	Tue Mar 14 14:46:43 2017 +0000
@@ -0,0 +1,66 @@
+/**
+ * Task that logs the state to a file on the SD card in csv format
+ *
+ * Author: Jacob Baungard Hansen
+ */
+
+#include "sdcard_task.h"
+
+/**
+ *
+ * @param starting_offset       when the task should but run first
+ * @param frequency_ms              the frequency in ms of how often the task should run
+* @param state                          pointer to the state object to print
+ */
+SDCardTask::SDCardTask(int starting_offset, int frequency_ms,
+                                                                     State * state)
+                                    : Task(starting_offset, frequency_ms) {
+                                        
+    this->state = state;
+    // mount the file system
+    this->sd = new SDFileSystem(p5, p6, p7, p8, "sd");
+    
+    // set the folder
+    this->folder = "/sd/embedded";
+    
+    // ensure folder exists
+    struct stat s = {0};
+
+    if (!stat(folder.c_str(), &s)) { }
+    else {
+      mkdir(folder.c_str(), 0777); 
+    }
+    
+    // set file to log to
+    this->file.append(folder);
+    file.append("/data.csv");
+    
+    // clear previous data and set headers
+    FILE *fp = fopen(file.c_str(), "w");
+    if(fp == NULL) {
+      error("Could not open file for write\n");
+    }
+    fprintf(fp, "frequency,digital1,digital2,analog1,analog2\n");
+    fclose(fp);
+
+}
+
+SDCardTask::~SDCardTask() {
+    delete this->sd;
+}
+
+void SDCardTask::action() {
+    
+    // ensure file can be opened
+    FILE *fp = fopen(file.c_str(), "a");
+    if(fp == NULL) {
+      error("Could not open file for write\n");
+    }
+    // print current state
+    fprintf(fp, "%d,%d,%d,%f,%f\n", this->state->get_freq(), this->state->get_digital_1(), 
+                                                                this->state->get_digital_2(), this->state->get_avg_analog_1(),
+                                                                this->state->get_avg_analog_2());
+    fclose(fp); 
+    
+    
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/task.cpp	Tue Mar 14 14:46:43 2017 +0000
@@ -0,0 +1,17 @@
+
+/**
+ * Base objects for all tasks to be executed by the TaskManager
+ *
+ * Author: Jacob Baungard Hansen
+ */
+
+#include "task.h"
+
+/**
+ * @param starting_offset           when the task should be run first
+ * @param frequency_ms              the frequency in ms of how often the task should run
+ */
+Task::Task(int starting_offset, int frequency_ms) {
+    this->next_run_ms=starting_offset;
+    this->frequency_ms = frequency_ms;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/task_manager.cpp	Tue Mar 14 14:46:43 2017 +0000
@@ -0,0 +1,157 @@
+/**
+ * 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) {}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/update_analog_task.cpp	Tue Mar 14 14:46:43 2017 +0000
@@ -0,0 +1,25 @@
+#include "update_analog_task.h"
+
+/**
+ *
+ * @param starting_offset           when the task should but run first
+ * @param frequency_ms              the frequency in ms of how often the task should run
+ * @param state                             pointer to the state object
+ */
+UpdateAnalogTask::UpdateAnalogTask(int starting_offset, int frequency_ms,
+                                                                     State * state)
+                                    : Task(starting_offset, frequency_ms) {
+                                        
+    this->state = state;
+    this->analog_in_1 = new AnalogIn(p17);
+    this->analog_in_2 = new AnalogIn(p18);
+}
+
+UpdateAnalogTask::~UpdateAnalogTask() {
+    delete this->analog_in_1;
+    delete this->analog_in_2;
+}
+
+void UpdateAnalogTask::action() {
+    this->state->update_analog(this->analog_in_1->read(), this->analog_in_2->read());
+}
\ No newline at end of file