
#include <iocan128.h>

#define ID_RX 0x301
#define ID_TX 0x351
#define StdID 0x00
#define ExtID 0x01
#define UseID ExtID
#define TX_DATA_LEN 3
#define RX_DATA_LEN 3




#define CAN_NO_WR_MAX 5000 //5 sek
int CAN_NO_WR = CAN_NO_WR_MAX;

unsigned int LED1_CNT = 0, LED1_CNT_MAX = 1000;

#define LED1 PORTE_PORTE2

#define LEDC1 PORTB_PORTB2
#define LEDC2 PORTB_PORTB3

#define J6 PORTD_PORTD7
#define J5 PORTB_PORTB4
#define eWDR PORTE_PORTE5

#define CAN_TX PORTD_PORTD5

void Set_ID (unsigned long int ID, char ID29)
{
  unsigned char r;
  if (!ID29)
  {
    CANIDT4 = 0;
    CANIDT3 = 0;
    r = (unsigned char) ID;
    r = r<<5;
    ID = ID>>3;
    CANIDT2 = r;
    r = (unsigned char) ID;
    CANIDT1 = r;
  }
  else
  {
    r = (unsigned char) ID;
    r = r<<3;
    ID = ID>>5;
    CANIDT4 = r;
    r = (unsigned char) ID;
    ID = ID>>8;
    CANIDT3 = r;
    r = (unsigned char) ID;
    ID = ID>>8;
    CANIDT2 = r;
    r = (unsigned char) ID;
    CANIDT1 = r;
  }
}

void Set_Mask (unsigned long int Mask, char ID29)
{
  unsigned char r;
  if (!ID29)
  {
    CANIDM4 = 0;
    CANIDM3 = 0;
    r = (unsigned char) Mask;
    r = r<<5;
    Mask = Mask>>3;
    CANIDM2 = r;
    r = (unsigned char) Mask;
    CANIDM1 = r;
  }
  else
  {
    r = (unsigned char) Mask;
    r = r<<3;
    Mask = Mask>>5;
    CANIDM4 = r;
    r = (unsigned char) Mask;
    Mask = Mask>>8;
    CANIDM3 = r;
    r = (unsigned char) Mask;
    Mask = Mask>>8;
    CANIDM2 = r;
    r = (unsigned char) Mask;
    CANIDM1 = r;
  }
}


char DO[24] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
char CAN_DO[3] = {0,0,0};

void InitPorts (void)
{
// Input/Output Ports initialization
// Port A initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTA=0x00;
DDRA=0x00;

// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0x00;
DDRB=0x1C;

// Port C initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=In Func2=In Func1=In Func0=In
// State7=0 State6=0 State5=0 State4=0 State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;

// Port D initialization
// Func7=In Func6=In Func5=Out Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=0 State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0xA0;

// Port E initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTE=0x00;
DDRE=0x24;

// Port F initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTF=0x00;
DDRF=0x00;

// Port G initialization
// Func4=In Func3=In Func2=In Func1=In Func0=In
// State4=T State3=T State2=T State1=T State0=T
PORTG=0x00;
DDRG=0x00;
}
//=============================================================================
//                                  TIMERS
//=============================================================================
void InitTimers (void)
{


//*****************************************************
//Т2 Задает основной цикл 
//TIMER2 initialize - prescale:128
// WGM: Normal
// desired value: 1mSec

  ASSR=0x00;
  TCCR2A=0x05;
  TCNT2=0x82;

//*****************************************************

  // Timer/Counter 0 Interrupt(s) initialization
  TIMSK0=0x00;
  // Timer/Counter 1 Interrupt(s) initialization
  TIMSK1=0x00;
  // Timer/Counter 2 Interrupt(s) initialization
  TIMSK2=0x01;
  // Timer/Counter 3 Interrupt(s) initialization
  TIMSK3=0x00;
}
//=============================================================================
//                                  INT
//=============================================================================
void InitInt (void)
{
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
// INT3: Off
// INT4: Off
// INT5: Off
// INT6: Off
// INT7: Off
EICRA=0x00;
EICRB=0x00;
EIMSK=0x00;
EIFR=0x00;
}

unsigned char flag_kvant=0;

#pragma vector = TIMER2_OVF_vect
__interrupt void timer2_ovf_isr(void)
{
 TCNT2 = 0x82; //reload counter value
 flag_kvant=1;
}

//=============================================================================
//                                  WatchDog
//=============================================================================
void InitWD (void)
{
#ifdef NDEBUG  
// Watchdog Timer initialization
// Watchdog Timer Prescaler: OSC/256k
WDTCR=0x1C;
WDTCR=0x0C; 
asm("wdr");
#endif
}
//=============================================================================
//                                  CAN
//=============================================================================
unsigned char ch; // MOb reset loop counter used for CAN initialization
unsigned char data; // MOb data reset loop counter used for CAN initialization
void InitCAN(void)
{
  J6 = 1;
  LEDC2 = 1;
// CAN Controller initialization
// CAN enabled
// Reset the CAN controller
CANGCON=0x01;
// Reset all the MObs
for (ch=0; ch<15; ch++)
    {
    CANPAGE=ch<<4;
    CANSTMOB=0;
    CANIDT1=0;
    CANIDT2=0;
    CANIDT3=0;
    CANIDT4=0;
    CANIDM1=0;
    CANIDM2=0;
    CANIDM3=0;
    CANIDM4=0;
    for (data=0; data<8; data++) CANMSG=0;
    }
// Enable the CAN controller
CANGCON=0x02;
// MOb0..7 Interrupts: MOb0: On, MOb1: On, MOb2: Off, MOb3: Off, MOb4: Off, MOb5: Off, MOb6: Off, MOb7: Off
CANIE2=0x03;
// MOb8..14 Interrupts: MOb8: Off, MOb9: Off, MOb10: Off, MOb11: Off, MOb12: Off, MOb13: Off, MOb14: Off
CANIE1=0x00;
// CAN Interrupts:
// Timer Overrun: Off
// General Errors: Off
// Frame Buffer: Off
// MOb Errors: On
// Transmit: On
// Receive: On
// Bus Off: Off
// All, except Timer Overrun: Off
CANGIE=0x38;
// CAN System Clock: 2000,0 kHz
CANBT1=0x06;//0x0E;
// Propagation Time Segement: 1,500 us
// Re-Sync Jump Width: 0,500 us
CANBT2=0x0C;//0x04;
// Sample Point(s): 3
// Phase Segment 1: 1,000 us
// Phase Segment 2: 1,000 us
CANBT3=0x37;//0x13;
// CAN Timer Clock Period: 0,500 us
CANTCON=0x00;



   //Настройка MOB0=RX на прием
  CANPAGE  = 0x00;               //Выбор номера Mob - в данном случае Mob0                                              
  CANSTMOB = 0x00;               //Очистка регистра состояния Mob
  CANCDMOB = 0x80;               //Настройка выбранного MOb на прием(bi7=1), выбор стандартного идентификатора(bit4=0),
                                 //установка длины данных 8 байт(bit3..0=1000)    
  if (UseID == ExtID)
    CANCDMOB |= (1<<4);
  else
    CANCDMOB &= ~(1<<4); 
  CANCDMOB |= RX_DATA_LEN;
    
  Set_ID(ID_RX,UseID);
  Set_Mask(0x1FFFFFFF, UseID);
                                                                
 /* CANIDM4 = 0x00;               //Принудительный положительный результат сравнения                                             
  CANIDM3 = 0x00;               //Принудительный положительный результат сравнения                                              
  CANIDM2 = 0xF0;               //Принудительный положительный результат сравнения                                              
  CANIDM1 = 0xFF;               //Принудительный положительный результат сравнения */  
  
  //Настройка MOb1=Tx на передачу
  CANPAGE  = 0x10;                //Выбор номера Mob в данном случае Mob1
  CANSTMOB = 0x40;                //Установка бита удачного завершения передачи TXOK, для 1-й передачи
  if (UseID == ExtID)
    CANCDMOB |= 1<<4;
  else
    CANCDMOB &= ~(1<<4);
    
  CANCDMOB |= TX_DATA_LEN;                //Разрешение передачи, длина данных 8 байт
  
 /* CANIDT4  = 0x00;                                                              
  CANIDT3  = 0x00;                                                               
  CANIDT2  = 0xE0;                //Идентификатор равен 7                                               
  CANIDT1  = 0x00;*/
  Set_ID(ID_TX,UseID);
  Set_Mask(0, UseID);
                                                                                
 /* CANIDM4  = 0x00;                                                                                       
  CANIDM3  = 0x00;                                                                                        
  CANIDM2  = 0x00;                                                                                        
  CANIDM1  = 0x00;*/                                                              
   
  CANGIE=0xB0;                  //Разрешение прерываний по приему,по передаче,по общим ошибкам, по ошибкам Mob
  
  CANEN2=0xff;                 //Разрешить все Mob
  CANEN1=0xff;
  CANIE2=0x03;                 //Разрешить прерывания только по Mob0 и Mob1
  CANIE1=0x00;
   
  CANHPMOB=0x00;               //Установка высшего приоритета для MOb0

  CANGCON |= 0x02;             //Разрешить контроллер CAN
  

J6 = 0;
LEDC2=0;
}

unsigned char datatx_buf[8];
unsigned char flag, i, fl_tx=0;
#define ENRX 5
#define RXOK 5
#define TXOK 6

void can_send (unsigned char n)
{

   CANGIE &= ~(1<<ENRX);                          //Запретить прерывание по приему

    CANPAGE = (n<<4);                              //Выбрать n-й канал, автоинкремент, местоположение байта данных в FIFO 0
    if (fl_tx)                      //Если бит TXOK регистра CANSTMOB установлен в 1
    {
        fl_tx = 0;//CANSTMOB &= ~(1<<TXOK);                    //Сбросить бит TXOK
        
        Set_ID(ID_TX,UseID);
        
        for(i = 0; i < TX_DATA_LEN; i++)
        {
            CANMSG = datatx_buf[i];                //Запись данных в регистр данных CAN
        }
        
        if (UseID == ExtID)
          CANCDMOB |= 1<<4;
        else
          CANCDMOB &= ~(1<<4);
        CANCDMOB |= TX_DATA_LEN;         //длина данных 8 байт
        CANCDMOB |= (1<<6);    //Разрешение передачи
        
    }

    CANGIE |=(1<<ENRX);                            //Разрешить прерывание по приему
}


unsigned char datarx_buf[8], fl_rx=0;
// CAN interrupt service routine
#pragma vector = CANIT_vect
__interrupt void can_isr(void)
{
// Place your code here 
    CANGIE &= (~(1<<ENRX));                   //Запретить прерывание по приему
 
    flag = CANSIT2;                           //чтение регистра состояния прерываний(того где Mob0 и Mob1)
    //-----------------------------------------------------
    if (flag & (1<<0))                        //Если прерывание по Mob0
    {
        J6 = 1; 
        LEDC2=1;
        CANPAGE=0<<4;                         //Выбор Mob0
        for(i = 0; i < RX_DATA_LEN; i++)
        {
          datarx_buf[i]=CANMSG;             //Считать регистр данных сообщения 8 раз
        }
        CANPAGE = 0<<4;                       //Выбор Mob0
        CANSTMOB &= ~(1<<RXOK);               //сбросить влаг удачного завершения приема
        CANSTMOB = 0;
        fl_rx = 1;
        CANCDMOB |= 0x80;                      //Разрешить прием
        
    }
   if (flag & (1<<1))                        //Если прерывание по Mob1
    {
       
      fl_tx = 1;
      CANPAGE = 1<<4;
      CANSTMOB &= ~(1<<TXOK);
      CANSTMOB = 0;
    }
    //------------------------------------------------------

  

// Reset all flags
 CANGIT = CANGIT;
 CANGIE |=(1<<ENRX);
}


//=============================================================================
//                                  MAIN
//=============================================================================
unsigned char tst=0;
unsigned int tst_cnt=0;
int main( void )
{
//  MCUCR |= 0x80;
   InitPorts();
   InitTimers();
   InitCAN();
   InitInt();
   InitWD();
   asm("sei");

   while (1)
   {
     eWDR=!eWDR;
     if (fl_rx)
     {
       fl_rx=0;
       CAN_NO_WR = 0;
       
       CAN_DO[0] = datarx_buf[0];
       CAN_DO[1] = datarx_buf[1];
       CAN_DO[2] = datarx_buf[2];
       if (datarx_buf[1]==0x1C)
         J5=!J5;
       else 
         J5=0;
       datatx_buf[0]=tst;
       datatx_buf[1]=CAN_DO[1];
       datatx_buf[2]=CAN_DO[2];
       
      // can_send(1);
     }
     
     
   if (flag_kvant)
   {
     flag_kvant = 0;
     
     LED1_CNT++;
     CAN_NO_WR++;
     tst_cnt++;
     
     if (CAN_NO_WR>=CAN_NO_WR_MAX)
     {
        CAN_NO_WR = CAN_NO_WR_MAX;
        for(i = 0; i < 8; i++)
        {
            datarx_buf[i]=0;
        }
        for(i = 0; i < 3; i++)
        {
            CAN_DO[i]=0;
        }          
          
        LED1_CNT_MAX = 200;
        J6 = 1;
        LEDC2 = 1;
     }
     else
     {
       LED1_CNT_MAX = 1000;
       J6 = 0;
       LEDC2 = 0;
       
     }
     

     
     if (tst_cnt>=50)
     {
       tst_cnt=0;
       tst++;
       datatx_buf[0]=tst;
       
      // CAN_TX=!CAN_TX;
      can_send(1);
       
     }

     if (LED1_CNT>=LED1_CNT_MAX)
     {
       LED1_CNT = 0;       
       LED1 = !LED1;
       LEDC1 = !LEDC1;
       
       
     }
       
   }
   asm("wdr");
  
   }
}
