#include <macros.h>
#include <iom128v.h>
#include <iccioavr.h>

#pragma interrupt_handler IntTimer0:iv_TIMER0_OVF

#define sbi(port,bit)	(port |=  (1<<bit))
#define cbi(port,bit)	(port &= ~(1<<bit))
#define tst(port,bit)	(port && (1<<bit))

#define XTAL 8000000 // Частота кристала, Mhz
#define CYCLES_PER_US ((XTAL+500000)/1000000)

#define Te (200) // us
#define Th ( 6000 / Te ) // Te
//#define Tg ( 8000 / Te ) // Te
#define Tg ( 10 ) // Te

#define BitPerPacket 16 // Число бит в пакете. Для отладки - 8.

#define RXDATA      PORTD0
#define RXDATA_PORT PORTD
#define RXDATA_DDR  DDRD
#define RXDATA_PIN  PIND

#define LED_DDR DDRB
#define LED_PORT PORTB

// Состояние чтения данных
#define StateWait         0
#define StatePreambleH    1
#define StatePreambleL    2
#define StateHead         3
#define StateData         4
#define StateTimeOut      5

unsigned short Timer; // Сколько микросекунд находимся в текущем состоянии

unsigned char CurrentLevel; // Текущий уровень порта ввода
unsigned char PreviousLevel; // Предыдущий уровень порта ввода

unsigned char Byte; // Прочитанный байт данных
unsigned char RunFlag = 0; // Прочитанный байт данных

unsigned char Bits[ 3 ];
unsigned char BitsIndex = 0;

// Инициализация порта входных данных
void InitRxData( void )
{
    cbi( RXDATA_DDR , RXDATA ); // Порт на вход
    cbi( RXDATA_PORT, RXDATA ); // Порт в состояние Hi-Z
}


// Инициализация порта светодиодов
void InitLed( void )
{
    LED_DDR  = 0xFF; // Порт ны выход
    LED_PORT = 0xFF; // Все диоды выключены

    DDRE = 0xFF;
    PORTE = 0x00;
}


// Инициализация таймера 1
void InitTimer0( void )
{
    CLI();         // Отключить прерывания
    Timer = 0;
    TIMSK = 0x01;  // Включить перывание таймера 0
    TCCR0 = 0x01;  // Дилитесь CK/1
    SEI();         // Включить прерывания
}

void delay_us(unsigned short time_us)
{
	unsigned short delay_loops;
	register unsigned short i;
	delay_loops = (time_us+3)/5*CYCLES_PER_US; // +3 for rounding up (dirty)

	// one loop takes 5 cpu cycles
	for (i=0; i < delay_loops; i++) {};

}

//unsigned char b1 = 0;
//unsigned char b2 = 0;
unsigned char ff = 1;

// Функция прерывания таймера
void IntTimer0(void)
{
    Timer += ( 256 * 1000000 / XTAL );

    if( Timer >= Te - ( 256 * 1000000 / XTAL ) )
    {
        Timer = 0;
        RunFlag = 1;
    }
}


int main(void)
{

    unsigned char CurrentState; // Состояние программы

    unsigned char ReceiveBitCount = 0; // Сколько принято бит
    unsigned char WidthFirst; // Длительность первой части бита
    unsigned char WidthLast;  // Длительность второй части бита



    unsigned char Counter = 0;

    CurrentState = StateWait;

    CurrentLevel  = 0;
    PreviousLevel = 0;

    // Инициализация таймера 0
    InitTimer0();

    // Инициализация порта входного сигнал
    InitRxData();

    // Инициализация порта светодиодов
    InitLed();

    //RunFlag = 0;

    while(1)
    {
        // Считываем данные с порта

        CurrentLevel = tst( RXDATA_PIN, RXDATA );

        if( CurrentLevel != PreviousLevel )
        {
            Timer = Te/2;

            //delay_us( 10 );
            //if( PreviousLevel != tst( RXDATA_PIN, RXDATA ) )
            //{
            //    Timer = Te/2;
            //    RunFlag=0;
            //}
        }


        if( RunFlag == 1 )
        {
            RunFlag = 0;

            switch( CurrentState )
            {
            // Если ждали начала передачи, пытаемся читать преамбулу
            case StateWait:
                if( CurrentLevel == 1 )
                    CurrentState = StatePreambleH;
                break;

            // Если прошел высокий уровень преамбулы, ждем нижний
            case StatePreambleH:
                //LED_PORT = ~((~LED_PORT)+1);
                if( CurrentLevel == 0 )
                    CurrentState = StatePreambleL;
                else
                    CurrentState = StateWait;
                break;

            // Если прошел нижний уровень преамбулы, ждем высокий
            case StatePreambleL:
                if( CurrentLevel == 1 )
                    CurrentState = StatePreambleH;
                else
                {
                    CurrentState = StateHead;
                    Counter = 1;
                }
                break;

            // Читаем Заголовок
            case StateHead:
                if( CurrentLevel == 0 )
                {
                    Counter++;
                }
                else if( CurrentLevel == 1 && Counter < Th )
                {
                    BitsIndex = 1;
                    ReceiveBitCount = 0;
                    Bits[ 0 ] = 1;
                    CurrentState = StateData;
                }
                else
                    CurrentState = StateWait;
                break;



            // Читаем данные
            case StateData:
                Bits[ BitsIndex++ ] = CurrentLevel;

                if( BitsIndex == 3 )
                {
                    BitsIndex = 0;

                    if( Bits[0]==1 && Bits[1]==1 && Bits[2]==0 )
                    {
                        // Приняли "0"
                        cbi( Byte, ReceiveBitCount );
                    }
                    else if( Bits[0]==1 && Bits[1]==0 && Bits[2]==0 )
                    {
                        // Приняли "1"
                        sbi( Byte, ReceiveBitCount );
                    }
                    else
                    {
                        CurrentState = StateWait;
                    }

                    if( Bits[1] == 1 )
                        cbi( Byte, ReceiveBitCount%8 );
                    else
                        sbi( Byte, ReceiveBitCount%8 );

                    ReceiveBitCount++;
                    if( ReceiveBitCount == BitPerPacket )
                    {
                        CurrentState = StateTimeOut;
                        Counter = 0;
                    }

                }
                break;

            case StateTimeOut:
                if( CurrentLevel == 0 )
                {
                    Counter++;
                    if( Counter == Tg )
                    {
                        CurrentState = StateWait;
                        LED_PORT = ~Byte;
                    }
                }
                else
                    CurrentState = StateWait;
                break;

            }
        }
        PreviousLevel = CurrentLevel;
    }

    return 0;
}
