homework 7

Dependencies:   mbed-rtos mbed C12832_lcd LM75B

main.cpp

Committer:
gatedClock
Date:
2013-09-12
Revision:
108:da479434bd7d
Parent:
107:7de171a8464e
Child:
109:2fa55ab6e178

File content as of revision 108:da479434bd7d:

/*----------------------------------------------//------------------------------
    student   : m-moore
    class     : rtos
    directory : RTOS_HW_07
    file      : main.cpp
----description---------------------------------//------------------------------
    gotchyas
    1. using pc.printf inside a ticker routine will freeze the routine.
    2. using queues (get, put) will not work within a ticker routine.
    3. Ticker has a bug.  http://mbed.org/questions/1563/Mbed-Tickerfunction-hangs-system-from-re/
    
    improvements
    countdown timer needs to be sync'd to start button press.
    this could not be done, use granularity setting instead.
    
    
-----includes-----------------------------------//----------------------------*/
    #include "mbed.h"                           // mbed class.
    #include "rtos.h"                           // rtos class.
    #include "LM75B.h"                          // thermometer class.
    #include "C12832_lcd.h"                     // LCD  class.
//---defines------------------------------------//------------------------------
    #define LCD1 lcd.locate(0, 0);              // LCD line 1.
    #define LCD2 lcd.locate(0,11);              // LCD line 2.
    #define LCD3 lcd.locate(0,22);              // LCD line 3.
       

    #define DEBOUNCEmS       16                 // debounce wait in mS.
    #define uS_TIMEOUT      100                 // Timer uS timeout.
    #define LBSIG             1                 // left button signal code.
    #define PIPEuS         1000                 // pipeline clock period.
    #define SLOWCLOCKuS  500000                 // slow-clock period.
    #define TEMPCLOCKS        1                 // temperature-measuring period in S.
    #define PIPEDATASIZE      8                 // dimension of tPipeData.
    #define THREAD_1_WAITmS 400                 // thread 1 wait in mS.
    #define THREAD_2_WAITmS  40                 // LCD thread wait.
    #define THREAD_3_WAITmS  80                 // thread 3 wait in mS.
    #define THREAD_4_WAITmS   1                 // thread 4 wait in mS.
    #define THREAD_5_WAITmS   100                 // FSM thread wait.
    #define HB_MODULO      1024                 // heartbeat modulo divisor.
    
    #define MSG_INC_TIME   0x01
    #define MSG_DEC_TIME   0x02
    #define MSG_START      0x04
    #define MSG_STOP       0x08
    #define MSG_OPEN       0x10
    #define MSG_CLOSED     0x20
    
    #define FSM_IDLE       0x01                 // cook-state state-machine.
    #define FSM_COOK       0x02                 // cook-state state-machine.
    #define FSM_PAUSE      0x04                 // cook-state state-machine.
    #define FSM_CONTINUE   0x08                 // cook-state state-machine.
    #define FSM_DONE       0x10                 // cook-state state-machine.
    
    #define RT_PRELOAD     0x01                 // remaining-time preload.
    #define RT_DECREMENT   0x02                 // remaining-time decrement.
    #define RT_PAUSE       0x03                 // remaining-time don't change.
    #define RT_CLEAR       0x04                 // remaining-time set to zero.
    
    #define TEMP_READ      0x01                 // temperature synthesizer control.
    #define TEMP_CALC      0x02                 // temperature synthesizer control.
    #define TEMP_FREEZE    0x03                 // temperature synthesizer control.
    
    #define GRANULARITY    0x400                // 1-second countdown ticker granularity.
    #define MAXSECONDS       180                // maximum microwave-on time.
    #define BEEPTIME           3                // beep duration in S.
    #define BEEPFREQ         300                // beep frequency in Hz.
    
    #define TIMEINC           10                // time increment in seconds.
//--global_definitions--------------------------//------------------------------
    struct tButtons                             // button ISR updates.
    {
      char cLeftButton;                         // cooktime +60S.
      char cRightButton;                        // cooktime -60S.
      char cTopButton;                          // start cook.
      char cBottomButton;                       // stop cook.
      char cCenterButton;                       // center button pressed.
      char cDoorOpen;                           // door open. 
    };
    
    struct tRemainingTime                       // remaining time related.
    {
      char cControl;                            // countdown control.
      int  dTotalTime;                          // initialize to this.
      int  dRemainingTime;                      // the countdown value.
    };
    
    struct tLCD                                 // LCD related.
    {
      int   dTotalCookTime;                     // display time in seconds.
      int   dRemainingTime;                     // display time in seconds.
      float fCelsius;                           // temperature in celsius.
    };
    
    
    
    Queue<int, 1> queueModTotalTime;            // modify total time.
    Queue<int, 1> queueUpdateFSM;               // tell FSM what button was pressed.
    Queue<int, 1> queueUpdateRemainingTime;     // message to update remaining time.
    Queue<int, 1> queueSetRemainingTime;        // tell countdown it's start time.
    Queue<int, 1> queueTemperatureControl;      // control the temperature synthesizer.
    Queue<int, 1> queueSuppressTimeAdjust;      // total time control.
    Queue<int, 1> queueClearTotalTime;          // total time control.
//--global_variables----------------------------//------------------------------ 
    tButtons       giButtons;                   // ISR button updates.
    tRemainingTime giRemainingTime;             // structure instance.
    tLCD           giLCD;                       // structure instance.
    
    int      gdDiagTotalTime;
    char gcBeepEnable;
//--global_instances----------------------------//------------------------------ 
    Serial      pc(USBTX, USBRX);               // PuTTY terminal communication.
    LM75B        temperature(p28,p27);          // on-board thermometer.   
    C12832_LCD   lcd;                           // LCD object.
    DigitalOut   led0(LED4);                    // magnetron.
    DigitalOut   led1(LED3);
    DigitalOut   led2(LED2);
    DigitalOut   led3(LED1);
    DigitalOut   speaker(p26);                  // speaker device.
    
    InterruptIn  iJoyStickUp    (p15);          // joystick up rising edge.
    InterruptIn  iJoyStickDown  (p12);          // joystick down rising edge.
    InterruptIn  iJoyStickLeft  (p13);          // joystick left rising edge.
    InterruptIn  iJoyStickRight (p16);          // joystick right rising edge.
    InterruptIn  iJoyStickCenter(p14);          // 1 if joystick middle pressed.
    
    Timer        debounceTimer;                 // button debounce timer.
    Timer        beepTimer;                     // beep-duration timer.
    Timer        temperatureTimer;              // how often to raise temperature.


    Ticker       tickerButtonStateManager;      // manage the button states.
    Ticker       tickerSlowClock;               // generate a ~1Hz clock.
    Ticker       tickerCookCountdown;           // remaining cook time.      
    Ticker       tickerBeep;                    // beeper ticker. 
//-------prototypes-----------------------------//------------------------------

    void slowClock();                           // 1Hz or thereabouts.

    void initialization();                      // initialize settings.
    
    void ISRleftButtonRising();                 // cook-time increase.
    void ISRleftButtonFalling();                // button-release debounce.
    void ISRrightButtonRising();                // cook-time decrease.
    void ISRrightButtonFalling();               // button-release debounce.
    void ISRtopButtonRising();                  // cook start.
    void ISRtopButtonFalling();                 // button-release debounce.
    void ISRbottomButtonRising();               // cook stop.
    void ISRbottomButtonFalling();              // button-release debounce.
    void ISRcenterButtonRising();               // door state toggle.
    void ISRcenterButtonFalling();              // button-release debounce.
    void disableSignalWaiting();                // break from signal waiting.
    
    void threadButtonStateManager(void const *args);
    void threadTotalTimeControl(void const *args);
    void threadCookStateFSM(void const *args);
    void tickCookRemainingTime();               // remaining time countdown.
    
    void temperatureThread(void const *args);   // temperature measurement.
    void LCDthread        (void const *args);   // LCD display thread.

    void tickerBeeper();                        // beep oscillator.
//==============================================//==============================
    int main(void) 
    {
      char cLeftButtonState;                    // 1 means button was pressed.
    
    
    
      iJoyStickLeft.rise (&ISRleftButtonRising);
      iJoyStickLeft.fall (&ISRleftButtonFalling);
      
      iJoyStickRight.rise(&ISRrightButtonRising);
      iJoyStickRight.fall(&ISRrightButtonFalling);
   
      iJoyStickUp.rise   (&ISRtopButtonRising);
      iJoyStickUp.fall   (&ISRtopButtonFalling);      
      
      iJoyStickDown.rise (&ISRbottomButtonRising);
      iJoyStickDown.fall (&ISRbottomButtonFalling);
      
      iJoyStickCenter.rise(&ISRcenterButtonRising);
      iJoyStickCenter.fall(&ISRcenterButtonFalling);
      
      debounceTimer.start();                    // kick-off debounce timer.
      
      

      
      initialization();                         // initialize variables.

      led1 = 0;
      giButtons.cDoorOpen = 0;                  // initialize with door closed.
      gcBeepEnable =0;
      

      

       tickerCookCountdown.attach_us(&tickCookRemainingTime,1000000/GRANULARITY);
       
       tickerBeep.attach_us(&tickerBeeper,2000);
 
      
      Thread thread_1(temperatureThread       ,NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL);
      Thread thread_2(LCDthread               ,NULL,osPriorityHigh,DEFAULT_STACK_SIZE,NULL);
      Thread thread_3(threadTotalTimeControl  ,NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL);
      Thread thread_4(threadButtonStateManager,NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL); // was osPriorityIdle
      Thread thread_5(threadCookStateFSM      ,NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL);

//Thread thread_4(threadButtonStateManager);


 // the message-receiving threads need 'else' for message-receive-timeout.
 
//     int dSeconds;
//     dSeconds = 8;
     
 

      
      while(1)
      {
 //       pc.printf("\n\r gdDiagTotalTime %d",gdDiagTotalTime);
 
        Thread::wait(1000);
      
      
      
 
      }
    }     
/*----------------------------------------------//----------------------------*/

//  this serves as the bottom-half for all of the button-press IRSs.
//  it sends button-status messages to other threads, and it also
//  clears the button-state globals to prepare them for the next
//  button press.


    void threadButtonStateManager(void const *args)         
    {
      int dMessage;                             // message.
      
      while(1)                                  // thread loop.
      {     
//---                                           // TOTAL TIME CONTROL.

                                                // encoded integers will be sent,
                                                // not pointers.
      
      if (giButtons.cLeftButton)                // total time increment button.
      {
        dMessage = MSG_INC_TIME;                // set message.
        queueModTotalTime.put((int *) dMessage,1);// pretend it's a pointer.
        giButtons.cLeftButton = 0;              // clear the button state.
      }

      if (giButtons.cRightButton)               // total time decrement button.
      {
        dMessage = MSG_DEC_TIME;                // set message.
        queueModTotalTime.put((int *) dMessage,1);// pretend it's a pointer.
        giButtons.cRightButton = 0;             // clear the button state.
      }
   
//---                                           // COOK-STATE FSM.
    
      if (giButtons.cTopButton)                 // start-cook button.             
      {
        dMessage = MSG_START;                   // set message.
        queueUpdateFSM.put((int *) dMessage,1);   // pretend it's a pointer.
        giButtons.cTopButton = 0;               // clear the button state.
      }
     
      if (giButtons.cBottomButton)              // stop-cook button.
      {
        dMessage = MSG_STOP;                    // set message.
        queueUpdateFSM.put((int *) dMessage,1);   // pretend it's a pointer.
        giButtons.cBottomButton = 0;            // clear the button state.
      }
  
      if (giButtons.cCenterButton)              // door-state-toggle.
      {
        dMessage = giButtons.cDoorOpen;         // determined in ISR.
        queueUpdateFSM.put((int *) dMessage,1);   // pretend it's a pointer.
        giButtons.cCenterButton = 0;            // clear the button state.      
      }
//---     
      
        Thread::wait(THREAD_4_WAITmS);          // multitasking.
      }                                         // thread loop.
    }                                           // threadButtonStateManager.
/*----------------------------------------------//----------------------------*/
//  the incoming messages are mutually-exclusive.
                                                // total time controller.
    void threadTotalTimeControl(void const *args)           
    {
      static int   dTotalTime = 0;              // total time variable.
             int   dMessage;                    // message.
             int   dSuppress;                   // 1 to suppress operation.
         osEvent   queueEvent;                  // queue event.
             int   dRC;
      
      dSuppress = 0;                            // initialize.
      
      while(1)                                  // thread loop.
      {
      
      
      
                                                // if FSM tells this to clear
                                                // the total time.
        queueEvent = queueClearTotalTime.get(1);     
        if (queueEvent.status == osEventMessage)
        {
          dTotalTime = 0;
          dRC = queueSetRemainingTime.put((int *) dTotalTime,1);
          giRemainingTime.dTotalTime = dTotalTime;
        }
      
 
                                                // suppression mail from FSM.
        queueEvent = queueSuppressTimeAdjust.get(1);     
        if (queueEvent.status == osEventMessage)
        {
          dSuppress = (int) queueEvent.value.p;
        }
      
      
 
      
        queueEvent = queueModTotalTime.get(1);  // get message.
        if (queueEvent.status == osEventMessage)
        {
          dMessage = (int) queueEvent.value.p;  // interpret as integer, not pointer.
          
          if (!dSuppress)                       // increment total time.
          if (dMessage == MSG_INC_TIME) dTotalTime += TIMEINC; 
          
          if (!dSuppress)                       // decrement total time.
          if (dMessage == MSG_DEC_TIME) dTotalTime -= TIMEINC;
          
                                                // saturations.
          if (dTotalTime > 180) dTotalTime = 180; 
          if (dTotalTime <   0) dTotalTime =   0;         
          
          dRC = queueSetRemainingTime.put((int *) dTotalTime,1);
          giRemainingTime.dTotalTime = dTotalTime;
        }

             
        Thread::wait(THREAD_3_WAITmS);          // multitasking. 
      }                                         // thread loop.
    }                                           // threadTotalTimeControl.
/*----------------------------------------------//----------------------------*/

    void threadCookStateFSM(void const *args)   // cook-cycle FSM.
    {
      int   dFSMstate     = FSM_IDLE;    // state of this FSM.    
      int   dFSMstateLast = FSM_IDLE;    // previous FSM state.
      int   dButtonState;                // received button state.
      int   dRemainingTime = 0;          // received remaining time.
      
      int   dButtonStart   = 0;
      int   dButtonStop    = 0;
      int   dDoorOpen      = 0;
      int   dBeepSeconds   = 0;
            
      osEvent   queueEvent;                     // from button state manager.
      beepTimer.start();                        // run the beep timer.


      dBeepSeconds = BEEPTIME;
      

      
      
      queueTemperatureControl.put((int *) TEMP_READ,1);
      
      while(1)                                  // thread loop.
      {
 //     pc.printf("\n\r state: %d",dFSMstate);
  
        switch (dFSMstate)                      // cook-mode state machine.
        {
//---        
          case  FSM_IDLE :                      // IDLE.
          {
          led0 = 0;
            if (dFSMstate != dFSMstateLast)     // if just entered state.
            {      
              queueTemperatureControl.put((int *) TEMP_READ,1);   
              queueSuppressTimeAdjust.put((int*) 0,1);
              queueClearTotalTime.put    ((int*) 1,1);
            }
            
            giLCD.dTotalCookTime = giRemainingTime.dTotalTime;
            giLCD.dRemainingTime = 0;           // suppress remaining time display.
//            giLCD.fCelsius       = 0;
            
            giRemainingTime.cControl = RT_PRELOAD;                                           
            dFSMstateLast = dFSMstate;          // determine next state.
            if ((dButtonStart == 1) && (dDoorOpen == 0) && (giRemainingTime.dTotalTime > 0)) dFSMstate = FSM_COOK;
            break;
          }
//---   
           case  FSM_COOK :                     // COOK.
          {
            if (dFSMstate != dFSMstateLast)     // if just entered state.
            { 
              giRemainingTime.cControl = RT_DECREMENT;
              queueTemperatureControl.put((int *) TEMP_CALC,1);
              queueSuppressTimeAdjust.put((int*) 1,1);
            }    
            
            giLCD.dTotalCookTime = giRemainingTime.dTotalTime;
            giLCD.dRemainingTime = giRemainingTime.dRemainingTime;
 //           giLCD.fCelsius       = 0;            
            
            
                                                
            dFSMstateLast = dFSMstate;          // determine next state.
            if ((dDoorOpen == 1) && (dRemainingTime > 0)) dFSMstate = FSM_PAUSE; 
            else
            if (dButtonStop) dFSMstate = FSM_IDLE;
            else
            if (dRemainingTime <= 0) dFSMstate = FSM_DONE;
            break;
          }
//---   
          case  FSM_PAUSE :                     // PAUSE.
          {
              
            if (dFSMstate != dFSMstateLast)     // if just entered state.
            { 
              queueTemperatureControl.put((int *) TEMP_FREEZE,1);
            }
            
            
            giLCD.dTotalCookTime = giRemainingTime.dTotalTime;
            giLCD.dRemainingTime = giRemainingTime.dRemainingTime;
 //           giLCD.fCelsius       = 0;              
            
            
            giRemainingTime.cControl = RT_PAUSE;
                                                // determine next state.
            dFSMstateLast = dFSMstate;
            if ((dButtonStart == 1) && (dDoorOpen == 0) && (giRemainingTime.dTotalTime > 0)) dFSMstate = FSM_CONTINUE;
            else
            if (dButtonStop) dFSMstate = FSM_IDLE; 
            break;
          }
          
//---             
          case  FSM_CONTINUE :                  // CONTINUE.
          {
              
            if (dFSMstate != dFSMstateLast)     // if just entered state.
            { 
              queueTemperatureControl.put((int *) TEMP_CALC,1);
            }
            
            
            giLCD.dTotalCookTime = giRemainingTime.dTotalTime;
            giLCD.dRemainingTime = giRemainingTime.dRemainingTime;
   //         giLCD.fCelsius       = 0;              
            
            
            giRemainingTime.cControl = RT_DECREMENT;
                                                // determine next state.
            dFSMstateLast = dFSMstate;
            if (dRemainingTime <= 0) dFSMstate = FSM_DONE;
            else
            if (dButtonStop) dFSMstate = FSM_IDLE; 
            else
            if ((dDoorOpen == 1) && (dRemainingTime > 0)) dFSMstate = FSM_PAUSE;
            break;
          }          
          
          
//---             
          case  FSM_DONE :                      // DONE.
          {
            led0 = 1;
            led3 = 0;
            if (dFSMstate != dFSMstateLast)     // if just entered state.
            { 

              queueTemperatureControl.put((int *) TEMP_FREEZE,1);

              
              gcBeepEnable = 1;
              beepTimer.reset();                // clear the beep timer.
            }
           
            
            giLCD.dTotalCookTime = giRemainingTime.dTotalTime;
            giLCD.dRemainingTime = giRemainingTime.dRemainingTime;
//            giLCD.fCelsius       = 0;              
            
            
            
            giRemainingTime.cControl = RT_CLEAR;
                                                // determine next state.
            dFSMstateLast = dFSMstate;
            if (beepTimer.read() >= BEEPTIME) {dFSMstate = FSM_IDLE; gcBeepEnable = 0;}
            else dFSMstate = FSM_DONE; 
            
            led3 = 1;
            
            break;
          }       
//---           
          default       : {dFSMstate = FSM_IDLE; break;}
        
        }
        
     
    
        queueEvent = queueUpdateFSM.get(1);     // threadButtonStateManager
        if (queueEvent.status == osEventMessage)// update state variable.  
        {
                                                // interpret as integer, not pointer.
          dButtonState = (int) queueEvent.value.p; 
          

          
          if (dButtonState == MSG_START)
          {
            dButtonStart = 1;
            dButtonStop  = 0;
            
                                                // if the door is open, ignore
                                                // and cancel 'start' state.
            if (dDoorOpen) dButtonStart = 0;
          }
          if (dButtonState == MSG_STOP)
          {
            dButtonStart = 0;
            dButtonStop  = 1;
            queueClearTotalTime.put    ((int*) 1,1);
          }    
          
          if (dButtonState == MSG_OPEN)
          {
                                                // if the door opens, clear current 'start' state.
            dDoorOpen    = 1;
            dButtonStart = 0;
          }       
          
          if (dButtonState == MSG_CLOSED)
          {
            dDoorOpen = 0;
          }               
                
        }
        else                                    // no queue update available.
        {
          dButtonStart   = 0;
          dButtonStop    = 0;
//        dDoorOpen      = 0;   
        
        
        }
 
                                                // fetch from global scope.
        dRemainingTime = giRemainingTime.dRemainingTime;

                      // pipeline variable.
        Thread::wait(THREAD_5_WAITmS);          // multitasking. 
      }                                         // thread loop.
    }                                           // threadCookStateFSM.
/*----------------------------------------------//----------------------------*/
    void initialization(void)                   // program initializations.
    {
  //    gcSignalWaitEnable = 1;
    }
/*----------------------------------------------//----------------------------*/
    void ISRleftButtonRising(void)              // cooktime plus 60s.
    {
      if (debounceTimer.read_ms() > DEBOUNCEmS)
      giButtons.cLeftButton = 1;                // detect left button.
      
      debounceTimer.reset();                    // begin debounce period.
    } 
/*----------------------------------------------//----------------------------*/
    void ISRleftButtonFalling(void)             // button-release debounce.
    {
      debounceTimer.reset();                    // begin debounce period.
    } 
/*----------------------------------------------//----------------------------*/
    void ISRrightButtonRising(void)             // cooktime -60s.
    {
      if (debounceTimer.read_ms() > DEBOUNCEmS)
      giButtons.cRightButton = 1;               // detect right button.
      
      debounceTimer.reset();                    // begin debounce period.
    } 
/*----------------------------------------------//----------------------------*/
    void ISRrightButtonFalling(void)            // button-release debounce.
    {
      debounceTimer.reset();                    // begin debounce period.
    } 
/*----------------------------------------------//----------------------------*/
    void ISRtopButtonRising(void)               // cook start.
    {
      if (debounceTimer.read_ms() > DEBOUNCEmS)
      giButtons.cTopButton = 1;                 // detect top button.
      
      debounceTimer.reset();                    // begin debounce period.
    } 
/*----------------------------------------------//----------------------------*/
    void ISRtopButtonFalling(void)              // button-release debounce.
    {
      debounceTimer.reset();                    // begin debounce period.
    } 
/*----------------------------------------------//----------------------------*/
//  front-end control of magnetron off.
//  due to physical danger, the magnetron is turned off immediately
//  upon off-button press, in the interrupt that it generates.

    void ISRbottomButtonRising(void)            // cook stop.
    {
      if (debounceTimer.read_ms() > DEBOUNCEmS)
      {
        led0 = 0;                               // magnetron off.
        giButtons.cBottomButton = 1;            // detect bottom button.
      }
      debounceTimer.reset();                    // begin debounce period.
    }
/*----------------------------------------------//----------------------------*/
    void ISRbottomButtonFalling(void)           // button-release debounce.
    {
      debounceTimer.reset();                    // begin debounce period.
    } 
/*----------------------------------------------//----------------------------*/
//  front-end control of magnetron off.
//  due to physical danger, the magnetron is turned off immediately
//  upon detection of an open door.

    void ISRcenterButtonRising(void)            // toggle door state.
    {
      if (debounceTimer.read_ms() > DEBOUNCEmS)
      {
        if (giButtons.cDoorOpen == MSG_OPEN)    // calculate door state.
        giButtons.cDoorOpen = MSG_CLOSED;
        else
        giButtons.cDoorOpen = MSG_OPEN;
      
                                                // magnetron off.
        if (giButtons.cDoorOpen == MSG_OPEN) led0 = 0;        
      
        giButtons.cCenterButton = 1;              
      }
      debounceTimer.reset();                    // begin debounce period.
    } 
/*----------------------------------------------//----------------------------*/
    void ISRcenterButtonFalling(void)           // button-release debounce.
    {
      debounceTimer.reset();                    // begin debounce period.
    } 
/*----------------------------------------------//----------------------------*/ //====================================================
    void temperatureThread(void const *args)    // temperature measurement.
    {
      int       dTempControl = 0;               // temperature control.
      int       dCurrentTimerMs;
      int       dPreviousTimerMs;
      float     fLastMeasuredTemperature;
      float     fCelsius;
      osEvent   queueEvent;                     // from button state manager.
      
      dCurrentTimerMs = 0;
      dPreviousTimerMs = 0;
      fLastMeasuredTemperature = 0.0;
      
 //     temperatureTimer.start();
    
      while(1)                                  // thread loop.
      {
                                                // obtain temperature command.
        queueEvent = queueTemperatureControl.get(1);  
        if (queueEvent.status == osEventMessage)
        {
          dTempControl = (int) queueEvent.value.p;  
        }
      
        if (dTempControl == TEMP_READ)
        {
          fCelsius = temperature.read();         // physical measurement.
          fLastMeasuredTemperature = fCelsius;
//          temperatureTimer.reset();             // reset timer while we're not using it.
        }
        
        if (dTempControl == TEMP_CALC)
        
        
        
        
         fCelsius = ((float) (giRemainingTime.dTotalTime - giRemainingTime.dRemainingTime) / (float) 6.0) + fLastMeasuredTemperature;
            
            
            
        
    //    gfCelsius = fLastMeasuredTemperature + (temperatureTimer.read_ms() / 6000.0);

      
      
      
        giLCD.fCelsius = fCelsius;
        
      
        Thread::wait(THREAD_1_WAITmS);          // multitasking. 
      }                                         // thread loop.
    }                                           // temperatureThread.
/*----------------------------------------------//----------------------------*/
    void LCDthread(void const *args)            // LCD display thread.
    {
    
      static int   dLCDtotalCookTimeSec  = 0;   // sample current values.
      static int   dCookTimeRemainingSec = 0;
      static float fLCDcelsius           = 0.0;
    
                                                // remember previous values.
      static int   dLCDtotalCookTimeSecLast  = 0;
      static int   dCookTimeRemainingSecLast = 0;
      static float fLCDcelsiusLast           = 0.0;
      
      while(1)                                  // thread loop.
      {
                                                // don't allow the values to
                                                // change in the middle of the 
                                                // below else the anti-blink
                                                // code won't work.
        dLCDtotalCookTimeSec  = giLCD.dTotalCookTime;
        dCookTimeRemainingSec = giLCD.dRemainingTime;
        fLCDcelsius           = giLCD.fCelsius;
        

        

                                                // clear display only when
                                                // necessary, in order to avoid
                                                // 'blinkieness'. 
        if (dLCDtotalCookTimeSec  != dLCDtotalCookTimeSecLast  ||
            dCookTimeRemainingSec != dCookTimeRemainingSecLast || 
            fLCDcelsius           != fLCDcelsiusLast)
        lcd.cls();
      
        LCD1;                                   // line 1.
        lcd.printf(" total   cook time: %d",dLCDtotalCookTimeSec);
      
        LCD2;                                   // line 2.
        lcd.printf(" remaing cook time: %d",dCookTimeRemainingSec);
    
        LCD3;                                   // line 3.
        lcd.printf(" temperature      : %5.3f",fLCDcelsius);
        
                                                // pipeline variables.
        dLCDtotalCookTimeSecLast  = dLCDtotalCookTimeSec;
        dCookTimeRemainingSecLast = dCookTimeRemainingSec;
        fLCDcelsiusLast           = fLCDcelsius;
      
        Thread::wait(THREAD_2_WAITmS);          // multitasking.
      }                                         // thread loop.
    }                                           // LCDthread.
/*----------------------------------------------//----------------------------*/

//  cook remaining time countdown counter.
//  possibly due to a bug in Ticker
//  http://mbed.org/questions/1563/Mbed-Tickerfunction-hangs-system-from-re/
//  I've been unable to detach/attach this routine in order to reset its phase
//  when I tried it at a 1s resolution.  In order to provide the human perception
//  of an immediate restart, I've increased the ticker frequency by the factor
//  'GRANULARITY' and likewise divide that factor out when this routine
//  promotes the remaining time to the global variable.

//  communication is via a global instance of struct tRemainingTime.

    void tickCookRemainingTime(void)            // cook-cycle countdown.
    {
      static int dRemainingTime = 0;            // remaining time in seconds.
             int dMaximum;                      // MAXSECONDS * GRANULARITY.
             
      dMaximum = MAXSECONDS * GRANULARITY;      // precalculate.
      
      switch (giRemainingTime.cControl)         // control processing.
      {
      
        case RT_PRELOAD   :                     // preload with total time.
        {
                                                // the 'GRANULARITY - 1' factor
                                                // compensates for integer division
                                                // dropping the right-of-decimal result,
                                                // that occuring at the bottom of this
                                                // routine.
          dRemainingTime = (giRemainingTime.dTotalTime * GRANULARITY) + (GRANULARITY - 1);
          break;
        }
        
        case RT_DECREMENT :                     // count-down.
        {
          dRemainingTime--;
          break;
        }
      
        case RT_PAUSE    :                      // suspend countdown.
        {
          dRemainingTime = dRemainingTime;
          break;
        }
        
        case RT_CLEAR    :                      // clear countdown.
        {
          dRemainingTime = 0;        
          break;
        }
      
        default          :                      // saturate, just in case.
        {
        }
      }                                         // control processing.
      
                                                // saturate value.
      if (dRemainingTime >  dMaximum) dRemainingTime = dMaximum;
      if (dRemainingTime <         0) dRemainingTime = 0;
      
                                                // promote to global scope.
      giRemainingTime.dRemainingTime = dRemainingTime/GRANULARITY;
      
    }                                           // cookRemainingTime.
/*----------------------------------------------//----------------------------*/
    void tickerBeeper(void)                     // beep when gcBeepEnable is 1.
    {
      static char cState = 0;
      if (gcBeepEnable)
      {
        if (cState) {speaker = 1; cState = 0;}
        else        {speaker = 0; cState = 1;}
      }
    }
/*----------------------------------------------//----------------------------*/