Embedded Software Assignment 3

Dependencies:   MCP23017 Servo WattBob_TextLCD mbed-rtos mbed

Fork of ES_Assignment_3_Pub by M L

main.cpp

Committer:
usmb192
Date:
2016-05-27
Revision:
1:15edb3b6763a
Parent:
0:6b3496e7a954

File content as of revision 1:15edb3b6763a:

/*****************************************************************************************************

                                        Assigment 3 Embedded Software
                                                Markus 
                                                 



                    This Software is a Car Control Software as no Real Car can be connected it Simulates
                    a car as well.
                    For the Display it uses an LCD Screen
                    For the Speedometer it uses an Servo
                    The Emulation and Synchronisation is implemented using TimerThreads and Semaphores
                    for the reason of existing thread limits, conventional timers are helping to slicing
                    timeslots

@version 1.4
@updateDate 30.03.2016
@author Markus

******************************************************************************************************/

#include "mbed.h"
#include "MCP23017.h"                                               // include 16-bit parallel I/O header file
#include "WattBob_TextLCD.h"                                        // include 2*16 character display header file
#include "rtos.h"
#include "Servo.h"
#include <deque>


//Unfortunately the definition doesnt work, either here or anywhere else...
//#define OS_TIMERCBQS 20 // define a new number of timers we want +1 timer!
//#define OS_TASKCNT 20 // maximum threads


MCP23017            *par_port;                                      // pointer to 16-bit parallel I/O object
WattBob_TextLCD     *lcd;                                           // pointer to 2*16 chacater LCD object
Serial              serpc(USBTX, USBRX);                            // serial usb connection tx, rx

AnalogIn AinBreak(p15);                                             // Port for the Break Value
AnalogIn AinAccel(p16);                                             // Port for the Accelerator Value

DigitalIn DinSwitchEngine(p11);                                     // Port for the Engine Switch
DigitalIn DinSwitchLight(p12);                                      // Port for the Light Switch
DigitalIn DinSwitchRindic(p13);                                     // Port for the Right Indicator
DigitalIn DinSwitchLindic(p14);                                     // Port for the Left Indicator

Servo Odometer(p26);
DigitalOut LEDSpeedWarning(p8);

DigitalOut DoutLEDLight(LED1);                                      // Output Port for LED1
DigitalOut DoutLEDLeft(LED2);                                       // Output Port for LED2
DigitalOut DoutLEDRight(LED3);                                      // Output Port for LED3
DigitalOut DoutLEDEngine(LED4);                                     // Output Port for LED4


void Timer1_void(void const *args);                                 // Timer 1
void Timer2_void(void const *args);                                 // Timer 2
void Timer3_void(void const *args);                                 // Timer 3


                                                                    // Task Functions
void task1_break_accelerate();
void task2_read_show_engine_state();
void task3_show_odometer();
void task4_speed_warning();
void task5_update_odometer();
void task6_fill_mail_queue();
void task7_dump_mail_to_serial();
void task8_read_single_side_light();
void task9_read_indicators();
void task10_calc_avg_speed();
void task11_emulate_car();


                                                                    // Init Variables
int Convert_Hz_to_Ms(double Hz);

float accerlator(0);
float speed(0);
float avgSpeed(0);
float brake(0);
float dist(0);

bool engine(0);

bool indicator_L(1);
bool indicator_R(1);

bool sw_timer1(0);
bool sw_timer11(0);
bool sw_timer2(0);
bool sw_timer21(0);
int sw_timer3(4);                                                   // sw_timer3 initalize with a first run

std::deque<float> AvgSpeedDB;                                       // used for storing the average speed

                                                        
Semaphore SemAvgSpeedDB(1);                                         // declare used Semaphores
Semaphore SemAvgSpeed(1);
Semaphore SemSpeed(1);
Semaphore SemBreak_Accelerate(1);
Semaphore SemDistance(1);
Semaphore SemEngine(1);
Semaphore SemMailCnT(1);

typedef struct {
    float    speed;
    float    accel;
    float brake;
} mail_t;

int mailcounter(0);                                                 // counts the mails in the queue
Mail<mail_t, 100> mail_box;                                         // the mail queue has a maximum size of 100 mails

int main()
{
    // 20.00 Hz = 00050 ms
    // 10.00 Hz = 00100 ms
    // 05.00 Hz = 00200 ms
    // 02.00 Hz = 00500 ms
    // 01.00 Hz = 01000 ms
    // 00.50 Hz = 02000 ms
    // 00.20 Hz = 05000 ms
    // 00.05 Hz = 20000 ms

    serpc.baud(19200);                                              // setup the bautrate
    serpc.printf("Init Software\r\n");
    par_port = new MCP23017(p9, p10, 0x40);                         // initialise 16-bit I/O chip (0x40 = 64)
    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
    lcd->locate(0,0);                                               // set cursor to location (0,0) - top left corner

    RtosTimer Timer1(Timer1_void,osTimerPeriodic,(void *)NULL);     // create the necesarry timers to overcome a thread issue (max threads)
    Timer1.start(Convert_Hz_to_Ms(20.0));

    RtosTimer Timer2(Timer2_void,osTimerPeriodic,(void *)NULL);
    Timer2.start(Convert_Hz_to_Ms(2.0));

    RtosTimer Timer3(Timer3_void,osTimerPeriodic,(void *)NULL);
    Timer3.start(Convert_Hz_to_Ms(0.2));

    Thread::wait(osWaitForever);

}

/*
##############################################################
Timer 1 runs at 20 Hz, but starts tasks at 20 Hz, 10 Hz, 5 Hz
    task11_emulate_car();
    task1_break_accelerate();
    task10_calc_avg_speed();
#############################################################
*/

void Timer1_void(void const *args)
{
    task11_emulate_car();                                           // runs every time, so at 20 Hz
    sw_timer1 = !sw_timer1;
    if(sw_timer1) {                                                 // runs just every second time, so at 10 hz
        task1_break_accelerate();
        sw_timer11 = !sw_timer11;
        if(sw_timer11) {                                            // runs just every fourth time, so at 5 hz
            task10_calc_avg_speed();
        }
    }
}


/*
##############################################################
Timer 2 runs at 2 Hz, but starts tasks at 2 Hz, 1 Hz, 0.5 Hz

    task2_read_show_engine_state();
    task5_update_odometer();
    Updates Indicators

    task3_show_odometer();
    task8_read_single_side_light();

    task4_speed_warning();
    task9_read_indicators();
#############################################################
*/
void Timer2_void(void const *args) // timer runs at 2 hz
{
    task2_read_show_engine_state();
    task5_update_odometer();
    sw_timer2 = !sw_timer2;

    if(indicator_L && indicator_R ) {                               // Sets the Left and Right Inidcators
        DoutLEDLeft=!DoutLEDRight;                                  // needs to get the inverted status of led1 before led1 is changed
        DoutLEDRight=!DoutLEDRight;
    } else if (!indicator_R && !indicator_L) {
        DoutLEDLeft=0;
        DoutLEDRight=0;
    }

    if(sw_timer2) {                                                 // runs just every second time, so at 1 hz
        task3_show_odometer();
        task8_read_single_side_light();
        sw_timer21 = !sw_timer21;

        if (!indicator_R && indicator_L) {                          // switch the left / right indicator
            DoutLEDRight=0;
            DoutLEDLeft=!DoutLEDLeft;
        } else if(indicator_R && !indicator_L) {
            DoutLEDRight=!DoutLEDRight;
            DoutLEDLeft=0;
        }


        if(sw_timer21) {                                            // runs just every second time, so at 0.5 hz
            task4_speed_warning();
            task9_read_indicators();
        }
    }

}


/*
##############################################################
Timer 3 runs at 0.2 Hz, but starts tasks at 0.2 Hz and 0.05 Hz
    task6_fill_mail_queue();
    task7_dump_mail_to_serial();
##############################################################
*/
void Timer3_void(void const *args)                                  // timer runs at 0.2 hz
{
    task6_fill_mail_queue();
    if((sw_timer3%4)==0) {                                          // task runs at 0.05 Hz
        task7_dump_mail_to_serial();                                // dump the queue to serial
        sw_timer3=0;                                                // reset the timer
    }
    sw_timer3++;
}


/*
Reads the brake / acceleration of the car
*/
void task1_break_accelerate()
{
                                                                        // Let the Semaphores wait
    SemBreak_Accelerate.wait();
    
    accerlator = AinAccel;                                              // save the accerlator value
    brake = AinBreak;                                                   // save the brake value
                                                                        // Let the Semaphores release
    SemBreak_Accelerate.release();
}


/*
Reads the Engine On/Off Switch and displays its state
*/
void task2_read_show_engine_state()
{
                                                                        // Let the Semaphores wait
    SemEngine.wait();
    
    engine = DinSwitchEngine;                                           // read the engine state
    DoutLEDEngine = engine;                                             // write the engine state
                                                                        // Let the Semaphores release
    SemEngine.release();
}


/*
Updates the Odometer (Servo Motor)
*/
void task3_show_odometer()
{
                                                                        // Let the Semaphores wait
    SemAvgSpeed.wait();                                                 
    Odometer = avgSpeed/250.0;                                          // Calculate the odometer
                                                                        // Let the Semaphores release
    SemAvgSpeed.release();
}


/*
Indicates a Speed warning at 75 Mph
*/
void task4_speed_warning()
{
                                                                        // Let the Semaphores wait
    SemAvgSpeed.wait();
    if(avgSpeed>75.0)                                                   // check our speed
        LEDSpeedWarning = !LEDSpeedWarning;                             // and switch the Warning on/off
    else
        LEDSpeedWarning = 0;
                                                                         // Let the Semaphores release
    SemAvgSpeed.release();
}


/*
Updates the LCD Display
*/
void task5_update_odometer()
{
                                                                    // Let the Semaphores wait
    SemDistance.wait();
    SemAvgSpeed.wait();

    lcd->locate(0,0);                                               // set cursor to location (0,0) - top left corner
    lcd->printf("s: %5.0f",avgSpeed);
    lcd->locate(1,0);
    lcd->printf("d: %5.0f",dist);
                                                                    // Let the Semaphores release
    SemDistance.release();
    SemAvgSpeed.release();
}



/*
Reads the Left and Right Inidcator
*/
void task6_fill_mail_queue()
{
                                                                                // Let the Semaphores wait
    SemMailCnT.wait();
    SemBreak_Accelerate.wait();
    SemSpeed.wait();

    mail_t *mail = mail_box.alloc();                                            // reserve the space for our new message
    mail->speed = speed;                                                        // fill with values
    mail->accel = accerlator;
    mail->brake = brake;
    mail_box.put(mail);                                                         // put the new message into the mail queue
    mailcounter++;

                                                                                // Let the Semaphores release
    SemBreak_Accelerate.release();
    SemSpeed.release();
    SemMailCnT.release();
}

/*
Reads the Mail Queue and Sends the Content to the Serial Port
*/
void task7_dump_mail_to_serial()
{
                                                                                // Let the Semaphores wait
    SemMailCnT.wait();

    while(mailcounter) {                                                        // as long as we got mail

        osEvent evt = mail_box.get();                                           // we are getting them
        if (evt.status == osEventMail) {
            mail_t *mail = (mail_t*)evt.value.p;                                // print the mail to serial
            serpc.printf("\nspeed: %.0f \n\r"   , mail->speed);
            serpc.printf("accerlator: %.2f\n\r"     , mail->accel);
            serpc.printf("brake: %.2f\n\r", mail->brake);
            mail_box.free(mail);                                                // clear up the mailbox
        }
        mailcounter--;
    }

                                                                                // Release the Semaphores
    SemMailCnT.release();
}

/*
Single Side Light
*/
void task8_read_single_side_light()
{
    DoutLEDLight = DinSwitchLight;                                             // Reading the value
}


/*
Reads the Left and Right Inidcator
*/
void task9_read_indicators()
{
    indicator_R = DinSwitchRindic;                                            // Reading the value
    indicator_L = DinSwitchLindic;                                            // Reading the value
}


/*
Calculates the Average Speed
*/
void task10_calc_avg_speed()
{

                                                                              // Let the Semaphores wait
    SemAvgSpeed.wait();
    SemAvgSpeedDB.wait();

    float sum(0);
    for(deque<float>::const_iterator i = AvgSpeedDB.begin(); i != AvgSpeedDB.end(); ++i)
        sum+= *i;                                                             // calculate the average by iterating over the queue
    avgSpeed = sum/AvgSpeedDB.size();

                                                                              // Release the Semaphores
    SemAvgSpeedDB.release();
    SemAvgSpeed.release();
}


/*
Emulates the car
*/
void task11_emulate_car()
{
                                                                              // Let the Semaphores wait
    SemAvgSpeed.wait();
    SemAvgSpeedDB.wait();
    SemDistance.wait();
    SemBreak_Accelerate.wait();
    SemSpeed.wait();
    SemEngine.wait();

    if(accerlator<=brake || !engine)                                        // are we braking more than accelerating? is the engine on?
        speed = 0;
    else
        speed = (accerlator-brake) *0.5 +speed;
    if(speed>250)
        speed=250;                                                           // maximum speed
    if(AvgSpeedDB.size()>=4)                                                 // if we already got 4 values, we have to
        AvgSpeedDB.pop_front();                                              // make space by deleting the oldest value
    AvgSpeedDB.push_back(speed);                                             // safe a new reading

    dist += speed * 1.0/20.0;                                                // runs at 20 Hz so we have to take this into account

                                                                             // Release the Semaphores
    SemDistance.release();
    SemAvgSpeed.release();
    SemAvgSpeedDB.release();
    SemBreak_Accelerate.release();
    SemSpeed.release();
    SemEngine.release();
}



/*
Function used for converting Hz to Ms for a Steps
*/
int Convert_Hz_to_Ms(double Hz)
{
    return 1000.0 / Hz;
}