/***************************************************************************/
/*                                                                         */
/*  Nordik.c                                                               */
/*             Dual timer for F5J-Nordik competition flying                */
/*                                                                         */
/*   Version : 0.13                                                        */
/*                                                                         */
/*                                                                         */
/*         By: J. Vehmaa                                                   */
/*                                                                         */
/*       Date: 11.01.2004                                                  */
/*                                                                         */
/*                                                                         */
/* Version      Comments                                                   */
/* 0.07         PortAConfig 0x08 --> 0x00, PortBConfig 0x0F --> 0x03       */
/* 0.08         Buzzer and LCD's back light control taken in use           */
/*              Note: Summeri toimii käänteisellä logiikalla               */
/* 0.09		Pre scaler 1:16 --> 1:256, comments added to PIC init part */
/*              timer tibles to save results for later use                 */
/* 0.10         countdown functionality taken in use                       */
/* 0.11         List mode						   */
/* 0.12         LCD's back light control removed, buzzer control moved to  */
/*              main loop                                                  */ 
/* 0.13         buzzer control moved for a while...			   */  
/***************************************************************************/

#pragma  CLOCK_FREQ 4000000	// Timing settings for delay functions	

#define  MAIN


#include "lcd.h"


/* General definitions */ 

#define TRISA               5

#define TRISB               6 

#define PORTA               5 

#define PORTB               6

#define RBPU                7

#define BUZZER              4       // Buzzer in RA4    

#define LCD_BACK_LIGHT_C    3       // LCD's led back light control in RA3   

#define MOTOR_KEY           1       // Motor key in RB0

#define START_KEY           2       // Fly key   in RB1

#define INTS_IN_SEC_C	   15	    // 4000000/(4*256*256)

#define BUZZER_TICS_C       2	    // ~ 0.1 x INTS_IN_SEC_C 

  
/* PIC PORT SETUP */ 

#define PortAConfig         0x00    // Configuration of port A ( 1 = in, O = output )

                                    // RA543210
                                    //   000000
#define PortBConfig         0x0F    // Configuration of port B                         

                                    // RB76543210                              
                                    //   00001111                              
#define STATE_IDLE          0       // the both timers are stopped, display resetted    

#define STATE_MOTOR_ON      1       // motor and fly timers are running

#define STATE_MOTOR_OFF     2       // motor timer is stopped and fly timer is running

#define STATE_STOP          3       // the both timers are stopped, not resetted

#define STATE_LIST          4	    // list saved filght timers


#define F_HRS_POS_C         0x87    // pos 08..09 in line 1

#define F_MIN_POS_C         0x8A    // pos 11..12 in line 1

#define F_SEC_POS_C         0x8D    // pos 14..15 in line 1


#define M_MIN_POS_C         0xCA    // pos 11..12 in line 2

#define M_SEC_POS_C         0xCD    // pos 14..15 in line 2

#define MAX_MIN_SEC_C       59

#define FULL_MIN_HRS_C      60

#define SAVED_RESULTS_C      5

#define FOREVER              1


char     fly_hrs_t[SAVED_RESULTS_C]; // table for saved timers
char     fly_min_t[SAVED_RESULTS_C];
char     fly_sec_t[SAVED_RESULTS_C];
char     mot_min_t[SAVED_RESULTS_C]; 
char     mot_sec_t[SAVED_RESULTS_C];
char     mot_min;                    // variable for motor timer
char     mot_sec;
char     fly_hrs;                    // variable for fly timer
char     fly_min;
char     fly_sec;

char     buzzer_time;                // variable for different buzzer sounds
char     lcd_bck_time;               // time out counter for LCD's back light
char     state;                      // state machine variable
char     timer;                      // interrupt multiplier counter
char     fly_index;		     // index to save timers into table
char     disp_index;
 
//////////////////////////////////////////////////////////////////////

void update_fly_timer( void )            
{
    fly_sec++;                      // sec increment    

    if( fly_sec == 60 ){            // 60 sec has gone -> 1 MINUTES
        fly_sec = 0;                // prepare for another count
        fly_min++;                  // min increment
        buzzer_time = 5;	    // summeri päälle XX ms ajaksi
    
        if( fly_min == 60 ){        // 60 min has gone -> 1 HOURS
            fly_hrs++;              // hrs increment            
            fly_min = 0;            // prepare for another count

            if( fly_hrs == 24 ){    // 24 hrs has gone -> reset all
                fly_hrs = 0;
                fly_min = 0;
                fly_sec = 0; 
                state   = STATE_IDLE;
            }
            LCD_WriteIntPos( fly_hrs, F_HRS_POS_C );                        
        }
        LCD_WriteIntPos( fly_min, F_MIN_POS_C );                
    }
    LCD_WriteIntPos( fly_sec, F_SEC_POS_C );
}    

//////////////////////////////////////////////////////////////////////

void update_mot_timer( void )            
{
    mot_sec++;                    // sec increment
    
    if( ( mot_min == 59 ) && ( mot_sec == 59 ) ){  
        mot_sec = 0;
        mot_min = 0;            
        state   = STATE_MOTOR_OFF;
    }

    else if( mot_sec == 60 ){       // 60 s has gone -> 1 MINUTES
        mot_sec = 0;                // prepare for another count
        mot_min++;                  // min increment
    }    
    LCD_WriteIntPos( mot_min, M_MIN_POS_C );    
    LCD_WriteIntPos( mot_sec, M_SEC_POS_C );
}    

//////////////////////////////////////////////////////////////////////

void print_counters(void)
{
    printf( " Lento:00:00\'00\"Moottori: 00\'00\"");           

}


//////////////////////////////////////////////////////////////////////

void print_timers(void)
{
    char j;

    print_counters();
    LCD_Command(RETURN_HOME_C);
    LCD_Write_4_Bit('0' + disp_index);

    j = fly_hrs_t[disp_index];
    LCD_WriteIntPos( j, F_HRS_POS_C );     

    j = fly_min_t[disp_index];	                   
    LCD_WriteIntPos( j, F_MIN_POS_C );   

    j = fly_sec_t[disp_index];             
    LCD_WriteIntPos( j, F_SEC_POS_C );

    j = mot_min_t[disp_index];
    LCD_WriteIntPos( j, M_MIN_POS_C );
   
    j = mot_sec_t[disp_index]; 
    LCD_WriteIntPos( j, M_SEC_POS_C );
}

//////////////////////////////////////////////////////////////////////

void timer_reset( void )             
{

    fly_hrs_t[fly_index] = fly_hrs; 
    fly_min_t[fly_index] = fly_min;
    fly_sec_t[fly_index] = fly_sec;
    mot_min_t[fly_index] = mot_min;                 
    mot_sec_t[fly_index] = mot_sec;
    
    timer   = 0;
    mot_min = 0;
    mot_sec = 0;
    fly_hrs = 0;
    fly_min = 0;
    fly_sec = 0;
    buzzer_time = 0;       
    print_counters();
}

 
//////////////////////////////////////////////////////////////////////

void interrupt( void )              // every 66ms 
{
  
    // Interrupt processing: TMR0 Overflow processing
    if( INTCON & 4 ){  
        timer++;        
        if ( timer == INTS_IN_SEC_C ){   
            timer=0;                // prepare for another count
            if ( ( state == STATE_MOTOR_ON ) || ( state == STATE_MOTOR_OFF ) ){ 
                update_fly_timer(); 
                if( state == STATE_MOTOR_ON ){
                    update_mot_timer();    
                }    
            }
        }  
        clear_bit( INTCON, T0IF );  // flag from RTCC overflow = 0 
				    // must be resetted before exiting ISR        
    }
}

//////////////////////////////////////////////////////////////////////

void ready_steady_go( void )             
{
    int i;

    LCD_Clear();	
    printf( "Lahtolaskenta:  ");
    for( i = 9 ; i > 0 ; i--){
	LCD_WriteIntPos( i, 0x8E );
	delay_s(1);

	// beep after every 2 sec
	if(( i == 2 ) || ( i == 4) || ( i == 6 )){
    		output_low_port_a( BUZZER );  
    		delay_ms( 20 );
    		output_high_port_a( BUZZER );
	}
    }	 
    print_counters();	
}

//////////////////////////////////////////////////////////////////////

void main(void) 
{
    char keys1, keys2;

    //*** First setup PIC ports and interrupts 
    
    disable_interrupt( GIE );       // Enable Global Interrupts 

    /*
     * Select Bank 1 to acess port config registers
     */
    set_bit( STATUS, RP0 );         

    /*
     * !RBPU = 1, PS2=1, PS1=1, PS0=1, pre scaler 1:256
     */	
    OPTION_REG = 0x07;		//0x87;            

    /*
     * Configuration of port A ( 1 = in, O = output )
     * RA543210
     *   000000 = 0x00
     */
    set_tris_a( PortAConfig);       // Setup port A

     /*  Configuration of port B ( 1 = in, O = output )
      *  RB76543210                              
      *    00001111 = 0x0F
      */
    set_tris_b( PortBConfig );      // Setup port B   


    clear_bit( STATUS, RP0 );       // Select Bank 0, INTCON in BANK 1
    INTCON = 160;                   // Configure the INTCON register 7.9.-03lisatty
    
    output_low_port_a( LCD_SEL );   // Disable LCD 
    enable_interrupt( T0IF );       // enable only TMR0 interrupt
          
    //*** End of PIC Setup 
    
    LCD_Setup();                    // Initialize the LCD device   
    output_low_port_a( BUZZER );    // boot procedures.....
    printf( "* Nordik timer *    ver 0.13  " );

   //kikkaile tasta eteenpain buzz_timella.....
   // buzzer_time = 2;
    delay_ms( 20 );
    output_high_port_a( BUZZER );
    delay_s( 3 );                   // ... here

    timer_reset();                  // reset timer variables and displays
    output_high_port_a( LCD_BACK_LIGHT_C );  
    state     = STATE_IDLE;
    fly_index = 0;
  
    //*** End of application setup

    while( FOREVER )                // main LOOP
    {
        keys1 = input_port_b();
        delay_ms( 20 );
        keys2 = input_port_b();
        if( keys1 == keys2 ){
            if( ! ( keys1 & 0x01 ) ){      // korjaa vakiot
                keys1 = START_KEY;
            }
            else if( ! ( keys1 & 0x02 ) ){    // korjaa vakiot
                keys1 = MOTOR_KEY;
            }
//	    output_low_port_a( BUZZER );	
            delay_ms( 250 );
//            output_high_port_a( BUZZER );            
        }
        switch ( state ){
            case STATE_IDLE:
                if( keys1 == START_KEY ){	// start the both timers
                    state = STATE_MOTOR_ON;                
                }    
                else if( keys1 == MOTOR_KEY ){	// start final countdown
		    ready_steady_go();             		
                    state = STATE_MOTOR_ON;                                
                }            
                break;
            case STATE_MOTOR_ON:
                if( keys1 == MOTOR_KEY ){	// stop motor timer
                    state = STATE_MOTOR_OFF;                
                }            
                else if( keys1 == START_KEY ){	// stop the both timers
                    state = STATE_STOP;                
                }    
                break;
            case STATE_MOTOR_OFF:
                if( keys1 == MOTOR_KEY ){	// re-start motor timer	
                    state = STATE_MOTOR_ON;                    
                }            
                else if( keys1 == START_KEY ){	// stop the both timers
                    state = STATE_STOP;                
                }    
                break;
            case STATE_STOP:			// reset timer displays 
                if( keys1 == START_KEY ){	// and variables  
                    state = STATE_IDLE;                
                    timer_reset();  
                }
		else if( keys1 == MOTOR_KEY ){	// go to list mode
                    state = STATE_LIST;
                    disp_index = 0;
                    print_timers();  			
		}
                break;
            case STATE_LIST:		
                if( keys1 == MOTOR_KEY ){	
                    state = STATE_IDLE;  
		    timer_reset();
                }            
                else if( keys1 == START_KEY ){	
                    if(++disp_index >= SAVED_RESULTS_C){
			disp_index = 0;
		    }
                    print_timers();			
                }    

                break;
        }    	
//       	if( buzzer_time-- ){      // if buzzer timer has been set
//       
//            output_low_port_a( BUZZER );
//       	}
//       	else {                  // if timer has expired
//            output_high_port_a( BUZZER );   // set buzzer off                               
//	}   
    }  
} 
  

syntax highlighted by Code2HTML, v. 0.9.1