A simple microwave demo

Dependencies:   C12832_lcd LM75B mbed-rtos mbed

rtos_hwk7.cpp

Committer:
joeroop
Date:
2014-03-16
Revision:
2:324dc8b89365
Parent:
1:896789dcc911
Child:
3:4fb0721ce794

File content as of revision 2:324dc8b89365:




#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     20 //3min
#define INIT_COOK_TIME_S    5 
#define TEMP_INTERVAL_S     5


//globals and types
DigitalOut  led1(LED1);
DigitalOut  led2(LED2);
DigitalOut  led3(LED3);
DigitalOut  led4(LED4);
C12832_LCD  lcd;
PwmOut      spkr(p26);
LM75B       therm(p28,p27);
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;


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
    } data;   
} message_t;




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

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

//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;
    

    
    t1.set_priority(osPriorityRealtime);
    proxy_state->signal_set(WAITING); //initialize all the threads
    
    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);
}

//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;
                proxy_led->signal_set(state);
                proxy_timer->signal_set(state);
                proxy_temp->signal_set(state);
                break;
            case COOKING:
                if(!openDoor){ //can't cook if door is open
                    state = COOKING;
                    proxy_led->signal_set(state);
                    proxy_timer->signal_set(state);
                    proxy_temp->signal_set(state);
                }
                break;
            case DONE: //timer can signal this
                state = DONE;
                //tell everyone we are done
                proxy_led->signal_set(state);
                proxy_timer->signal_set(state);
                proxy_temp->signal_set(state);
                
                proxy_state->signal_set(WAITING); //goto waiting
                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){
                    state = COOKING;
                    proxy_state->signal_set(state);
                }
                break;
            case STOP:
                if(state == COOKING){
                    state = DONE;
                    proxy_state->signal_set(state);
                }
                break;
            case DOOR: //door changed state
                openDoor = !openDoor;
                state = (openDoor == true) ? DONE : WAITING; //open door then done else state back to waiting 
                led4 = openDoor;
                proxy_state->signal_set(state); //signal back to state thread
                break;
        }
    }
}
//helper function for the timer thread
void send_time(void const *args){
    int time = (*((int*)args))--; //have the time in seconds send to lcd now
    state_t state = COOKING;
    if(time == 0){
        state = DONE;
        proxy_state->signal_set(state); //tell all threads cooking time up
        proxy_sound->signal_set(state);
    }
    proxy_temp->signal_set(state); //use this timer to schedule temperature read
    
    message_t *msg = mpool.alloc(); //allocate a new message
    msg->state = state;
    msg->type = TIME_ELPS;
    msg->data.time_elapsed = time;
    queue.put(msg);
}

void thread_timer(void const *args){
    int time_set, time;
    time_set = INIT_COOK_TIME_S;
    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:
                if(state != COOKING){ //protect agains multiple start pushed if already cooking
                    timer.stop();
                    state = COOKING;
                    time = time_set;
                    timer.start(1000); //this is the increments of the timer 1s
                }
                break;
            case DONE:
                if(state != DONE){
                    state = DONE;
                    time = INIT_COOK_TIME_S;
                    timer.stop();
                }
                break;
            case TIMEUP:
                if(state == WAITING){
                    time_set = (++time_set) > MAX_COOK_TIME_S ? MAX_COOK_TIME_S : time_set; //check limits 
                }
                break;
            case TIMEDN:
                if(state == WAITING)
                    time_set = (--time_set) < 1 ? 1 : time_set; //check limits  
                break;
        }
        if(sig){
            message_t *msg = mpool.alloc(); //allocate a new message
            msg->state = state;
            msg->type = TIME_RQST;
            msg->data.time_request = time_set;
            queue.put(msg);
        }
    }
}
//Threads
void thread_lcd(void const *args){
    osEvent evt;
    int32_t sig;
    state_t state;
    int time_set = 0;
    lcd.cls();
    while(1){
        evt = queue.get(10); //wait for data message to post
        if(evt.status == osEventMessage){
            message_t *msg = (message_t*)evt.value.p;
            lcd.locate(70,0);
            if(msg->state)
                lcd.printf("State: %s ",stateStr[msg->state]);
            switch(msg->type){
                case TIME_RQST:
                    time_set = msg->data.time_request;
                    lcd.locate(0,0);
                    lcd.printf("Request: %3d ",time_set);
                    break; 
                case TIME_ELPS:
                    lcd.locate(0,10);
                    lcd.printf("Elapsed: %3d ",time_set - msg->data.time_elapsed);
                    break; 
                case TEMP_VAL:
                    lcd.locate(0,20);
                    lcd.printf("Temp: %-3.2f  ",msg->data.temp);
                    break;                
            }
            mpool.free(msg);
        }
    }
}

void thread_temp(void const *args){
    osEvent evt;
    int32_t sig;
    int seconds = -1;
    float temp = 0.0;
    while(1){
        evt = Thread::signal_wait(0);
        sig = evt.value.signals;
        switch(sig){
            case COOKING:
                if(!(seconds++ % TEMP_INTERVAL_S)){
                    temp+= 10.0;
                }else{
                    sig = 0x0; //set to zero so don't print since no changes
                }
                break;
            case WAITING:
            case DONE:
                seconds = -1;
                temp = 0.0;
                break;
        }
        if(sig){
            message_t *msg = mpool.alloc(); //allocate a new message
            msg->state = (state_t)0; //don't pass a value
            msg->type = TEMP_VAL;
            msg->data.temp = seconds > 0 ? temp+9.0/5.0*therm.read()+32.0 : 0.0;
            queue.put(msg);
        }
    }
}
void thread_sound(void const *args){
    osEvent evt;
    int32_t sig;
    while(1){
        evt = Thread::signal_wait(0);
        sig = evt.value.signals;
        switch(sig){
            case DONE:
                spkr.period(1.0/5000);
                spkr=0.5;
                Thread::wait(1000);
                spkr=0.0;
                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;   
        }
    }    
}