#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define F_CPU 16000000 
#define SIZE_BUF 8

//кольцевой (циклический) буфер
volatile unsigned char usartTxBuf[SIZE_BUF];
unsigned char txBufTail = 0;      //"указатель" хвоста буфера 
unsigned char txBufHead = 0;  //"указатель" головы буфера
volatile unsigned char txCount = 0; //счетчик символов

uint8_t receive = 0;
uint8_t rx_data = 0;
volatile uint8_t rx_flag = 0;

void UARTInit(void) {
    UCSR1B=0; UCSR1C=0; // Обнулим, на всякий случай регистры статуса и контроля.
    UBRR0H = 0; // Старшие биты регистра скорости.
    UBRR0L = 103; //скорость передачи данных 9600
    UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(1<<TXCIE0)|(0<<UDRIE0);//Включаем (подключаем ножки контроллера) приём и передачу по UART.
    UCSR0C = (1<<UCSZ01)|(1<<UCSZ00); //8 bit
    

}

void UARTSend(uint8_t data) {
    while (!(UCSR0A & (1<<UDRE0))); // Ждём опустошения буфера передачи (читаем флаг).
    UDR0 = data; // Записываем в регистр значение переменной "data" для передачи.
}

//"очищает" буфер
void USART_FlushTxBuf(void)
{
  txBufTail = 0;
  txCount = 0;
  txBufHead = 0;

//положить символ в буфер
void USART_PutChar(unsigned char sym)
{
  if(((UCSRA0 & (1<<UDRE0)) != 0) && (txCount == 0)) //Если модуль USART не занят и передающий буфер пустой,
     UDR0 = sym;                                         //символ записывается в регистр UDR
  else {                                                      
    if (txCount < SIZE_BUF){                    //если в буфере еще есть место
      usartTxBuf[txBufTail] = sym;             //помещаем в него символ
      txCount++;                                     //инкрементируем счетчик символов
      txBufTail++;                                    //и индекс хвоста буфера
      if (txBufTail == SIZE_BUF) 
        txBufTail = 0;
    }
  }
}

//взять символ из буфера
unsigned char GetChar(void)
{
   unsigned char sym = 0;
   if (count > 0){                            //если буфер не пустой
      sym = cycleBuf[head];              //считываем символ из буфера
      count--;                                   //уменьшаем счетчик символов
      head++;                                  //инкрементируем индекс головы буфера
      if (head == SIZE_BUF) head = 0;
   }
   return sym;
}

//функция загрузки строк
void USART_SendStr(unsigned char * data)
{
  unsigned char sym;
  while(*data){         // пока не будет считан символ конца строки
    sym = *data++;
    USART_PutChar(sym);
  }
}
// unsigned char UARTGet() {
//     while(!rx_flag); //пока значение флага не станет равно "1"
//     rx_flag = 0;
//     return rx_data; //возвращет состояние переменной rx_data
// }

int main(void) {
    sei();
    UARTInit();
    DDRL = 0b11111111; // Определим порт "L" на выход
    while(1) {
        receive = UARTGet();
        receive++;
        UARTSend(receive);
    }
}

//обработчик прерывания по завершению передачи 
ISR(USART_TXC_vect) {
    if (txCount > 0){                              //если буфер не пустой
        UDR0 = usartTxBuf[txBufHead];         //записываем в UDR символ из буфера
        txCount--;                                      //уменьшаем счетчик символов
        txBufHead++;                                 //инкрементируем индекс головы буфера
        if (txBufHead == SIZE_BUF) 
          txBufHead = 0;
    }
    else {
        UCSR0B &= ~(0<<TXCIE0);
    }
    
    // rx_data = UDR0; //В нем данные из приемного буфера UDR переносятся в глобальную переменную rx_data
    // rx_flag = 1;  //выставляется флаг rx_flag, говорящий о том, что прием завершен
}
//прерывание по завершению приема
ISR (USART_RXC_vect) 
{
  if (rxCount < SIZE_BUF){                //если в буфере еще есть место                     
      usartRxBuf[rxBufTail] = UDR0;        //считать символ из UDR в буфер
      rxBufTail++;                             //увеличить индекс хвоста приемного буфера 
      if (rxBufTail == SIZE_BUF) rxBufTail = 0;  
      rxCount++;                                 //увеличить счетчик принятых символов
    }
}