/*****************************************************
Chip type               : ATtiny2313
AVR Core Clock frequency: 19,500000 MHz
Memory model            : Tiny
External RAM size       : 0
Data Stack size         : 32
*****************************************************/

#include <tiny2313.h>
#include <stdlib.h>
#include <math.h>


#ifndef RXB8
#define RXB8 1
#endif

#ifndef TXB8
#define TXB8 0
#endif

#ifndef UPE
#define UPE 2
#endif

#ifndef DOR
#define DOR 3
#endif

#ifndef FE
#define FE 4
#endif

#ifndef UDRE
#define UDRE 5
#endif

#ifndef RXC
#define RXC 7
#endif

#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<DOR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)

// USART Receiver buffer
#define RX_BUFFER_SIZE 8
char rx_buffer[RX_BUFFER_SIZE];

#if RX_BUFFER_SIZE<256
unsigned char rx_wr_index,rx_rd_index,rx_counter;
#else
unsigned int rx_wr_index,rx_rd_index,rx_counter;
#endif

// This flag is set on USART Receiver buffer overflow
bit rx_buffer_overflow;

// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{
char status,data;
status=UCSRA;
data=UDR;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
   {
   rx_buffer[rx_wr_index]=data;
   if (++rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0;
   if (++rx_counter == RX_BUFFER_SIZE)
      {
      rx_counter=0;
      rx_buffer_overflow=1;
      };
   };
}

#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+
char getchar(void)
{
char data;
while (rx_counter==0);
data=rx_buffer[rx_rd_index];
if (++rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0;
#asm("cli")
--rx_counter;
#asm("sei")
return data;
}
#pragma used-
#endif

// Standard Input/Output functions
#include <stdio.h>
char u=0,i,vol=0,df1=0,df2=0,df3=0,fase1=0,fase2=0,fase3=0;
char he=0,hfm=0,x[5];
long int finp;
// Declare your global variables here

flash const char ts[64]={128,140,153,165,177,188,199,209,218,226,234,240,245,250,253,254,
                          255,254,253,250,245,240,234,226,218,209,199,188,177,165,153,140,
                          128,116,103,91,79,68,57,47,38,30,22,16,11,6,3,2,
                          1,2,3,6,11,16,22,30,38,47,57,68,79,91,103,116};

char t[64];
// Timer 0 output compare A interrupt service routine
interrupt [TIM0_COMPA] void timer0_compa_isr(void)
{
   #asm
   in r15,sreg
   add r10,r9
   adc r13,r8
   adc r12,r11
   mov r26,r12
   andi r26,0x3f
   ldi r16,0x93
   add r26,r16
   ldi r27,0
   ld r16,x
   out 0x18,r16
   out sreg,r15
   #endasm
}

void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization
PORTA=0x00,DDRA=0x00;
PORTB=0x00,DDRB=0xFF;
PORTD=0x00,DDRD=0x00;

// Timer/Counter 0 initialization
// Clock value: 12000,000 kHz
// Mode: CTC top=OCR0A
TCCR0A=0x02,TCCR0B=0x01,TCNT0=0x00;
OCR0A=0x27,OCR0B=0x00;


// Timer/Counter 1 initialization
// Clock value: Timer1 Stopped
TCCR1A=0x00,TCCR1B=0x00,TCNT1H=0x00;
TCNT1L=0x00,ICR1H=0x00,ICR1L=0x00;
OCR1AH=0x00,OCR1AL=0x00,OCR1BH=0x00,OCR1BL=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
GIMSK=0x00;
MCUCR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x01;

// Universal Serial Interface initialization
// Mode: Disabled
// Clock source: Register & Counter=no clk.
// USI Counter Overflow Interrupt: Off
USICR=0x00;

// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: Off
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=0x00;
UCSRB=0x90;
UCSRC=0x06;
UBRRH=0x00;
UBRRL=0x7E;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;

for (i=0;i<64;i++)
   {
   t[i]=128+sign(ts[i]-128)*(cabs(ts[i]-128))>>vol;
   };

// Global enable interrupts
#asm("sei")

while (1)
      {
      while (!(getchar()==0xff)) {};                        //получение данных по usart
      he=getchar();                                         // ff-синхробайт
      vol=getchar();
      hfm=getchar();
      for (i=0;i<5;i++) x[i]=getchar();
      #asm("cli")                                           //формирование таблицы в RAM
      if (hfm==0)   //синус
        {
         for (i=0;i<64;i++)
           {
            t[i]=128+sign(ts[i]-128)*(cabs(ts[i]-128))>>vol;
           };
        };
      if(hfm==1)    //меандр
        {
          for (i=0;i<32;i++) t[i]=128+127>>vol;
          for (i=32;i<64;i++) t[i]=128-127>>vol;
          };
      if(hfm==2)    //треугольник
        {
          for (i=0;i<32;i++) t[i]=128+(i*8-127)>>vol;
          for (i=32;i<64;i++) t[i]=128+(127-(i-32)*8)>>vol;
          };
      if(hfm==3)     //пила нарастающая
        {
          for (i=0;i<64;i++) t[i]=128+(i*4-127)>>vol;
        };    
      if(hfm==4)     //пила спадающая
        {
          for (i=0;i<64;i++) t[i]=128+(127-i*4)>>vol;
          };
      if (!he) for (i=0;i<64;i++) t[i]=128;
        
      finp=10000*x[0]+1000*x[1]+100*x[2]+10*x[3]+x[4];     //расчет частоты
      if (finp<10000) DDRD.1=1;                            //подключение конденсаторов фильтра
         else DDRD.1=0;
      if (finp<3000) DDRD.2=1;
         else DDRD.2=0;
      if (finp<1000) DDRD.3=1;
         else DDRD.3=0;
      if (finp<300) DDRD.4=1;
         else DDRD.4=0;
      if (finp<100) DDRD.5=1;
         else DDRD.5=0;
      if (finp<30) DDRD.6=1;
         else DDRD.6=0;
      finp=finp*2202;
      df3=finp/0x01000000;                                 //вычисление приращения фазы
      df2=(finp-df3*0x01000000)/0x010000;
      df1=(finp-df3*0x01000000-df2*0x010000)/0x0100;
      #asm("sei")
      };
}
