/****************************************************************************
Module
   Time.c
 Revision
   1.0.1
 Description
   This is a file for implementing time flat state machines under the
   Gen2 Events and Services Framework.
 Notes
 History
 When            Who     What/Why
 -------------- ---      --------
 01/15/12 11:12 jec       revisions for Gen2 framework
 11/07/11 11:26 jec       made the queue static
 10/30/11 17:59 jec       fixed references to CurrentEvent in RunTemplateSM()
 10/23/11 18:20 jec       began conversion from SMTemplate.c (02/20/07 rev)
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
/* include header files for this state machine as well as any machines at the
   next lower level in the hierarchy that are sub-machines to this machine
*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "Time.h"
#include "MusicSequence.h"
#include "Car.h"
#include "PWM16Tiva.h"
// the headers to access the GPIO subsystem
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
// the headers to access the TivaWare Library
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include "BITDEFS.H"
/*----------------------------- Module Defines ----------------------------*/
/*---------------------------- Module Functions ---------------------------*/
/* prototypes for private functions for this machine.They should be functions
   relevant to the behavior of this state machine
*/
void Write_Green_Full(void);
void Write_Passage_Color(void);
void Write_Defeat_Color(void);
void Write_Celebrate_Color(void);
/*---------------------------- Module Variables ---------------------------*/
// everybody needs a state variable, you may need others as well.
// type of state variable should match htat of enum in header file
// with the introduction of Gen2, we need a module level Priority var as well
static uint8_t MyPriority;
static TimeState_t CurrentState;
static uint8_t ResetEarly = 0;
//10 positions, one servo extreme to the other (need to find desire angles...the first
index needs to be for initialization so leftmost)
static uint16_t SunPositions[] = {
   900, 1000, 1200, 1400, 1600, 1800, 2000, 2200, 2400, 2500
};
static uint8_t SunIndex = 0;
static uint8_t SunHome = 0;
// colors: green, yellow, orange (need to start with green)
static uint16_t PassageR[] = {
   0, 100, 100, 100, 100, 100, 100, 100, 100, 100
};
static uint16_t PassageG[] = {
   100, 90, 70, 60, 50, 40, 30, 20, 10, 0
};
//cam use this chart http://www.rapidtables.com/web/color/RGB_Color.htm
static uint16_t PassageB[] = {
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static uint8_t ColorIndex = 0;
static uint8_t ShowIndex = 0;
//celebrate colors: bright green, dark blue, purple, dark pink, skyblue
static uint16_t CelebrateR[] = {
   0, 0, 50, 100, 0, 0, 0, 50, 100, 0, 50, 0, 0, 50, 100, 0, 0, 0, 50, 100, 0, 50
};
static uint16_t CelebrateG[] = {
   100, 0, 0, 0, 100, 100, 0, 0, 0, 100, 0, 100, 0, 0, 0, 100, 100, 0, 0, 0, 100, 0
};
static uint16_t CelebrateB[] = {
   0, 100, 100, 50, 100, 0, 100, 100, 50, 100, 100, 0, 100, 100, 50, 100, 0, 100, 100,
50, 100, 100
};
//defeat bounces between red, red, orange, yellow      (looks white), red
static uint16_t DefeatR[] = {
   100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 100,   0, 100, 0, 100, 0, 100, 0, 100,
0, 100
};
static uint16_t DefeatG[] = {
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0
};
static uint16_t DefeatB[] = {
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0
};
#define MAINTIME 45000 //<--check these times main time is 45 s
//static uint16_t SUNTIME; //so sun can have 10 positions
#define SUNTIME MAINTIME / 10
#define PASSAGETIME (MAINTIME / 10) //so first part of game has green backlight then
yellow (~halfway through game), then orange (game is soon ending)
static uint16_t SHOWTIME = 500;
#define SHOWMAX 21 // before last color in array
// these times assume a 1.000mS/tick timing
#define ONE_SEC 976
#define SERVO_PERIOD 25000                         // 20ms in 0.8us ticks
#define SERVO_RESET_PERIOD (SERVO_PERIOD * 10)     //20ms *10
#define SERVO_GROUP 4
#define SUN_SERVO 9
#define    RG_GROUP 2
#define    B_GROUP 3
#define    R_CHANNEL 4
#define    G_CHANNEL 5
#define    B_CHANNEL 6
#define COLOR_FREQ 200
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
 Function
     InitTime
    Parameters
        uint8_t : the priorty of this service
    Returns
        bool, false if error in initialization, true otherwise
    Description
        Saves away the priority, sets up the initial transition and does any
        other required initialization for this state machine
    Notes
  Author
      J. Edward Carryer, 10/23/11, 18:55
****************************************************************************/
bool InitTime(uint8_t Priority)
{
   //printf("I got to InitTime\r\n");
   ES_Event ThisEvent;
     MyPriority = Priority;
     //The port lines (sun PWMSs,LED PWMs) are initialized in main PWM initialize
     // post the initial transition event
     ThisEvent.EventType = ES_INIT;
     CurrentState = InitializingTime;
     if (ES_PostToService(MyPriority, ThisEvent) == true)
     {
       return true;
     }
     else
     {
       return false;
     }
}
/****************************************************************************
 Function
     PostTime
    Parameters
        EF_Event ThisEvent , the event to post to the queue
    Returns
        boolean False if the Enqueue operation failed, True otherwise
    Description
     Posts an event to this state machine's queue
 Notes
  Author
      J. Edward Carryer, 10/23/11, 19:25
****************************************************************************/
bool PostTime(ES_Event ThisEvent)
{
   return ES_PostToService(MyPriority, ThisEvent);
}
/****************************************************************************
 Function
    RunTime
 Parameters
   ES_Event : the event to process
 Returns
   ES_Event, ES_NO_EVENT if no error ES_ERROR otherwise
  Description
    add your description here
  Notes
    uses nested switch/case to implement the machine.
  Author
    J. Edward Carryer, 01/15/12, 15:23
****************************************************************************/
ES_Event RunTime(ES_Event ThisEvent)
{
   ES_Event ReturnEvent;
   ReturnEvent.EventType = ES_NO_EVENT; // assume no errors
   static TimeState_t NextState;
   NextState = CurrentState;
  switch (CurrentState)
  {
    case InitializingTime:
    {
      if (ThisEvent.EventType == ES_INIT)    // only respond to ES_Init
      {
        //Set RGB channels to make green backlight
        Write_Passage_Color();
        //set sun to home position
        PWM_TIVA_SetPeriod(SERVO_PERIOD, SERVO_GROUP);
        PWM_TIVA_SetPulseWidth(SunPositions[SunHome], SUN_SERVO);
          // now put the machine into the actual initial state
          NextState = Welcome_Time;
      }
    }
    break;
    case Welcome_Time:
    {
      if (ThisEvent.EventType == CAR_PLACED)
      {
        //Set Main Timer
        ES_Timer_InitTimer( MainTimer,       MAINTIME);
        //Set Sun Timer
        ES_Timer_InitTimer( SunTimer,        SUNTIME);
        //Set Backlight Timer
        ES_Timer_InitTimer( BacklightTimer, PASSAGETIME);
        //set next state to WaitForTimeouts
        NextState = WaitForTimeouts;
      }
      else if (ThisEvent.EventType == EARLY_RESET)
      {
        ResetEarly = 1;
        NextState = WaitForReset_Time;
      }
    }
    break;
    case WaitForTimeouts:
    {
      if ((ThisEvent.EventType == ES_TIMEOUT) && (ThisEvent.EventParam ==
SunTimer))
      {
        //Write sun position using SunPosition[SunIndex]
        PWM_TIVA_SetPulseWidth(SunPositions[SunIndex], SUN_SERVO);
        SunIndex = SunIndex + 1;
        //set Sun Timer
        ES_Timer_InitTimer(SunTimer, SUNTIME);
        //set next state to WaitForTimeouts
        NextState = WaitForTimeouts;
      }
      else if ((ThisEvent.EventType == ES_TIMEOUT) && (ThisEvent.EventParam ==
BacklightTimer))
      {
        //Write red, green, and blue channels using PassageR[ColorIndex],
PassageG[ColorIndex, and PassageB[ColorIndex]
        Write_Passage_Color();
        //final color test
        if (ColorIndex != (sizeof(PassageR) / sizeof(PassageR[0])) - 1)
        {
           ColorIndex = ColorIndex + 1;
        }
        //set backlight(passage) Timer
        ES_Timer_InitTimer(BacklightTimer, PASSAGETIME);
        //set next state to WaitForTimeouts
        NextState = WaitForTimeouts;
      }
      else if ((ThisEvent.EventType == ES_TIMEOUT) && (ThisEvent.EventParam ==
MainTimer))
      {
        //Write RGB channels using DefeatR[ShowIndex], DefeatG[ShowIndex],
DefeatB[ShowIndex]
        Write_Defeat_Color();
        ShowIndex = ShowIndex + 1;
        //set backlight(showtime) Timer
        ES_Timer_InitTimer(BacklightTimer, SHOWTIME);
        //set next state to Defeat_Time
        NextState = Defeat_Time;
      }
      else if (ThisEvent.EventType == VICTORY)
      {
        //Write sun to home position, period reset to give more time to get home
        PWM_TIVA_SetPulseWidth(SunPositions[SunHome], SUN_SERVO);
        //Write RGB channels using CelebrateR[ShowIndex], CelebrateG[ShowIndex],
CelebrateB[ShowIndex]
        Write_Celebrate_Color();
        ShowIndex = ShowIndex + 1;
        //set backlight(showtime) Timer
        ES_Timer_InitTimer(BacklightTimer, SHOWTIME);
        //set next state to Defeat
        NextState = Celebrate_Time;
      }
      else if ((ThisEvent.EventType == EARLY_RESET) || (ThisEvent.EventType ==
HEADPHONES_RESET))
      {
        ResetEarly = 1;
        NextState = WaitForReset_Time;
      }
    }
    break;
    case Defeat_Time:
    {
      if ((ThisEvent.EventType == ES_TIMEOUT) && (ThisEvent.EventParam ==
BacklightTimer) && (ShowIndex != SHOWMAX))
      {
        //Write RGB channels using DefeatR[ShowIndex], DefeatG[ShowIndex],
DefeatB[ShowIndex]
        Write_Defeat_Color();
          ShowIndex = ShowIndex + 1;
          //set backlight(showtime) Timer
          ES_Timer_InitTimer(BacklightTimer, SHOWTIME);
          //set next state to Defeat_Time
          NextState = Defeat_Time;
      }
      else if ((ThisEvent.EventType == ES_TIMEOUT) && (ThisEvent.EventParam ==
BacklightTimer) && (ShowIndex == SHOWMAX))
      {
        //Write RGB channels using DefeatR[ShowIndex], DefeatG[ShowIndex],
DefeatB[ShowIndex]
        Write_Defeat_Color();
        //post this event to MusicSquence
        ES_Event ThisEvent;
        ThisEvent.EventType = TIMEOUT_POT;
        PostMusicSequence(ThisEvent);
        PostCar(ThisEvent);
        //set next state to WaitForReset_Time
        NextState = WaitForReset_Time;
      }
      else if ((ThisEvent.EventType == EARLY_RESET) || (ThisEvent.EventType ==
HEADPHONES_RESET))
      {
        ResetEarly = 1;
        NextState = WaitForReset_Time;
      }
    }
    break;
    case Celebrate_Time:
    {
      if ((ThisEvent.EventType == ES_TIMEOUT) && (ThisEvent.EventParam ==
BacklightTimer) && (ShowIndex != SHOWMAX))
      {
        //Write RGB channels using CelebrateR[ShowIndex], CelebrateG[ShowIndex],
CelebrateB[ShowIndex]
        Write_Celebrate_Color();
          ShowIndex = ShowIndex + 1;
          //set backlight(showtime) Timer
          ES_Timer_InitTimer(BacklightTimer, SHOWTIME);
          //set next state to Celebrate_Time
          NextState = Celebrate_Time;
      }
      else if ((ThisEvent.EventType == ES_TIMEOUT) && (ThisEvent.EventParam ==
BacklightTimer) && (ShowIndex == SHOWMAX))
      {
        //Write RGB channels using CelebrateR[ShowIndex], CelebrateG[ShowIndex],
CelebrateB[ShowIndex]
        Write_Celebrate_Color();
        //post this event to MusicSquence
        ES_Event ThisEvent;
        ThisEvent.EventType = TIMEOUT_POT;
        PostCar(ThisEvent);
        //set next state to WaitForReset_Time
        NextState = WaitForReset_Time;
      }
      else if ((ThisEvent.EventType == EARLY_RESET) || (ThisEvent.EventType ==
HEADPHONES_RESET))
      {
        ResetEarly = 1;
        NextState = WaitForReset_Time;
      }
    }
    break;
       case WaitForReset_Time:
       {
         if ((ThisEvent.EventType == HEADPHONES_RESET) || (ResetEarly == 1))
         {
           //Set PWM channels to make green backlight
           Write_Green_Full();
           //Write sun to home position, period reset to give more time to get home
           PWM_TIVA_SetPulseWidth(SunPositions[SunHome], SUN_SERVO);
           //Write red channel using CelebrateR[ShowIndex]
           //Reset indexes
           ColorIndex = 0;
           SunIndex = 0;
           ShowIndex = 0;
           //set next state to Welcome_Time
           ResetEarly = 0;
           NextState = Welcome_Time;
             ES_Timer_StopTimer(MainTimer);
         }
       }
       break;
     }                                        // end switch on Current State
     CurrentState = NextState;
     return ReturnEvent;
}
/***************************************************************************
 private functions
 ***************************************************************************/
/****************************************************************************
****************************************************************************
 Function
 Write_Green_Full
    Parameters
        None
    Returns
        none
    Description
     turns backlight fully green
 Notes
****************************************************************************/
void Write_Green_Full(void)
{
  //set frequency for red, green, and blue clannels
  PWM_TIVA_SetFreq( COLOR_FREQ, RG_GROUP);
  PWM_TIVA_SetFreq( COLOR_FREQ, B_GROUP);
  //set duty cycles for red, green, and blue clannels
  PWM_TIVA_SetDuty( PassageR[0], R_CHANNEL);
  PWM_TIVA_SetDuty( PassageG[0], G_CHANNEL);
  PWM_TIVA_SetDuty( PassageB[0], B_CHANNEL);
}
/****************************************************************************
 Function
 Write_Passage_Color
 Parameters
     None
 Returns
     none
 Description
     turns backlight various colors during the Passage Sequence
 Notes
****************************************************************************/
void Write_Passage_Color(void)
{
  //frequency already set for red, green, and blue clannels
  //set duty cycles for red, green, and blue clannels
  PWM_TIVA_SetDuty( PassageR[ColorIndex], R_CHANNEL);
  PWM_TIVA_SetDuty( PassageG[ColorIndex], G_CHANNEL);
  PWM_TIVA_SetDuty( PassageB[ColorIndex], B_CHANNEL);
}
/****************************************************************************
 Function
 Write_Defeat_Color
 Parameters
     None
 Returns
     none
 Description
     turns backlight various colors during the Defeat Sequence
 Notes
****************************************************************************/
void Write_Defeat_Color(void)
{
  //frequency already set for red, green, and blue clannels
  //set duty cycles for red, green, and blue clannels
  PWM_TIVA_SetDuty( DefeatR[ShowIndex], R_CHANNEL);
  PWM_TIVA_SetDuty( DefeatG[ShowIndex], G_CHANNEL);
  PWM_TIVA_SetDuty( DefeatB[ShowIndex], B_CHANNEL);
}
/****************************************************************************
 Function
 Write_Celebrate_Color
 Parameters
     None
 Returns
     none
 Description
     turns backlight various colors during the Celebrate Sequence
 Notes
****************************************************************************/
void Write_Celebrate_Color(void)
{
  //frequency already set for red, green, and blue clannels
  //set duty cycles for red, green, and blue clannels
  PWM_TIVA_SetDuty( CelebrateR[ShowIndex], R_CHANNEL);
  PWM_TIVA_SetDuty( CelebrateG[ShowIndex], G_CHANNEL);
  PWM_TIVA_SetDuty( CelebrateB[ShowIndex], B_CHANNEL);
}