A simple microwave demo

Dependencies:   C12832_lcd LM75B mbed-rtos mbed

rtos_hwk7.cpp

Committer:
joeroop
Date:
2014-03-15
Revision:
1:896789dcc911
Parent:
0:3a19dcea1a01
Child:
2:324dc8b89365

File content as of revision 1:896789dcc911:




#include "mbed.h"
#include "rtos.h"
#include "C12832_lcd.h" //LCD interface
#include "LM75B.h"      //temperature interface


#define DEBOUNCE_TIME_MS    10
#define MAX_COOK_TIME_S     180 //3min
#define INIT_COOK_TIME_S    5 


//globals and types
DigitalOut  led1(LED1);
DigitalOut  led2(LED2);
DigitalOut  led3(LED3);
DigitalOut  led4(LED4);
C12832_LCD  lcd;
Timer       debounceTimer;
InterruptIn irptTimeDn(p16);    //cook down
InterruptIn irptTimeUp(p13);    //cook up
InterruptIn irptStart(p15);    //start cooking
InterruptIn irptStop(p12);   //stop cooking
InterruptIn irptDoor(p14);   //door interrupt
Thread      *proxy_lcd;
Thread      *proxy_temp;
Thread      *proxy_sound;
Thread      *proxy_state;
Thread      *proxy_led;
Thread      *proxy_timer;
Thread      *proxies[] = {
                proxy_lcd,
                proxy_temp,
                proxy_sound,
                proxy_state,
                proxy_led,
                proxy_timer,
            };
int PROXIES_SIZE = sizeof(proxies)/sizeof(Thread*);


typedef enum { //start at one as we are using this as signals
    //states
    WAITING = 1, 
    COOKING, 
    DONE, 
    //interrupts signals
    TIMEUP, 
    TIMEDN, 
    START, 
    STOP,
    DOOR
} state_t; 

char *stateStr[] = {"NULL","WAIT","COOK","DONE"};


typedef enum {TEMP_VAL, TIME_ELPS, TIME_RQST} type_t;
typedef enum {STATE, TEMP, SOUND, LCD, LED, TIMER, ALL} thread_t; 
char *threadStr[] = {"STATE", "TEMP", "SOUND", "LCD", "LED", "TIMER", "ALL"};

typedef struct {
    state_t state;
    type_t type;
    union {
        float temp;
        int time_elapsed; //seconds of cooking
        int time_request; //seconds
    } value;   
} data_t;




MemoryPool<data_t,10> mpool; //used to hold all messages
Queue<data_t,10> queue; //used to hold the messages

bool debounce(void);
void blink_led(void const *args);
void send_time(const void *args);
//void send_state(const void *args);

void send_state(state_t state, thread_t pthr);
//Threads
void thread_state(void const *args);
void thread_lcd(void const *args);
void thread_temp(void const *args);
void thread_sound(void const *args);
void thread_led(void const *args);
void thread_timer(void const *args);



//ISRs
void isrTimeUp(void);
void isrTimeDn(void);
void isrStart(void);
void isrStop(void);
void isrDoor(void);



int main(void){
    debounceTimer.start();
    //interrupts
    irptTimeUp.rise(&isrTimeUp);
    irptTimeDn.rise(&isrTimeDn);
    irptStart.rise(&isrStart);
    irptStop.rise(&isrStop);
    irptDoor.rise(&isrDoor); //debounce everything except for the door

    Thread t1(thread_state);    
    Thread t2(thread_temp);
    Thread t3(thread_sound);
    Thread t4(thread_lcd);
    Thread t5(thread_led);
    Thread t6(thread_timer);

    proxy_state =   &t1;
    proxy_temp =    &t2;
    proxy_sound =   &t3;
    proxy_lcd =     &t4;
    proxy_led =     &t5;
    proxy_timer =   &t6;
    

    
    t4.set_priority(osPriorityRealtime);
    
    while(1){
        Thread::wait(250);   
    }   
}

//function for a global debounce on the isrstick
bool debounce(void){
    if(debounceTimer.read_ms() > DEBOUNCE_TIME_MS){
        debounceTimer.reset();
        return true;
    }else{
        return false;   
    }
}
//ISRs
void isrTimeUp(void){
    if(debounce()){
        proxy_state->signal_set(TIMEUP); //left
    }
}
void isrTimeDn(void){
     if(debounce()){
        proxy_state->signal_set(TIMEDN); //right
    }
}
void isrStart(void){
    if(debounce()){
        proxy_state->signal_set(START); //up
    }
}
void isrStop(void){
    if(debounce()){
        proxy_state->signal_set(STOP); //down
    }
}
void isrDoor(void){
    //no debounce this is most important function!
    proxy_state->signal_set(DOOR);
}

//Threads
void thread_lcd(void const *args){
    osEvent evt;
    int32_t sig;
    state_t state;
    while(1){
        evt = Thread::signal_wait(0);
        sig = evt.value.signals;
        switch(sig){
            case WAITING:
                state = WAITING;
                break;
            case COOKING:
                state = COOKING;
                break;
            case DONE:
                state = DONE;
                break;
             
        }
        //print the state
        lcd.locate(70,0);
        lcd.printf("State: %s ",stateStr[state]);
        //call the queue
    }
}
void thread_temp(void const *args){
    while(1){
        Thread::wait(100);
    }
}
void thread_sound(void const *args){
    while(1){
        Thread::wait(100);
    }
}
//helper function to send all the threads the current state except for thread* passed in
void send_state(state_t state, thread_t pthr){
    short i;
    for(i=0; i<PROXIES_SIZE;i++){
        if(i != pthr){ //if you don't match the Thread* then send a signal to that thread
            proxies[pthr]->signal_set(state);
        }else{
            lcd.locate(0,20);
            lcd.printf("send: %s, %s",stateStr[state],threadStr[i]);
        }
    }
}
//State thread to do most of the main state machine logic
void thread_state(void const *args){
    osEvent evt;
    int32_t mask;
    bool openDoor = false; //start with door closed
    state_t state = WAITING; //WAITING, COOKING, DONE
    while(1){
        evt = Thread::signal_wait(0);
        mask = evt.value.signals;
        switch(mask){
            case WAITING:
                state = WAITING;
                //send_state((void*)WAITING); //send state to all threads
                send_state(state,STATE);
                break;
            case COOKING:
                state = COOKING;
                send_state(state,STATE);
                break;
            case DONE: //timer can signal this
                state = WAITING;
                send_state(state,STATE);
                //send signal to timer, led and pwm
                break;
            case TIMEUP: //change the timer up
                if(state == WAITING) proxy_timer->signal_set(TIMEUP); 
                break;
            case TIMEDN: //change the timer down
                if(state == WAITING) proxy_timer->signal_set(TIMEDN);
                break;
            case START:
                if(state == WAITING) proxy_state->signal_set(COOKING);
                break;
            case STOP:
                if(state == COOKING) proxy_state->signal_set(DONE);
                break;
            case DOOR: //door changed state
                openDoor = !openDoor;
                state = (openDoor == true) ? DONE : WAITING; //open door then done else state back to waiting 
                led1 = led2 = led3 =led4 = openDoor;
                send_state(state,ALL); //signal back to state thread
                //proxy_lcd->signal_set(openDoor);
                break;
        }
    }
}
//helper function to thread_led used to blink led
void blink_led(void const *args){
    led1 = !led1;   
}
//Thread led to blink the light when cooking and stop when done
void thread_led(void const *args){
    RtosTimer timer(blink_led, osTimerPeriodic);
    osEvent evt;
    int32_t sig;
    while(1){
        //may need to sleep somewhere to give up thread check to see if signal_wait equiv of wait
        evt = Thread::signal_wait(0); //will time out then loop not needed
        sig = evt.value.signals;
        switch(sig){
            case COOKING:
                timer.start(250);
                break;
            case DONE:
                timer.stop();
                led1 = 0;
                break;
            default:
                //Thread::wait(2000); if wait can miss signal
                break;   
        }
    }    
}
//helper function for the timer thread
void send_time(const void *args){
    int time = (*((int*)args))--; //have the time in seconds send to lcd now
    //lcd.locate(0,10);
    //lcd.printf("ELPS %d",time);
    if(time == 0) send_state(DONE,TIMER); //tell all threads cooking time up
}
void thread_timer(void const *args){
    int time;
    int *ptime = &time;
    RtosTimer timer(send_time, osTimerPeriodic,(void*)ptime);
    osEvent evt;
    int32_t sig;
    state_t state;
    while(1){
        evt = Thread::signal_wait(0); //will time out then loop not needed
        sig = evt.value.signals;
        switch(sig){
            case WAITING:
                state = WAITING;
                break;
            case COOKING:
                state = COOKING;
                timer.start(1000); //this is the increments of the timer 1s
                break;
            case DONE:
                state = DONE;
                time = INIT_COOK_TIME_S;
                 //default time
                //send request time to lcd queue reset
                //lcd.locate(0,0);
                //lcd.printf("RQST %d",time);
                timer.stop();
                break;
            case TIMEUP:
                if(state == WAITING){
                    time = (++time) > MAX_COOK_TIME_S ? MAX_COOK_TIME_S : time; //check limits 
                    //send request time to lcd queue
                    //lcd.locate(0,0);
                    //lcd.printf("RQST %d",time);
                }
                break;
            case TIMEDN:
                if(state == WAITING){
                    time = (--time) < 0 ? 0 : time; //check limits  
                    //send request time to lcd
                    //lcd.locate(0,0);
                    //lcd.printf("RQST %d",time);
                }
                break;
            default:
                //Thread::wait(2000); if wait can miss signal
                break;   
        }
    }
}