/** @(#)main.c Created on: <30-Nov-2003 06:52:44 Z4303>
 *  Last Time-stamp: <30-Nov-2003 10:27:20 Z4303>
 *
 *  \file main.c
 *  \ingroup Esterel Automation
 *  \brief  main() for Esterel Reflex Game Demonstration.
 *
 */

/*lint -save */

#include "includes.h" 

#define  DEFINE_SPACE_MAIN_H (1) 
#include "main.h" 

#include "hardware.h" 

#include "debounce.h" 
#include "led_digits.h" 
#include "reflex_game.h" 

static uint8_t isr_ms_tick_u8; /* Incremented every 1 mS by IRQ */
static uint8_t isr_coin_u8;    /* Incremented by press of the 'coin' button */

/*
 * This Timer ISR get called every 1 mS.
 * It is the system base 'tick'.
 */
#pragma interrupt 
void isr_timer0(void)
{
    DISABLE_INTERRUPTS();
    IRQ0ENH &= (uint8_t) ~T0ENH;     /* Disable Timer0 Interrupts */
    IRQ0ENL &= (uint8_t) ~T0ENL;
    ENABLE_INTERRUPTS();

    ++isr_ms_tick_u8;		     /* Use counter instead of flag, so ticks will not be missed */
    ++random_number_u16;	     /* Used to generate a random number of mS for pseudo-random delay */

    DISABLE_INTERRUPTS();
    IRQ0ENL |= T0ENL;		     /* IRQ0 Enable; Timer0 is programed to Level-1/Low priority */
    ENABLE_INTERRUPTS();
}

/*
 * Initialize Timer-0  for continuous mode,
 * and for interrupts to occur every 1ms.
 *
 * FREQ18432 18,432,000 Hz
 * Time-Out Period (s) = (Reload Value * Prescale)/ System Clock (Hz)
 *
 */
#define TIMER0_RELOAD (144)	      /* = (18,432,000/(1/1mS))/128 */ 
#define TIMER0_RELOAD_HIGH (TIMER0_RELOAD>>8) 
#define TIMER0_RELOAD_LOW  (TIMER0_RELOAD & 0xFF) 

void init_timer0(void);
void init_timer0(void)
{
    SET_VECTOR(TIMER0, isr_timer0);  /* Pass the vector number and the ISR
				      * address to be placed into the interrupt
				      * table
				      */

    T0H = 0x00;                      /* Timer High */
    T0L = 0x00;		             /* Timer Low */
    T0CPH = TIMER0_RELOAD_HIGH;      /* Reload Compare High and Low */
    T0CPL = TIMER0_RELOAD_LOW;       /* To get 1ms time period */

    IRQ0ENH &= (uint8_t) ~T0ENH;     /* Set Timer0 for Level-1/Low priority */
    IRQ0ENL |= T0ENL;

    T0CTL  = (TEN|TPRESCALE128|TMODE_CONTINUOUS); /* Timer Enable */
}

/*
 * Timer1 ISR called to update LED Display.
 */
#pragma interrupt 
void isr_timer1(void)
{
    DISABLE_INTERRUPTS();
    IRQ0ENH &= (uint8_t) ~T1ENH;     /* Disable Timer1 Interrupts */
    IRQ0ENL &= (uint8_t) ~T1ENL;
    ENABLE_INTERRUPTS();

    isr_led_digits_timer();

    DISABLE_INTERRUPTS();
    IRQ0ENH |= T1ENH;		     /* IRQ Enable; Timer1 is programed to Level-2/Medium priority */
    ENABLE_INTERRUPTS();
}

#define TIMER1_RELOAD (4608) 
#define TIMER1_RELOAD_HIGH (TIMER0_RELOAD>>8) 
#define TIMER1_RELOAD_LOW  (TIMER0_RELOAD & 0xFF) 

void init_timer1(void);
void init_timer1(void)
{
    SET_VECTOR(TIMER1, isr_timer1);  /* Pass the vector number and the ISR
				      * address to be placed into the interrupt
				      * table
				      */

    T1H = 0x00;                      /* Timer High */
    T1L = 0x00;		             /* Timer Low */
    T1CPH = TIMER1_RELOAD_HIGH;      /* Reload Compare High and Low */
    T1CPL = TIMER1_RELOAD_LOW;       /* To get 1ms time period */

    IRQ0ENH |= T1ENH;		     /* Set Timer1 for Level-2/Medium priority */
    IRQ0ENL &= (uint8_t) ~T1ENL;

    T1CTL  = (TEN|TPRESCALE64|TMODE_CONTINUOUS); /* Timer Enable */
}

#pragma interrupt 
void isr_coin_button(void)	     /* Restart game at any time if 'coin is inserted' */
{
    ++isr_coin_u8;
}

void init_coin_button(void);
void init_coin_button(void)
{
    IRQPS |= PAD3S;		     /* Interrupt Port Select Register (IRQPS), Select PD3 as IRQ */

    SET_VECTOR(P3AD, isr_coin_button);
    IRQ1ENH |= PAD3EN;		     /* Set Interrupt Level-3/High priority*/
    IRQ1ENL |= PAD3EN;
}

int main()
{
    uint8_t buttons_u8;

    DISABLE_INTERRUPTS();

    /* Setup I/O ports: */

    PFDD   = (PF7|PF6);  /* Data Direction,            0 = Output Direction, PF6&5 are inputs */
    PFAF   = 0x00;       /* Alternate Function,        0 = Normal/Follow DDx bit */
    PFOC   = 0x00;       /* Output Control,            1 = Open Drain */
    PFHDE  = 0xFF;       /* High Drive Enable,         1 = High Current Drive */
    PFSMRE = 0x00;       /* Stop Mode Recovery Enable, 1 = Stop Mode Recovery Source */
    PFOUT  = 0x00;       /* Output,   1 = Logical High Output, PF6&5 are inputs */

    isr_ms_tick_u8 =
    isr_coin_u8    = 0;

    init_timer0();
    init_timer1();
    init_timer2();
    init_coin_button();

    led_digits_all_off();

    REFLEX_GAME_reset(); /* Reset the Esterel code */

    /*
     * Programs often contain instantaneous initial statements, such
     * as signal emissions or variable initializations, to be performed
     * during the first reaction. To perform them, it is often useful
     * (but not mandatory) to generate a blank initial event by calling
     * the reaction function before calling any input C function. (This
     * boot transition is different from the automaton reset).
     */
    REFLEX_GAME(); /* Iniz the Esterel code */

    /* Interrupts will be enabled in the main()line code, no need to do here. */

    for(;;)/*ever*/
    {
	/*
	 * Interrupts are disabled briefly because the Esterel Automation code
	 * expects all inputs to be stable for the duration of its execution.
	 * Counters that are incremented by interrupts are decremented here
	 * in the main()line code.
	 *
	 * By using counters instead of flags, multiple IRQs will not be
	 * missed, because they might have been preempted by a higher
	 * priority interrupt.  Doing a tick a bit late is better than
	 * missing the tick for this project.
	 *
	 */
	DISABLE_INTERRUPTS();
	if( isr_coin_u8 > 0 )
	    {
		--isr_coin_u8;
		REFLEX_GAME_I_COIN();
	    }

	if( isr_ms_tick_u8 > 0 )
	    {
		--isr_ms_tick_u8;
		REFLEX_GAME_I_MS();
	    }
	ENABLE_INTERRUPTS();

	buttons_u8 = debounce_buttons( BUTTONS_IN );/* Register buttons as edge
						     * sensitive rather than level sensitive. 
						     * Using level sensing
						     * rather than edge sensing	can cause
						     * race conditions in the
						     * Esterel Automation code.
						     */
	if( BUTTON_READY & buttons_u8 )/* Is the button asserted? */
	    {/* Yes */
		display_rdy();	       /* Let the human know the button 'took' when it was pressed */
		REFLEX_GAME_I_READY(); /* Let the Esterel code know that SW2/READY has been asserted */
	    }

	if( BUTTON_STOP & buttons_u8 )/* Is the button asserted? */
	    {/* Yes */
		REFLEX_GAME_I_STOP(); /* Let the Esterel code know that SW1/STOP has been asserted */
	    }

	REFLEX_GAME(); /* Call the Esterel Automation code.
		        * It must be called at least as often as the 'system
			* tick() happens, 1 mS in this example.
			*/
    }
}

/*lint -restore */