#define F_CPU 16000000UL
#include <avr/io.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <util/delay.h>
#include <avr/interrupt.h>

inline void setbit(volatile uint8_t &reg, uint8_t bit)
{
  reg = reg | (1 << bit);
}

inline void clearbit(volatile uint8_t &reg, uint8_t bit)
{
  reg = reg & ~(1 << bit);
}

void USART0inicializace()
{
  UBRR0 = 103;  //9615 Bd
  //8bitovy znak, bez parity, povoleni vysilace a prijimace,
  //povoleni preruseni pri prijmu:
  UCSR0A = 0;
  UCSR0B = (1 << TXEN0) | (1 << RXEN0) | (1 << RXCIE0);
  UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
}

//pro odesilani textu:
static char odesilanytext[40];
volatile uint8_t odesilanyindex = 0;
volatile bool odeslano = true;
//pro prijem cisla:
volatile uint16_t cislo;
volatile bool novecislo = false;

void USART0posli(const char *text)
{
  if((odeslano) && (text[0] != '\0'))
  {
    strcpy(odesilanytext, text);  //kopie textu
    odesilanyindex = 0;  //priprava
    //spusti odesilani:
    odeslano = false;  
    setbit(UCSR0B, UDRIE0);
  }
}

//obsluha vyprazdneni vysilaciho registru:
ISR(USART0_UDRE_vect)
{
  if(!odeslano)
  {
    UDR0 = odesilanytext[odesilanyindex];
    odesilanyindex++;
    //test nasledujiciho znaku:
    if(odesilanytext[odesilanyindex] == '\0')
    {
      //zablokuje dalsi odesilani:
      odeslano = true;  
      clearbit(UCSR0B, UDRIE0);
    }      
  }
}

//obsluha prijmu:
ISR(USART0_RX_vect)
{
  static uint8_t pocitadlo = 0;  //pocitadlo bajtu
  
  pocitadlo++;
  switch(pocitadlo)
  {
    case 1:  //1. bajt
      cislo = UDR0;
      break;
    case 2:  //2. bajt
      cislo = (cislo << 8) | UDR0;
      novecislo = true;
      pocitadlo = 0;
      break;
  }
}

int main(void)
{
  char zprava[40];
  
  USART0inicializace();
  sei();
  
  while (1)
  {
    if(novecislo && odeslano)
    {
      sprintf(zprava, "cislo = 0x%04x\n", cislo);
      USART0posli(zprava);
      novecislo = false; 
    }
  }
}

