/*********************************** MODULE INFO ****************************
	   
   Device       : AT90S4433

   File name    : BC.c

   Ver nr.      : 1.1 

   Description  : Standalone Battery Charger with AT90S4433 (main program)
                 
   Compiler    : GCC 3
   
   Author      : Asmund Saetre / Terje Frostad / Dietmar Koenig
                 Modified for GCC by Don Carveth 
  
   Change log   : 02.02.2000 Changed to fit Battery Charger refrence 
                  design board   AS  
                  18.02.2000 Final test and review AS                  

****************************************************************************/
#include "BC.H"
#include "StdDefs.h"
#include "LiIon.h"
#include "SBComm.h" 

time_struct time;                         //Globale struct

void Setup(void)
{
// definition of PWM, Ports, UART and Real-Time-Clock
  
  TCCR1A  = 0x81;         // define timer1 as 8-bit PWM  
  TIFR    = 0x80;         // clear counter1 overflow flag  
  TIMSK   = 0x00;         // enable counter1 overflow interrupt
  TCNT1   = 0x00;         // set counter1 to zero      
  TCCR1B  = 0x00;         // PWM disabLED
  
  TCCR0 = 0x05;           // Timer0 enabled, divide by 1024
  sbi(TIMSK, 0);          // Enable TCNT0 TOF interrupt

  PORTC   = 0x01;         // Prepare Port C as analog input
  DDRC    = 0x00;         // with no pull-ups, except PC0
  
  PORTB   = 0xFF;         // Turn off Leds on Port B, PWM off
  DDRB    = 0x0F;         // Set PORTB as output, 4,5 as input                    

  PORTD   = 0xFF;         // Turn on internal pull-ups for PORTD 
  
  ADCSR   = 0x96;         // Single A/D conversion, fCK/64 

  CHARGE_STATUS = 0x00;
  
  time.sec = 0x00;
  time.min = 0x00;
  time.hour = 0x00;
  time.t_count = 27;
  
  UART_CONTROL_REG = 0x08;   //Transmitter enabled, receiver disabled, no interrupts
  setbaud(BAUD115K);
  
  if (I2cInit()) putchar('E'); else putchar ('G'); 
  
  sei();               // global interrupt enable        
}

void Stop_PWM(void)                         // Stops the PWM in off pos.
{
  if ((TERMINATION == 0x00)&&(TCCR1B & (1<<CS10))&&(OC_REG_1 != 0))
  {
    if (OC_REG_1 == 1)
    {
      while(TCNT1 > 2);                     // Wait for PWM == 1
      while(TCNT1 < 2);                     // Wait for PWM == 0  
    }
    else
    {
      while(TCNT1 > OC_REG_1);                  // Wait for PWM == 1
      while(OC_REG_1 > TCNT1);                  // Wait for PWM == 0  
    }
    TCCR1B = 0x00;                          // Turn PWM off 
  }
}    

void Stable_ADC(void)                     // loop until you have a stable value
{ 
  int V[4];
  unsigned char i;
  int Vmax, Vmin;
  
    //Loop until the ADC value is stable. (Vmax <= (Vmin+1))
    for (Vmax=10,Vmin= 0;Vmax <= (Vmin+1);)
    {
        V[3] = V[2];
        V[2] = V[1];
        V[1] = V[0];
        ADCSR |= 0x40;                      // Start a new A/D conversion
        while (!(ADCSR & (1<<ADIF)))        // wait until ADC is ready      
            ;
        V[0] = ADC;
        Vmin = V[0];                          // Vmin is the lower VOLTAGE
        Vmax = V[0];                          // Vmax is the higher VOLTAGE  
        /*Save the max and min voltage*/
        for (i=0;i<=3;i++)
        { 
            if (V[i] > Vmax)
                Vmax=V[i];
            if (V[i] < Vmin)
              Vmin=V[i];  
        }
    }
}

int Battery(unsigned char value)
{
  char i;
  int av;

  switch (value)
  {
    case VOLTAGE_WITH_PWM_TURNOFF: 
        /*Stop PWM and select ADMUX ch. VOLTAGE_WITH_PWM_TURNOFF for battery
        voltage measurement. Wait until ADC value is stable*/   
        Stop_PWM();
        ADMUX = VBAT2;
        Stable_ADC();
        break;   
    case TEMPERATURE:
        /*Stop PWM and select ADMUX ch. TEMPERATURE for temperature 
        measurement. Wait until ADC value is stable*/   
        Stop_PWM();
        ADMUX = TBAT2;
        Stable_ADC();
        break; 
    case VOLTAGE: 
        /*Stop PWM and select ADMUX ch. VOLTAGE for charge voltage 
        measurement.*/   
        ADMUX = VBAT2;
        break;   
    case CURRENT: 
        /*Stop PWM and select ADMUX ch. CURRENT for charge current 
        measurement.*/   
        ADMUX = IBAT2;
        break;
   }  

    //Calculate a average out of the next 8 A/D conversions
    for(av=0,i=8;i;--i)
    {
        ADCSR |= 0x40;                      // start new A/D conversion
        while (!(ADCSR & (1<<ADIF)))        // wait until ADC is ready
            ;      
        av = av+ADC;
    }
    av = av/8;

    TCCR1B = 0x01;                          // turn on PWM
    CLRBIT(ADCSR,ADIF);                     // clear ADC interrupt flag

    return(av);  
}

int main(void)
{
    Setup();

    for (;;)
    {
    // To converse with a Smart Battery without charging, comment out the 
    // meat of this routine and uncomment the next few lines
/*    GetSmartBattery();
    CRLF();
    PrintSmartBattery();
    msleep(10000);
    run_led(1,1);  */
     
        //Makes the charger start in FAST mode every time and clear 
        //TERMINATION indication before starting new charge
        SETBIT(CHARGE_STATUS,FAST);
        TERMINATION = 0x00;
        
        SETBIT(PORTB,(LED0+LED1));// Turn all LEDs off    
    
        while (!(CHKBIT(CHARGE_STATUS,ERROR)))
        {
            if ((CHKBIT(CHARGE_STATUS,FAST)) && (!(CHKBIT(CHARGE_STATUS,ERROR))))
            {
                //Turn only LED0 on, LED0 indicates "FAST Charge" 
                //Enter FAST_charge function which handles the fast  
                //charge algorithme. When returning send a state change message 
                //throug the UART
                SETBIT(PORTB,(LED0+LED1));
                CLRBIT(PORTB,(LED0));
                TERMINATION = 0x00;
                CHARGE_STATUS = 0x00;
                FAST_charge();
            }                    
            if ((CHKBIT(CHARGE_STATUS,TRICKLE)) && (!(CHKBIT(CHARGE_STATUS,ERROR))))
            {
                //Turn only LED1 on, LED1 indicates "TRICKLE Charge" 
                //Enter TRICKLE_charge function which handles the trickle 
                //charge algorithme. When returning send a state change message 
                //throug the UART
                SETBIT(PORTB,(LED0+LED1));
                CLRBIT(PORTB,(LED1));
                TERMINATION = 0x00;
                CHARGE_STATUS = 0x00;
                //TRICKLE_charge();
                //FAST_charge();
            }
            RUNLED_OFF();  // Actually Run LED on since outputs wired as sinks.
            return 0;
        }
        
        if (CHKBIT(CHARGE_STATUS,ERROR))
        {
            //Turn only LED2 on, LED2 indicates "ERROR". 
            //Enter a eternal loop and no ERROR recovery except "reset-button"
            //is possible
            SETBIT(PORTB,(LED0+LED1));
            LED_ERR_ON();
            for(;;);
        }   
    } 
}

SIGNAL (SIG_OVERFLOW0)
{  
  if (0x0000 == --time.t_count)
  {     
    if ( 60 == ++time.sec )
    {
      if ( 60 == ++time.min )
      {
        if ( 24 == ++time.hour )
        {
         time.hour = 0x00;
        }
        time.min = 0x00;
      }
      time.sec = 0x00;       
    }
     
    time.t_count = 27;
    // Testing
/*    if (time.sec % 2)
       CLRBIT(PORTB,(LED1));		// red LED1 on every odd sec
    else 
    	SETBIT(PORTB,(LED1));		// red LED1 off every even sec
*/
             
  }
}



// ************************[ End of BC.C ]*******************************

