#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h> // itoa()

// ggf. Ausgabe an PD5 und PD6
// für Logikanalysator
// #define DEBUG

/***************************/
/**** TARGET = ATMEGA32 ****/
/***************************/
#if defined(__AVR_ATmega32__)

#define F_CPU 1000000L

#define DISABLE_INT0()    do { \
                            GICR &= ~(1<<INT0); \
                          } while(0)

#define ENABLE_INT0()     do { \
                            GIFR |= (1<<INTF0); \
                            GICR |= (1<<INT0); \
                          } while(0)

#define INIT_TIMER_CTC()   do { \
                            /* Prescaler 1 @ 1 MHz */ \
                            TCCR0 |= (1<<CS00); \
                            OCR0 = 127-1; /* 127 µs, Start bei 0 */ \
                            TCCR0 |= (1<<WGM01); \
                          } while(0)

#define ENABLE_TIMER0()  do { \
                            TCNT0 = 0; \
                            TIMSK |= (1<<OCIE0); \
                          } while(0)

#define DISABLE_TIMER0() do { \
                            TIMSK &= ~(1<<OCIE0); \
                          } while(0)

#define TIMER0_COMP_VECT  TIMER0_COMP_vect 

#endif /* defined(__AVR_ATmega32__) */

/*****************************/
/**** TARGET = ATTINY2313 ****/
/*****************************/
#if defined(__AVR_ATtiny2313__)

#define DISABLE_INT0()    do { \
                            GIMSK &= ~(1<<INT0); \
                          } while(0)

#define ENABLE_INT0()     do { \
                            EIFR |= (1<<INTF0); \
                            GIMSK |= (1<<INT0); \
                          } while(0)

#define INIT_TIMER_CTC()   do { \
                            /* Prescaler 8 @ 8 MHz */ \
                            TCCR0B |= (1<<CS01); \
                            OCR0A = 127-1; /* 127 µs, Start bei 0 */ \
                            TCCR0A |= (1<<WGM01); \
                          } while(0)

#define ENABLE_TIMER0()  do { \
                            TCNT0 = 0; \
                            TIMSK |= (1<<OCIE0A); \
                          } while(0)

#define DISABLE_TIMER0() do { \
                            TIMSK &= ~(1<<OCIE0A); \
                          } while(0)

#define TIMER0_COMP_VECT  TIMER0_COMPA_vect

#endif /* defined(__AVR_ATtiny2313__) */

#define NUM_RC5_BITS 14

volatile unsigned char wartezeit;
volatile unsigned char anzahl_bits;
unsigned char code_B[NUM_RC5_BITS];

static void code_ausgeben(void);

int main(void) 
{
  // PD2 auf Port D Eingang
  DDRD &= ~(1<<PD2);

#ifdef DEBUG
  DDRD |= (1<<PD5) | (1<<PD6);
#endif /* DEBUG */

  // INT0 auf fallende Flanke
  MCUCR |= (1<<ISC01);
  ENABLE_INT0();

  // Timer0 im CTC-Modus betreiben
  INIT_TIMER_CTC();

  sei();
  
  while(1)
  {
    if(anzahl_bits == NUM_RC5_BITS) // 14 Bits empfangen?
    {
      DISABLE_TIMER0();
      code_ausgeben();
      anzahl_bits = 0;
      ENABLE_INT0();
    }
  }
}


ISR(TIMER0_COMP_VECT) 
{
#ifdef DEBUG
  PORTD ^= (1<<PD5);
#endif /* DEBUG */

  wartezeit++;

  if(wartezeit == 14) // 1 Bit = 14 * 127 µs gewartet?
  {
    wartezeit = 0;

    if (anzahl_bits < NUM_RC5_BITS)
    {
#ifdef DEBUG
      PORTD |= (1<<PD6);
#endif /* DEBUG */
      // 2. bis 14. Bit pollen
      code_B[anzahl_bits] = (PIND & (1<<PD2)); // Bit pollen
      anzahl_bits += 1;
#ifdef DEBUG
      PORTD &= ~(1<<PD6);
#endif /* DEBUG */
    }
  }
}


ISR(INT0_vect) 
{
  DISABLE_INT0();
  // Pollen in ca. der Mitte des Halbbits
  wartezeit = 2; 
  ENABLE_TIMER0();
 
#ifdef DEBUG
  PORTD |= (1<<PD5);
#endif /* DEBUG */

  // 1. Bit ist bekannt (HIGH)
  code_B[0] = (1<<PD2); 
  anzahl_bits = 1;

#ifdef DEBUG
  PORTD &= ~(1<<PD5);
#endif /* DEBUG */
}


void uart_init(void)
{
#if defined(__AVR_ATmega32__)
  /*******************************/
  //*        2400, 8N1           */
  /*******************************/
  UBRRH = (uint8_t) ((F_CPU / (16 * 2400L) - 1) >> 8);
  UBRRL = (uint8_t)  (F_CPU / (16 * 2400L) - 1);
  UCSRB = (1<<RXEN) | (1<<TXEN);
  UCSRC = ((1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0)); // 8N1
#endif /* defined(__AVR_ATmega32__) */

#if defined(__AVR_ATtiny2313__)
  /*******************************/
  //*        9600, 8N1           */
  /*******************************/
  UBRRH = (uint8_t) ((F_CPU / (16 * 9600L) - 1) >> 8);
  UBRRL = (uint8_t)  (F_CPU / (16 * 9600L) - 1);
  UCSRB = (1<<RXEN) | (1<<TXEN);
  UCSRC = ((1<<UCSZ1) | (1<<UCSZ0)); // 8N1
#endif /* defined(__AVR_ATtiny2313__) */
}


int uart_putchar( char c )
{
  if( c == '\n' )
    uart_putchar( '\r' );
  loop_until_bit_is_set( UCSRA, UDRE );
  UDR = c;
  return 0;
}


void uart_puts(char *s)
{
  while(*s)
    uart_putchar(*s++);
}


static void code_ausgeben(void)
{
  char buffer[20];
  uint16_t code = 0;
  uint8_t i;

  uart_init();

  // Sk T AAAAA KKKKKK

  // Ausgabe BINÄR
  for(i = 0; i < NUM_RC5_BITS; i++)
  {
    code <<= 1;
    code |= (code_B[i]>>PD2); 
    uart_putchar((code & 1) + '0');
    if (i == 1 || i == 2 || i == 7)
      uart_putchar( ' ' );
  }
  uart_puts( "\n\r" );

  // Ausgabe DEZIMAL
  uart_puts( " s=" );
  uart_putchar(( code >> 12 & 1) + '0');	// 2. Startbit
  uart_puts( " T=" );
  uart_putchar(( code >> 11 & 1) + '0');	// Togglebit
  uart_puts( " A=" );
  itoa((code >> 6) & 0x1F, buffer, 10);	  // Adresse
  uart_puts( buffer );
  uart_puts( "   K=" );
  itoa((code & 0x3F) | (((~code)>>12) & 0x40), buffer, 10); // Kommando
  uart_puts( buffer );
  uart_puts( "\n\r" );
}
