/*

 +-------------------------------------+
 |                          Sig Vd Gnd |
 |  +---------+   5V o     PB0 [o o o] |
 |  | 7805  O |   Vd o     PB1 [o o o] |
 |  +---------+   V+ o     PB2 [o o o] |
 |                         PB3 [o o o] |
 |                         PB4 [o o o] |
 |                         PB5 [o o o] |
 |                         PB6 [o o o] |
 |                         PB7 [o o o] |
 |                         PA0 [o o o] |
 |                         PA1 [o o o] |
 |        +----------+     PA2 [o o o] |
 |        |O         |     PA3 [o o o] |
 |        |          |     PA4 [o o o] |
 |        |          |     PA5 [o o o] |
 |        |          |     PA6 [o o o] |
 |        |          |     PA7 [o o o] |
 |        |          |     PC7 [o o o] |
 |        |          |     PC6 [o o o] |
 |        |          |     PC5 [o o o] |
 |        | ATMEGA32 |     PC4 [o o o] |
 |        |          |     PC3 [o o o] |
 |        |          |     PC2 [o o o] |
 |        |          |     PC1 [o o o] |
 |        |          |     PC0 [o o o] |
 |        |          |     PD7 [o o o] |
 |        |          |     PD2 [o o o] |
 |        |          |     PD3 [o o o] |
 |        |          |     PD4 [o o o] |
 |        |          |     PD5 [o o o] |
 |        +----------+     PD6 [o o o] |
 |      E.D.S BABYBOARD III            |
 +-------------------------------------+


*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>


#define IsHigh(BIT, PORT)    ((PORT & (1<<BIT)) != 0)
#define IsLow(BIT, PORT)     ((PORT & (1<<BIT)) == 0)
#define SetBit(BIT, PORT)     PORT |= (1<<BIT)
#define ClearBit(BIT, PORT)   PORT &= ~(1<<BIT)

#define OUTPUT   1
#define INPUT    0

#define PWM1BIT  0
#define PWM2BIT  1
#define PWM3BIT  2
#define PWM4BIT  3

#define PWM1PORT PORTB
#define PWM2PORT PORTB
#define PWM3PORT PORTB
#define PWM4PORT PORTB
/*****************************| VARIABLES |********************************/
 
volatile int AdcValues[8];
unsigned char pwmcount;
volatile unsigned char pwm1, pwm2, pwm3, pwm4;
 
/************************| FUNCTION DECLARATIONS |*************************/
 
void timerInit(void);
void AnalogInit (void);
int Analog (int n);

/****************************| CODE... |***********************************/

int main (void) {

  // set up directions 
  DDRA = (INPUT << PA0 | INPUT << PA1 |INPUT << PA2 |INPUT << PA3 |INPUT << PA4 |INPUT << PA5 |INPUT << PA6 |INPUT << PA7);
  DDRB = (OUTPUT << PB0 | OUTPUT << PB1 |OUTPUT << PB2 |OUTPUT << PB3 |INPUT << PB4 |INPUT << PB5 |INPUT << PB6 |INPUT << PB7);
  DDRC = (INPUT << PC0 | INPUT << PC1 |INPUT << PC2 |INPUT << PC3 |INPUT << PC4 |INPUT << PC5 |INPUT << PC6 |INPUT << PC7);
  DDRD = (INPUT << PD0 | INPUT << PD1 |INPUT << PD2 |INPUT << PD3 |INPUT << PD4 |INPUT << PD5 |INPUT << PD6 |INPUT << PD7);        

  pwm1 = 64;
  pwm2 = 0;
  pwm3 = 0;
  pwm4 = 0;
  
  AnalogInit();
  timerInit();
  
  // turn interrupts on
  sei();
  
  // chase tail
  while(1){
    pwm1 = AdcValues[0]/4;
  }

}

//------------------------| FUNCTIONS |------------------------

/*********************************************************
  !!!!!!!!! SEVERLY OPTIMIZED CODE  !!!!!!!!!
   REFERNENCE ASSEMBLER OUTPUT WHEN MODIFYING
               THIS PWM FUNCTION
                    gcc -O1
**********************************************************/
SIGNAL (SIG_OVERFLOW0) {
 if (++pwmcount == 0){
  SetBit(PWM1BIT, PWM1PORT);
  SetBit(PWM2BIT, PWM2PORT);
  SetBit(PWM3BIT, PWM3PORT);
  SetBit(PWM4BIT, PWM4PORT);
 };

 if ((pwm1 ^ pwmcount) == 0) { ClearBit(PWM1BIT, PWM1PORT); }
 if ((pwm2 ^ pwmcount) == 0) { ClearBit(PWM2BIT, PWM2PORT); }
 if ((pwm3 ^ pwmcount) == 0) { ClearBit(PWM3BIT, PWM3PORT); }
 if ((pwm4 ^ pwmcount) == 0) { ClearBit(PWM4BIT, PWM4PORT); }
 
}

void timerInit(void) {

  // set prescaler to /1
  TCCR0 = (0 << FOC0 | 0 << WGM00 |0 << COM01 |0 << COM00 |0 << WGM01 |0 << CS02 |0 << CS01 |1 << CS00);
  
  // set interrupt mask register 
  TIMSK |= (1<<TOIE0);  

}

void AnalogInit (void) {

  int i;

  // Activate ADC with Prescaler 
  ADCSRA =  1 << ADEN  |
            1 << ADSC  | /* start a converstion, irq will take from here */
            0 << ADATE |
            0 << ADIF  |
            1 << ADIE  | /* enable interrupt */
            1 << ADPS2 |
            0 << ADPS1 |
            0 << ADPS0 ;
                        
            
  for (i = 0; i < 8; AdcValues[i++] = 0);
  
}

int Analog (int n) {
  return AdcValues[n & 7];
}

SIGNAL(SIG_ADC) {
  int i;
  
  i = ADMUX & 7;       // what channel we on?
  AdcValues[i] = ADC;  // save value
  i++;                 // next value
  ADMUX = i & 7;       // select channel
  ADCSRA |= _BV(ADSC); // start next conversion
  return;
}


