// компилятор  IAR-AVR  : 15.03.2009 15:43:58
// Процессор : M16
// Кварц: 16.000Mhz


//подключение библиотек

#include <ioavr.h>



//переименование для удобства


#define NOP() asm("nop")//пауза в один такт
#define SEI() asm("sei")//разрешить прерывания
#define CLI() asm("cli")//запретить прерывания
#define WDR() asm("wdr")//сброс сторожевого таймера

#define START_TIMER_0            TCCR0 = 0x02
#define START_TIMER_2            TCCR2 = 0x03

#define STOP_TIMER_0             TCCR0 = 0x00
#define STOP_TIMER_2             TCCR2 = 0x00


/** пороги уровней сигнала ****/

#define HI_SIGNAL  50 //порог высокий уровень сигнала
#define MED_SIGNAL 35 //порог средний уровень сигнала
#define LOW_SIGNAL 10 //порог низкий  уровень сигнала

/*****************************/

/*** Регистры частот *********/
// рассчитаны спец программой для AT86RF211S


#define F0 0x4D3C68D2 //передача лог 1
#define F1 0xF8F4CC70 //передача лог 0
#define F2 0xD8DCFA5E //прием

/*****************************/

/** Регистр управления ******/

#define CNTRL1 0x80000220

/*************************************************************************************************************
CTRL1 Overview описание регистра управления


Название  	PDN 	RXTX  DATACLK  TXLOCK  PAPDN   WUEN   LNAGSEL  MVCC 	TRSSI 	HRSSI 
номер бита 	31 	30 	29 	28 	27 	26 	25 	24 	23-18 	17-15 
кол. бит 	0	0	0	1	0	0	0	0     (000000)2	(000)2 



Название         TXLVL 	TXFS 	-	RXFS 	XTALFQ 	FSKBW 	FSKPOL 	DSREF 	-	-   MOFFSET  ADDFEAT 
номер бита 	14-12 	11 	10 	9-8 	7	6	5	4	3	2	1	0
кол. бит 	(000)2 	0	0	(10)2 	0	1	1	1	0	0	0	0


Значение после сброса CNTRL1 = 0x10000270 

**************************************************************************************************************/

/*
433.07 Mhz dev=2.5 kHz 
F0=0x4D3C68D2
F1=0xF8F4CC70
F2=0xD8DCFA5E



433.07 Mhz dev=5 kHz 
F0=0xF8546A78
F1=0xE994EEC8
F2=0xD8DCFA5E
*/


#define SET_BIT(x,y)   (x |= y)
#define CLR_BIT(x,y)   (x &= (0xFF-y))
#define INV_BIT(x,y)   (x ^= y)

#define SIGNAL_HI_LED       SET_BIT(PORTD,0x80)
#define SIGNAL_MED_LED      SET_BIT(PORTD,0xC0)
#define SIGNAL_LOW_LED      SET_BIT(PORTD,0x40)
#define SIGNAL_OFF_LED      CLR_BIT(PORTD,0xC0)

#define RESIVE_LED_ON       SET_BIT(PORTC,0x02)
#define TRANSIVE_LED_ON     SET_BIT(PORTC,0x01)
#define TRANSIVE_LED_INV    INV_BIT(PORTC,0x01)
#define RX_TX_LEDS_OFF      CLR_BIT(PORTC,0x03)

#define RF_SETTINGS_LED_OK        SET_BIT(PORTC,0x04)
#define RF_SETTINGS_LED_FAIL      CLR_BIT(PORTC,0x04)


/*** режимы приема  ***/

#define pream  1 //ловим заголовок
#define packet 0 //принимаем пакет                        

/*********************/

#define SLE_1            (PORTC|=0x40)
#define SLE_0            (PORTC &= (0xFF - 0x40))
#define SCK_1            (PORTC|=0x08)
#define SCK_0            (PORTC &= (0xFF-0x08))
#define SDATA_1          (PORTC|=0x10)
#define SDATA_0          (PORTC &= (0xFF-0x10))
#define SDATA_IN         ((PINC&0x10)>>4)
#define READ_DATA        (DDRC  &= (0xFF-0x10))
#define WRITE_DATA       (DDRC |= 0x10)
#define SEND             (DDRC |= 0x20) 
#define GET              (DDRC &= (0xFF-0x20))
#define DMSG_1           (PORTC |=0x20)
#define DMSG_INV         (PORTC ^=0x20)
#define DMSG_0           (PORTC  &=(0xFF-0x20))



//декларирование подпрограмм
 
void WRITE_RF(char adr,unsigned long write);// запись настроек в регистры AT86RF211S


// таблицы для быстрого расчета контрольной суммы CRC16 полином 0xA001

__flash unsigned char srCRCHi[]={
         0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
         0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
         0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
         0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
         0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
         0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
         0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
         0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
         0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
         0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
         0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
         0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
         0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
         0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
         0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
         0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
         0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
         0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
         0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
         0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
         0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
         0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
         0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
         0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
         0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
         0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
};
__flash unsigned char srCRCLo[]={
         0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
         0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
         0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
         0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
         0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
         0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
         0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
         0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
         0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
         0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
         0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
         0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
         0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
         0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
         0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
         0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
         0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
         0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
         0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
         0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
         0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
         0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
         0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
         0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
         0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
         0x43, 0x83, 0x41, 0x81, 0x80, 0x40
};

/************ Объявление глобальных переменных ********************************/

unsigned char s1;         //переменная для избежания ложной синхронизации 0-1
unsigned char s0;         //переменная для избежания ложной синхронизации 1-0

unsigned char cnt_bit0;   //счетчик количества лог.нулей в бите
unsigned char cnt_bit1;   //счетчик количества лог.еденичек в бите
unsigned char bit_cnt;    //счетчик количества бит

unsigned char stat;       //режимы работы, прием заголовка или данных пакета
unsigned char buff[16];   //буффер хранения принятых байт
unsigned char cnt;        //счетчик количества байт
unsigned char byte_cnt;   // количество байт
unsigned char b1;         //просто переменная
unsigned char signal;     //уровень сигнала 0-63
unsigned char off;        // переменная для задержки выключения светодиода 
unsigned char off2;       // переменная для задержки выключения светодиода
unsigned long PREAMBULE;  //переменнная в 32 бит, для работы с заголовком пакета

/******************************************************************************/



/****** прерывание по переполнению таймера_0 **/

#pragma vector = TIMER0_OVF_vect
__interrupt void Timer0_Ovf (void)
  {

    char temp_1,temp_0,temp_s0,temp_s1;// локальные переменные

    TCNT0 = 0xF4; 

    temp_1 = cnt_bit1;

    temp_0 = cnt_bit0;

    temp_s0 = s0;

    temp_s1 = s1;

/****** подсчет лог единичек нулей в бите, синхронизация по перепаду ***********/    
 
    if (PINC&0x20) 
 
    {
   
      if ((temp_0>29)&&(temp_s1>9))temp_s1=0,TCNT2 = 0xFE; 
 
      temp_1++;
    
      temp_s1++;
       
      s0=0;
 
    }

    else
 
    {
   
      if ((temp_1>29)&&(temp_s0>9))temp_s0=0,TCNT2 = 0xFE;
  
      temp_0++;
   
      temp_s0++;
   
      s1=0;
    }
  
    cnt_bit1 =temp_1;
  
    cnt_bit0 =temp_0;
 
    s0 = temp_s0;
 
    s1 = temp_s1;
 
 
  }
/**********************************************/ 




/****** прерывание по переполнению таймера_2 **/

#pragma vector = TIMER2_OVF_vect 
__interrupt void Timer2_Ovf (void)
   {

     char inbit=0;
     TCNT0 = 0xF5; 
     TCNT2 = 0x2A;


     if (cnt_bit1>cnt_bit0) inbit=1;


     cnt_bit1 = 0;

     cnt_bit0 = 0;

     off2++;

     off++;


    if (stat)                //если статус преамбула 
                        { 
  
                          PREAMBULE  = (PREAMBULE  << 1) | inbit;


                          if (PREAMBULE == 0xA9696AAA) // ловим заголовок

                                                    {// поймали


                                                      cnt=0;

                                                      byte_cnt=10;

                                                      bit_cnt=0;

                                                      b1=0;

                                                      stat=packet;

                                                      off2=1;

                                                      char i;

                                                      char sig=0;

/********************************** получение уровня принимаемого сигнала *****/
                                                      
                                                      DDRC  |= 0x58;

                                                      WRITE_DATA;

                                                      SLE_1;

                                                      NOP();

                                                      SCK_0;

                                                      NOP();

                                                      SLE_0;

                                                      NOP();

                                                      SDATA_0;

                                                      NOP();

                                                      SCK_1;

                                                      NOP();

                                                      SCK_0;

                                                      NOP();

                                                      SDATA_1;

                                                      NOP();

                                                      SCK_1;

                                                      NOP();

                                                      SCK_0;

                                                      NOP();

                                                      SDATA_0;

                                                      NOP();

                                                      SCK_1;

                                                      NOP();

                                                      SCK_0;

                                                      NOP();

                                                      SDATA_1;

                                                      NOP();

                                                      SCK_1;

                                                      NOP();

                                                      SCK_0;
                                                      
                                                      NOP();

                                                      SDATA_0;

                                                      NOP();

                                                      SCK_1;

                                                      SDATA_0;

                                                      NOP();

                                                      SCK_0;

                                                      NOP();

                                                      READ_DATA;

                                                      SCK_0;

                                                      NOP();

                                                      SCK_1;

                                                      NOP();

                                                      SCK_0;

                                                      NOP();

                                                      SCK_1;


                                                      for (i=0;i<6;i++)

                                                      {

                                                        NOP();

                                                        sig<<=1;

                                                        sig|=SDATA_IN;

                                                        SCK_0;

                                                        NOP();

                                                        SCK_1;

                                                      }

                                                      NOP();

                                                      SLE_1;


                                                      signal=sig;


/******************************************************************************/
                                                    }

                        }

           else // иначе принимаем пакет
                {
                if (b1) 
                      {
                        buff[cnt] <<= 1;
                        buff[cnt] |= inbit;
                        b1=0;
                      }
                else b1=1;

                bit_cnt++;
                if (bit_cnt==16)
                                {
                                  bit_cnt=0;
                                  cnt++;
                                  
                                  if (cnt==1)
                                            {

                                              byte_cnt=(buff[1]);
                                              
                                              if (byte_cnt>2) 
                                                              {

                                                              stat=pream; 
                                                              return;

                                                              }

                                            }



                                }


             


}

}
/**********************************************/


/*******  Основная программа       ***********/
void main(void)
{ 
  /** объявление локальных переменных  **/
  char CRC_Low;     
  char CRC_High ;
  char k;
  char carry;
  /**************************************/
  
  CLI();             // запрет всех прерываний
  DDRD |= 0xC3;      // установка заданных пинов порта Д на выход 1100 0011
  DDRC |= 0x07;      // установка заданных пинов порта С на выход 0000 0111
  
  WRITE_RF(11,0);    // reset AT86RF211S
  WRITE_RF(0,F0);    // write F0 in AT86RF211S adres 0 register F0
  WRITE_RF(1,F1);    // write F1 in AT86RF211S adres 1 register F1
  WRITE_RF(2,F2);    // write F2 in AT86RF211S adres 2 register F2
  WRITE_RF(4,CNTRL1);// write CNTRL1 in AT86RF211S adres 4(control register)
  
  GET;               // переключить пин на вход для приема
  stat=pream;        //режим приема (прием заголовка)
  START_TIMER_0;     // настройка предделителя таймера 0 запуск
  START_TIMER_2;     // настройка предделителя таймера 2 запуск
  TIMSK = 0x41;      //Регистр масок прерываний таймера/счетчика
  SEI();             //установить флаг глобального прерывания разрешить прерывания
  WDR();             //сброс сторожевого таймера
  WDTCR = 0x0E;      //включение сторожевого таймера
 
  while(1)// основной цикл 
        {
 
 
          if (cnt>=byte_cnt+4) // если количество принятых байт больше или равно указанному в пакете

          {
            STOP_TIMER_0; // остовить таймер 0
           
            STOP_TIMER_2; // остовить таймер 1
           
            cnt=0;        // очистить счетчик принятых байт

            WDR();        // сбросить сторожевой таймер

            CRC_Low = 0xFF; // записать в переменную 255
 
            CRC_High = 0xFF;// записать в переменную 255

    
            for (k=1; k < (byte_cnt+2); k++) // выполнить подсчет контрольной суммы пакета CRC16
   
            {
    
              carry = CRC_Low ^ buff[k];
    
              CRC_Low = CRC_High ^ srCRCHi[carry]; //srCRCHi[carry] берется из таблицы с верху
    
              CRC_High = srCRCLo[carry]; //srCRCHi[carry] берется из таблицы с верху
   
            };
  

            if ((buff[byte_cnt+2]==CRC_Low) && (buff[byte_cnt+3]==CRC_High))// сравнить CRC16 расчетное с принятым в пакете

            { // контрольная сумма совпала
 
              PORTD = buff[2]<<1; // сдвинуть на один бит полученный байт и записать его в регистр порта Д

              RESIVE_LED_ON;   // Включить светодиод приема

              off=1;           // записать 1 в переменную задержки выключения светодиода

              if (buff[2]) RF_SETTINGS_LED_FAIL;else RF_SETTINGS_LED_OK       ; // состояние принятого байта отобразить на светодиоде

            } 

            if(signal>LOW_SIGNAL) // индикация уровня принимаемого сигнала три цвета

            {

              SIGNAL_LOW_LED; // красный слабый

              off2=1; // взаписать 1 в переменную задержки выключения светодиодов 

            }

            if(signal>MED_SIGNAL)

            {

              SIGNAL_MED_LED; // красный + зеленый = желтый средний

            }

            if(signal>HI_SIGNAL)

            {

              SIGNAL_OFF_LED; // выключить красный + зеленый

              SIGNAL_HI_LED; // включить зеленый сильный

            }


            stat=pream;     // режим приемника ловим загаловок 

            START_TIMER_0;
            
            START_TIMER_2;


          }
   
 

          if (!off2) // если переменная задержки равна 0

          {

            SIGNAL_OFF_LED;

            signal=0;

            RX_TX_LEDS_OFF;

          }

          if(!off) RX_TX_LEDS_OFF;

        
        }
 
 
}

/**********************************************/


/************* запись значений  регистры радиомодуля *************************/
void WRITE_RF(char adr,unsigned long write) // адрес, значение
    {
      char i;// локальная переменная
      DDRC  |= 0x58; 
      WRITE_DATA; 
      SLE_1; 
      NOP(); 
      SCK_0; 
      SDATA_0; 
      SLE_0; 
      NOP(); 
      for(i=0;i<4;i++)    
      {     
       SCK_0;     
       NOP();      
       if (adr & 0x08) SDATA_1; else SDATA_0;      
       adr<<=1;      
       NOP();      
       SCK_1;      
       NOP();    
      } 
      SCK_0; 
      NOP();
      SDATA_1;
      NOP();
      SCK_1;
      NOP();
      SDATA_1;
      NOP();
      SCK_1;
      NOP();
      SCK_0;
      for(i=0;i<32;i++)
          {
           NOP();
           if ( write & 0x80000000 ) SDATA_1; else SDATA_0;
           write<<=1;          
           NOP();          
           SCK_1;          
           NOP();
           SCK_0;
          }
      NOP();
      SDATA_0;
      SLE_1;
    }











